之前了解使用寄存器操作GPIOA口的LED灯亮灭程序,原理是将寄存器的地址强制转换成指针形式, 然后对指针进行操作。这一章尝试通过将外设定义成结构体的形式来操作外设寄存器。
本章重点在于理解和使用<结构体>来控制外设寄存器,然后举例一个按键控制LED灯实现亮灭功能,通过结构体访问RCC和GPIO的相关寄存器。
预备知识
寄存器地址和结构体在形式上都是地址连续分布
通过C语言的学习可以得知,在结构体中地址都是连续分布的。而在STM32的寄存器中同样也是连续的地址分布的,且恰好相差四个字节。
1 在main函数中定义结构体,首先将始终信号RCC转化为结构体形式,通过在参考手册中可以查询到相关寄存器
#ifndef __MAIN_H_
#define __MAIN_H_
typedef struct
{
unsinged int CR;
unsinged int CFGR;
unsinged int CIR;
unsinged int APB2RSTR;
unsinged int APB1RSTR;
unsinged int AHBENR;
unsinged int APB2ENR;
unsinged int APB1ENR;
unsinged int BDCR;
unsinged int CSR;
unsinged int AHBRSTR; //其中后两个寄存器是互联型的
unsinged int CFRG2;
}RCC_Typedef;
#endif
2此时,在主函数中定义一个指针变量,使其恰好等于RCC_Typedef的基地址,那么根据基地址+偏移地址的方式,就可以利用结构体来访问相关寄存器而不用再去记忆一系列的地址。
RCC_Typedef *p;
p = (RCC_Typedef *) 0x40021000 ;
由此,若需要使用某一个寄存器.
RCC-> APB2ENR |= (1<<2); //使用APB2ENR寄存器,将其第2位置1
依次对GPIO也进行类似的转换,那么main.h文件中
#ifndef __MAIN_H_
#define __MAIN_H_
typedef struct
{
unsinged int CR;
unsinged int CFGR;
unsinged int CIR;
unsinged int APB2RSTR;
unsinged int APB1RSTR;
unsinged int AHBENR;
unsinged int APB2ENR;
unsinged int APB1ENR;
unsinged int BDCR;
unsinged int CSR;
unsinged int AHBRSTR; //其中后两个寄存器是互联型的
unsinged int CFRG2;
}RCC_Typedef;
#define RCC ((RCC_Typedef *) 0x400210000)
typedef struct
{
unsinged int CRL;
unsinged int CRH;
unsinged int IDR;
unsinged int ODR;
unsinged int BSRR;
unsinged int BRR;
unsinged int LCKR;
}GPIOA_Typedef;
#define GPIOA ((GPIOA_Typedef *) 0x40010800)
#endif
那么替换后的代码格式即为:
#include "stm32f10x.h"
#include "main.h"
void Delay(unsigned long N);
int main(void)
{
RCC -> APB2ENR |=(1<<2); //RCCAPB2ENR |= (1<<2);
GPIOA -> CRL &= 0xfff0000f; //GPIOA_CRL &= 0xfff0000f;
GPIOA -> CRL |= 0x00033330; //GPIOA_CRL |= 0x00033330;
GPIOA -> ODR &= ~((1<<1)|(1<<2)|(1<<3)|(1<<4)); //GPIOA_ODR &= ~((1<<1)|(1<<2)|(1<<3)|(1<<4));
while(1)
{
GPIOA -> ODR &= ((1<<1)|(1<<2)|(1<<3)|(1<<4)); // GPIOA_ODR &= ((1<<1)|(1<<2)| (1<<3)|(1<<4));
Delay(10000);
}
}
void Delay(unsigned long N)
{
for(;N!=0;N--);
}