stm32寄存器点亮LED

Kael'thas / 2023-05-27 / 原文

stm32编程三种方法

  1. 寄存器操作
  2. 标准库
  3. hal库

寄存器操作:

为什么要有位操作?因为STM32本身只支持8、16、32位整体操作,而不下支持单独一位操作。但是实际中有单独位操作的需求。一般是这么做的:读取整个32位地址,修改,再整体写回去。

什么是寄存器(control register)?

给具有特殊功能的内存地址起了个名字叫xxx寄存器,这些寄存器可以被过软件编程修改从而控制硬件资源。寄存器起码具备以下功能:输入、输出、存储、清除。

什么是GPIO(general purpose input output )?

GPIO是一种寄存器(stm32上的引脚不全是GPIO,有一部分是),作为GPIO的这类引脚可以被编程控制其工作模式、电压高低等。

stm32外设使用的一般步骤

第一步、了解该硬件的通用工作原理,再查看具体原理图

第二步、软件件编程

用寄存器编程点亮一颗LED

第一步、原理:

LED通用原理:LED本身有2个接线点,一个是LED的正极,一个是LED的负极。

LED硬件功能:点亮或熄灭,想要点亮一颗LED只需要给他的正负极上加正电压即可,要熄灭一颗LED只需要去掉电压即可。

image-20230525102732996

第二步、软件件编程:

  1. 使能GPIOB所在时钟:APB2 外设时钟使能寄存器(RCC_APB2ENR)

  2. 设置工作模式设为推挽输出:GPIOx_CRL对应设为0001

  3. 设置GPIOB_ODR点亮LED:GPIOx_ODR给低电平

使能GPIOB所在时钟:

RCC_APB2ENR地址:0x40021000+0x18。3号是B时钟。输入1开启时钟。

*(unsigned int*)0x40021018 |=((1)<<3);
image-20230525221134674 image-20230525215813061

设置工作模式设为推挽输出

CRL实际地址为0x40010C00。四位为一组共有八组,PB1指的是CNF1+MODE1,赋值 0001 0000就是给蓝灯设置通用推挽输出。

//设置蓝灯CRL推挽输出,CNF1+MODE1赋值0001
*( unsigned int*)0x40010C00|= ((1)<<(4*1));
image-20230526223312066

设置ODR点亮LED低电平,ODR实际地址0x40010C0C

*( unsigned int*)0x40010C0C= 0XFFFD;// lighten green led
*( unsigned int*)0x40010C0C= 0XFFFF;// distinguish

源码例程

2023-05-26例程源码:testReg.zip

例程源码:main.c

#define PERIPHERAL_BASE         0x40000000    

#define APB2PERIPHERAL_BASE     (PERIPHERAL_BASE+0x10000)
#define AHBPERIPHERAL_BASE      (PERIPHERAL_BASE+0x20000)

//RCC
#define RCC_BASE                (AHBPERIPHERAL_BASE+0x1000)
#define RCC_APB2ENR             (*(unsigned int*)(RCC_BASE+0x18))
   
//GPIOB
#define GPIOB_BASE              (APB2PERIPHERAL_BASE+0x0C00)
#define GPIOB_CRL               (*(unsigned int*)GPIOB_BASE)
#define GPIOB_CRH               (*(unsigned int*)(GPIOB_BASE+0x04))
#define GPIOB_ODR               (*(unsigned int*)(GPIOB_BASE+0x0C))
 
void delay(unsigned int z);
int main(void){
 
    //打开GPIOB端口的时钟
    RCC_APB2ENR |=((1)<<3);

    //CRL寄存器写入0001,配置推挽输出
    GPIOB_CRL &= ~( 0x0F<< (4*5));//目标位置零
    GPIOB_CRL |= ((1)<<(4*5));//配置0001,red_led推挽输出

    GPIOB_CRL &= ~( 0x0F<< (4*0));
    GPIOB_CRL |= ((1)<<(4*0));//配置0001,green推挽输出
    
    GPIOB_CRL &= ~( 0x0F<< (4*1));
    GPIOB_CRL |= ((1)<<(4*1));//配置0001,blue推挽输出

    while(1){//控制ODR寄存器,低电平点亮led
        
        GPIOB_ODR  = 0XFFDF;
        delay(10000);
        GPIOB_ODR  = 0XFFFF;
        delay(10000);
              
        GPIOB_ODR = 0XFFFE;//lighten green led
        delay(10000);
        GPIOB_ODR = 0XFFFF;
        delay(10000);
        
        GPIOB_ODR = 0XFFFD;//lighten blue led
        delay(10000);
        GPIOB_ODR = 0XFFFF;
        delay(10000);
    }		
}
void SystemInit(void){
	//骗过编译器不报错
}
 
//毫秒级延时函数
void delay(unsigned int z){
	unsigned int x,y;
	for(x = z; x > 0; x--)
		for(y = 114; y > 0 ; y--);
}

遇到的bug

问题1:编译缺少 axf文件,解决:

void SystemInit(){
    //在main.c文件中添加空函数,骗过startup编译器
}

问题2:keil5通过dap仿真烧录到开发板,找不到axf文件

说明编译没通过,否则自动生成axf文件,在Objects文件夹下。

问题3:Flash Download failed - “Cortex-M3“解决方法

image-20230526223312066