第十届蓝桥杯省赛真题解析

本文介绍了如何准备蓝桥杯竞赛,重点是ADC2测量电阻和LCD显示的题目,涉及到ADC电压采集、LCD界面设计以及按键交互。文章提供了代码示例,包括主函数、ADC处理、按键处理和LCD显示的实现,展示了如何通过按键切换界面、设置参数以及LED灯的显示逻辑。
摘要由CSDN通过智能技术生成

1.0题目来源

可直接上网下载或者在线搜索蓝桥杯历年真题,这有一个宝藏的刷题网站(其他博主推荐)

刷题

2.0题目考点

这一届真题并不难,在考试内容上考了“固定的三件套”(led,lcd,按键),除此之外就考了一个ADC2测量R37电阻,而且串口,pwm波均不涉及。

3.0题目底层环境搭建

图3-1 总体配置

图3-2时钟配置

图3-3ADC2的配置

图3-4ADC2的配置

4.0题目分析:

4.1解题步骤
一、状态分解
  1. 状态1:初始状态,刚上电的主界面(Main),实现ADC实时电压信号的采集

  1. 状态2:切换到参数设置界面(Setting)

  1. 状态3:在参数设置界面按键选择参数实现高亮显示

  1. 状态4:在参数设置界面进行上下限值的加减以及灯的序号的加减

二、状态的实现

①状态1:设置Main 页面为page=1,然后用LCD实现显示ADC实时采集到的电压值

②状态2:将初始值进行设置,将Setting页面设置为page=2,通过按键B1实现它的切换过程,设置完之后通过LCD显示出来

③状态3:要实现高亮显示,首先将所想要的颜色放在if判断语句后的执行语句,然后在显示完之后再将所选行恢复原来的颜色。

④状态4: 通过按键三和四实现上下限值进行设置,在实现LED灯顺序切换的时候将每一个LED灯亮度的数值存储到数组中。这个数组可以是指针数组,也可以是普通的数组,虽然指针数组可以提高运行效率,避免拷贝构造,通过传地址即可实现灯的顺序切换,但是为了方便理解,本题用了普通的数组,直接传值来改变LED灯的顺序

三、关键部分代码展示

①主函数:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lcd.h"
#include "led.h"
#include "key.h"
#include "stdio.h"
#include "string.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
//函数声明区
void led_proc(void);
void key_proc(void);
void lcd_proc(void);

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//变量定义区
uint8_t page=1;//界面变量
//按键专用变量
__IO uint32_t uwtick_key=0;//按键减速变量
unsigned char uckey_val,//用于保存当前键值
    uckey_up,//保存按键放开后的值
  uckey_down,//保存按键按下的键值
  uckey_old;//保存上一次的键值
//记录按键按下的次数
uint8_t counter=0;
//参数值
double data1=2.4;
double data2=1.2;


//LCD显示变量
__IO uint32_t uwtick_lcd=0;//LCD减速变量
unsigned char Lcd_disp_string[21];
uint8_t i=3;//实现选行和高亮显示变量

//adc变量
double adc=0.0;
//led显示变量数组
__IO uint32_t uwtick_led=0;//led灯减速变量
unsigned char led[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
int j=0;//当做数组的下标(led1的递增或递减)
int k=1;//数组的下标(LED2的递增或递减)
unsigned char temp1=0x01;//临时变量储存数组值
unsigned char temp2=0x02;//临时变量储存数组值
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
  LCD_Init();//LCD的初始化
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC2_Init();
  /* USER CODE BEGIN 2 */
 //LCD初始化
// LCD_Init();
 LCD_Clear(Black);//执行清屏操作
 LCD_SetBackColor(Black);
 LCD_SetTextColor(White);
             
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        led_proc();
        key_proc();//调用函数
    lcd_proc();
        
  }
 
}
//LED灯,用数组来实现
//led
//LED部分超过上限LD1显示,低于下限LD2闪烁
void led_proc()
{
    
   if((uwTick-uwtick_led)<50) return;
     uwtick_led=uwTick;
  adc=get_adc2()*3.3/4096;//将读取到的电压值存放到adc中
    //实现功能:LED的闪烁
    if(adc>data1)
    {
    
      led_disp(temp1);
        HAL_Delay(100);
        led_disp(0x00);
      HAL_Delay(100);
    }
    
        if(adc<data2)
    {
      led_disp(temp2);
        HAL_Delay(100);
        led_disp(0x00);
    HAL_Delay(100);
    }
}
//通过按键设置各个界面
void key_proc()
{

   if((uwTick-uwtick_key)<10) return;
      uwtick_key=uwTick;
     
    uckey_val=Key_Scan();
    uckey_down=uckey_val&(uckey_old^uckey_val);
    uckey_up=~uckey_val&(uckey_old^uckey_val);
  uckey_old=uckey_val;
  
//B0按下
  if(uckey_down==1)    
    {
      //切换界面
        
        if(page==1)
        {
          page=2;
        }
        else page=1;
        LCD_Clear(Black);
    }
    
    //B2按键按下,功能:切换,高亮显示
    if(uckey_down==2&&page==2)
    {
          i+=2;
            if(i>9)
            {
             i=3;
            } 
    }
    //按键三 实现+0.3V,每按下一次,所选参数+0.3,实现LED序号的加功能
    if((uckey_down==3)&&(page==2))
    {
      if(i==3&&(data1<3.0))
        {
        data1+=0.30;
    
        }
        if(i==5&&((data1-data2)>=0.3))
        {
            
          data2+=0.30;
        } 
        //此时选择第七行 led1灯的切换
  if((i==7)&&(adc>data1))
        {
          temp1=led[j+1];//j的初值是0,当按键按下时,led的序号会发生加一的改变,所以对应数组下标要+1
            j++;
          if(j==7)//当数组下标j=7,j=6,表示来到LED1灯序号加到了第八个灯,无法再加,下面同理
         j=6;    
             
        }
        //此时选择第九行 led2灯的切换
   if((i==9)&&(adc<data2))
                {
                     temp2=led[k+1];
                k++;
                if(k==7)
                k=6;
                }
    }
//进行减操作:减上下限值,减LED灯的序号
if(uckey_down==4&&page==2)
    {
      if(i==3&&((data1-data2)>=0.3)&&(data1>0.3))
        {
        data1-=0.30;
        }
        if(i==5&&(data2>0))
        {
          data2-=0.30;
        }
          if((i==7)&&(adc>data1)&&(j>(-1)))//对LED灯的序号进行减操作
        {
             
       temp1=led[j];
             j--;  //当上面的j=0时候,执行完这条语句直接变成了-1
             if(j==-1)
             {
                 temp1=led[0];
             }
        }
        
   if((i==9)&&(adc<data2)&&(k>0))//对LED灯的序号进行减操作
        {
       temp2=led[k];
             k--;
             if(k==0)
             {
                 temp2=led[1];

             }
        }
        
        }
    
}

//LCD显示部分
void lcd_proc()
{
  if((uwTick-uwtick_lcd)<50) return;
    uwtick_lcd=uwTick;
    

    //数据显示界面
    if(page==1)
    {
      sprintf((char*)Lcd_disp_string,"       Main");
      LCD_DisplayStringLine(Line1,Lcd_disp_string);
        //将采集到的电压值进行打印
        sprintf((char*)Lcd_disp_string,"    Volt:%3.2fV",adc);
        LCD_DisplayStringLine(Line3,Lcd_disp_string);
        
        //随着实时参数的变化,这个显示的内容也不同
    if((adc>data1)&&(adc<3.3))    //当采集的ADC值大于上限值
    {
//Upper后面一定要打一个空格(实现清屏),下面也一样,normal就不用
         sprintf((char*)Lcd_disp_string,"    Status:Upper ");
    }

    if((adc<data2)&&(adc>=0))//当采集的ADC值小于下限值
    {

         sprintf((char*)Lcd_disp_string,"    Status:Lower ");
    }
    
    if((adc<data1)&&(adc>data2))//当处于中间时为正常值
    {
         sprintf((char*)Lcd_disp_string,"    Status:Normal");
    }
         LCD_DisplayStringLine(Line6,Lcd_disp_string);

 }
    //数据设置界面    并且实现参数选择功能:选到的参数进行高亮显示
else 
    {

        sprintf((char*)Lcd_disp_string,"       Setting    ");
        LCD_DisplayStringLine(Line1,Lcd_disp_string);
        //实现高亮显示
          sprintf((char*)Lcd_disp_string,"   MaxVolt:%3.2fV     ",data1);
          if(i==3)
          LCD_SetBackColor(Green);//高亮显示时的背景色    
            LCD_DisplayStringLine(Line3,Lcd_disp_string);
          LCD_SetBackColor(Black);//执行完后恢复原色
      //实现高亮显示
          sprintf((char*)Lcd_disp_string,"   MinVolt:%3.2fV     ",data2);
          if(i==5)
          LCD_SetBackColor(Green);//高亮显示时的背景色    
        LCD_DisplayStringLine(Line5,Lcd_disp_string);
            LCD_SetBackColor(Black);//执行完后恢复原色
            
            //实现高亮显示
            sprintf((char*)Lcd_disp_string,"   Upper:LD1        ");
      if(i==7)    
      LCD_SetBackColor(Green);    //高亮显示时的背景色            
            LCD_DisplayStringLine(Line7,Lcd_disp_string);
            LCD_SetBackColor(Black);//执行完后恢复原色
        //实现高亮显示
            sprintf((char*)Lcd_disp_string,"   Lower:LD2        ");
            if(i==9)
            LCD_SetBackColor(Green);//高亮显示时的背景色    
        LCD_DisplayStringLine(Line9,Lcd_disp_string);
            LCD_SetBackColor(Black);//执行完后恢复原色
    }
    
}

  /* USER CODE END 3 */


/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

②ADC代码:

注:只需要在adc.c上添加142~148行的代码即可。

③:其它LED显示函数和按键扫描函数

声明:

本人自己编写代码,可能由于时间匆忙会有不正之处,希望有大佬能指正一下,提高代码的运行效率

非常感谢阅读,希望能对你有所帮助,如有什么不正确的或者Bug,请留言,不喜勿喷,照顾一下新人,谢谢!!!!!!!!😃

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值