目录
一、寄存器是什么
根据百度百科介绍,寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。
简单来说,寄存器就是存放东西的东西。从名字来看,跟火车站寄存行李的地方好像是有关系的。只不过火车站行李寄存处,存放的行李;寄存器可能存放的是指令、数据或地址。
个人理解:给CPU存储东西的地方。等CPU转到寄存器这个地方的时候,就拿出寄存器里存放的东西,或是根据寄存器里的命令做一些事情。比如厨房就是个寄存器,负责做饭。仓库也是个寄存器,负责存东西。需要某些功能的时候,就要操作某个寄存器。可以把寄存器类比为,有特殊功能的地方,既然是个地方当然就有地址了,所以,可以把寄存器想象为特殊的地址。
二、寄存器地址映射和寄存器映射原理
1.寄存器地址映射
地址映射:由百度词条可知为了保证CPU执行指令时可正确访问存储单元,需将用户程序中的逻辑地址转换为运行时由机器直接寻址的物理地址,这一过程称为地址映射。
2.寄存器映射原理
由于32位的STM32最大寻址能力位32位,那么2^32为4GB,于是只要拿到这个内核进行外设的时候内存均不能超过4GB。并且在这4GB内,ARM已经进行了分类:
在存储器的区域单元中,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到每个单元的起始地址,然后通过 C 语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
三、用C语言实现LED流水灯
假设你手中已有 STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿LED,并搭建了电路,分别GPIOA-5、GPIOB-9、GPIOC-14 这3个引脚上控制LED灯(最高时钟2Mhz),轮流闪烁,间隔时长1秒。
GPIO端口的初始化
1、时钟配置
本次实验采用GPIOA、B、C三个端口。由下图分析得,该三个端口都属于APB2总线。
找到时钟使能寄存器映射基地址
定义宏使得使能对应端口时钟
//----------------APB2使能时钟寄存器 ---------------------
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
RCC_APB2ENR|=1<<2|1<<3|1<<4; //APB2-GPIOA、GPIOB、GPIOC外设时钟使能
2、输入输出模式设置
我们这次实验采用通用推挽输出模式,最高输出时钟频率2Mhz。分别用到A5、B9、C14三个引脚。其中A5属于端口配置低寄存器偏移地址为0x00,B9、C14属于端口配置高寄存器偏移地址为0x04。
配置对应引脚寄存器,基地址+偏移量
//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRL *((unsigned volatile int*)0x40010C04)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
设置输出模式为推挽输出,输出速度为2Mhz
GPIOA_CRL&=0xFF0FFFFF; //设置位 清零
GPIOA_CRL|=0x00020000; //PA4推挽输出,把第23、22、21、20位变为0010
GPIOB_CRL&=0xFFFFFF0F; //设置位 清零
GPIOB_CRL|=0x00200000; //PB5推挽输出,把第7、6、5、4变为0010
GPIOC_CRH&=0xF0FFFFFF; //设置位 清零
GPIOC_CRH|=0x00200000; //PC14推挽输出,把第27、26、25、24变为0010
C语言实现流水灯
原理:
本次实验采用三个灯实现,亮灯状态用1表示,灭灯状态用0表示。
初始状态为0 0 0,
状态一为1 0 0
状态二为0 1 0
状态三为0 0 1
状态三结束后继续进入状态一,一直循环达到流水灯效果。
代码实现:
打开keil软件,写入代码,具体操作参考下面:
https://blog.csdn.net/m0_50257213/article/details/127206815
代码:
#include "stm32f10x.h"
//----------------APB2使能时钟寄存器 ---------------------
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
#define GPIOA_ODR *((unsigned volatile int*)0x4001080C)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRH *((unsigned volatile int*)0x40010C04)
#define GPIOB_ODR *((unsigned volatile int*)0x40010C0C)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
#define GPIOC_ODR *((unsigned volatile int*)0x4001100C)
//延时函数
void Delay()
{
u32 i=0;
for(;i<2000000;i++);
}
int main(void)
{
RCC_APB2ENR|=1<<2; //APB2-GPIOA、GPIOB、GPIOC外设时钟使能
RCC_APB2ENR|=1<<3; //APB2-GPIOA、GPIOB、GPIOC外设时钟使能
RCC_APB2ENR|=1<<4;
GPIOA_CRL&=0xFF0FFFFF; //设置位 清零
GPIOA_CRL|=0x00300000; //PA5推挽输出,把第23、22、21、20位变为0010
GPIOA_ODR |= 1<<5; //设置初始灯为灭
GPIOB_CRH&=0xFFFFFF0F; //设置位 清零
GPIOB_CRH|=0x00000020; //PB9推挽输出,把第7、6、5、4变为0010
GPIOB_ODR |= 1<<9; //设置初始灯为灭
GPIOC_CRH&=0xF0FFFFFF; //设置位 清零
GPIOC_CRH|=0x02000000; //PC14推挽输出,把第27、26、25、24变为0010
GPIOC_ODR |= 1<<14; //设置初始灯为灭
while(1){
//A灯 //PA5高电平
GPIOA_ODR&=~(1<<5); //PA5低电平,因为是置0,所以用按位与
Delay();
GPIOA_ODR|=1<<5;
//B灯 //PB9高电平
GPIOB_ODR&=~(1<<9); //PB9低电平,因为是置0,所以用按位与
Delay();
GPIOB_ODR|=1<<9;
//C灯
GPIOC_ODR&=~(1<<14); //PC14低电平,因为是置0,所以用按位与
Delay();
GPIOC_ODR|=1<<14; //PC14高电平
}
}
void SystemInit(void){
}
注意我们使用的引脚是PA5,PB9,PC14
在编译之前,应勾选生成.hex文件,如下图
硬件连接
线路连接
电源接3.3v,小灯泡长的那根引脚接在正极。
USB与stm32c8t6连线遵循下面这张图:
烧录
使用软件:FlyMcu
烧录之前需要将boot0置1,默认的boot0和boot1都是0
下载FlyMcu
1.链接:https://pan.baidu.com/s/1VxMUZFOVvpAf-L_YbATMag
提取码:fasf
2.下载之后执行以下步骤:
- 双击点开FlyMcu.exe
- 将Port改成连接开发板的那个端口(右键单击此电脑,点击管理,找到计算机管理->系统工具->设备管理器->端口(COM和LPT)中查看)
- bps选择115200 在联机下载时的程序文件那选择keil中生成的.hex文件 选择不使用RTS和DTR 点击STMISP
- 再在开发板上按住RESET 按键,然后再点击开始编程§,显示开始连接后,再放开RESET 按键
注意:如果一直连接不上,按下开发板的RESET键或者清除芯片,如果还是不行请检查一下前面的步骤。
成功烧录到开发板上,会这样显示
烧录之后拔出usb插口,再将boot0置于0,然后重新再插usb即可亮灯
视频:
三个小灯泡依次亮灯,间隔一秒
四、stm32cubeMX使用HAL库点亮LED流水灯
实验工具
STM32CubeMX
下载地址:官网
下载之后一直点下一步即可完成安装
安装HAL库
STM32 HAL固件库是Hardware Abstraction Layer的缩写,中文名称是:硬件抽象层。HAL库是ST公司为STM32的MCU最新推出的抽象层嵌入式软件,为更方便的实现跨STM32产品的最大可移植性。HAL库的推出,可以说ST也慢慢的抛弃了原来的标准固件库,这也使得很多老用户不满。但是HAL库推出的同时,也加入了很多第三方的中间件,有RTOS,USB,TCP / IP和图形等等。
和标准库对比起来,STM32的HAL库更加的抽象,ST最终的目的是要实现在STM32系列MCU之间无缝移植,甚至在其他MCU也能实现快速移植。
并且从16年开始,ST公司就逐渐停止了对标准固件库的更新,转而倾向于HAL固件库和 Low-layer底层库的更新,停止标准库更新,也就表示了以后使用STM32CubeMX配置HAL/LL库是主流配置环境;
1.打开安装好的STMCubeMX
2.点击HELP->Manage embedded software packages
3.会跳出来一个选择型号界面 勾选上你要安装的HAL库, 点击“Install Now” 直到安装成功。 如下图:
新建项目
1.回到STMCubeMX的主界面,创建新项目:
2.在part name里选择自己的芯片,点击信息栏中的具体芯片信息选中,点击start project:
3.点击system core,进入SYS,在debug下选择serial wire:
4.配置时钟,进入上面的rcc,有两个时钟,一个是hse和lse,我们要用是GPIO接口,而这些接口都在APB2里:
5.接下来观察时钟架构,APB2总线的时钟由hse控制,同时在这个界面得把PLLCLK右边选上:
6.将hse那里设为Crystal/Ceramic Resonator:
7.接下来就是点击相应的引脚设置输出寄存器了,就是output那一项,一共选了三个,是PB0,PA1,PB5:
8.点击project manager,配置好自己的路径和项目名,然后IDE那项改为MDK-ARM
9.进入 code generate界面,选择生成初始化.c/.h文件,后面点击generate code,选择open project,然后就到KEIL5了:
调试
上一步之后,打开main.c文件
将下面代码放入主函数的while中(替代里面的内容)
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_5,GPIO_PIN_RESET);
HAL_Delay(1000);
电路连接和烧录运行
电路连接和烧录运行可参考上一部分
运行结果与上一部分相同
三个小灯泡依次亮灯,间隔一秒
观察GPIO端口的输出波形
引脚为低电平的灯亮,高电平的灯不亮,高低电平转换周期(LED闪烁周期)为1.12s左右。
五、总结
自己单独用keil写程序时比较棘手,需要参考很多资料。不过用STMCubeMX+keil+hal库实现程序就简单许多。