本文使用到的硬件有STM32F103C8T6、电源模块、红黄绿小灯各一个、USB转TTL接头、杜邦线等,软件有Keil MDK、mcuisp串口下载烧录软件、CH340-driver等。
一、STM32F103系列芯片的地址映射和寄存器映射原理
- 存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址
的过程就称为存储器映射 - 给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射
- 片上外设区分为三条总线,根据外设速度的不同,不同总线挂载着不同的外设,APB1
挂载低速外设,APB2 和 AHB 挂载高速外设。相应总线的最低地址我们称为该总线的基地 址,总线基地址也是挂载在该总线上的首个外设的地址。其中 APB1 总线的地址最低,片 上外设从这里开始,也叫外设基地址。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/bc9b9bc57d9547ec888eee6283b263e9.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f79095216afe49e3976c3705286acfa8.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/3fa02c5424974b71a783bf1b80282dc9.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/ea774fb8c9df4a70a12c4e9115327255.png)
二、点亮小灯——软件模块
2.1 使用KeilMDK建立工程
具体的KeilMDK软件使用过程请看:基于Keil MDK STM32完成对汇编程序的编写
![在这里插入图片描述](https://img-blog.csdnimg.cn/52308f9cdea347d1bd2d14a581dfa5b9.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/72a3df35931b42e981a375d95c018d4a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/7c30ad548ea34a02933a5458008b1963.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/f3f3e603437d4407834e8886a438a0b1.png#pic_center)
魔法棒配置 ![在这里插入图片描述](https://img-blog.csdnimg.cn/c664196df985425ca3870cff7515f347.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
2.2 流水灯的c程序—寄存器点亮流水灯
代码如下
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
#define GPIOB_CRL *((unsigned volatile int*)0x40010C00)
#define GPIOB_ODR *((unsigned volatile int*)0x40010C0C)
#define GPIOB_CRH *((unsigned volatile int*)0x40010C04)
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
#define GPIOA_ODR *((unsigned volatile int*)0x4000180C)
void delay(unsigned long t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
int main()
{
RCC_APB2ENR|=1<<2;
RCC_APB2ENR|=1<<3;
GPIOB_CRL&=0XFF0FFFFF;
GPIOB_CRL|=0X00300000;
GPIOB_ODR|=1<<5;
GPIOB_CRL&=0XFFFFFFF0;
GPIOB_CRL|=0X00000003;
GPIOB_ODR|=1<<0;
GPIOB_CRH&=0xFFFFFF0F;
GPIOB_CRH|=0x00000020;
GPIOB_ODR|=1<<9;
while(1)
{
GPIOB_ODR&=~(1<<5);
delay(1000);
GPIOB_ODR|=1<<5;
delay(1000);
GPIOB_ODR&=~(1<<0);
delay(1000);
GPIOB_ODR|=1<<0;
delay(1000);
GPIOB_ODR&=~(1<<9);
delay(1000);
GPIOB_ODR|=1<<9;
delay(1000);
}
}
代码分析
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
想要打开时钟,我们要先直到GPIO口挂在哪里 ![在这里插入图片描述](https://img-blog.csdnimg.cn/ba2146ac276f49758d5f8cfd41352437.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16) 所以我们需要打开APB2的时钟 ![在这里插入图片描述](https://img-blog.csdnimg.cn/5f04411820e04b84900412dad050e49b.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16) 2~8位分别控制GPIOA ~ GPIOG,需要使用哪个,哪个位置就置1,就打开相应的GPIO口的时钟,置0就关闭了时钟。
#define GPIOB_CRL *((unsigned volatile int*)0x40010C00)
#define GPIOB_ODR *((unsigned volatile int*)0x40010C0C)
#define GPIOB_CRH *((unsigned volatile int*)0x40010C04)
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
#define GPIOA_ODR *((unsigned volatile int*)0x4000180C)
GPIO口有八种模式: ─ 输入浮空 ─ 输入上拉 ─ 输入下拉 ─ 模拟输入 ─ 开漏输出 ─ 推挽式输出 ─ 推挽式复用功能 ─ 开漏复用功能 ![在这里插入图片描述](https://img-blog.csdnimg.cn/015ca86a9a45472c8d830aa5c21920e0.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16) ![在这里插入图片描述](https://img-blog.csdnimg.cn/7f5a6fda7c9d44fda618fdf0ca49b1a1.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_20,color_FFFFFF,t_70,g_se,x_16)
图里标注出了,0~3位控制 0 号引脚,4~7位控制1 号引脚,依次类推,端口低位配置寄存器控制0~7号引脚,端口高位配置寄存器控制8~15号引脚,两个寄存器配置方式一样,我们先配置MODE,再配置CNF,我们在点灯时需要设置推挽输出,先配置MODE就是10,再配置CNF就是00,所以,给哪个引脚设置0010,哪个引脚就是推挽输出
GPIOB_ODR|=1<<5;
GPIOB_ODR|=1<<0;
GPIOB_ODR|=1<<9;
我在这里用PB5 接红灯 ,PB0 接黄灯 ,PB9 接 绿灯
void delay(unsigned long t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
GPIOB_ODR&=~(1<<5);
GPIOB_ODR&=~(1<<0);
GPIOB_ODR&=~(1<<9);
2.3 流水灯的硬件配置
![在这里插入图片描述](https://img-blog.csdnimg.cn/884f78c08edb4a32bf5012b4daebb6af.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAaXN5dXV1bg==,size_12,color_FFFFFF,t_70,g_se,x_16#pic_center)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2f214bfedc524f50a8b45a21308907bc.gif)
三、总结
在硬件实验过程中,我们会出现很多不同的问题,杜邦线的连接、程序寄存器接口的地址错误、面包板两边不导通等问题,这也是我们经常会遇见的,丰富自己的经验了。
参考文献: https://blog.csdn.net/gelad_w/article/details/115429648 https://blog.csdn.net/gelad_w/article/details/115555631
|