这次是从头开始学习STM32,看野火的视频开始学习,感觉需要记录的时候就要记录一下学习的心得。野火视频学习的老师讲的还是很到位的,能够学习到很多的细节之处,有时会感觉很啰嗦,但是不得不说确实很详细,只有这样对于真正的底层才能更清楚明白是怎么回事,原理很重要。写这篇博文的目的是记录我的练习过程中连续好几天犯得同一个错误,每次写都这样,而且找半天找不到哪里错了,必须拿着原来写的一行一行的对,才能发现问题,特此记录一下,下次再范同样的错误时就来看这篇文章吧!感觉这样就能快速的定位错误了。我犯得错误就是每次宏定义外设基地址时都定义成了无符号整型指针类型了,其实只需要定义成无符号整型类型就好了。结果每次都忘了这事,今天有一次查了半天,感觉还是要记录一下才对,太浪费时间了。
好了,多了不想说了,直接贴代码吧:
#include "stm32f10x.h"
int main(void)
{
/*
RCC_APB2ENR = 0x0008; //APB2外设时钟使能寄存器
GPIOB_CRL = 0x0003; //GPIOB端口配置低寄存器
GPIOB_ODR = 0xFFFE; //GPIOB端口输出配置寄存器
*/
RCC->APB2ENR = 0x0008; //APB2外设时钟使能寄存器
GPIOB->CRL = 0x0003; //GPIOB端口配置低寄存器
GPIOB->ODR = 0xFFFE; //GPIOB端口输出配置寄存器
}
void SystemInit(void)
{
}
#ifndef __STM32F10X_H //如果没有编译__STM32F10X_H
#define __STM32F10X_H //就编译 __STM32F10X_H
typedef unsigned int uint32_t; //把无符号整型重新命名为 :uint32_t
#define PERIPHL_BASE ((uint32_t )0x40000000) // 外设基地址(**********这里主要只是强转成无符号整型(不是指针)**********)
#define APB1_PERIPHL_BASE (PERIPHL_BASE) // APB1基地址 = 外设基地址
#define APB2_PERIPHL_BASE (PERIPHL_BASE + 0x10000) // APB2基地址 = 外设基地址 + 0x10000
#define AHB_PERIPHL_BASE (PERIPHL_BASE + 0x20000) // AHB基地址 = 外设基地址 + 0x20000
#define RCC_BASE (AHB_PERIPHL_BASE + 0x1000) //RCC基地址 = AHB基地址 + 0x1000
#define GPIOB_BASE (APB2_PERIPHL_BASE + 0x0C00) //GPIOB基地址 = APB2基地址 + 0x0C00
//#define RCC_APB2ENR *((uint32_t *)(RCC_BASE + 0x18)) //APB2外设时钟使能寄存器
//#define GPIOB_CRL *((uint32_t *)(GPIOB_BASE + 0x00)) //GPIOB端口配置低寄存器
//#define GPIOB_ODR *((uint32_t *)(GPIOB_BASE + 0x0C)) //GPIOB端口输出配置寄存器
typedef struct
{ //创建结构体GPIO_TypeDef 里面的每个成员地址正好相差4个字节,把GPIOB的地址赋给他
uint32_t CRL; //结构体内部的每个成员的地址就正好是GPIOB每个寄存器的地址,免去了一个一个的#define了
uint32_t CRH;
uint32_t IDR;
uint32_t ODR;
uint32_t BSRR;
uint32_t BRR;
uint32_t LCKR;
}GPIO_TypeDef;
typedef struct
{ //创建结构体RCC_TypeDef 里面的每个成员地址正好相差4个字节,把RCC的基地址赋给他
uint32_t CR; //结构体内部的每个成员的地址就正好是RCC每个寄存器的地址,免去了一个一个的#define了
uint32_t CFGR;
uint32_t CIR;
uint32_t APB2_RSTR;
uint32_t APB1_RSTR;
uint32_t AHBENR;
uint32_t APB2ENR;
uint32_t APB1ENR;
}RCC_TypeDef;
#define GPIOB ((GPIO_TypeDef *)GPIOB_BASE) // GPIOB就是把GPIOB的基地址强转成GPIO结构体的指针
#define RCC ((RCC_TypeDef *)RCC_BASE) // RCC就是把RCC的基地址强转成RCC结构体的指针
#endif /*__STM32F10X_H*/ //结束编译
这个工程是很简单的,从0开始建立工程,自己手写寄存器映射,感觉对标准库的理解又前进了一大步。
整个工程只是参考了数据手册中对RCC和GPIO的寄存器描述
最后编译就能正常点亮GPIOB 0的LED灯了: