学前班
最后登录1970-1-1
在线时间 小时
注册时间2018-9-27
|
本帖最后由 amengde 于 2018-9-29 18:37 编辑
在这一讲我们用寄存器映射,代替直接操作内存地址,优化了代码的可读性。在完成课后作业的过程中,我尝试了几种闪烁LED的方式,初步了解了STM32寄存器的处理方式。
以下先介绍寄存器的映射工作,然后在此基础上,介绍我尝试的6种闪烁LED的方式,有问题请指正,多谢。
【寄存器的映射】
stm32片上外设有3条总线,按地址从低到高分别为APB1总线,APB2总线,AHB总线。3总线上挂载有各种外设,比如GPIOA~E在APB2总线上,当然GPIOA~E各自对应的寄存器也在APB2总线上,比如GPIOA_ODR。为了方便实现寄存器的映射,以APB1总线的起始地址OX40000000为整个片上外设的基地址(PERPH_BASE),同时也是APB1总线的基地址(APB1_BASE),在此基础上我们就可以根据其余2条总线与基地址的地址偏移算出APB2_BASE,AHB_BASE,同时也可以得出各寄存器的映射,参考STM32F10X系列中文手册。具体程序如下:
[mw_shl_code=c,true]/****************在stm32f10x.h文件中对外设上的寄存器进行映射*********************/
/*******片上外设,各总线基地址**********/
#define PERPH_BASE ((unsigned int)0x40000000)
#define APB1_BASE PERPH_BASE
#define APB2_BASE PERPH_BASE + 0x10000
#define AHB_BASE PERPH_BASE + 0x20000
/*******各类寄存器基地址**********/
#define RCC_BASE AHB_BASE + 0x1000
#define GPIOB_BASE APB2_BASE + 0x0C00
#define GPIOA_BASE APB2_BASE + 0x0800
/*******具体寄存器地址**********/
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE + 0x18)
#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE + 0x00)
#define GPIOB_CRH *(unsigned int*)(GPIOB_BASE + 0x04)
#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE + 0x0C)
#define GPIOB_BSRR *(unsigned int*)(GPIOB_BASE + 0x10)
#define GPIOB_BRR *(unsigned int*)(GPIOB_BASE + 0x14)
#define GPIOA_CRL *(unsigned int*)(GPIOA_BASE + 0x00)
#define GPIOA_CRH *(unsigned int*)(GPIOA_BASE + 0x04)
#define GPIOA_ODR *(unsigned int*)(GPIOA_BASE + 0x0C)[/mw_shl_code]
【闪烁LED】
在处理闪烁LED时,我发现可以通过设置CRL、ODR、BSRR、BRR几个寄存器来组合实现LED闪烁,将2*LED亮的方式与3*LED灭的方式自由组合,得到6种方式。重点是注意BSRR,BRR与ODR的对应关系。具体程序如下:
[mw_shl_code=c,true]
#include"stm32f10x.h"
typedef unsigned int uint32_t;
#define __IO volatile
#define DELAY Delay(0xfffff)
void Delay(__IO uint32_t nCount) //简单的延时函数
{
for(; nCount != 0; nCount--);
}
int main(void)
{
while(1)
{
/******************用6种方式控制PB0_LED闪烁**********************/
RCC_APB2ENR |= ((1) << 3);//打开GPIO端口的时钟,即操作RCC_APB2ENR寄存器(APB2外设时钟使能寄存器)
GPIOB_CRL |= ((1) << (4*0));//配置IO口为推挽输出,即操作GPIOX_CRL寄存器(端口配置低寄存器,4位一组)
/******************LED亮**********************/
/*法1:直接操作ODR,设置ODR0=0,LED亮*/
GPIOB_ODR &=~ (1 << 0);//设置ODR位,即操作GPIOB_ODR寄存器(端口输出数据寄存器)由于开发板PB0连接LED,因此操作GPIOB_ODR的第0位
/*法2:操作BRR,设置BR0=1,间接设置ODR0=0,LED亮*/
// GPIOB_BRR |=(1 << 0);//BR0=1,ODR0=0,灯亮
/******************LED亮end**********************/
DELAY;
/******************LED灭**********************/
/*法1:操作CRL,关闭GPIOB输出,不改变ODR0=0,LED灭*/
// GPIOB_CRL &= ~( 0x0F<< (4*0));//控制PB0的端口位,关闭输出
/*法2:直接操作ODR,设置ODR0=1,LED灭*/
// GPIOB_ODR |=(1 << 0);//设置ODR位,ODR0=1,灯灭
/*法3:操作BSRR,设置BS0=1,间接设置ODR0=1,LED灭*/
GPIOB_BSRR |=(1 << 0);//BS0=1,ODR0=1,灯灭。
/******************LED灭end**********************/
DELAY;
}
}
void SystemInit(void)
{
//函数体为空,目的是骗过编译器使其不报错
}
[/mw_shl_code]
由以上可以看出,在51中,LED闪烁是给IO的数据寄存器置1清0来实现;而在stm32中除了给IO的数据寄存器置1清0(利用GPIOX_ODR,GPIOX_BSRR,GPIOX_BRR)来实现,还可以通过控制IO的输出/输入方式(利用GPIOX_CRH,GPIOX_CRL)来实现。
|
|