ST意法半导体生产的32位MCU(微控制器)
硬件
NB-loT通信扣板:SMA天线,NB86-G通信模块,STM32F0主控芯片,外部晶振
一键还原底板:供电电路,LED指示灯,电源开关,五向按键,复位按键,USB串口(Mini USB)
LCD扣板:128*128像素的16位彩色LCD 屏幕
锂电池(蓝色串口线使用USB接口进行充电)
USB数据线(蓝色):充电,查看串口打印
ST-link:烧写器,将程序和数据烧写到芯片内部的Flash中,调试。
烧写器转接板
开发环境
Keil MDKv5:uVision IDE,调试器,编译器,中间件(函数库),设备软件包。
注意:1.安装路径中不要出现空格或者中文字符。
2.使用管理员运行安装程序。
3. 对于STMF0系列的处理器商业和非商业使用免费,对其他系列处理器非商业使用免费(社区版)社区版注册:MDK-Community edition
4. 芯片软件包(Keil.STM32F0xx_DFP.2.1.1.pack):
下载:MDK5 Device List (keil.com),双击安装,安装路径中不要有中文字符。
5. ST-Link烧写器驱动(STSW_LINK009_V2.0.1.zip):
1. 驱动下载:https://www.st.com/en/development-tools/st-link-v2.html
2. 先解压缩,双击(dpinst_amd64.exe)安装
3. 安装成功后,连接ST-Link硬件,可以在设备管理器中看到对应设备

6.安装补丁:解决MDK5.38版本使用ST-Link闪退问题,MDK uVision crashes when using ST-Linkdebugger (arm.com),将压缩包内的dll文件复制到keil安装目录中的ARM\STLink目录下,覆盖同名文件。
7. STM32CubeMX工具:生成工程框架和初始化代码。
1. 下载:https://www.st.com/en/development-tools/stm32cubemx.html
2. 安装:安装路径中不能出现中文字符。
芯片型号:STM32F051K8U6

芯片资料:
英文官网:www.st.com
中文社区:www.stmcu.org.cn
点灯
验证开发环境和硬件是否能够正常工作。


MDK5.38只支持ARMCC版本6编译器,需要修改工程编译器版本

while(1)
{//开灯HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, GPIO_PIN_RESET);HAL_Delay(500);//关灯HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, GPIO_PIN_SET);HAL_Delay(500);
}
工程目录说明:
IOC文件:
STM32CubeMX的工程文件,CubeMX中配置数据保存在此文件中。
2.MDK-ARM目录:
MDK工程文件:扩展名uvprojx
芯片启动代码:startup_stm32f051x8.s
DebugConfig:调试配置信息
以工程命名的目录:编译生成的文件
RTE:工程使用的组件配置
CRF文件:代码跳转使用
AXF文件:编译生成的可执行文件(ELF)
SCT文件:分散加载描述文件(连接器,_main函数)
3.Core目录:
Inc:用户的头文件
src:用户的源代码
mian.c:存放main函数
stm32f0xx_it.c:存放中断处理函数
stm32f0xx_hal_msp.c:存放板级初始化代码
4.Drivers目录:
CMSIS:Common Microcontroller Software Interface Standard,定义芯片级的函数接口(函数名,类型,寄存器定义)
STM32F0xx_HAL_Driver: STM32的固件库。
四种开发方式:
直接操作寄存器
标准外设库
HAL库
LL库
优化工程占用磁盘空间

芯片手册
选型手册(Selection Guide)
数据手册(data sheet)
参考手册(Reference Manual)
编程手册(Programming manual):指令集,CPU寄存器,CPU核心外设
勘误表(Errata sheet):芯片的已知问题和规避方法。
应用手册
芯片启动流程

当BOOT0引脚为低电平时,将芯片内部的Flash映射到0地址,CPU直接从Flash芯片取指令运行。
当BOOT0和BOOT1引脚都为搞电平时,将芯片内部的ROM映射到0地址,CPU执行ROM中预先烧录的代码。(串口下载)
当BOOT0为高电平,BOOT1低电平,将芯片内部的RAM映射到0地址,CPU从RAM中取指令运行。
CPU启动后从0地址获取栈顶指针,从Flash的第4个字节取指令运行。
程序默认栈大小1024字节。
使用STM32CubeMX修改堆和栈空间大小。

CPU执行的第一个函数Reset_Handler
Reset_Handler调用SystemInit函数
Reset_Handler调用_main函数,根据分散加载文件将数据从Flash复制到RAM中。
_main调用用户的main函数
STM32F0是基于ARM Cortex-M0系列的处理器,使用Thumb指令集,不是ARM指令集。
MX前缀的函数是根据CubeMX中的配置生成的函数。
STM32中一个GPIO控制器可以控制16个引脚。
GPIO控制器原理图

GPIO输出模式
推挽(Push Pull):既可以输出高电平,也可以输出低电平
开漏(Open Drain):只能输出低电平,不能输出高电平(i²c)
处理器运行模式
处理模式Handler:不使用操作系统时,都运行在此模式下,使用MSP(R13)保存栈顶地址。
线程模式Thread:使用操作系统时,任务运行在此模式下,中断处理函数运行在Handler模式下,使用PSP(R13)保存栈顶地址。
注意:在CubeMX生成的文件中,修改代码必须放在“USER CODE BEGIN”和“USER CODE END”注释中间,否则重新生成代码时会被CubeMX删除。
GPIO输出
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin, GPIO_PinState PinState);
//参数1:GPIO控制器寄存器组的起始地址
//参数2:控制引脚的掩码
//参数3:输出电平
HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, GPIO_PIN_SET);
延时函数
void HAL_Delay(uint32_t Delay);
//参数:延时时间,单位毫秒
设置MDK编辑器支持中文

时钟树配置
STM32芯片内部集成了时钟振荡电路(阻容式RC)
F051K8芯片内部有3个时钟源:低速内部LSI(40KHz),高速内部HSI(8MHz),HSI14(14MHz)
阻容式振荡电路精度不高并且容易受外部温度的影响,造成时钟周期变化,一般只在芯片上电或外部时钟源失效时使用。
在系统运行过程中,使用外部晶振作为时钟源,精度更高。
启用外部时钟源(高速外部HSE):

设置CPU的运行频率为48MHZ

生成代码时,CubeMX会将时钟树配置生成到SystemClock_config()函数中。
系统定时器(SysTick)
HAL库的延时函数默认使用系统定时器实现。
SystemClock_Config()函数在配置完时钟树之后,根据CPU主频配置系统定时器,每毫秒发送一次中断到CPU。
每次调用系统定时器中断处理函数SysTick_Handler(),将全局变量uwTick的值加1,因此此变量中记录的是系统启动后经过的时间(单位毫秒)
HAL_Delay()函数中获取当前时间与调用起始时间相减,如果小于等待时间就执行空循环,否则退出循环完成延时操作。
串口的使用


发送数据
HAL_StatusTypeDef
HAL_UART_Transmit(UART_HandleTypeDef
*huart, uint8_t *pData, uint16_t Size,
uint32_t Timeout);
//参数1:串口控制器的句柄(对象)
//参数2:发送数据的起始地址
//参数3:发送数据长度
//参数4:发送超时时间(单位毫秒),不超时
(HAL_MAX_DELAY)
//返回值:
HAL_OK 成功
HAL_ERROR 失败
HAL_BUSY 上次发送未完成
HAL_TIMEOUT 发送超时
//向串口发送OK和换行,不超时
HAL_UART_Transmit(&huart1,(uint8_t*)"OK\r\n", 4, HAL_MAX_DELAY);
接收数据
HAL_StatusTypeDef
HAL_UART_Receive(UART_HandleTypeDef *huart,uint8_t *pData, uint16_t Size, uint32_t Timeout);
使用标准IO函数
定义fputc()和fgetc()函数,重定向标准输出和输入到串口1,fputc函数由printf函数自动调用,fgetc()函数由scanf函数自动调用。
//将标准输出重定向到串口1
int fputc(int c, FILE* fp)
{if (fp == stdout){HAL_UART_Transmit(&huart1,(uint8_t*)&c, 1, HAL_MAX_DELAY);}return c;
}
//将标准输入重定向到串口1
int fgetc(FILE* fp)
{uint8_t c = EOF;if (fp == stdin){//如果没读到数据,返回EOFif (HAL_UART_Receive(&huart1, &c, 1,100) != HAL_OK){return EOF;}}return c;
}
包含标准IO头文件
/* USER CODE BEGIN Includes */
#include <stdio.h>
/* USER CODE END Includes */
在main函数中调用标准IO函数输出字符串到串口1,从串口1读取字符串并回显。
/* Initialize all configured peripherals*/
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
//向串口1发送数据
puts("OK");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */while (1)
{char line[80] = {0};if (fgets(line, sizeof line, stdin) != NULL){printf("%s", line);}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
链接C语言标准库
