完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
一、STM32寄存器规则及IO口介绍 本博客将要实现的是控制 STM32 开发板上的三个IO口实现一个类似流水灯的效果,该实验的关键在于如何控制 STM32 的IO口输出。了解了 STM32的IO口如何输出的,就可以实现流水灯了。通过这次的学习,你将初步掌握 STM32 基本 IO 口的使用,而这是迈向STM32的第一步。 STM32 的 IO 口可以由软件配置成如下 8 种模式: 1、输入浮空 2、输入上拉 3、输入下拉 4、模拟输入 5、开漏输出 6、推挽输出 7、推挽式复用功能 8、开漏复用功能 每个 IO 口可以自由编程,但 IO 口寄存器必须要按 32 位字被访问。STM32 的每个 IO 端口都有 7 个寄存器来控制。他们分别是:配置模式的 2 个 32 位的端口 配置寄存器 CRL 和 CRH;2 个 32 位的数据寄存器 IDR 和 ODR;1 个 32 位的置位/复位寄存器 BSRR;一个 16 位的复位寄存器 BRR;1 个 32 位的锁存寄存器 LCKR;这里我们仅介绍常用 的 几个寄存器,我们常用的 IO 端口寄存器只有 4 个:CRL、CRH、IDR、ODR。 CRL 和 CRH 控制着每个 IO 口的模式及输出速率。 STM32 的 IO 口位配置表如表所示: STM32 输出模式配置如表所示: 接下来我们看看端口低配置寄存器 CRL 的描述,如图所示: 该寄存器的复位值为 0X4444 4444,从图 6.1.1 可以看到,复位值其实就是配置端口为浮空 输入模式。从上图还可以得出:STM32 的 CRL 控制着每组 IO 端口(A~G)的低 8 位的模式。 每个 IO 端口的位占用 CRL 的 4 个位,高两位为 CNF,低两位为 MODE。这里我们可以记住几 个常用的配置,比如 0X0 表示模拟输入模式(ADC 用)、0X3 表示推挽输出模式(做输出口用, 50M 速率)、0X8 表示上/下拉输入模式(做输入口用)、0XB 表示复用输出(使用 IO 口的第二 功能,50M 速率)。 CRH 的作用和 CRL 完全一样,只是 CRL 控制的是低 8 位输出口,而 CRH 控制的是高 8 位输出口。这里我们对 CRH 就不做详细介绍了。 给个实例,比如我们要设置 PORTC 的 11 位为上拉输入,12 位为推挽输出。代码如下: GPIOC->CRH&=0XFFF00FFF;//清掉这 2 个位原来的设置,同时也不影响其他位的设置 GPIOC->CRH|=0X00038000; //PC11 输入,PC12 输出 GPIOC->ODR=1<<11; //PC11 上拉 通过这 3 句话的配置,我们就设置了 PC11 为上拉输入,PC12 为推挽输出。 IDR 是一个端口输入数据寄存器,只用了低 16 位。该寄存器为只读寄存器,并且只能以 16 位的形式读出。该寄存器各位的描述如图所示: 要想知道某个 IO 口的状态,你只要读这个寄存器,再看某个位的状态就可以了。使用起 来是比较简单的。 ODR 是一个端口输出数据寄存器,也只用了低 16 位。该寄存器为可读写,从该寄存器读 出来的数据可以用于判断当前 IO 口的输出状态。而向该寄存器写数据,则可以控制某个 IO 口 的输出电平。该寄存器的各位描述如图所示: 了解了这几个寄存器,我们就可以开始流水灯实验的真正设计了。 二、硬件连接设计 根据题目要求,使用GPIOB,GPIOC,GPIOD端口来控制LED灯,在查询STM32数据手册后,我选用了PB6,PC6,PD2管脚分别连接红绿蓝三种颜色的灯(由于我只有红绿黄三个小灯,在之后实际硬件中,会用黄灯代替蓝灯) 三、软件设计 3.1配置IO口 我们首先需要配置IO口,这里我们采用的配置方法是使用寄存器。通过配置寄存器的值,来改变IO口的值进行变化。 led.h #ifndef __LED_H #define __LED_H #include "sys.h" //LED端口定义 #define LED0 BIT_ADDR(GPIOB_ODR_Addr,6) // PB6输出 #define LED1 BIT_ADDR(GPIOC_ODR_Addr,6) // PC6输出 #define LED2 BIT_ADDR(GPIOD_ODR_Addr,2) // PD2输出 void LED_Init(void); //初始化 #endif led.c #include "sys.h" #include "led.h" //初始化PB6、PC6和PD2为输出口,并使能这3个口的时钟 //LEDIO初始化 void LED_Init(void) { RCC->APB2ENR|=1<<3; //使能PORTB时钟 RCC->APB2ENR|=1<<4; //使能PORTC时钟 RCC->APB2ENR|=1<<5; //使能PORTD时钟 GPIOB->CRL&=0XF0FFFFFF; //PB6清零 GPIOB->CRL|=0X03000000; //PB6推挽输出 GPIOB->ODR|=1<<6; //PB6输出高 GPIOC->CRL&=0XF0FFFFFF; //PC6清零 GPIOC->CRL|=0X03000000; //PC6推挽输出 GPIOC->ODR|=1<<6; //PC6输出高 GPIOD->CRL&=0XFFFFF0FF; //PD2清零 GPIOD->CRL|=0X00000300;//PD2推挽输出 GPIOD->ODR|=1<<2; //PD2输出高 } 3.2编写主函数 test.c #include "sys.h" #include "led.h" void delay(unsigned int i) //简单延时函数 { unsigned char j; unsigned char k; for(;i>0;i--) for(j=500; j>0; j--) for(k =200; k>0; k--); } int main(void) { LED_Init(); //初始化与LED连接的硬件接口 while(1) { LED0=0; //灯亮 LED1=1; //灯灭 LED2=1; delay(20); //延时 LED0=1; LED1=0; LED2=1; delay(20); LED0=1; LED1=1; LED2=0; delay(20); } } 3.3烧录:STM32与PC端连接 借助FLYMCU下载软件,即可将test.hex载入,软件资料同样可在网盘下载。这里我利用FlyMcu进行。 四、汇编语言实现 代码: RCC_APB2ENR EQU 0x40021018 GPIOA_CRH EQU 0x40010804 GPIOA_ODR EQU 0x4001080C GPIOB_CRL EQU 0x40010C00 ;寄存器映射 GPIOB_ODR EQU 0x40010C0C GPIOC_CRH EQU 0x40011004 GPIOC_ODR EQU 0x4001100C Stack_Size EQU 0x00000400 AREA STACK, NOINIT, READWRITE, ALIGN=3 ;NOINIT: = NO Init,不初始化。READWRITE : 可读,可写。ALIGN =3 : 2^3 对齐,即8字节对齐。 Stack_Mem SPACE Stack_Size __initial_sp AREA RESET, DATA, READONLY __Vectors DCD __initial_sp DCD Reset_Handler AREA |.text|, CODE, READONLY THUMB REQUIRE8 PRESERVE8 ENTRY Reset_Handler MainLoop BL LED2_Init BL LED2_ON BL Delay ;LED2灯闪烁 BL LED2_OFF BL Delay BL LED1_Init BL LED1_ON BL Delay ;LED1灯闪烁 BL LED1_OFF BL Delay BL LED3_Init BL LED3_ON BL Delay ;LED3灯闪烁 BL LED3_OFF BL Delay B MainLoop LED1_Init PUSH {R0,R1, LR} ;R0,R1,LR中的值放入堆栈 LDR R0,=RCC_APB2ENR ;LDR是把地址装载到寄存器中(比如R0)。 ORR R0,R0,#0x08 ;开启端口GPIOB的时钟,ORR 按位或操作,01000将R0的第二位置1,其他位不变 LDR R1,=RCC_APB2ENR STR R0,[R1] ;STR是把值存储到寄存器所指的地址中,将r0里存储的值给rcc寄存器 ;上面一部分汇编代码是控制时钟的 LDR R0,=GPIOB_CRL ORR R0,R0,#0X00000020 ;GPIOB_Pin_1配置为通用推挽输出;开启的是pb1,所以是2,为0010,是推挽输出模式,最大速度为2mhz LDR R1,=GPIOB_CRL STR R0,[R1] LDR R0,=GPIOB_ODR BIC R0,R0,#0X00000002 ;BIC 先把立即数取反,再按位与 LDR R1,=GPIOB_ODR ;GPIOB_Pin_1输出为0;由r1控制ord寄存器 STR R0,[R1] ;将ord寄存器的值变为r0的值 POP {R0,R1,PC} ;将栈中之前存的R0,R1,LR的值返还给R0,R1,PC LED1_OFF PUSH {R0,R1, LR} LDR R0,=GPIOB_ODR BIC R0,R0,#0X00000002 ;因为是PB1所以对应二进制0010;GPIOB_Pin_1输出为0,LED1熄灭 LDR R1,=GPIOB_ODR STR R0,[R1] POP {R0,R1,PC} LED1_ON PUSH {R0,R1, LR} LDR R0,=GPIOB_ODR ORR R0,R0,#0X00000002 ;GPIOB_Pin_1输出为1,LED1亮 LDR R1,=GPIOB_ODR STR R0,[R1] POP {R0,R1,PC} LED2_Init PUSH {R0,R1, LR};R0,R1,LR中的值放入堆栈 LDR R0,=RCC_APB2ENR ORR R0,R0,#0x04 ;打开GPIOA的时钟 LDR R1,=RCC_APB2ENR STR R0,[R1] LDR R0,=GPIOA_CRH ORR R0,R0,#0X00020000 ;GPIOA_Pin_12配置为通用推挽输出 LDR R1,=GPIOA_CRH STR R0,[R1] LDR R0,=GPIOA_ODR BIC R0,R0,#0X00001000 LDR R1,=GPIOA_ODR ;GPIOA_Pin_12输出为0 STR R0,[R1] POP {R0,R1,PC} LED2_OFF PUSH {R0,R1, LR} LDR R0,=GPIOA_ODR BIC R0,R0,#0X00001000 ;GPIOA_Pin_12输出为0,LED2熄灭 LDR R1,=GPIOA_ODR STR R0,[R1] POP {R0,R1,PC} LED2_ON PUSH {R0,R1, LR} LDR R0,=GPIOA_ODR ORR R0,R0,#0X00001000 ;GPIOA_Pin_12输出为1,LED2亮 LDR R1,=GPIOA_ODR STR R0,[R1] POP {R0,R1,PC} LED3_Init PUSH {R0,R1, LR} LDR R0,=RCC_APB2ENR ORR R0,R0,#0x10 ;打开GPIOC的时钟 LDR R1,=RCC_APB2ENR STR R0,[R1] LDR R0,=GPIOC_CRH ORR R0,R0,#0X02000000 ;GPIOC_Pin_14配置为通用推挽输出 LDR R1,=GPIOC_CRH STR R0,[R1] LDR R0,=GPIOC_ODR BIC R0,R0,#0X00004000 ;GPIOC_Pin_14输出为0 LDR R1,=GPIOC_ODR STR R0,[R1] POP {R0,R1,PC} LED3_OFF PUSH {R0,R1, LR} LDR R0,=GPIOC_ODR BIC R0,R0,#0X00004000 ;GPIOC_Pin_14输出为0,LED3熄灭 LDR R1,=GPIOC_ODR STR R0,[R1] POP {R0,R1,PC} LED3_ON PUSH {R0,R1, LR} LDR R0,=GPIOC_ODR ORR R0,R0,#0X00004000 ;GPIOC_Pin_14输出为1,LED3亮 LDR R1,=GPIOC_ODR STR R0,[R1] POP {R0,R1,PC} Delay PUSH {R0,R1, LR} MOVS R0,#0 MOVS R1,#0 MOVS R2,#0 DelayLoop0 ADDS R0,R0,#1 CMP R0,#300 BCC DelayLoop0 MOVS R0,#0 ADDS R1,R1,#1 CMP R1,#300 BCC DelayLoop0 MOVS R0,#0 MOVS R1,#0 ADDS R2,R2,#1 CMP R2,#15 BCC DelayLoop0 POP {R0,R1,PC} END 编译烧录方法同上,效果展示 |
|
|
|
只有小组成员才能发言,加入小组>>
3278 浏览 9 评论
2955 浏览 16 评论
3455 浏览 1 评论
8987 浏览 16 评论
4050 浏览 18 评论
1102浏览 3评论
570浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
568浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2301浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1857浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 06:31 , Processed in 1.118911 second(s), Total 81, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号