STM32入门教程:按键控制LED灯和蜂鸣器

文章目录

  • 功能要求
  • 一、开发思路
  • 二、详细步骤及相关代码
  • 1.查看原理图
  • 2.各个模块代码的编写
  • LED灯
  • 按键
  • 蜂鸣器
  • 三、主函数编写
  • 四、总结

  • 功能要求

    设备上电,4个灯灭
    按键1按下,4个灯灭
    按键2按下,4个灯亮
    按键3按下,蜂鸣器响
    按键4按下,蜂鸣器关闭


    一、开发思路

    1.打开原理图找到对应模块的引脚,分析电路工作的原理。
    2.顺着引脚找到连接芯片的对应位置,看看到底是PX几。
    3.打开参考手册找到GPIOX的位置,并顺着GPIOX的位置找到该部分的时钟总线。
    4.在参考手册中找到该总线的寄存器,查看如何配置能够开启对应的时钟。
    5.配置引脚模式。低八位(0-7)配置GPIOx_CRL,高八位(8-15)配置GPIOx_CRH。
    6.通过ODR/IDR,配置默认输出/输入数据。
    7.根据以上编写好对应模块的.c和.h文件。
    8.在main函数中进行综合编程,以满足功能要求。

    二、详细步骤及相关代码

    1.查看原理图

    找到所需模块的位置并分析工作高低电平。
    LED灯模块:

    分析电路:
    4个LED灯末端接低电平时开始工作。

    按键模块:

    分析电路:
    KEY1默认低电平,按下时会产生一个高电平信号
    KEY2,KEY3,KEY4均为默认高电平,按下时会产生一个低电平信号。

    蜂鸣器模块:

    分析电路:
    当输入低电平时电路截止,蜂鸣器不响。
    等输入高电平时电路导通,蜂鸣器开始响。

    找到芯片上每个模块对应的引脚
    1.LED灯:

    2.按键:

    3.蜂鸣器:

    2.各个模块代码的编写

    LED灯

    从原理图上我们可以得知四个LED灯分别对应的引脚为PE2-PE5,且低电平使能。
    此时我们可以打开参考手册找到系统结构,在系统结构中找到控制GPIOE的时钟。


    由图可知:
    控制GPIOE的时钟在APB2总线上。
    时钟可以理解为控制GPIOE的开关总闸,若要使用该部分就必须先打开该部分的时钟。

    如何打开对应的时钟呢?
    首先在芯片手册中找到APB2外设时钟使能寄存器。

    我们可以看到,IOPE的位置在底6位。
    该寄存器默认都是0,所有时钟均为关闭状态,置为1时为打开。
    所以为了使用PE部分的引脚,我们需要将第6位置为1。
    在代码中为:

    	RCC->APB2ENR |= 0X01 << 6;
    

    开启完时钟后,为了能够将引脚输出高低电平。
    此时我们还要配置引脚模式,引脚为低八位查看数据手册的GPIOx_CRL,引脚为低八位查看数据手册的GPIOx_CRH。
    该LED灯为低八位,所以我们查看数据手册的GPIOx_CRL:

    配置模式前我们要简单了解一下各个模式的意思:
    输入模式
    00:模拟输入模式
    在这种模式下,引脚的输入缓冲器被禁用,通常用于模拟信号输入,例如 ADC。

    01:浮空输入模式
    这是复位后的默认状态。在这种模式下,没有内部上拉或下拉电阻,适用于需要外部电路提供信号驱动的情况。

    10:上拉/下拉输入模式
    这种模式下,可以使用内部上拉或下拉电阻。具体是上拉还是下拉通过 ODR(输出数据寄存器)来决定:
    ODR 为 1 时,上拉。
    ODR 为 0 时,下拉。

    11:保留
    这种模式在输入模式下是保留的,通常不使用。
    输出模式

    00:通用推挽输出模式(最常用)
    在这种模式下,GPIO 引脚可以输出高电平和低电平,适用于大多数需要输出固定电平的场景。

    01:通用开漏输出模式
    在这种模式下,GPIO 引脚只能拉低电平或者处于高阻状态,适用于需要连接到多路总线的场景,如 I2C。

    10:复用功能推挽输出模式
    在这种模式下,GPIO 引脚被配置为外围设备的推挽输出,例如 USART 的 TX 引脚。如果外设需要推挽输出,这种模式非常合适。

    11:复用功能开漏输出模式
    在这种模式下,GPIO 引脚被配置为外围设备的开漏输出,例如 I2C 的 SDA 和 SCL 引脚。这种模式适用于需要外设驱动的开漏输出。

    了解以上各种模式之后,就可以得知LED灯引脚只需要配置为0011。(4位配置一个引脚)
    放在代码中即为:

    //配置PE2--PE5为通用推挽输出
    	GPIOE->CRL &=~(0X0F << 20);//PE5
    	GPIOE->CRL |= 0X03 << 20;
    	GPIOE->CRL &=~(0X0F << 16);//PE4
    	GPIOE->CRL |= 0X03 << 16;
        GPIOE->CRL &=~(0X0F << 12);//PE3
    	GPIOE->CRL |= 0X03 << 12;
    	GPIOE->CRL &=~(0X0F << 8);//PE2
    	GPIOE->CRL |= 0X03 << 8;
    

    最后,我们还需要给该LED灯一个初始值,使其初始化为全灭的状态。

    //4个引脚均输出高电平
    	GPIOE->ODR |= (0x0F << 2);
    

    根据需求整合成一个完整的.c和.h文件:

    #include "stm32f10x.h"
    
    void Led_Init()
    {
    	//配置好模式,然后全灭
    	//开APB2时钟
    	RCC->APB2ENR |= 0X01 << 6;
      //配置PE2--PE5为通用推挽输出
    	GPIOE->CRL &=~(0X0F << 20);//PE5
    	GPIOE->CRL |= 0X03 << 20;
    	GPIOE->CRL &=~(0X0F << 16);//PE4
    	GPIOE->CRL |= 0X03 << 16;
        GPIOE->CRL &=~(0X0F << 12);//PE3
    	GPIOE->CRL |= 0X03 << 12;
    	GPIOE->CRL &=~(0X0F << 8);//PE2
    	GPIOE->CRL |= 0X03 << 8;
    	//4个引脚均输出高电平
    	GPIOE->ODR |= (0x0F << 2);
    	
    }
    //添加一个开关灯,方便后续使用
    void Led1_Ctrl(int flag)
    {
      if(!!flag)
    	 {
    		GPIOE->ODR &= ~(0x0F << 2);
    	 }
    	else
    	 {
    		GPIOE->ODR |= (0x0F << 2);
    	 }
    }
    
    #ifndef _LED_H_
    #define _LED_H_
    
    void Led_Init();
    void Led1_Ctrl(int flag);
    
    #endif
    

    按键

    开时钟:
    大致流程跟上述LED灯的差不多,不过KEY的引脚分为PA0和PC4-PC6
    所以此时我们要在APB2总线上开启对应A、C两个时钟

    //开时钟
    	RCC->APB2ENR |= 0x01<<4;//PC
    	RCC->APB2ENR |= 0x01<<2;//PA
    

    配置引脚模式:
    按键按下时会发出一个电平信号,此时我们需要将模式改为浮空输入(0100)

    	//配置模式
    	GPIOC->CRL &=~(0X0F << 24);//PC6   key4
    	GPIOC->CRL |= 0X04 << 24;
      GPIOC->CRL &=~(0X0F << 20);//PC5   key3
    	GPIOC->CRL |= 0X04 << 20;
    	GPIOC->CRL &=~(0X0F << 16);//PC4   key2
    	GPIOC->CRL |= 0X04 << 16;
    	GPIOA->CRL &=~0X0F;//PA0   key1
    	GPIOA->CRL |= 0X04;
    

    最后,根据要求我写了一个按下按键返回其对应按键序号的函数方便后续操作。

    完整代码如下:

    #include "stm32f10x.h"
    
    void key_Init()
    {
    	//开时钟
    	RCC->APB2ENR |= 0x01<<4;//PC
    	RCC->APB2ENR |= 0x01<<2;//PA
    	//配置模式
    	GPIOC->CRL &=~(0X0F << 24);//PC6   key4
    	GPIOC->CRL |= 0X04 << 24;
      GPIOC->CRL &=~(0X0F << 20);//PC5   key3
    	GPIOC->CRL |= 0X04 << 20;
    	GPIOC->CRL &=~(0X0F << 16);//PC4   key2
    	GPIOC->CRL |= 0X04 << 16;
    	GPIOA->CRL &=~0X0F;//PA0   key1
    	GPIOA->CRL |= 0X04;
    	
    }
    
    int Get_Key_Val(void)
    {
    	int key_val = 0;
    	if(!!(GPIOA->IDR &(0X01 << 0))==1)
    		key_val = 1;
    	if(!!(GPIOC->IDR &(0X01 << 4))==0)
    		key_val = 2;
    	if(!!(GPIOC->IDR &(0X01 << 5))==0)
    		key_val = 3;
    	if(!!(GPIOC->IDR &(0X01 << 6))==0)
    		key_val = 4;
    	
    	return key_val;
    }
    
    #ifndef _KEY_H_
    #define _KEY_H_
    
    void key_Init();
    int Get_Key_Val(void);
    
    #endif
    

    其中,需要注意的是:KEY1按下时发出的是一个高平信号,不要忘记了。

    蜂鸣器

    开时钟:
    该对应引脚为PC0,开启C的时钟即可

    	//开时钟
    	RCC->APB2ENR |= 0x01<<4;//PC
    

    配置引脚模式:
    和LED灯一样,配置成通用推挽输出(0011)就行。

    	//配置模式
    	GPIOC->CRL &=~(0X0F << 0);//PC0
    	GPIOC->CRL |= 0X03 << 0;
    

    最后,为了防止上电后蜂鸣器就响,我们需要设置一个初始值低电平,使其初始化后就关闭。

    	GPIOC->ODR &= ~0x01;//默认低电平,关闭
    

    完整代码:

    #include "stm32f10x.h"
    
    void Beep_Init()
    {
    	//开时钟
    	RCC->APB2ENR |= 0x01<<4;//PC
    	//配置模式
    	GPIOC->CRL &=~(0X0F << 0);//PC0
    	GPIOC->CRL |= 0X03 << 0;
    	GPIOC->ODR &= ~0x01;//默认低电平,关闭
    }
    
    #ifndef _BEEP_H_
    #define _BEEP_H_
    
    void Beep_Init();
    
    #endif
    

    三、主函数编写

    #include "stm32f10x.h"
    #include "led.h"
    #include "key.h"
    #include "beep.h"
    
    int main()
    {
        Led_Init();
        key_Init();
        Beep_Init();
        while(1)
        {
            switch(Get_Key_Val())
              {
                   case 1:
                   // 全灭
                   Led1_Ctrl(0);
                   break;
                   case 2:
                   // 全亮
                   Led1_Ctrl(1);
                   break;
                   case 3:
                   // 蜂鸣器响
                   GPIOC->ODR |= 0x01; 
                   break;
                   case 4:
                   // 蜂鸣器关
    			   GPIOC->ODR &= ~0x01;	
                   break;
               }
         }
         return 0;
    }
    

    思路解析:
    先对各个模块进行初始化操作,完成后进入到while(1)死循环,通过Switch语句和按键反馈函数循环检测按键具体为哪一个。
    当按键1按下时,运行预设的LED灯全亮/灭函数(真为全亮)
    当按键2按下时,同上给一个真值使其全亮。
    当按键3按下时,将PC0引脚置为1,蜂鸣器开始工作。
    当按键4按下时,将PC0引脚置为0,蜂鸣器结束工作。


    四、总结

    完全掌握了LED灯、按键和蜂鸣器模块。
    学习了STM32的工作原理,对STM32的开发流程较为熟悉。能够通过看数据手册和原理图进行一些简单模块的开发和使用。

    作者:小白橘颂

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32入门教程:按键控制LED灯和蜂鸣器

    发表回复