目标是自己编写一个简单的寄存器地址映射程序,来控制GPIO口输出高低电平
首先来简单的介绍一下控制stm32IO口的基本操作
1.时钟初始化
2.配置GPIO模式
3.控制GPIO端口输出
时钟初始化 我们需要控制的是GPIOB.5端口 我们可以从下图了解到GPIOB端口是挂载到APB2总线上面的,需要初始化时钟的话就需要用到RCC寄存器 而RCC寄存器是挂载到AHB总线上的,所以接下来我们需要了解一下它们的地址。
先来看2.3节的存储器映像图 每一个外设的功能都对应一个地址我们直接操作的话不方便每次操作都需要来查看手册所以我们自己定义一个映射的话操作起来就要方便很多。当然我这里只是简单的定义一下我们用32的话还是要用库函数因为这些地址的映射工作已经有人给您完成了,有白票的为什么不用。当然自己操作一下的话更容易理解,首先我们看到它对应的地址非常多我们没必要每一个都要去映射只需要映射我们要用到的寄存器就可以了。
#define PERIPH_BASE ((unsigned int)0x40000000)//强制转换为32位的
/*APB2 总线基地址 */
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
我们看见我们要使用的GPIOB端口就是挂载在APB2总线上面的 它比APB2地址多了 0xc00
/*GPIOB外设基地址*/
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
/* AHB总线基地址 */
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
还有RCC的地址需要映射
/*RCC外设基地址*/
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
总结一下刚刚我们把 APB1 APB2 AHB RCC GPIOB的地址映射了接下来我们还需要映射几个地址
下图中的偏移地址我们需要注意它的意思就是基于RCC的偏移地址
/*RCC的AHB1时钟使能寄存器地址,强制转换成指针*/
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)//这里是把这个数据强制转换为一个32位的指针地址 unsigned int 就是转换为32位的意思
下图我们了解到配置寄存器是 GPIOx_CRL, GPIOx_CRH
我们来详细的了解一下 图中我们需要了解的就是偏移地址
/* GPIOB寄存器地址,强制转换成指针 */
#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)
好的通过上面的了解我们就已经完成了一个简单的映射
stm32f10x.h
/*本文件用于添加寄存器地址及结构体定义*/
/*片上外设基地址 */
#define PERIPH_BASE ((unsigned int)0x40000000)
/*APB2 总线基地址 */
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
/* AHB总线基地址 */
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
/*GPIOB外设基地址*/
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
/* GPIOB寄存器地址,强制转换成指针 */
#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE+0x00)
#define GPIOB_CRH *(unsigned int*)(GPIOB_BASE+0x04)
#define GPIOB_IDR *(unsigned int*)(GPIOB_BASE+0x08)
#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 GPIOB_LCKR *(unsigned int*)(GPIOB_BASE+0x18)
//这里还有一个*号的意思是访问对应的内存地址改变它的值
/*RCC外设基地址*/
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
/*RCC的AHB1时钟使能寄存器地址,强制转换成指针*/
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)//这里是把这个数据强制转换为一个32位的指针地址 unsigned int 就是转换为32位的意思
主函数部分
/*
*工程模板(寄存器版本)
*/
#include "stm32f10x.h"
/**
* 主函数
*/
int main(void)
{
// 开启GPIOB 端口时钟
RCC_APB2ENR |= (1<<3);// 1.时钟初始化
//清空控制PB0的端口位
GPIOB_CRL &= ~( 0x0F<< (4*0));//清空寄存器里面的值好进行配置
// 配置PB0为通用推挽输出,速度为10M // 2.GPIO模式配置
GPIOB_CRL |= (1<<4*0);
// PB0 输出 低电平
GPIOB_ODR &= ~(1<<0);// 3.控制GPIO输出电平
while(1);
}
// 函数为空,目的是为了骗过编译器不报错
void SystemInit(void)
{
}
/*********************************************END OF FILE**********************/
最后总结一下要了解stm32就一定要看stm32中文参考手册