点亮一个LED灯-寄存器版

一. 流程简述

1.打开MDK5新建一个工程并保存, 选择芯片具体型号(F103C8).
2.添加启动文件, 创建main文件, 放在工程根目录即可.

3.编写代码通过控制寄存器点亮LED灯

二. 查看参考手册

1.需要控制LED的亮灭就需要控制GPIO输出高低电平. 所以需要找到对应GPIO的寄存器, 对其写入0或1进行控制, 描述GPIO的寄存器在参考手册第八章.
2.本次实验使用到的寄存器有: CRL(低位控制寄存器), ODR(输出寄存器).

3.在CRL和ODR中写入对应的值, 配置好GPIO的输出模式以及输出值.
4.要想在寄存器中写入/修改值, 就需要拿到寄存器的地址. 以上只能得到基于GPIO的偏移地址. 还需要在第二章存储器和总线架构中查看GPIO的基地址.

5.这里以GPIOB端口0位例分析, 根据GPIOB基地址40010c00, 以及CRL偏移地址0x00. 可以得到CRL准确地址为: 40010c00.

/*
  1. 这里首先0x40010c00在编译器看来只是一个立即数, 需要使用(unsigned int *) 将其强转为无符号整形指针类型.
  2. 最前面的*表示拿到0x40010c00这个地址上的值, 默认是0x4444 4444(复位值).
  3. 将0x4444 4444 | 0x01 (这种方式可以将自己想要的位置置1而且不影响其他位). 这里的含义是选择了开漏输出模式.
*/
*(unsigned int *)0x40010C00 |= ((1) << (4*0));

6.操作ODR寄存器将GPIOB0端口输出1, ODR寄存器偏移地址为: 0x0C. 得到准确地址为40010C0C.

/*
  将第0位写0, GPIOB0将会输出低电平0.
*/
*(unsigned int *)0x40010C0C &= ~(1 << 0);

7.和51不同的是, 由于GPIO是属于外设挂载在APB2总线上, stm32外设使用前都需要使能, 所以需要去操作APB2时钟使能外设在第六章

8.RCC_APB2ENR是APB2时钟使能寄存器, 其偏移地址为0x18, 基地址是AHB(复位和RCC时钟控制): 0x40021000. 得到准确地址为: 0x400210018.

/*
  将第3位置1, 即IOPBEN:IO端口B时钟使能 (I/O port B clock enable)
*/
*(unsigned int *)0x40021018 |= ((1) << 3);

三. 代码优化迭代

1.直接操作寄存器
2.通过将寄存器地址映射, 采用#define方式命名, 可以通过使用名称来操作(不用再去记寄存器地址)
3.使用结构体优化寄存器的定义, 优化前每个GPIO都需要去为其对应的寄存器定义一个名称十分繁琐. 优化后直接将所有GPIO的寄存器定义在一个结构体中, 由于GPIO寄存器CRL地址与GPIO基地址相同, 这样我们就可以通过将GPIO基地址强转为GPIO结构体类型, 就可以使用指针操作每一个GPIO对应的寄存器.

/*
  main函数部分代码
*/

#include "stm32f10x.h"

void delay_my(int num);
void SystemInit(void);
void LED_Bright(void);

int main(void)
{
#if 0
    //打开GPIOB端口的时钟
    *(unsigned int *)0x40021018 |= ((1) << 3);
    
    //控制CRL寄存器(输入输出模式和速度)
    *(unsigned int *)0x40010C00 |= ((1) << 0);
    *(unsigned int *)0x40010C00 &= ~((1) << 2);
    
    //控制ODR输出寄存器
    *(unsigned int *)0x40010C0C &= ~(1 << 0);
#elif 0

    RCC_APB2ENABLE = 0x00000008;
    GPIO_CRL = 0x44444402;
    GPIO_ODR = 0x00000001;
    GPIO_BSRR = 0x00010000;
#elif 1
    RCC_ENABLE->RCC_APB2ENR = 0x00000008;
    GPIOB->CRL = 0x44444402;
    GPIOB->ODR = 0x00000000;
    //GPIOB->BSRR = 0x00010001;
#endif
    
}
void SystemInit(void){}

/*
  stm32f10x.h部分代码
*/

//外设peripheral
#define PERIPH_BASE         ((unsigned int)0x40000000)
#define APB1PERIPH_BASE     PERIPH_BASE
#define APB2PERIPH_BASE     (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE      (PERIPH_BASE + 0x20000)
#define GPIOB_BASE          (APB2PERIPH_BASE + 0x0C00)

#define RCCPERIPH_BASE      (AHBPERIPH_BASE + 0x1000)

#define RCC_APB2ENABLE      *(unsigned int *)(RCCPERIPH_BASE + 0x18)
#define GPIO_CRL            *(unsigned int *)(GPIOB_BASE)
#define GPIO_CRH            *(unsigned int *)(GPIOB_BASE + 0x04)
#define GPIO_ODR            *(unsigned int *)(GPIOB_BASE + 0x0C)
#define GPIO_BSRR           *(unsigned int *)(GPIOB_BASE + 0x10)
#define GPIO_BRR            *(unsigned int *)(GPIOB_BASE + 0x14)
    

typedef unsigned int    uint32_t;
typedef unsigned short  uint16_t;

typedef struct
{
    uint32_t CRL;
    uint32_t CRH;
    uint32_t IDR;
    uint32_t ODR;
    uint32_t BSRR;
    uint32_t BRR;
    uint32_t LCKR;

}GPIO_TypeDef;

#define GPIOB       ((GPIO_TypeDef*)GPIOB_BASE)

typedef struct
{
    uint32_t RCC_CR;
    uint32_t RCC_CFGR;
    uint32_t RCC_CIR;
    uint32_t RCC_APB2RSTR;
    uint32_t RCC_APB1RSTR;
    uint32_t RCC_AHBENR;
    uint32_t RCC_APB2ENR;
    uint32_t RCC_APB1ENR;
    uint32_t RCC_BDCR;
    uint32_t RCC_CSR;
}RCC_TypeDef;

#define RCC_ENABLE  ((RCC_TypeDef*)RCCPERIPH_BASE)

posted @   一步一磕头的菜鸡  阅读(251)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示