STM32F103的流水灯点亮版本1(寄存器地址操作)
实物图连接电路依旧不变,利用6.1连接好的电路图!本次实验巩固了前面我做的基础:点亮STM32LED灯的操作与知识,因为本次实验可以说是之前做的点亮一个STM32LED灯的升级版操作;进一步强化了我利用寄存器来进行编写程序的能力。本人这次也成功做出来了关于STM32红、黄和绿三个灯的Proteus仿真实验,真的非常高兴!!!
目录
6.1、解决第二问的题干问题和1与2两个小问(外接红、黄、绿三个灯来形成流水灯)
6.2、解决第二问的最后第三小问(外接红、黄灯和利用STM已有接好的PC13上的绿灯来形成流水灯)
一、问题提出:
1、了解STM32最小系统核心板(STM32F103C8T6,国际上又统称 STM32 Blue Bill开发板)的电路原理图,用Proteus 设计一个STM32最小系统板+LED流水灯实验原理图,仿真运行。
2、以 STM32最小系统核心板(STM32F103C8T6)+面板板+3只_(或更多)红绿蓝LED 搭建电路,使用GPIOA、GPIOB、GPIOC这3个端口控制LED灯,轮流闪烁,间隔时长1秒。
1)写出程序设计思路,包括GPIOx端口的各寄存器地址和详细参数;
2)用C语言寄存器方式编程实现,代码须有详细注解。
3)STM32最小系统核心板子出厂时已经焊接好了1个led灯(标注了PC13处),一般可通过此灯的点亮让编程者验证自己烧录的代码是否正常运行了。请查阅最小版电路原理图和相关资料,将这个灯也用在流水灯中,重编新程序。
二、STM32F103系列芯片的地址映射和寄存器映射原理
1、寄存器:
寄存器是中央处理器内的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和地址。
简单来说,寄存器就是存放东西的东西。寄存器存放的是指令、数据或地址。
存放数据的寄存器是最好理解的,如果你需要读取一个数据,直接到这个寄存器所在的地方来问问他,数据是多少就行了。问寄存器这个动作,叫做访问寄存器。不同的数据会存放在不同的寄存器,例如引脚PA2与PB8的高低电平数据(1或0)肯定放在不同的寄存器里,那么怎么区分不同的寄存器呢?通过地址,不同的寄存器有不同的地址,就像老张行李寄存处在101号店铺,老王行李寄存处在258号店铺。
指令、地址寄存器与数据寄存器类似,里边存放的都是0和1,毕竟单片机也只认识机器码,机器码都是0或1,只是特别的规定下,数据寄存器里面存放的0和1表示数据,指令寄存器里存放的表示指令。
2、存储器映射:
存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址的过程就称为存储器映射,具体见图。如果给存储器再分配一个地址就叫存储器重映射。
3、寄存器映射:
在存储器 Block2 这块区域,设计的是片上外设,它们以四个字节为一个单元,共 32bit,每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到每个单元的起始地址,然后通过 C 语言指针的操作方式来访问这些单元,如果每次都是通过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
三、GPIO端口的初始化设置
GPIO 是通用输入输出端口的简称,简单来说就是 STM32 可控制的引脚,STM32 芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、控制以及数据采集的功能。STM32 芯片的 GPIO 被分成很多组,每组有 16 个引脚,如型号为 STM32F103VET6 型号芯片有 GPIOA、GPIOB、GPIOC至 GPIOE共 5组 GPIO,芯片一共 100个引脚,其中 GPIO就占了一大部分,所有的 GPIO 引脚都有基本的输入输出功能。
点亮LED灯,实现流水灯效果需要用到GPIO
端口。为了点亮LED灯,进行以下三个步骤:
- 打开GPIO口的时钟
- 初始化GPIO口(选择推挽输出)
- 设置低电平
1、打开时钟:
GPIO的地址:
时钟的地址:
即0x40021018
,则打开三个IO口的时钟需要将三个位都置1:
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
// 打开时钟
RCC_APB2ENR |= (1<<3); // 打开 GPIOB 时钟
RCC_APB2ENR |= (1<<4); // 打开 GPIOC 时钟
RCC_APB2ENR |= (1<<2); // 打开 GPIOA 时钟
2、初始化GPIO口:
GPIO口有八种模式:
- 输入浮空
- 输入上拉
- 输入下拉
- 模拟输入
- 开漏输出
- 推挽式输出
- 推挽式复用功能
- 开漏复用功能
本次实验使用推挽输出:
端口1-7为低,端口8-15为高。每个引脚由四个位控制。
以GPIOB
和0号引脚(B0)为例,将其设置为推挽输出
,并设置最大速度为10MHz
,则将控制B0
的四个位设置为0001
:
#define GPIOA_CRL (*(unsigned int *)0x40010800)
// 最后四位变为0001
GPIOA_CRL |= (1<<0); // 最后一位变1
GPIOA_CRL &= ~(0xE<<0); // 倒数2、3、4位变0
对于GPIOB的B9、GPIOC的C15、GPIOA的A4,设置如下:
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
GPIOB_CRH&= 0xffffff0f;
GPIOB_CRH|=0x00000020;
GPIOC_CRH &= 0x0fffffff;
GPIOC_CRH|=0x30000000;
GPIOA_CRL &= 0xfff0ffff;
GPIOA_CRL|=0x00010000;
3、设置高电平:
输出高电平则为1,低电平则为0
以GPIOB和0号引脚(B0)为例,将其设置为低电平:
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
GPIOB_ODR &= ~(1<<0); // 最后一位变0
对于GPIOB的B9、GPIOC的C15、GPIOA的A4,设置如下:
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
GPIOB_ODR &= ~(1<<9);
GPIOC_ODR &= ~(1<<15);
GPIOA_ODR &= ~(1<<4);
四、工程文件建立与项目编写
1、STM32(keil)项目创建:
参考我之前这篇blog,里面有详细介绍如何下载STM32(keil)和创建STM32(keil)项目:stm32通过寄存器方式利用GPIO端口点亮LED_-HSheng的博客-CSDN博客
2、项目准备:
添加一个main.c
文件:
接着:
我是用的江协科技的STM32资料中的文件复制到新建的项目下,如果自己电脑上没有的话可以去网上找与下载:
右击文件夹,选择Add Existing Files to Group Source Group 1(或双击文件夹),选择All FIles,选择刚刚添加的启动文件,Add,Add之后Close:
接着打开魔术棒,如下图所示勾选Create HEX File:
3、项目编写:
在main.c中写入寄存器代码(利用了PB9、PC15、PA4这三个GPIO口):
#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define GPIOA_BASE 0x40010800
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
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<<4; //PA4低电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x1<<15; //PC15高电平
}
void B_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x0<<9; //PB9低电平
GPIOC_ODR=0x1<<15; //PC15高电平
}
void C_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x0<<15; //PC15低电平
}
int main(){
int j=100;
// 开启时钟
RCC_APB2ENR |= (1<<3); // 开启 GPIOB 时钟
RCC_APB2ENR |= (1<<4); // 开启 GPIOC 时钟
RCC_APB2ENR |= (1<<2); // 开启 GPIOA 时钟
// 设置 GPIO 为推挽输出
GPIOB_CRH&= 0xffffff0f; //设置位 清零
GPIOB_CRH|=0x00000020; //PB9推挽输出
GPIOC_CRH &= 0x0fffffff; //设置位 清零
GPIOC_CRH|=0x30000000; //PC15推挽输出
GPIOA_CRL &= 0xfff0ffff; //设置位 清零
GPIOA_CRL|=0x00010000; //PA4推挽输出
// 3个LED初始化为不亮(即高点位)
GPIOB_ODR |= (1<<9);
GPIOC_ODR |= (1<<15);
GPIOA_ODR |= (1<<4);
while(j){
B_LED_LIGHT();
Delay_ms(1000000);
C_LED_LIGHT();
Delay_ms(1000000);
A_LED_LIGHT();
Delay_ms(1000000);
}
}
void SystemInit(){
}
五、STM32LED流水灯Proteus仿真(解决第一问)
1、Proteus项目创建:
参考我之前这篇blog,里面有详细介绍如何下载Proteus和创建Proteus项目:
51单片机流水灯程序的Proteus设计和仿真_-HSheng的博客-CSDN博客
2、建立Proteus项目电路图:
依次找出以下需要的器件:RES、LED-RED、LED-GREEN、LED-YELLOW、VCC电源、STM32F103C8;然后对这些元器件进行如下图所示连线摆放,下图为连接好的Proteus仿真电路图(利用了PB9、PC15、PA4这三个GPIO口):
3、编译STM32(Keil)项目
生成用于仿真的hex文件:
4、运行Proteus仿真电路:
双击STM32F103C8单片机,点击2处选择生成的hex文件,接着点击三处的确定,最后点击4处的运行符号即可!
运行结果如下所示:
六、STM32LED流水灯板子实现
6.1、解决第二问的题干问题和1与2两个小问(外接红、黄、绿三个灯来形成流水灯)
1、对实物STM32进行连接电路(利用了PB9、PC15、PA4这三个GPIO口):
(1)总电路:
红——B9
绿——C15
黄——A4
(2)对于ST-link与STM32连接的电路图:
图中方框圈住的是ST-link,关于ST-link的使用和配置以及相应固件的安装参考我这篇blog文章,里面有详细介绍: stm32通过寄存器方式利用GPIO端口点亮LED_-HSheng的博客-CSDN博客
2、烧录代码:
点击1处编译;接着点击2处烧录
3、烧录进STM32板子效果:
6.2、解决第二问的最后第三小问(外接红、黄灯和利用STM已有接好的PC13上的绿灯来形成流水灯)
1、对实物STM32进行连接电路(利用了PB9、PC13、PA4这三个GPIO口):
实物图连接电路依旧不变,利用6.1连接好的电路图!
2、烧录代码:
本次这里因为更换了GPIO口,所以代码相应部分也要跟着变,所以改变后的总代码如下,并且用改变的代码替换在keil工程里面原来的main代码 ,然后按照6.1的流程进行烧录即可:
#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define GPIOA_BASE 0x40010800
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
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<<4; //PA4低电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x1<<13; //PC13高电平
}
void B_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x0<<9; //PB9低电平
GPIOC_ODR=0x1<<13; //PC13高电平
}
void C_LED_LIGHT(){
GPIOA_ODR=0x1<<4; //PA4高电平
GPIOB_ODR=0x1<<9; //PB9高电平
GPIOC_ODR=0x0<<13; //PC13低电平
}
int main(){
int j=100;
// 开启时钟
RCC_APB2ENR |= (1<<3); // 开启 GPIOB 时钟
RCC_APB2ENR |= (1<<4); // 开启 GPIOC 时钟
RCC_APB2ENR |= (1<<2); // 开启 GPIOA 时钟
// 设置 GPIO 为推挽输出
GPIOB_CRH&= 0xffffff0f; //设置位 清零
GPIOB_CRH|=0x00000020; //PB9推挽输出
GPIOC_CRH &= 0xff0fffff; //设置位 清零
GPIOC_CRH|=0x00300000; //PC15推挽输出
GPIOA_CRL &= 0xfff0ffff; //设置位 清零
GPIOA_CRL|=0x00010000; //PA4推挽输出
// 3个LED初始化为不亮(即高点位)
GPIOB_ODR |= (1<<9);
GPIOC_ODR |= (1<<13);
GPIOA_ODR |= (1<<4);
while(j){
B_LED_LIGHT();
Delay_ms(2000);//单片机上2000 100
C_LED_LIGHT();
Delay_ms(3000);//单片机上3000 200
A_LED_LIGHT();
Delay_ms(3000);//单片机上3000 200
}
}
void SystemInit(){
}
3、烧录进去STM32板子效果:
七、总结
本次实验巩固了前面我做的基础:点亮STM32LED灯的操作与知识,因为本次实验可以说是之前做的点亮一个STM32LED灯的升级版操作;进一步强化了我利用寄存器来进行编写程序的能力。本人这次也成功做出来了关于STM32红、黄和绿三个灯的Proteus仿真实验,真的非常高兴!!!
八、参考资料
1、【精选】STM32F103点亮LED流水灯_stm32f103 流水灯_江南烟浓雨的博客-CSDN博客
更多推荐
所有评论(0)