StartKit_NB开发板是中国电信基于意法半导体公司的 MCU 和移远的 NBIOT 通信模组开发的开发板。MCU 采用的意法半导体公司的 STM32F103系列芯片,通信模组采用移远的低功耗 NBIOT 模组,开发者通过使用板载的ST-LINK 功能可以实现对主控 MCU 进行程序的下载及调试。开发板上包含有按键、SWD 调试接口、USB 接口、RGB 三色灯、马达、温湿度传感器、红外传感器、扩展 IO、调试串口等功能。具体功能分布如下图所示:
STM32是一个微控制器产品系列的总称,这个系列中已经包含了多个子系列,分别是:STM32小容
量产品、STM32中容量产品、STM32大容量产品和STM32互联型产品。
STM32主要有如下几个方面的特点:
1, 超低的价格。以 8 位机的价格,得到 32 位机,是 STM32 最大的优势。
2, 超多的外设。STM32 拥有包括:FSMC、TIMER、SPI、IIC、USB、CAN、IIS、SDIO、
ADC、DAC、RTC、DMA 等众多外设及功能,具有极高的集成度。
3, 丰富的型号。目前STM32 仅 M3 内核就拥有 F100、F101、F102、F103、F105、F107、F207、
F217 等 8 个系列上百种型号,具有 QFN、LQFP、BGA 等封装可供选择。同时 STM32
还推出了 STM32L 和 STM32W 等超低功耗和无线应用型的 M3 芯片。
4, 优异的实时性能。84 个中断,16 级可编程优先级,并且所有的引脚都可以作为中断输
入。
5, 杰出的功耗控制。STM32 各个外设都有自己的独立时钟开关,可以通过关闭相应外设
的时钟来降低功耗。
6, 极低的开发成本。STM32 的开发不需要昂贵的仿真器,只需要一个串口即可下载代码,
并且支持 SWD 和 JTAG 两种调试口。SWD 调试可以为你的设计带来跟多的方便,只
需要 2 个 IO 口,即可实现仿真调试
该开发板使用的是STM32F103CB型号,其中C代表48脚,B代表闪存存储器容量为128K。
库函数进行编程,操作对象是调用STM封装好的库函数,固件库就是函数的集合,固件库函数的作用是向下负责与寄存器直接打交道,向上提供用户函数调用的接口(API)。比如要控制某些 IO 口的状态,官方库封装了一个函数。
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
GPIOx->BRR = GPIO_Pin;
}
这个时候就不需要再直接去操作寄存器了,你只需要知道怎么使用这个函数就可以了。
GPIO_ResetBits()
该库函数怎么使用,可以在keil5中打开STM32官方提供的固件库中 stm32f10x_gpio.h然后找到该函数处,可以看到该函数的用法。
在对外设的工作原理有一定的了解之后,再去看固件库函数,基本上看函数名字就能知道这个函数的功能是什么。
在51单片机中,使用的是寄存器位操作的开发模式,比如要控制某个IO口的状态,常使用以下程序:
sbit led=P1^3;
led=1;
而开发者转而想进一步学习 STM32 开发,显然对于STM32 这种级别的 MCU,数百个寄存器不容易清楚的记忆并加以使用,但并不是不可以继续使用寄存器编程的方法,在STM32中使用寄存器编程控制IO口可使用如下例程;
GPIOx->BRR = 0x0011;
此处操作的是BRR寄存器实现电平控制,但是这种方法的劣势是你需要去掌握每个寄存器的用法,你才能正确使用STM32。与前面库函数编程方法相比较,库函数开发就不需要再直接去操作 BRR 寄存器了,只需要知道怎么使用 GPIO_ResetBits()这个函数就可以了。
开发软件使用keil5,搭建好开发环境,此处应先建立一个通用的库函数开发环境模板,以后直接复制此模板,即可在此基础上进行二次开发,实现自己的业务代码。新建文件夹开发环境模板,然后依次在该文件夹下新建以下文件,如图6所示。然后点击 MDK 的菜单:Project –>New Uvision Project ,然后将目录定位到刚才建立的开发环境模板 之下的子文件夹 USER,我们的工程文件就都保存到 USER 文件夹下面。工程命名为自己想做的工程名字,点击保存,如图1所示。CORE 用来存放核心文件和启动文件。如图2所示,OBJ 是用来存放编译过程文件以及hex文件,STM32F103文件夹顾名思义用来存放 ST 官方提供的库函数源码文件,如图5所示。SYSTEM此文件夹里面的代码由 ALIENTEK 提供,是STM32F10x 系列的底层核心驱动函数,可以用在STM32F10x 系列的各个型号上面,方便快速构建自己的工程。SYSTEM 文件夹下包含了 delay、sys、usart 等三个文件夹,如图3所示。分别包含delay.c、sys.c、usart.c及其头文件。通过这 3 个 c 文件,可以快速的给任何一款STM32F1 构建最基本的框架。 USER 目录除了用来放工程文件外,还用来存放主函数文件 main.c,以及其他包括system_stm32f10x.c 等等,如图4所示。
以上操作完成后,在keil内把各文件的路径添加进来(keil无法自主寻找所建立文件的地址,编译时会报错)。然后编译一次,该工程模板就建立完成了。
图1. 新建工程
图2.CORE内文件
图3. SYSTEM内文件
图4. USER内文件
图5. STM32F103内文件
图6.需新建的文件夹
根据外设LED灯的原理,我们需要利用IO口每间隔一段时间翻转一次高低电平,那么此时与单片机相连接的LED灯,就会间断亮灭,如果两个LED灯,不同时亮灭,就形成了跑马灯的效果。在编写时先对IO口初始化,和IO口使能端的设定,同时此程序还应用到延时函数。
首先新建一个led.h文件,文件内代码如下。
#ifndef __LED_H
#define __LED_H
void led_init(void);
#endif
然后新建一个led.c文件,接着在该工程一级目录下新建HAREWARE文件,存放我们自己定义的库函数,方便一会自己调用,不要忘记在KEIL中手动添加该文件的地址。
在led.c中,输入以下代码。该段代码为自定义的对led进行初始化的函数,以后如果在用到该LED,可直接在该工程里调用。
#include "led.h"
#include "sys.h"
void led_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //配置该外设的时候先配置使能端
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //将IO口设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口翻转速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIO,PB5脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PE.5端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //将IO口设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口翻转速度为50MHz
GPIO_Init(GPIOE, &GPIO_InitStructure); //根据设定参数初始化GPIO,PE5脚
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);
在配置 STM32 外设的时候,任何时候都要先使能该外设的时钟。GPIO 是挂载在 APB2 总线上的外设,在固件库中对挂载在 APB2 总线上的外设时钟使能是通过函数 RCC_APB2PeriphClockCmd()来实现的。这行代码的作用是使能 APB2 总线上的 GPIOB 和 GPIOE 的时钟。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //将IO口设置为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口翻转速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIO,PB5脚
这四行代码是对PB5脚初始化,使用的是GPIO_Init函数,双击该函数,然后点击鼠标右键,选择go to definition,即可跳转到相关文件,查看该函数的使用方法。同样的对于PE5引脚的初始化操作也是相似的原理。只需要把函数中的引脚由PB5改为PE5即可。
在主函数中,我们需要在USER中的main.c中编写,首先是调用头文件,因为刚才的初始化函数需要用到,且在led.h中,其他所用到的函数均在stm32f10x.h和sys.h中,所以首先应写的代码是头文件的调用,如下所示。
#include "stm32f10x.h"
#include "LED.h"
#include "sys.h"
接着编写延时函数。此处的延时函数也可以采取类似于上小节对于led初始化函数的使用方法,建立单独的头文件,方便以后调用。
void Delay(u32 count)
{
u32 i=0;
for(;i<count;i++);
}
然后进入主函数,进入后,先调用led初始化函数对相应的IO口进行初始化,然后进入while死循环,对两个引脚分别使用**GPIO_ResetBits()函数和GPIO_SetBits()函数,这两个函数的用法可参照上小节对于GPIO_Init()函数的使用方法介绍。其中GPIO_ResetBits()**先对PB5脚置为低电平,**GPIO_SetBits()**对PE5脚置于高电平,形成的效果就是两个LED灯不同时处于工作状态,经过延时函数后,后边的函数就是将LED灯的工作状态相反,然后进入延时函数,继而循环往复,就形成了跑马灯效果。
int main(void)
{
void led_init(void);
while(1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
GPIO_SetBits(GPIOE,GPIO_Pin_5);
Delay(3000000);
GPIO_SetBits(GPIOB,GPIO_Pin_5);
GPIO_ResetBits(GPIOE,GPIO_Pin_5);
Delay(3000000);
}
}