1.STM32:GPIO应用:点亮RGB LED

目录

点亮RGB LED

RGB LED原理图

寄存器点亮RGB

点亮前须知

代码段

标准库点亮RGB(演变过程)

代码段1

stm32f10x.h文件

main函数下

代码段2

stm32f10x.h文件

stm32f10x_gpio.h文件

stm32f10x_gpio.c文件

main函数下

代码段3

stm32f10x.h文件

stm32f10x_gpio.h文件

stm32f10x_gpio.c文件

main函数下

HAL库点亮rgb

MX_GPIO_Init函数(总IO初始化)

GPIO_InitTypeDef初始化结构体

打开时钟

HAL_GPIO_Init()初始化函数

HAL_GPIO接口函数

点亮RGB LED


点亮RGB LED

RGB LED原理图

根据原理图可知,LED低电平有效。上图中为了保护引脚,避免输入电流过大,所以加入了3个限流电阻。

寄存器点亮RGB

点亮前须知

要想实现LED点亮,需要三个步骤(以PB0为实验引脚):

1)打开GPIOB端口的时钟(RCC_APB2ENR寄存器)。

2)配置IO口为输出(GPIOx_CRL寄存器)。

3)控制ORD寄存器(GPIOx_ODR寄存器)。

翻阅STM32F103参考手册存储器映射,可发现:

代码段

//打开GPIOB端口的时钟 
* (unsigned int *)0x40021018 |= ( (1) << 3 );
		
//配置IO口为推挽输出,最大速度10MHz
* (unsigned int *)0x40010C00 &=~ ( (0x0f) << (4*0) );	//先清零
* (unsigned int *)0x40010C00 |=  ( (1) << (4*0) );		//再取值
	
//控制ODR寄存器
* (unsigned int *)0x40010C0C &=~ (1<<0);	            //低电平有效

标准库点亮RGB(演变过程)

代码段1

对程序进行改进,引入stm32f10x.h,描述的是寄存器映射。

stm32f10x.h文件
//用来存放STM32寄存器映射的代码

//外设 perirhral
#define PERIRH_BASE				((unsigned int)0x40000000) 
#define APB1PERIRH_BASE			PERIRH_BASE 
#define APB2PERIRH_BASE			(APB1PERIRH_BASE + 0x10000) 
#define AHBPERIRH_BASE			(APB1PERIRH_BASE + 0x20000) 

#define RCC_BASE				(AHBPERIRH_BASE + 0x1000) 
#define GPIOB_BASE				(APB2PERIRH_BASE + 0x0C00)

#define RCC_APB2ENR				*(unsigned int*)(RCC_BASE + 0x18) 

#define GPIOB_CRL				*(unsigned int*)(GPIOB_BASE + 0x00)
#define GPIOB_CRH				*(unsigned int*)(GPIOB_BASE + 0x04)
#define GPIOB_ODR				*(unsigned int*)(GPIOB_BASE + 0x0C)	
main函数下
//打开GPIOB端口的时钟 
RCC_APB2ENR |= ( (1) << 3 );
		
//配置IO口为推挽输出,最大速度10MHz
GPIOB_CRL &=~ ( (0x0f) << (4*0) );
GPIOB_CRL |= ( (1) << (4*0) );
	
//控制ODR寄存器
GPIOB_ODR &=~ (1<<0);	//看原理图,高电平不亮。所以要输出低电平

代码段2

再进行改进。增加stm32f10x_gpio的文件。

stm32f10x.h文件
//用来存放STM32寄存器映射的代码

//外设 perirhral
#define PERIRH_BASE				((unsigned int)0x40000000) 
#define APB1PERIRH_BASE			PERIRH_BASE 
#define APB2PERIRH_BASE			(APB1PERIRH_BASE + 0x10000) 
#define AHBPERIRH_BASE			(APB1PERIRH_BASE + 0x20000) 

#define RCC_BASE				(AHBPERIRH_BASE + 0x1000) 
#define GPIOB_BASE				(APB2PERIRH_BASE + 0x0C00)

#define RCC_APB2ENR				*(unsigned int*)(RCC_BASE + 0x18) 

#define GPIOB_CRL				*(unsigned int*)(GPIOB_BASE + 0x00)
#define GPIOB_CRH				*(unsigned int*)(GPIOB_BASE + 0x04)
#define GPIOB_ODR				*(unsigned int*)(GPIOB_BASE + 0x0C)	

typedef unsigned int 		uint32_t;
typedef unsigned short 		uint16_t;

typedef struct
{
	uint32_t CRL;
	uint32_t CRH;
	uint32_t IDR;
	uint32_t ODR;
	uint32_t BSRR;
	uint32_t BRR;
	uint32_t LCKR;
}GPIO_TypeDef;

typedef struct
{
	uint32_t CR;
	uint32_t CFGR;
	uint32_t CIR;
	uint32_t APB2RSTR;
	uint32_t APB1RSTR;
	uint32_t AHBENR;
	uint32_t APB2ENR;
	uint32_t APB1ENR;
	uint32_t DBCR;
	uint32_t CSR;
}RCC_TypeDef;

#define GPIOB 					((GPIO_TypeDef *)GPIOB_BASE)
#define RCC 					((RCC_TypeDef *)RCC_BASE)
stm32f10x_gpio.h文件
#ifndef _STM32F10X_GPIO_H
#define _STM32F10X_GPIO_H

#include "stm32f10x.h"

#define GPIO_Pin_0		((uint16_t)0x0001) 	/*!<选择Pin1 */		//(00000000 00000001)b
#define GPIO_Pin_1		((uint16_t)0x0002) 	/*!<选择Pin2 */		//(00000000 00000010)b
#define GPIO_Pin_2		((uint16_t)0x0004) 	/*!<选择Pin3 */		//(00000000 00000100)b
#define GPIO_Pin_3		((uint16_t)0x0008) 	/*!<选择Pin4 */		//(00000000 00001000)b
#define GPIO_Pin_4		((uint16_t)0x0010) 	/*!<选择Pin5 */		//(00000000 00010000)b
#define GPIO_Pin_5		((uint16_t)0x0020) 	/*!<选择Pin6 */		//(00000000 00100000)b
#define GPIO_Pin_6		((uint16_t)0x0040) 	/*!<选择Pin7 */		//(00000000 01000000)b
#define GPIO_Pin_7		((uint16_t)0x0080) 	/*!<选择Pin8 */		//(00000000 10000000)b

#define GPIO_Pin_8		((uint16_t)0x0100) 	/*!<选择Pin9 */		//(00000001 00000000)b
#define GPIO_Pin_9		((uint16_t)0x0200) 	/*!<选择Pin10 */	//(00000010 00000000)b
#define GPIO_Pin_10		((uint16_t)0x0400) 	/*!<选择Pin11 */	//(00000100 00000000)b
#define GPIO_Pin_11		((uint16_t)0x0800) 	/*!<选择Pin12 */	//(00001000 00000000)b
#define GPIO_Pin_12		((uint16_t)0x1000) 	/*!<选择Pin13 */	//(00010000 00000000)b
#define GPIO_Pin_13		((uint16_t)0x2000) 	/*!<选择Pin14 */	//(00100000 00000000)b
#define GPIO_Pin_14		((uint16_t)0x4000) 	/*!<选择Pin15 */	//(01000000 00000000)b
#define GPIO_Pin_15		((uint16_t)0x8000) 	/*!<选择Pin16 */	//(10000000 00000000)b
#define GPIO_Pin_All	((uint16_t)0xFFFF) 	/*!<选择全部引脚 */	//(11111111 11111111)b

void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
	
#endif /*_STM32F10X_GPIO_H*/
stm32f10x_gpio.c文件
#include "stm32f10x_gpio.h"

void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
 	GPIOx->BSRR |= GPIO_Pin;
}

void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
 	GPIOx->BRR |= GPIO_Pin;
	//GPIOx->BSRR |= GPIO_Pin<<16;		和上行意思一样
}
main函数下
//打开GPIOB端口的时钟 
RCC->APB2ENR |= ( (1) << 3 );
		
//配置IO口为输出,控制CRL寄存器
GPIOB->CRL &=~ ( (0x0f) << (4*0) );
GPIOB->CRL |= ( (1) << (4*0) );
	
GPIO_SetBits(GPIOB,GPIO_Pin_0);			//高电平,灭
//GPIO_ResetBits(GPIOB,GPIO_Pin_0);		//低电平,亮

代码段3

最后进行改进。对于GPIO的初始化函数和GPIOMode结构体的枚举,可以通过下图来解释。

  

stm32f10x.h文件

照旧 

stm32f10x_gpio.h文件
#ifndef _STM32F10X_GPIO_H
#define _STM32F10X_GPIO_H

#include "stm32f10x.h"

#define GPIO_Pin_0		((uint16_t)0x0001) 	/*!<选择Pin1 */		//(00000000 00000001)b
#define GPIO_Pin_1		((uint16_t)0x0002) 	/*!<选择Pin2 */		//(00000000 00000010)b
#define GPIO_Pin_2		((uint16_t)0x0004) 	/*!<选择Pin3 */		//(00000000 00000100)b
#define GPIO_Pin_3		((uint16_t)0x0008) 	/*!<选择Pin4 */		//(00000000 00001000)b
#define GPIO_Pin_4		((uint16_t)0x0010) 	/*!<选择Pin5 */		//(00000000 00010000)b
#define GPIO_Pin_5		((uint16_t)0x0020) 	/*!<选择Pin6 */		//(00000000 00100000)b
#define GPIO_Pin_6		((uint16_t)0x0040) 	/*!<选择Pin7 */		//(00000000 01000000)b
#define GPIO_Pin_7		((uint16_t)0x0080) 	/*!<选择Pin8 */		//(00000000 10000000)b

#define GPIO_Pin_8		((uint16_t)0x0100) 	/*!<选择Pin9 */		//(00000001 00000000)b
#define GPIO_Pin_9		((uint16_t)0x0200) 	/*!<选择Pin10 */	//(00000010 00000000)b
#define GPIO_Pin_10		((uint16_t)0x0400) 	/*!<选择Pin11 */	//(00000100 00000000)b
#define GPIO_Pin_11		((uint16_t)0x0800) 	/*!<选择Pin12 */	//(00001000 00000000)b
#define GPIO_Pin_12		((uint16_t)0x1000) 	/*!<选择Pin13 */	//(00010000 00000000)b
#define GPIO_Pin_13		((uint16_t)0x2000) 	/*!<选择Pin14 */	//(00100000 00000000)b
#define GPIO_Pin_14		((uint16_t)0x4000) 	/*!<选择Pin15 */	//(01000000 00000000)b
#define GPIO_Pin_15		((uint16_t)0x8000) 	/*!<选择Pin16 */	//(10000000 00000000)b
#define GPIO_Pin_All	((uint16_t)0xFFFF) 	/*!<选择全部引脚 */	//(11111111 11111111)b

typedef enum
{
	GPIO_Speed_10MHz = 1,		//10MHz		(01)b
	GPIO_Speed_2MHz,			// 2MHz		(10)b		
	GPIO_Speed_50MHz			//50MHz		(11)b
}GPIOSpeed_TypeDef;

typedef enum
{
	GPIO_Mode_AIN  = 0x0, 				//模拟输入 		(0000 0000)b
	GPIO_Mode_IN_FLOATING = 0x04,		//浮空输入 		(0000 0100)b
	GPIO_Mode_IPD  = 0x28,				//下拉输入 		(0010 1000)b
	GPIO_Mode_IPU  = 0x48,				//上拉输入 		(0100 1000)b
	
	GPIO_Mode_OUT_OD  = 0x14,			//开漏输出 		(0001 0100)b
	GPIO_Mode_OUT_PP  = 0x10,			//推挽输出 		(0001 0000)b
	GPIO_Mode_AF_OD  = 0x1C,			//复用开漏输出 	(0001 1100)b
	GPIO_Mode_AF_PP  = 0x18				//复用推挽输出 	(0001 1000)b
}GPIOMode_TypeDef;

typedef struct
{
	uint16_t GPIO_Pin;
	uint16_t GPIO_Speed;
	uint16_t GPIO_Mode;
}GPIO_InitTypeDef;

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);

#endif /*_STM32F10X_GPIO_H*/
stm32f10x_gpio.c文件
#include "stm32f10x_gpio.h"

void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
 	GPIOx->BSRR |= GPIO_Pin;
}

void GPIO_ResetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
 	GPIOx->BRR |= GPIO_Pin;
	//GPIOx->BSRR |= GPIO_Pin<<16;		和上行意思一样
}

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
	uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
	uint32_t tmpreg = 0x00, pinmask = 0x00;
  
	/*---------------------- GPIO 模式配置 --------------------------*/
	// 把输入参数GPIO_Mode的低四位暂存在currentmode
	currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
		
	// bit4是1表示输出,bit4是0则是输入 
	// 判断bit4是1还是0,即首选判断是输入还是输出模式
	if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
	{ 
		// 输出模式则要设置输出速度
		currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
	}
	/*-------------GPIO CRL 寄存器配置 CRL寄存器控制着低8位IO- -------*/
	// 配置端口低8位,即Pin0~Pin7
	if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
	{
			// 先备份CRL寄存器的值
			tmpreg = GPIOx->CRL;
			
			// 循环,从Pin0开始配对,找出具体的Pin
			for (pinpos = 0x00; pinpos < 0x08; pinpos++)
			{
					// pos的值为1左移pinpos位
					pos = ((uint32_t)0x01) << pinpos;
			  
					// 令pos与输入参数GPIO_PIN作位与运算,为下面的判断作准备
					currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
							
					//若currentpin=pos,则找到使用的引脚
					if (currentpin == pos)
					{
							// pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
							pos = pinpos << 2;
						   //把控制这个引脚的4个寄存器位清零,其它寄存器位不变
							pinmask = ((uint32_t)0x0F) << pos;
							tmpreg &= ~pinmask;
							
							// 向寄存器写入将要配置的引脚的模式
							tmpreg |= (currentmode << pos);  
									
							// 判断是否为下拉输入模式
							if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
							{
								  // 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
								  GPIOx->BRR = (((uint32_t)0x01) << pinpos);
							}				
							else
							{
								  // 判断是否为上拉输入模式
								  if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
								  {
										// 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
										GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
								  }
							}
					}
			}
			// 把前面处理后的暂存值写入到CRL寄存器之中
			GPIOx->CRL = tmpreg;
	}
	/*-------------GPIO CRH 寄存器配置 CRH寄存器控制着高8位IO- -----------*/
	// 配置端口高8位,即Pin8~Pin15
	if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
	{
		// 先备份CRH寄存器的值
		tmpreg = GPIOx->CRH;
			
		// 循环,从Pin8开始配对,找出具体的Pin
		for (pinpos = 0x00; pinpos < 0x08; pinpos++)
		{
			  pos = (((uint32_t)0x01) << (pinpos + 0x08));
					
			  // pos与输入参数GPIO_PIN作位与运算
			  currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
					
			  //若currentpin=pos,则找到使用的引脚
			  if (currentpin == pos)
			  {
					//pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
					pos = pinpos << 2;
					
					//把控制这个引脚的4个寄存器位清零,其它寄存器位不变
					pinmask = ((uint32_t)0x0F) << pos;
					tmpreg &= ~pinmask;
							
					// 向寄存器写入将要配置的引脚的模式
					tmpreg |= (currentmode << pos);
					
					// 判断是否为下拉输入模式
					if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
					{
						  // 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
						  GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
					}
					// 判断是否为上拉输入模式
					if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
					{
						  // 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
						  GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
					}
			  }
		}
		// 把前面处理后的暂存值写入到CRH寄存器之中
		GPIOx->CRH = tmpreg;
	}
}
main函数下
#define 	LED_G_GPIO_PORT				GPIOB
#define 	LED_G_GPIO_CLK_ENABLE		(RCC_APB2ENR |= ( (1) << 3 ))
#define		LED_G_GPIO_PIN				GPIO_Pin_0

#define 	LED_B_GPIO_PORT				GPIOB
#define 	LED_B_GPIO_CLK_ENABLE		(RCC_APB2ENR |= ( (1) << 3 ))
#define		LED_B_GPIO_PIN				GPIO_Pin_1

#define 	LED_R_GPIO_PORT				GPIOB
#define 	LED_R_GPIO_CLK_ENABLE		(RCC_APB2ENR |= ( (1) << 3 ))
#define		LED_R_GPIO_PIN				GPIO_Pin_5

void Delay(uint32_t count)
{
	for( ; count != 0 ; count--)
	{}
}

int main()
{
    GPIO_InitTypeDef GPIO_InitStructure;
	
    //打开GPIOB端口的时钟 
    LED_G_GPIO_CLK_ENABLE;
	
    GPIO_InitStructure.GPIO_Pin = LED_B_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(LED_G_GPIO_PORT,&GPIO_InitStructure);
	
    while(1)
    {
	    GPIO_SetBits(LED_G_GPIO_PORT, LED_B_GPIO_PIN);		//高电平,灭
	    Delay(0xF5FF);
	    GPIO_ResetBits(LED_G_GPIO_PORT, LED_B_GPIO_PIN);	//低电平,亮
	    Delay(0xF5FF);
    }
}

HAL库点亮rgb

利用STM32CubeMX对RGB LED引脚进行推挽输出配置生成HAL库。

MX_GPIO_Init函数(总IO初始化)

void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_1, GPIO_PIN_RESET);

  /*Configure GPIO pins : PB0 PB1 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PB5 */
  GPIO_InitStruct.Pin = GPIO_PIN_5;
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

GPIO_InitTypeDef初始化结构体

typedef struct
{
  uint32_t Pin;		//GPIO_pins_define中选择
  uint32_t Mode;	//GPIO_mode_define中选择
  uint32_t Pull;	//GPIO_pull_define中选择
  uint32_t Speed;	//GPIO_speed_define中选择
} GPIO_InitTypeDef;	//stm32f1x_hal_gpio.h

4个32位的配置寄存器共同决定了I/O的功能配置选择,GPIO_InitTypeDef结构体的功能是选择GPIO的引脚号、模式、上下拉、最大速度。

打开时钟

__HAL_RCC_GPIOB_CLK_ENABLE();

#define __HAL_RCC_GPIOB_CLK_ENABLE()   do { \
                                        __IO uint32_t tmpreg; \
                                        SET_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN);\
                                        /* Delay after an RCC peripheral clock enabling */\
                                        tmpreg = READ_BIT(RCC->APB2ENR, RCC_APB2ENR_IOPBEN);\
                                        UNUSED(tmpreg); \
                                      } while(0U)

宏定义do...while(0) 的目的是为了确保宏定义在使用时与函数调用一样的语法,同时避免一些潜在的问题。

1、语法正确性:在C语言中,条件语句if、while等后面通常跟着一个代码块({}内语句),而宏定义展开后的代码会被直接替换到宏调用的地方。如果宏定义不适用do...while(0)包裹,当我们在使用if、while等语句调用宏时,可能会导致语法错误。使用do...while(0)可以确保宏定义展开后的代码成为一个完整的代码块,避免了这种问题。

2、语义正确性:使用do...while(0)可以确保宏定义在调用时作为一个整体,不会被其他语句的控制流程所影响。例如,如果没有do...while(0),在宏定义中使用的变量可能会与外部变量冲突,导致逻辑错误。

3、错误检查:使用do...while(0)可以让编辑器检查宏定义中的语法错误。如果宏定义中出现了语法错误,编译器会在编译时报错,而不是在运行时才发现。

4、代码规范性:使用do...while(0)可以使代码更具可读性和一致性。它使得宏定义的调用方法与函数调用相似,提高了代码的可读性和可维护性。

HAL_GPIO_Init()初始化函数

/**
  * @brief  Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.
  * @param  GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
  * @param  GPIO_Init: pointer to a GPIO_InitTypeDef structure that contains
  *         the configuration information for the specified GPIO peripheral.
  * @retval None
  */
void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{
  uint32_t position = 0x00u;
  uint32_t ioposition;
  uint32_t iocurrent;
  uint32_t temp;
  uint32_t config = 0x00u;
  __IO uint32_t *configregister; /* Store the address of CRL or CRH register based on pin number */
  uint32_t registeroffset;       /* offset used during computation of CNF and MODE bits placement inside CRL or CRH register */

  /* Check the parameters */
  assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
  assert_param(IS_GPIO_MODE(GPIO_Init->Mode));

  /* Configure the port pins */
  while (((GPIO_Init->Pin) >> position) != 0x00u)
  {
    /* Get the IO position */
    ioposition = (0x01uL << position);

    /* Get the current IO position */
    iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition;

    if (iocurrent == ioposition)
    {
      /* Check the Alternate function parameters */
      assert_param(IS_GPIO_AF_INSTANCE(GPIOx));

      /* Based on the required mode, filling config variable with MODEy[1:0] and CNFy[3:2] corresponding bits */
      switch (GPIO_Init->Mode)
      {
        /* If we are configuring the pin in OUTPUT push-pull mode */
        case GPIO_MODE_OUTPUT_PP:
          /* Check the GPIO speed parameter */
          assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
          config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_PP;
          break;

        /* If we are configuring the pin in OUTPUT open-drain mode */
        case GPIO_MODE_OUTPUT_OD:
          /* Check the GPIO speed parameter */
          assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
          config = GPIO_Init->Speed + GPIO_CR_CNF_GP_OUTPUT_OD;
          break;

        /* If we are configuring the pin in ALTERNATE FUNCTION push-pull mode */
        case GPIO_MODE_AF_PP:
          /* Check the GPIO speed parameter */
          assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
          config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_PP;
          break;

        /* If we are configuring the pin in ALTERNATE FUNCTION open-drain mode */
        case GPIO_MODE_AF_OD:
          /* Check the GPIO speed parameter */
          assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
          config = GPIO_Init->Speed + GPIO_CR_CNF_AF_OUTPUT_OD;
          break;

        /* If we are configuring the pin in INPUT (also applicable to EVENT and IT mode) */
        case GPIO_MODE_INPUT:
        case GPIO_MODE_IT_RISING:
        case GPIO_MODE_IT_FALLING:
        case GPIO_MODE_IT_RISING_FALLING:
        case GPIO_MODE_EVT_RISING:
        case GPIO_MODE_EVT_FALLING:
        case GPIO_MODE_EVT_RISING_FALLING:
          /* Check the GPIO pull parameter */
          assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
          if (GPIO_Init->Pull == GPIO_NOPULL)
          {
            config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_FLOATING;
          }
          else if (GPIO_Init->Pull == GPIO_PULLUP)
          {
            config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;

            /* Set the corresponding ODR bit */
            GPIOx->BSRR = ioposition;
          }
          else /* GPIO_PULLDOWN */
          {
            config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_INPUT_PU_PD;

            /* Reset the corresponding ODR bit */
            GPIOx->BRR = ioposition;
          }
          break;

        /* If we are configuring the pin in INPUT analog mode */
        case GPIO_MODE_ANALOG:
          config = GPIO_CR_MODE_INPUT + GPIO_CR_CNF_ANALOG;
          break;

        /* Parameters are checked with assert_param */
        default:
          break;
      }

      /* Check if the current bit belongs to first half or last half of the pin count number
       in order to address CRH or CRL register*/
      configregister = (iocurrent < GPIO_PIN_8) ? &GPIOx->CRL     : &GPIOx->CRH;
      registeroffset = (iocurrent < GPIO_PIN_8) ? (position << 2u) : ((position - 8u) << 2u);

      /* Apply the new configuration of the pin to the register */
      MODIFY_REG((*configregister), ((GPIO_CRL_MODE0 | GPIO_CRL_CNF0) << registeroffset), (config << registeroffset));

      /*--------------------- EXTI Mode Configuration ------------------------*/
      /* Configure the External Interrupt or event for the current IO */
      if ((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
      {
        /* Enable AFIO Clock */
        __HAL_RCC_AFIO_CLK_ENABLE();
        temp = AFIO->EXTICR[position >> 2u];
        CLEAR_BIT(temp, (0x0Fu) << (4u * (position & 0x03u)));
        SET_BIT(temp, (GPIO_GET_INDEX(GPIOx)) << (4u * (position & 0x03u)));
        AFIO->EXTICR[position >> 2u] = temp;


        /* Enable or disable the rising trigger */
        if ((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
        {
          SET_BIT(EXTI->RTSR, iocurrent);
        }
        else
        {
          CLEAR_BIT(EXTI->RTSR, iocurrent);
        }

        /* Enable or disable the falling trigger */
        if ((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
        {
          SET_BIT(EXTI->FTSR, iocurrent);
        }
        else
        {
          CLEAR_BIT(EXTI->FTSR, iocurrent);
        }

        /* Configure the event mask */
        if ((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
        {
          SET_BIT(EXTI->EMR, iocurrent);
        }
        else
        {
          CLEAR_BIT(EXTI->EMR, iocurrent);
        }

        /* Configure the interrupt mask */
        if ((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
        {
          SET_BIT(EXTI->IMR, iocurrent);
        }
        else
        {
          CLEAR_BIT(EXTI->IMR, iocurrent);
        }
      }
    }

	position++;
  }
}

HAL_GPIO接口函数

void  HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init);
void  HAL_GPIO_DeInit(GPIO_TypeDef  *GPIOx, uint32_t GPIO_Pin);
 
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
 
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

点亮RGB LED

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于使用STM32控制RGB,可以通过以下几个步骤实现: 1. 首先,确定所使用的STM32开发板型号,并在开发环境中配置好相关的开发工具和库文件。 2. 确定RGB的接口方式,一般可以通过GPIO(通用输入输出)来控制。根据的类型和电路连接方式,确定需要使用哪些GPIO引脚。 3. 在代码中配置GPIO引脚的工作模式,将其设置为输出模式。使用STM32的库函数或者直接操作寄存器来完成配置。 4. 根据需求,编写代码来控制RGB的颜色和亮度。可以通过控制每个颜色通道的电平来实现。 下面是一个简单的示例代码,以控制三种颜色分别为红、绿、蓝的RGB为例: ```c #include "stm32f4xx.h" #define RED_LED_PIN GPIO_Pin_0 #define GREEN_LED_PIN GPIO_Pin_1 #define BLUE_LED_PIN GPIO_Pin_2 void delay_ms(uint32_t ms) { while (ms--) { for (volatile uint32_t i = 0; i < 2000; i++); } } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; // 使能GPIO时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // 配置GPIO引脚为输出模式 GPIO_InitStructure.GPIO_Pin = RED_LED_PIN | GREEN_LED_PIN | BLUE_LED_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure); while (1) { // 依次点亮红、绿、蓝 GPIO_SetBits(GPIOA, RED_LED_PIN); delay_ms(1000); GPIO_ResetBits(GPIOA, RED_LED_PIN); GPIO_SetBits(GPIOA, GREEN_LED_PIN); delay_ms(1000); GPIO_ResetBits(GPIOA, GREEN_LED_PIN); GPIO_SetBits(GPIOA, BLUE_LED_PIN); delay_ms(1000); GPIO_ResetBits(GPIOA, BLUE_LED_PIN); } } ``` 以上代码只是一个简单示例,您可以根据实际需求进行修改和扩展。希望对您有所帮助!如果有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值