点亮一个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)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)