野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 11160|回复: 3

【交作业】火哥指南者视频第8讲《使用寄存器点亮LED》作业:使用6种方式闪烁LED

[复制链接]
发表于 2018-9-29 18:39:04 | 显示全部楼层 |阅读模式
本帖最后由 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)来实现。
回复

使用道具 举报

发表于 2018-9-29 20:12:44 来自手机 | 显示全部楼层
漂亮 学习的非常认真。
回复 支持 反对

使用道具 举报

发表于 2018-9-30 12:07:11 | 显示全部楼层
向你学习
回复

使用道具 举报

发表于 2023-8-3 16:34:50 | 显示全部楼层
膜拜大佬
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-4-27 19:10 , Processed in 0.037784 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表