基于STM32G431嵌入式学习笔记——四、LED+KEY+LCD综合练习(基于第12届蓝桥杯显示部分题目)

本文详细介绍了一道蓝桥杯竞赛中的LCD显示题目,包括按键处理、LED指示及LCD显示等核心功能的实现方法。文章提供了完整的代码示例,帮助读者理解和实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在学习了前三节LED、LCD、KEY基本操作后,我们就已经成功掌握蓝桥杯必考的三大样内容了,本节以第12届蓝桥杯显示部分内容进行综合练习:

一、真题引入
1.功能概述

在这里插入图片描述

2.LCD显示界面
(1)车位显示界面

在这里插入图片描述

(2)费率显示界面

在这里插入图片描述
在这里插入图片描述

(3)LCD通用显示要求

在这里插入图片描述

3.按键功能

在这里插入图片描述

4.LED指示灯功能

在这里插入图片描述

5.初始状态说明

在这里插入图片描述

二、题目分析

上述为作者将三大模块的输出截取出来的题目要求,并非蓝桥杯竞赛全部比赛要求。

1.解题思路

为了使解题过程循序渐进一气呵成,我们首先要先总结出以下几点内容:

①LCD屏幕一共两个屏幕界面,因此要书写两段LCD输出的代码
②板子上电后就有内容显示,默认处于车位显示界面,因此可以首先书写该屏幕的内容保证初始化没问题
③按键是为LED、LCD服务的,因此最后书写按键状态切换的逻辑
④LED在本题中一共两种状态——LED1亮 or 都灭

2.解题步骤

因此解题步骤如下:
编写车位显示界面 --> 编写费率显示界面 --> 编写LED灯功能 -->编写按键的逻辑限制

三、环境搭建

新建CubeMX
在这里插入图片描述配置外部时钟
在这里插入图片描述在这里插入图片描述配置基础引脚(LED与KEY)
我们可以看出这里并没有像第一节那样去将所有的灯引脚置为High,是因为当时这么做的目的是初始化的时候LED灯全灭,这是硬件控制的方法
事实上我们也可以用一行代码实现我们想要的功能,即采用软件控制的方法(见后续代码实现中的操作)
在这里插入图片描述配置工程基础信息
在这里插入图片描述

进入keil,初始化编译
在这里插入图片描述

添加lcd.c lcd.h模块文件,并编译
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

四、通用功能函数书写以及文件导入
1.key.h
#include "stm32g4xx_hal.h"

#define KEY1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define KEY2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KEY3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define KEY4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)

char key_scan(void);
char key_scan_cd(void);

在这里插入图片描述

2.key.c
#include "stm32g4xx_hal.h"
#include "key.h"

char key_scan(void)
{
    static int count1,count2,count3,count4;
    char value=0;
    count1 = count2 = count3 = count4 = 0;
    if(KEY1==0)
    {
        HAL_Delay(10);
        if(KEY1==0)
        {
            count1++;
            if(count1==1)
            {
                value = 1;
                while(KEY1==GPIO_PIN_RESET);
            }
        }
    }
    else
    {
        count1 = 0;
    }
    if(KEY2==0)
    {
        HAL_Delay(10);
        if(KEY2==0)
        {
            count2++;
            if(count2==1)
            {
                value = 2;
                while(KEY2==GPIO_PIN_RESET);
            }
        }
    }
    else
    {
        count2 = 0;
    }
    if(KEY3==0)
    {
        HAL_Delay(10);
        if(KEY3==0)
        {
            count3++;
            if(count3==1)
            {
                value = 3;
                while(KEY3==GPIO_PIN_RESET);
            }
        }
    }
    else
    {
        count3 = 0;
    }
    if(KEY4==0)
    {
        HAL_Delay(10);
        if(KEY4==0)
        {
            count4++;
            if(count4==1)
            {
                value = 4;
                while(KEY4==GPIO_PIN_RESET);
            }
        }
    }
    else
    {
        count4 = 0;
    }
    return value;
}
char key_scan_cd(void)
{
    static int count1,count2,count3,count4;
    char value=0;
    count1 = count2 = count3 = count4 = 0;
    if(KEY1==0)
    {
        HAL_Delay(10);
        if(KEY1==0)
        {
            count1++;
            if(count1>70)
            {
                value = 11;
            }
        }
    }
    else
    {
        if(count1>0&&count1<=50)
        {
            value = 1;
        }
        count1 = 0;
    }
    if(KEY2==0)
    {
        HAL_Delay(10);
        if(KEY2==0)
        {
            count2++;
            if(count2>70)
            {
                value = 22;
            }
        }
    }
    else
    {
        if(count2>0&&count2<=50)
        {
            value = 2;
        }
        count2 = 0;
    }
    if(KEY3==0)
    {
        HAL_Delay(10);
        if(KEY3==0)
        {
            count3++;
            if(count3>70)
            {
                value = 33;
            }
        }
    }
    else
    {
        if(count3>0&&count3<=50)
        {
            value = 3;
        }
        count3 = 0;
    }
    if(KEY4==0)
    {
        HAL_Delay(10);
        if(KEY4==0)
        {
            count4++;
            if(count4>70)
            {
                value = 44;
            }
        }
    }
    else
    {
        if(count4>0&&count4<=50)
        {
            value = 4;
        }
        count4 = 0;
    }
    return value;
}

在这里插入图片描述

3.led.h
#include "stm32g4xx_hal.h"
//灯光的亮灭
#define ON 1
#define OFF 0
//定义引脚
#define LED1 GPIO_PIN_8
#define LED2 GPIO_PIN_9
#define LED3 GPIO_PIN_10
#define LED4 GPIO_PIN_11
#define LED5 GPIO_PIN_12
#define LED6 GPIO_PIN_13
#define LED7 GPIO_PIN_14
#define LED8 GPIO_PIN_15
#define LEDALL GPIO_PIN_All

//相关函数的声明
void control_led(uint16_t LED, uint8_t status);

在这里插入图片描述

4.led.c
#include "led.h"

void control_led(uint16_t LED, uint8_t status)
{
    if(status == 0)//灭灯
    {
        HAL_GPIO_WritePin(GPIOC,LED,GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
    }
    else//亮灯
    {       
        HAL_GPIO_WritePin(GPIOC,LED,GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
    }
}

在这里插入图片描述
随后将两个.c文件导入项目工程中:
在这里插入图片描述

导入后编译,随即.h文件会相应归类到对应的.c文件中

温馨提示,建议采用下述步骤导入:
①创建两个.h的空白文件,保存
②创建两个.c文件,分别在其中输入#include “led.h” #include"key.h",后保存。
③将两个.c文件导入项目工程
④编译一遍,通过后进行后续操作。
⑤书写两个.h文件的内容
⑥书写两个.c文件的内容
⑦再次编译

五、本题目中功能函数书写

为了方便,接下来书写的函数均定义在main.c中,不创建额外文件。

1.按键函数

在这里插入图片描述

void key_proc(void)
{
  char value = key_scan();
  switch(value)
  {
    case 1:
      /*切换LCD显示屏界面的操作*/
      break;
    case 2:
      /*CNBR、VNBR费率增加0.5元*/
      break;
    case 3:
      /*CNBR、VNBR费率减少0.5元*/
      break;
  }
}

(0)头文件的添加
因为用到了key_scan()函数,所以需要在开头添加头文件:
在这里插入图片描述

(1)case1:LCD屏幕内容的切换
最简单的思路就是设置一全局变量,该值为1则显示一界面,0为另一个界面。
在这里插入图片描述
初始值设定为1是因为题目要求默认处于车位显示界面
在这里插入图片描述因此key_proc函数更新(借助三元运算符实现0和1的转换)

void key_proc(void)
{
  char value = key_scan();
  switch(value)
  {
    case 1:
      /*切换LCD显示屏界面的操作*/
      lcd_flag = (lcd_flag == 1 ? 0 : 1);
      break;
    case 2:
      /*CNBR、VNBR费率增加0.5元*/
      break;
    case 3:
      /*CNBR、VNBR费率减少0.5元*/
      break;
  }
}

(2)case 2 case 3 费率的变化
依旧是在文件中定义两个全局变量,表示两种费率的数值:
在这里插入图片描述

函数更新为:

void key_proc(void)
{
  char value = key_scan();
  switch(value)
  {
    case 1:
      /*切换LCD显示屏界面的操作*/
      lcd_flag = (lcd_flag == 1 ? 0 : 1);
      break;
    case 2:
      /*CNBR、VNBR费率增加0.5元*/
      cnbr += 0.5f;
      vnbr += 0.5f;
      break;
    case 3:
      /*CNBR、VNBR费率减少0.5元*/
      cnbr -= 0.5f;
      vnbr -= 0.5f;
      break;
  }
}
2.LED灯显示函数

由于这是内容节选题目,LED灯仅要求实现一个功能

空闲涉及到空闲车位的计数,设置一全局变量:
在这里插入图片描述
添加头文件
在这里插入图片描述

void led_proc()
{
  if(idle>0)
  {
    control_led(LED1,ON);//LED1亮
  }
  else
  {
    control_led(LED1,OFF);
  }
}

仍需注意修改lcd.c中三个Write函数以解决LED与LCD的冲突
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
3944f2.png)

3.LCD屏幕显示函数

更新头文件
在这里插入图片描述

(1)设置背景色——黑色

LCD_SetBackColor(Black);

(2)设置前景色——白色

LCD_SetTextColor(White);

(3)设置车位显示界面
与停车界面有关的全局变量也需要提前声明:
在这里插入图片描述

这里用到了sprintf函数,其位于stdio.h中
在这里插入图片描述

  if(lcd_flag == 1)//车位显示界面
  {
    LCD_DisplayStringLine(Line2,(unsigned char *)"       Data         ");
    /*
      sprintf函数
      用于将我们本应该直接格式化输出的语句内容存储至字符串
      位于stdio.h中
    */
    sprintf(str,"   CNBR:%d           ",car1);//第四行即将显示的内容
    LCD_DisplayStringLine(Line4,(unsigned char *)str);
    sprintf(str,"   VNBR:%d           ",car2);//第六行即将显示的内容
    LCD_DisplayStringLine(Line6,(unsigned char *)str);
    sprintf(str,"   IDLE:%d           ",idle);//第八行即将显示的内容
    LCD_DisplayStringLine(Line8,(unsigned char *)str);
  }

(4)设置费率显示界面

  else//费率设置界面
  {
    LCD_DisplayStringLine(Line2,(unsigned char *)"       Para         ");
    sprintf(str,"   CNBR:%.2f        ",cnbr);
    LCD_DisplayStringLine(Line4,(unsigned char *)str);
    sprintf(str,"   VNBR:%.2f        ",vnbr);
    LCD_DisplayStringLine(Line6,(unsigned char *)str);
  }

至此,lcd显示函数书写完毕,现展示完整代码:

void lcd_proc()
{
  LCD_SetBackColor(Black);
  LCD_SetTextColor(White);
  if(lcd_flag == 1)//车位显示界面
  {
    LCD_DisplayStringLine(Line2,(unsigned char *)"       Data         ");
    /*
      sprintf函数
      用于将我们本应该直接格式化输出的语句内容存储至字符串
      位于stdio.h中
    */
    sprintf(str,"   CNBR:%d           ",car1);//第四行即将显示的内容
    LCD_DisplayStringLine(Line4,(unsigned char *)str);
    sprintf(str,"   VNBR:%d           ",car2);//第六行即将显示的内容
    LCD_DisplayStringLine(Line6,(unsigned char *)str);
    sprintf(str,"   IDLE:%d           ",idle);//第八行即将显示的内容
    LCD_DisplayStringLine(Line8,(unsigned char *)str);
  }
  else//费率设置界面
  {
    LCD_DisplayStringLine(Line2,(unsigned char *)"       Para         ");
    sprintf(str,"   CNBR:%.2f        ",cnbr);
    LCD_DisplayStringLine(Line4,(unsigned char *)str);
    sprintf(str,"   VNBR:%.2f        ",vnbr);
    LCD_DisplayStringLine(Line6,(unsigned char *)str);
  }
}

三个函数定义完成后,不要忘记在程序开头进行函数声明
在这里插入图片描述

4.主函数内容的编写

①进入while循环前进行LCD初始化
②在while循环中调用三个模块函数
在这里插入图片描述

完成!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值