题目要求:假设你手中已有 STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿蓝LED,并搭建了电路,分别GPIOA-5、GPIOB-9、GPIOC-14 这3个引脚上控制LED灯(最高时钟2Mhz),轮流闪烁,间隔时长1秒。
一、程序设计
stm32点灯是通过使能外设GPIO时钟,发出指令给外设GPIO,外设GPIO收到指令后,着手配置自己的寄存器,然后给IO口模式,从而实现各种功能。其过程大致如下: CPU给指令→GPIO收到指令→配置内部寄存器→配置IO口模式→控制LED灯亮灭
(一)配置时钟效能
因为默认的时钟都是关闭的,所以在配置STM32之前必须先配置时钟。 时钟控制叫做RCC,是属于AHB总线的,我们使用的GPIOA/B/C端口都是属于APB2。
以GPIOA口为例,GPIO端口A的地址从0x4001 0800开始,从手册中可以得知复位和时钟控制RCC的地址从0x4002 1000开始,再找到APB2的外设时钟使能寄存器,可以看出其偏移地址为0x18,所以APB2的地址就是0x4002 1018。 根据手册可以知道IO端口B时钟使能是RCC_APB2ENR的位2,将RCC_APB2ENR位的2赋值为1,就能开启GPIOA时钟
#define RCC_AP2ENR ((unsigned volatile int)0x40021018) RCC_AP2ENR|=1<<2; //APB2-GPIOA外设时钟使能
(二)配置为通用输出
由于STM32的每个IO端口都需要4个位来配置,所以一个32位的寄存器最大只能配置8个IO端口。STM32中,用端口配置低寄存器(GPIOx_CRL)来配置引脚Px0-Px7,用端口配置高寄存器(GPIOx_CRH)来配置引脚Px8-Px15。 以本次实验用到的PA5为例,使用的寄存器为GPIOA_CRL。 如下图所示,偏移地址为0x00,意思是在基地址的基础上再加0x00,所以对于GPIOA来说就是0x4001 0800。配置PA5需要的寄存器是低位的寄存器GPIOA_CRL,其地址是0x4001 0800,找到需要操作的寄存器后,将其配置为通用输出。 将LED灯点亮需要输出低电平,所以我们需要找到端口输出数据寄存器,将第5位输出为0。(此处中文版端口输出数据寄存器地址偏移为0Ch,而英文版为0x0C)
#define GPIOA_CRL * ((unsigned volatile int*)0x40010800) #define GPIOA_ODR * ((unsigned volatile int*)0x4001080C) GPIOA_CRL&=0xFF0FFFFF; //设置位清零 GPIOA_CRL|=0X00200000; //PA5推挽输出 GPIOA_ODR|=1<<5; //设置PA5初始灯为灭
GPIOA的基本配置如上,其它口的配置可查询手册如上即可,再加上延迟函数即可实现流水灯。
二、C语言 寄存器方式实现编程
(一)启动文件
1.启动文件简介
启动文件由汇编编写,是系统上电复位后第一个执行的程序。主要做了以下工作:
1、初始化堆栈指针SP=_initial_sp 2、初始化PC 指针=Reset_Handler 3、初始化中断向量表 4、配置系统时钟 5、调用C 库函数_main 初始化用户堆栈,从而最终调用main 函数去到C 的世界
2.启动文件的选择
ST提供的3个启动文件,分别适用于不同容量的STM32芯片。 这三个文件为: startup_stm32f10x_ld.s startup_stm32f10x_md.s startup_stm32f10x_hd.s 其中,ld.s适用于小容量 产品;md.s适用于中等容量产品;hd适用于大容量产品; 这里的容量是指FLASH的大小判断方法如下: 小容量:FLASH≤32K 中容量:64K≤FLASH≤128K 大容量:256K≤FLASH 所以,大家需要根据自己所用的STM32芯片选择不同的.s文件。 此处查阅《STM32F103中文教程及参考手册》可知,C8T6的Flash容量为128K,属于中容量,因此这里采用 startup_stm32f10x_md.s作为启动文件。
(二)创建项目
1.打开Keil,创建项目:
2.选择STM32F103C8开发板,点击"OK": 3.右键点击Source Group1,然后选中Add New item to ‘Group…’,添加"C File (.c)"文件Text1:
5.添加启动文件
(三)代码编写
#define RCC_AP2ENR *((unsigned volatile int*)0x40021018)
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
#define GPIOA_ODR *((unsigned volatile int*)0x4001080C)
#define GPIOB_CRH *((unsigned volatile int*)0x40010C04)
#define GPIOB_ODR *((unsigned volatile int*)0x40010C0C)
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
#define GPIOC_ODR *((unsigned volatile int*)0x4001100C)
void SystemInit(void);
void Delay_ms(volatile unsigned int);
void A_LED_LIGHT(void);
void B_LED_LIGHT(void);
void C_LED_LIGHT(void);
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
void A_LED_LIGHT(){
GPIOA_ODR=0x0<<5;
GPIOB_ODR=0x1<<9;
GPIOC_ODR=0x1<<14;
}
void B_LED_LIGHT(){
GPIOA_ODR=0x1<<5;
GPIOB_ODR=0x0<<9;
GPIOC_ODR=0x1<<14;
}
void C_LED_LIGHT(){
GPIOA_ODR=0x1<<5;
GPIOB_ODR=0x1<<9;
GPIOC_ODR=0x0<<14;
}
int main()
{
int j=100;
RCC_AP2ENR|=1<<2;
RCC_AP2ENR|=1<<3;
RCC_AP2ENR|=1<<4;
GPIOA_CRL&=0xFF0FFFFF;
GPIOA_CRL|=0X00200000;
GPIOA_ODR|=1<<5;
GPIOB_CRH&=0xFFFFFF0F;
GPIOB_CRH|=0x00000020;
GPIOB_ODR|=0x1<<9;
GPIOC_CRH&=0xF0FFFFFF;
GPIOC_CRH|=0x02000000;
GPIOC_ODR|=0x1<<14;
while(j)
{
A_LED_LIGHT();
Delay_ms(1000000);
B_LED_LIGHT();
Delay_ms(1000000);
C_LED_LIGHT();
Delay_ms(1000000);
}
}
void SystemInit(){
}
(四)修改参数
1.生成HEX文件,运行程序时生成的相关的hex文件用于烧录到开发板上
2.改为相关芯片
(五)编译调试
1.进行编译时出现了以下错误: 出现该错误的原因是因为工程中包含了不止一个启动文件导致的。 这时需要在工程环境里找到Startup的驱动,将该驱动的√去掉,具体步骤如下图所示:
修改后重新编译即可: 2.调试时出现以下问题: 解决方法如下: 重新调试即可:
(六)波形图观察
1.在上述步骤调试过程中,点击下图图标后,点击Logic Analyzer
2.添加要观察的引脚,Display Type需要修改为Bit,输入引脚有三种方法,以PA5口为例: ①观测PA5口输入(PORTA&0x00000020)>>5; ②直接输入PORTA.5回车即可得到上述格式; ③输入PORTA回车后,点击Current Logic Analyzer Signals后在Shift Right中输入5。 3.相关设置
4.运行程序,观察波形图 引脚为低电平的灯亮,高电平的不亮。根据上面两个图可以观察到,PB9端口的灯在1.125159秒开始亮,在2.250163秒的时候熄灭,LED灯闪烁周期约为1秒。
三、安装STM32CubeMX软件+HAL库实现编程
(一)安装JRE、STM32CubeMX、HAL库
1.安装JRE 由于STM32CubeMX软件是基于JAVA环境运行的,所以需要安装JRE(Java Runtime Environment)才能使用,安装链接如下: https://www.java.com/en/download/manual.jsp 点击安装: 安装完成点击关闭: 2.安装STM32CubeMX 下载地址(官网中文): https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-configurators-and-code-generators/stm32cubemx.html#get-software 选择版本进行下载(需要提供邮箱账号,根据邮件的网址进行下载):
点击“NEXT”:
勾选“I accept the……”然后点击“NEXT”:
勾选"I have read ……",点击“NEXT”:
点击“NEXT”:
点击“Done": 3.安装HAL库
①打开STM32CubeMX.exe ②点击"Help"打开“Manage embedded software packages"(打开以后未出现安第三步骤的内容时,点击“Refresh”等待即可): ③根据持有的芯片类型选择对应芯片类型、对应固件类型版本,然后点击"Install"等待即可:
(二)完成初始化实现编程
1.在STM32CubeMX中新建项目 2.在Commercial Part Number中选择芯片类型,然后点击 Start Project,具体步骤如下所示: 3.点击System Core,进入SYS,在Debug下选择serial wire: 4.配置时钟,在Clock Configuration中选中PLLCLK 进入RCC中,在HSE中设置为Crystal/… 5.接下来就是点击相应的引脚设置输出寄存器,即output那一项,一共选择3个,为PA5、PB9、PC14 6.点击project manager,配置好自己的路径(注意:不要出现中文和空格否则后续步骤中将出现报错,如第七步)和项目名,然后IDE改为MDK-ARM 7.进入code generate界面,选择初始化.c/.h文件,然后点击generate code 在点击generate code后出现以下报错,原因是因为上述步骤中路径中出现了中文(空格也不行),重新修改路径即可 此处直接修改路径但未成功,因此重新操作上述步骤,最终成功,点击Open Project,然后就会进入KEIL 8.添加代码,代替在main.c文件中主函数内容:
SystemClock_Config();//系统时钟初始化 MX_GPIO_Init();//gpio初始化 while (1) { HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);//PA5亮灯 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);//PB9熄灯 HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);//PC14熄灯 HAL_Delay(1000);//延时1s HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//PA5熄灯 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);//PB9亮灯 HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);//PC14熄灯 HAL_Delay(1000);//延时1s HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//PA5熄灯 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);//PB9熄灯 HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);//PC14亮灯 HAL_Delay(1000);//延时1s }
(三)观察GPIO端口的输出波形
1.在Target界面中选择正确的晶振大小,如果选择错误,则波形错误,时间不准确 2.Debug页设置: 3.编译 4.调试 5.观察GPIO端口的输出波形(操作可参考本文上述寄存器实现编程的波形图观察步骤) 引脚为低电平时灯亮,高电平时灯不亮,上图以端口PA5为例,可以看出LED灯闪烁周期为1秒
四、总结
对比寄存器方式实现流水灯和STM32CubeMX+KEIL+HAL库实现流水灯的代码编写部分,可以明显看出后者代码编写的少一点,运用后者更容易实现流水灯仿真。运用STM32CubeMX+KEIL+HAL库能自动生成代码,只需要加入主函数代码即可,能够有效减少代码编写的烦恼。
五、参考文献
http://t.csdn.cn/rBbz4 https://blog.csdn.net/weixin_43778388/article/details/122136509 https://blog.csdn.net/Hxm1998/article/details/113066766 https://blog.csdn.net/darkchipman0/article/details/115455332 http://t.csdn.cn/SLkcJ
|