STM32使用寄存器点亮 LED 灯

一、GPIO口的简介

每个通用 I/O 端口包括 4 个 32 位配置寄存器(GPIOx_MODER、GPIOx_OTYPER、 GPIOx_OSPEEDR 和 GPIOx_PUPDR)、2 个 32 位数据寄存器(GPIOx_IDR 和 GPIOx_ODR)、1 个 32 位置位/复位寄存器 (GPIOx_BSRR)、1 个 32 位锁定寄存器 (GPIOx_LCKR) 和 2 个 32 位复用功能选择寄存器(GPIOx_AFRH 和 GPIOx_AFRL)。

二、GPIO口的主要模式

GPIO模式可以分为以下几种:

  1. 输入模式:
    • 浮空输入:引脚的电平状态不确定,完全由外部输入决定。
    • 上拉输入:在无输入的情况下,引脚保持高电平。
    • 下拉输入:在无输入的情况下,引脚保持低电平。
    • 模拟输入:输入信号不经施密特触发器直接接入,输入信号为模拟量而非数字量。
  2. 输出模式:
    • 推挽输出:可以输出高、低电平,连接数字器件。
    • 开漏输出:输出端相当于三极管的集电极,需要上拉电阻才能输出高电平。
    • 复用推挽输出:IO受内部外设控制,如定时器的PWM,SPI的MOSI等。
  3. 其他模式:
    • GPIO_Mode_AIN:模拟输入,主要用于读取外部模拟信号。
    • GPIO_Mode_IN_FLOATING:浮空输入,数据通道中仅接入TTL触发器。
    • GPIO_Mode_IPD:下拉输入,内部连接下拉电阻,悬空时默认为低电平。
    • GPIO_Mode_IPU:上拉输入,内部连接上拉电阻,悬空时默认为高电平。

每种模式都有其特定的应用场景,例如模拟输入模式主要用于读取外部模拟信号,而浮空输入模式则适用于需要外部控制信号的引脚。输出模式中,推挽输出和开漏输出是常见的,它们可以驱动数字器件,而复用推挽输出则用于连接内部外设模块。

在配置GPIO引脚时,需要根据具体的应用场景选择合适的模式,以确保引脚的功能能够满足需求。

三、GPIO 框图剖析:

1.保护二极管及上、下拉电阻:可以通过“上拉/下拉寄存器 GPIOx_PUPDR”控制引脚的上、下拉以及浮空模式。

2.P-MOS 管和 N-MOS 管 :

GPIO 引脚线路经过两个上、下拉电阻结构后,向上流向“输入模式”结构,向下流向“输出模 式”结构。先看输出模式部分,线路经过一个由 P-MOS 和 N-MOS 管组成的单元电路。这个结构 使 GPIO 具有了“推挽输出”和“开漏输出”两种模式。在该结构中输入高电平时,上 方的 P-MOS 导通,下方的 N-MOS 关闭,对外输出高电平;而在该结构中输入低电平时,N-MOS 管导通,P-MOS 关闭,对外输出低电平。

3.复用功能输出:

“复用功能输出”中的“复用”是指 STM32 的其它片上外设对 GPIO 引脚进行控制,此时 GPIO 引 脚用作该外设功能的一部分,算是第二用途。从其它外设引出来的“复用功能输出信号”与 GPIO 本身的数据据寄存器都连接到双 MOS 管结构的输入中,通过图中的梯形结构作为开关切换选择。 例如我们使用 USART 串口通讯时,需要用到某个 GPIO 引脚作为通讯发送引脚,这个时候就可 以把该 GPIO 引脚配置成 USART 串口复用功能,由串口外设控制该引脚,发送数据。

4.输入数据寄存器:

看 GPIO 结构框图的上半部分,它是 GPIO 引脚经过上、下拉电阻后引入的,它连接到施密特 触发器,信号经过触发器后,模拟信号转化为 0、1 的数字信号,然后存储在“输入数据寄存器 GPIOx_IDR”中,通过读取该寄存器就可以了解 GPIO 引脚的电平状态。

5.复用功能输入:

当 GPIO 引脚用于 ADC 采集电压的输入通道时,用作“模拟输入”功能,此时信号是不经过施 密特触发器的,因为经过施密特触发器后信号只有 0、1 两种状态,所以 ADC 外设要采集到原始 的模拟信号,信号源输入必须在施密特触发器之前。类似地,当 GPIO 引脚用于 DAC 作为模拟 电压输出通道时,此时作为“模拟输出”功能,DAC 的模拟信号输出就不经过双 MOS 管结构了, 在 GPIO 结构框图的右下角处,模拟信号直接输出到引脚。同时,当 GPIO 用于模拟功能时 (包括 输入输出),引脚的上、下拉电阻是不起作用的,这个时候即使在寄存器配置了上拉或下拉模式, 也不会影响到模拟信号的输入输出。

四、硬件连接

1.图LED 灯电路连接图 _ 中从 3 个 LED 灯的阳极引出连接到 3.3V 电源,阴极各经过 1 个电阻引入 至 STM32 的 3 个 GPIO 引脚 PH10、PH11、PH12 中,所以我们只要控制这三个引脚输出高低电 平,即可控制其所连接 LED 灯的亮灭。如果您的实验板 STM32 连接到 LED 灯的引脚或极性不 一样,只需要修改程序到对应的 GPIO 引脚即可,工作原理都是一样的。

2.把 GPIO 的引脚设置成推挽输出模式并且默认下拉,输出低电平,这样就能让 LED 灯亮起来,开启时钟,配置引脚模式,控制电平,经过这三步,我们就可以控制一个 LED 了。

五、main 文件

#include "stm32F4xx.h"
#include "stm32f4xx_conf.h"
#include "stdio.h"

int couter = 0;
uint8_t key1;
uint8_t key2;

int8_t color = 0;

void delay(__IO uint32_t ms)
{
    for(;ms!=0;ms--);
}


void LED_init()
{
    GPIO_InitTypeDef gpio_info;
    //PH0
    //初始化GPIOH时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOH,ENABLE);
    
    gpio_info.GPIO_Mode = GPIO_Mode_OUT;
    gpio_info.GPIO_OType = GPIO_OType_PP;
    gpio_info.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;
    gpio_info.GPIO_PuPd = GPIO_PuPd_UP;
    gpio_info.GPIO_Speed = GPIO_Low_Speed;
    
    GPIO_Init(GPIOH,&gpio_info);
}

void key_init()
{
    GPIO_InitTypeDef gpio_info;
    EXTI_InitTypeDef exti_info;
    NVIC_InitTypeDef  NVIC_InitStructure;
    //PA0
    //初始化GPIOA的时钟    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	
	
    //初始化中断时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
    
    //配置按键
    gpio_info.GPIO_Mode = GPIO_Mode_IN;
    gpio_info.GPIO_OType = GPIO_OType_PP;
    gpio_info.GPIO_Pin = GPIO_Pin_0;
    gpio_info.GPIO_PuPd = GPIO_PuPd_NOPULL;
    gpio_info.GPIO_Speed = GPIO_Low_Speed;
    GPIO_Init(GPIOA,&gpio_info);
    

    //配置按键的外部中断
    SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);
		SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC,EXTI_PinSource0);
    exti_info.EXTI_Line = EXTI_Line0;
    exti_info.EXTI_LineCmd = ENABLE;
    exti_info.EXTI_Mode = EXTI_Mode_Interrupt;
    exti_info.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_Init(&exti_info);
    
    //配置这个外部中断的优先级
    NVIC_InitStructure.NVIC_IRQChannel =  EXTI0_IRQn;   //PA0 对应的是EXTI0_IRQn
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_Init(&NVIC_InitStructure);
		
}
void key2_init()
{
    GPIO_InitTypeDef gpio_info;
    EXTI_InitTypeDef exti_info;
    NVIC_InitTypeDef  NVIC_InitStructure;
    //PA0
    //初始化GPIOA的时钟    
	  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC,ENABLE);
	
    //初始化中断时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);
    
    //配置按键
    gpio_info.GPIO_Mode = GPIO_Mode_IN;
    gpio_info.GPIO_OType = GPIO_OType_PP;
    gpio_info.GPIO_Pin = GPIO_Pin_13;
    gpio_info.GPIO_PuPd = GPIO_PuPd_NOPULL;
    gpio_info.GPIO_Speed = GPIO_Low_Speed;
	  GPIO_Init(GPIOC,&gpio_info);
    

    //配置按键的外部中断
   
		SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC,EXTI_PinSource0);
    exti_info.EXTI_Line = EXTI_Line13;
    exti_info.EXTI_LineCmd = ENABLE;
    exti_info.EXTI_Mode = EXTI_Mode_Interrupt;
    exti_info.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_Init(&exti_info);
    
    //配置这个外部中断的优先级
    NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;   //PA0 对应的是EXTI0_IRQn
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
}

void EXTI0_IRQHandler()
{
  if(EXTI_GetITStatus(EXTI_Line1)!=RESET)//证明触发了中断
		{
			//控制灯进行颜色切换
			color ++;
			if(color > 2)
				color=0;
			
			//清除中断标记
			EXTI_ClearITPendingBit(EXTI_Line1);
		}
	
}


//编写中断服务函数

void EXTI15_10_IRQHandler()
{
  if(EXTI_GetITStatus(EXTI_Line13)!=RESET)//证明触发了中断
		{
			//控制灯进行颜色切换
			color --;
			if(color<3)
				
			
			//清除中断标记
			EXTI_ClearITPendingBit(EXTI_Line13);
		}
	
}

#define LED_RED GPIO_Pin_10
#define LED_GREEN GPIO_Pin_11
#define LED_BLUE GPIO_Pin_12

//按下KEY1按键---红蓝绿、红蓝绿
//按下KEY2按键---绿蓝红、绿蓝红


int main(void)
{
    LED_init();
    key_init();
	  key2_init();
    
    //关闭11、12
    GPIO_SetBits(GPIOH,GPIO_Pin_11|GPIO_Pin_12);
     
    while(1)
    {
        //读取按键状态
		  if(color ==0)//亮红灯
			{
				GPIO_ResetBits(GPIOH,LED_RED);
				GPIO_SetBits(GPIOH,LED_GREEN|LED_BLUE);
			}
     else  if(color ==1)//亮蓝灯
			{
				GPIO_ResetBits(GPIOH,LED_GREEN);
				GPIO_SetBits(GPIOH,LED_RED|LED_BLUE);
			}
			else  if(color ==2)//亮绿灯
			{
				GPIO_ResetBits(GPIOH,LED_BLUE);
			GPIO_SetBits(GPIOH,LED_RED|LED_GREEN);
			}
		}	
    }
	

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值