【STM32】编写程序控制开发板的RGB LED灯

目录

1、原理图

如图知,拉低为点亮

  • LED

    引脚 状态
    D3红 PB5 输出, 拉低为亮
    D3绿 PB0 输出, 拉低为亮
    D3蓝 PB1 输出, 拉低为亮

2、文件结构

3、使用寄存器模式点亮

3.1、什么是寄存器

寄存器是微控制器(MCU)内部的一种特殊存储器,用于存储配置参数、状态信息或控制信号。每个寄存器通常有固定的地址,并且每一位或一组位对应特定的功能。

3.2、寄存器开发的本质

寄存器开发的本质是直接与硬件交互,绕过高级库(如 HAL 库或标准库)的封装,直接操作底层硬件。

STM32 的寄存器开发是通过直接读写寄存器来实现对外设的控制。

3.3、寄存器开发步骤

(1) 查找寄存器地址

  • 根据 STM32 的参考手册(Reference Manual),找到目标外设的寄存器地址。
  • 每个外设(如 GPIO、TIMER、USART 等)都有一组寄存器,用于配置和控制其行为。

(2) 配置寄存器

  • 通过指针操作或直接访问寄存器地址,向寄存器写入特定的值,以配置外设的工作模式、中断、时钟等。

(3) 读取寄存器

  • 通过读取寄存器的值,获取外设的状态信息(如标志位、数据等)。

3.4、主要源码

3.4.1、main.c
c 复制代码
#include "drv_gpio.h"

// SysTick 初始化
void SysTick_Init(void)
{
	SysTick->LOAD = 72000000 / 1000 - 1; // 1ms 延时
	SysTick->VAL = 0;					 // 清空当前值
	SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk;
}

// 精确延时函数(单位:ms)
void Delay_ms(uint32_t ms)
{
	for (uint32_t i = 0; i < ms; i++)
	{
		while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk))
			;
	}
}

int main()
{
	// 初始化 SysTick
	SysTick_Init();
	
	// 初始化 RGB LED
	RGB_Init();


	while (1)
	{
		RGB_RedOn();
		Delay_ms(500);  // 延时 500ms
		RGB_RedOff();

		RGB_GreenOn();
		Delay_ms(500);  // 延时 500ms
		RGB_GreenOff();

		RGB_BlueOn();
		Delay_ms(500);  // 延时 500ms
		RGB_BlueOff();
	}
}
3.4.2、drv_gpio.h
c 复制代码
#ifndef _DRV_GPIO_H_
#define _DRV_GPIO_H_

//ARM提供的,有所有外设寄存器的信息
#include "stm32f10x.h"

void RGB_Init(void);

void RGB_RedOn(void);

void RGB_RedOff(void);

void RGB_GreenOn(void);

void RGB_GreenOff(void);

void RGB_BlueOn(void);

void RGB_BlueOff(void);

#endif
3.4.3、drv_gpio.c
c 复制代码
#include "drv_gpio.h"

void RGB_Init(void)
{

	// 1.配置RCC
	RCC->APB2ENR |= (1 << 3);

	// 2.配置PB5的功能
	// bit 20~23 全部置为0
	//  bit 20 置为1
	//pb5
	GPIOB->CRL &= (uint32_t)(~(0xF << 20));
	GPIOB->CRL |= (uint32_t)(1 << 20);  //配置为通用推挽输出模式(0b0001)
	//pb0
	GPIOB->CRL &= (uint32_t)(~(0xF));
	GPIOB->CRL |= (uint32_t)(1);
	//pb1
	GPIOB->CRL &= (uint32_t)(~(0xF << 4));
	GPIOB->CRL |= (uint32_t)(1 << 4);  

	// 3.将pb5、pb0、pb1的初始值改为1,防止配置完就亮灯
	GPIOB->ODR |= (1 << 5);
	GPIOB->ODR |= 1;
	GPIOB->ODR |= (1 << 1);


}


void RGB_RedOn(void)
{
	// 3.拉低PB5对应的ODR寄存器地址
	GPIOB->ODR &= ~(1 << 5);
}


void RGB_RedOff(void)
{
	GPIOB->ODR |= (1 << 5);
}

void RGB_GreenOn(void)
{
	GPIOB->ODR &= ~(1);
}

void RGB_GreenOff(void)
{
	GPIOB->ODR |= 1;
}

void RGB_BlueOn(void)
{
	GPIOB->ODR &= ~(1 << 1);
}

void RGB_BlueOff(void)
{
	GPIOB->ODR |= (1 << 1);
}
3.4.4、使用BSRR和BRR影子寄存器优化drv_gpio.c

由于对ODR直接操作, 可能有意无意修改到其他引脚的状态

c 复制代码
#include "drv_gpio.h"

void RGB_Init(void)
{

	// 1.配置RCC
	RCC->APB2ENR |= (1 << 3);

	// 2.配置PB5的功能
	// bit 20~23 全部置为0
	//  bit 20 置为1
	//pb5
	GPIOB->CRL &= (uint32_t)(~(0xF << 20));
	GPIOB->CRL |= (uint32_t)(1 << 20);  //配置为通用推挽输出模式(0b0001)
	//pb0
	GPIOB->CRL &= (uint32_t)(~(0xF));
	GPIOB->CRL |= (uint32_t)(1);
	//pb1
	GPIOB->CRL &= (uint32_t)(~(0xF << 4));
	GPIOB->CRL |= (uint32_t)(1 << 4);  

	// 3.将pb5、pb0、pb1的初始值改为1,防止配置完就亮灯
	GPIOB->ODR |= (1 << 5);
	GPIOB->ODR |= 1;
	GPIOB->ODR |= (1 << 1);


}


void RGB_RedOn(void)
{
	// 3.拉低PB5对应的ODR寄存器地址
	//GPIOB->ODR &= ~(1 << 5); 
	GPIOB->BRR &= (1 << 5);// 直接将PB5拉低,同时不影响其他位
}


void RGB_RedOff(void)
{
	//GPIOB->ODR |= (1 << 5);
	GPIOB->BSRR |= (1 << 5); //直接拉高,并不影响
}

void RGB_GreenOn(void)
{
	//GPIOB->ODR &= ~(1);
	GPIOB->BRR &= (1);
}

void RGB_GreenOff(void)
{
	//GPIOB->ODR |= 1;
	GPIOB->BSRR |= (1);
}

void RGB_BlueOn(void)
{
	//GPIOB->ODR &= ~(1 << 1);
	GPIOB->BRR &= (1 << 1);
}

void RGB_BlueOff(void)
{
	//GPIOB->ODR |= (1 << 1);
	GPIOB->BSRR |= (1 << 1);
}
3.4.5、效果演示

4、使用标准库模式点亮

4.1、使用标准库模式的好处

标准库封装了底层寄存器的操作,提供了易于理解的API函数,开发者无需直接读写寄存器。

4.2、主要源码

4.2.1、main.c
c 复制代码
#include "drv_gpio.h"

// SysTick 初始化
void SysTick_Init(void)
{
	SysTick->LOAD = 72000000 / 1000 - 1; // 1ms 延时
	SysTick->VAL = 0;					 // 清空当前值
	SysTick->CTRL = SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_CLKSOURCE_Msk;
}

// 精确延时函数(单位:ms)
void Delay_ms(uint32_t ms)
{
	for (uint32_t i = 0; i < ms; i++)
	{
		while (!(SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk))
			;
	}
}

int main()
{
	// 初始化 SysTick
	SysTick_Init();
	
	// 初始化 RGB LED
	RGB_Init();


	while (1)
	{
		 RGB_RedOn();
		 Delay_ms(500);  // 延时 500ms
		 RGB_RedOff();

		 RGB_GreenOn();
		 Delay_ms(500);  // 延时 500ms
		 RGB_GreenOff();

		 RGB_BlueOn();
		 Delay_ms(500);  // 延时 500ms
		 RGB_BlueOff();

		 RGB_WriteOn();
		 Delay_ms(500);  // 延时 500ms
		 RGB_WriteOff();

	
	}
}
4.2.2、drv_gpio.h
c 复制代码
#ifndef _DRV_GPIO_H_
#define _DRV_GPIO_H_

//使用gpio标准库
#include "stm32f10x_gpio.h"

#define RGB_Port GPIOB
#define RGB_Pin_R GPIO_Pin_5
#define RGB_Pin_G GPIO_Pin_0
#define RGB_Pin_B GPIO_Pin_1


void RGB_Init(void);

void RGB_RedOn(void);

void RGB_RedOff(void);

void RGB_GreenOn(void);

void RGB_GreenOff(void);

void RGB_BlueOn(void);

void RGB_BlueOff(void);

void RGB_WriteOn(void);

void RGB_WriteOff(void);


#endif
4.2.3、drv_gpio.c
c 复制代码
#include "drv_gpio.h"

void RGB_Init(void)
{

	// 1.RCC配置
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

	// 2、配置红、绿、蓝灯输出
	GPIO_InitTypeDef gpio_initStruct = {0};
	gpio_initStruct.GPIO_Pin = RGB_Pin_R | RGB_Pin_G | RGB_Pin_B;
	gpio_initStruct.GPIO_Speed = GPIO_Speed_50MHz;
	gpio_initStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(RGB_Port, &gpio_initStruct);

	GPIO_SetBits(RGB_Port, RGB_Pin_R | RGB_Pin_G | RGB_Pin_B);
}


void RGB_RedOn(void)
{
	// 3.拉低PB5对应的ODR寄存器地址
	GPIO_ResetBits(RGB_Port, RGB_Pin_R);
}

void RGB_RedOff(void)
{
	GPIO_SetBits(RGB_Port, RGB_Pin_R);
}

void RGB_GreenOn(void)
{
	GPIO_ResetBits(RGB_Port, RGB_Pin_G);
}

void RGB_GreenOff(void)
{
	GPIO_SetBits(RGB_Port, RGB_Pin_G);
}

void RGB_BlueOn(void)
{
	GPIO_ResetBits(RGB_Port, RGB_Pin_B);
}

void RGB_BlueOff(void)
{
	GPIO_SetBits(RGB_Port, RGB_Pin_B);
}

void RGB_WriteOn(void)
{
	GPIO_ResetBits(RGB_Port, RGB_Pin_R | RGB_Pin_G | RGB_Pin_B);
}

void RGB_WriteOff(void)
{
	GPIO_SetBits(RGB_Port, RGB_Pin_R | RGB_Pin_G | RGB_Pin_B);
}
4.2.4、效果演示多了白灯
相关推荐
LS_learner10 小时前
树莓派(ARM64 架构)Ubuntu 24.04 (Noble) 系统 `apt update` 报错解决方案
嵌入式硬件
来自晴朗的明天10 小时前
16、电压跟随器(缓冲器)电路
单片机·嵌入式硬件·硬件工程
钰珠AIOT11 小时前
在同一块电路板上同时存在 0805 0603 不同的封装有什么利弊?
嵌入式硬件
代码游侠11 小时前
复习——Linux设备驱动开发笔记
linux·arm开发·驱动开发·笔记·嵌入式硬件·架构
代码游侠21 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
xuxg20051 天前
4G 模组 AT 命令解析框架课程正式发布
stm32·嵌入式·at命令解析框架
CODECOLLECT1 天前
京元 I62D Windows PDA 技术拆解:Windows 10 IoT 兼容 + 硬解码模块,如何降低工业软件迁移成本?
stm32·单片机·嵌入式硬件
BackCatK Chen1 天前
STM32+FreeRTOS:嵌入式开发的黄金搭档,未来十年就靠它了!
stm32·单片机·嵌入式硬件·freertos·低功耗·rtdbs·工业控制
全栈游侠1 天前
STM32F103XX 02-电源与备份寄存器
stm32·单片机·嵌入式硬件