当前位置: 首页 > news >正文

第十届 蓝桥杯 嵌入式 省赛

一、分析

这届的真题,有点像第七届的液位检测。

这届的题目开始,貌似比赛描述的功能,逻辑上变得更好梳理了。一开始就把大致的功能给你说明一遍,不像之前都是一块一块的说明。

1. 基本功能

1)测量竞赛板上电位器 R37 输出的模拟电压信号,并通过 LCD 显示

2)通过 LED 指示灯实现超出上限、低于下限的提醒功能

3)通过按键实现阈值范围和输出提醒指示灯的设置功能

4)通过 E2PROM 实现参数的断电存储功能

2. 显示功能

显示界面有两个:数据显示界面和参数配置界面

1)数据显示界面

  • 显示 界面名称、采集的实时电压数据 和 状态
  • 电压单位为 V,保留小数点后两位
  • 状态(Status):超出上限(Upper)、低于下限(Lower)和正常(Normal)

2)参数配置界面

  • 显示:界面名称、电压上限、电压下限;电压超出上限 LD1,电压低于下限 LD2 指示灯。
  • 电压上下限:0~3.3V,设备应具备错误设置的保护功能

伪代码

typedef enum{
    Data_Disp,
    Set_Pama
}Lcd_State;
Lcd_State L_state = Data_Disp;

typedef enum{
    Upper,
    Lower,
    Normal
} Volt_Status;
Volt_Status Status = Normal;

float R37_Volt_Sum, R37_Volt, R37_Volt_AVE;
unsigned int choose_pama = 1;



float Get_Volt(){
    //均值滤波
    for(int i = 0; i < 9; i++){
        R37_Volt = ADC_Get1();
        R37_Volt_Sum += R37_Volt;
    }
    //16位精度,分4096
    R37_Volt_Sum *= 3.3;
    R37_Volt_Sum /= 4096;
    R37_Volt_AVE = R37_Volt_AVE/10;
    return R37_Volt_AVE;
}
void Lcd_Proc(void){
    if(L_state == Data_Disp){
        R37_Volt_AVE = Get_Volt();
        //显示 界面、电压、状态
        Lcd_Disp(Line0, "Main");
        Lcd_Disp(Line2, "Volt: %fV", R37_Volt_AVE);
        Lcd_Disp(Line3, "%s", Status);
    }
    else if(L_state == Set_Pama){
        i2c_read(Save_Volt_Max_Min_Led, 0, 4);

        Lcd_Disp(Line0, "Setting");
        if(choose_pama == 1) 
            LCD_SetBackColor(Green);
        Lcd_Disp(Line1, "Max Volt: %f", Save_Volt_Max_Min_Led[0]);
        LCD_SetBackColor(White);


        Lcd_Disp(Line2, "Min Volt: %f", Save_Volt_Max_Min_Led[1]);        
        Lcd_Disp(Line3, "Upper:LD%d",Save_Volt_Max_Min_Led[2]);
        Lcd_Disp(Line4, "Lower:LD%d",Save_Volt_Max_Min_Led[3]);
    }
}

3. 按键功能

1)B1:设置按键,用来切换2个显示界面的。退出参数设置界面时,应将参数保存到 E2PROM

2)B2:选择按键,被选中的需要高亮

3)B3:加    按键,电压增加 0.3V,LED序号+1

4)B3:减    按键,电压减少 0.3V,LED序号-1

LED 范围为:1~8.

伪代码

void Key_Proc(){
    if(L_state == Data_Disp){
        if(Key_down == 1){
            L_state = Set_Pama;
        }
    }
    else if(L_state == Set_Pama){
        switch (Key_down)
        {
        case 1:
            LCD_Clear(White);
            i2c_write(Save_Volt_Max_Min_Led, 0 , 4);
            L_state = Data_Disp;
            break;
        case 2:
            if(++choose_pama == 5)
                choose_pama = 1;
            break;
        case 3:
            switch (choose_pama)
            {
            case 1:
                Save_Volt_Max_Min_Led[0]+=3;
                    if(Save_Volt_Max_Min_Led[0] >=33 && Save_Volt_Max_Min_Led[0] <40)
						Save_Volt_Max_Min_Led[0] = 33;
            break;

            case 2:
                if((Save_Volt_Max_Min_Led[1]+3)<Save_Volt_Max_Min_Led[0])
                    Save_Volt_Max_Min_Led[1] += 3;    
            break;

            case 3:
                //到了8以后,再加就原地不动
                if(++Save_Volt_Max_Min_Led[2] >= 8)
                    Save_Volt_Max_Min_Led[2] = 8;
                //如果相同
                if(Save_Volt_Max_Min_Led[2] == Save_Volt_Max_Min_Led[3]){
                    if(Save_Volt_Max_Min_Led[3] == 8){
                        Save_Volt_Max_Min_Led[2]=7;
                    }
                    else {
                            Save_Volt_Max_Min_Led[2] += 1;
                    }
                }
            break;

            case 4:
                if(++Save_Volt_Max_Min_Led[3] >= 8)
                    Save_Volt_Max_Min_Led[2] = 8;
                if(Save_Volt_Max_Min_Led[2] == Save_Volt_Max_Min_Led[3]){
                    if(Save_Volt_Max_Min_Led[2] == 8){
                        Save_Volt_Max_Min_Led[3]=7;
                    }
                    else {
                            Save_Volt_Max_Min_Led[3] += 1;
                    }
                }
            break;                    
            }
        break;

        case 4:
            switch (choose_pama)
            {
            case 1:
                if((Save_Volt_Max_Min_Led[1]+3) < Save_Volt_Max_Min_Led[0])
                    Save_Volt_Max_Min_Led[0] -= 3;
            break;

            case 2:
                Save_Volt_Max_Min_Led[1] -= 3;
                if(Save_Volt_Max_Min_Led[1] >= 200)
                    //补码
                    Save_Volt_Max_Min_Led[1] = 0;
            break;

            case 3:
                if(--Save_Volt_Max_Min_Led[2] == 0)
                    Save_Volt_Max_Min_Led[2] = 1;

                if(Save_Volt_Max_Min_Led[2] == Save_Volt_Max_Min_Led[3])
                {
                    if(Save_Volt_Max_Min_Led[3] == 1)
                    {
                        Save_Volt_Max_Min_Led[2] = 2;
                    }
                    else {
                        Save_Volt_Max_Min_Led[2] -= 1;
                    }
                }
            break;

            case 4:
                if(--Save_Volt_Max_Min_Led[3] == 0)
                    Save_Volt_Max_Min_Led[3] = 1;
                if(Save_Volt_Max_Min_Led[3] == Save_Volt_Max_Min_Led[2])
                {
                    if(Save_Volt_Max_Min_Led[2] == 1)
                    {
                        Save_Volt_Max_Min_Led[3] = 2;
                    }
                    else {
                        Save_Volt_Max_Min_Led[3] -= 1;
                    }
                }
            break;            
            }
        }
    }
}

4. LED 指示灯

1)R37 输出电压值超过电压上限值时,上限提醒指示灯以 0.2 秒闪烁,下限指示灯熄灭。

2)R37 输出电压值低于电压下限值时,下限提醒指示灯以 0.2 秒闪烁,上限指示灯熄灭。

3)R37 输出电压值介于上限和下限电压之间时,全灭。

伪代码

ucled = 0x0;
void Led_Proc(void){
    if(R37_Volt_AVE*10 >= Save_Volt_Max_Min_Led[0])
    {   ucled ^= (0x01 << (Save_Volt_Max_Min_Led[2]-1));
        Status = Upper;
    }
    else if(R37_Volt_AVE*10 <= Save_Volt_Max_Min_Led[1])
    {
        ucled ^= (0x01 << (Save_Volt_Max_Min_Led[3]-1));
        Status = Lower;
    }
    else if( Save_Volt_Max_Min_Led[1] <= R37_Volt_AVE <= Save_Volt_Max_Min_Led[0])
    {
        Led_Disp(0x00);
        Status = Normal;
    }
        
}

5. 初始状态

1)重新上电,从 E2PROM 载入各个参数。

2)默认指示灯 LD1 和 LD2

3)默认阈值 2.4V 和 1.2V

unsigned int Save_Volt_Max_Min_Led[4] = {24,12,1,2};

二、CubeMx

这次只用配置 Key、LED、ADC即可。打开赛点资源包,按照原理图配置。

1. LED

2. Key

3. ADC

三、模版编写

1. LED

void Led_Disp(uint8_t ucled){
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10
	|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15, GPIO_PIN_SET);
	
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
	
		HAL_GPIO_WritePin(GPIOC, ucled << 8, GPIO_PIN_RESET);
	
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

2. Key

uint8_t Key_Scan(){
	uint8_t Key_val;
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0)==GPIO_PIN_RESET)
		Key_val = 1;
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)==GPIO_PIN_RESET)
		Key_val = 2;
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2)==GPIO_PIN_RESET)
		Key_val = 3;
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==GPIO_PIN_RESET)
		Key_val = 4;
	return Key_val;
}

3. ADC

uint16_t Get_ADC2(){
	uint16_t adc = 0;
	
	HAL_ADC_Start(&hadc2);
	adc = HAL_ADC_GetValue(&hadc2);
	return adc;
}

4. I2C

void i2c_read(uint8_t* buf, uint8_t addr, uint8_t num){
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(addr);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	
	while(num--){
		*buf++ = I2CReceiveByte();
		if(num)
			I2CSendAck();
		else
			I2CSendNotAck();
	}
	I2CStop();
}
void i2c_write(uint8_t* buf, uint8_t addr, uint8_t num){
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(addr);
	I2CWaitAck();
	
	while(num--){
		I2CSendByte(*buf++);
		I2CWaitAck();
	}
	I2CStop();
	HAL_Delay(500);
}

四、完整代码编写

1. 全局变量

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "gpio.h"

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

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/*两个界面*/
typedef enum{
    Data_Disp,
    Set_Pama
}Lcd_State;
Lcd_State L_state = Data_Disp;

/*状态*/
typedef enum{
    Upper,
    Lower,
    Normal
} Volt_Status;


const char* StatusStrings[] = {
	"Upper",
	"Lower",
	"Nomal"
};
Volt_Status Status = Normal;
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
float R37_Volt, R37_Volt_Sum, R37_Volt_AVE;
uint8_t Lcd_Str_Disp[21];
uint8_t Save_Volt_Max_Min_Led[4] = {24,12,1,2};

uint8_t Key_val, Key_up, Key_down, Key_old;
uint8_t choose_pama = 1;
__IO uint32_t uwTick_Set_Lcd = 0;
__IO uint32_t uwTick_Set_Key = 0;
__IO uint32_t uwTick_Set_Led = 0;

uint8_t ucled = 0x0;
/* USER CODE END PD */

2. 主函数

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

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

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC2_Init();
  /* USER CODE BEGIN 2 */
	LCD_Init();
	LCD_Clear(White);
	LCD_SetBackColor(White);
	LCD_SetBackColor(Blue);
	
	I2CInit();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
		Lcd_Proc();
		Key_Proc();
		Led_Proc();
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

3. 显示功能

void Lcd_Proc(){
	if((uwTick - uwTick_Set_Lcd) < 100)
		return;
	uwTick_Set_Lcd = uwTick;
	if(L_state == Data_Disp){
		
		//R37_Volt_AVE = Get_Volt();
		R37_Volt_AVE = (((float)Get_ADC2())/4096)*3.3;
		//显示:界面、电压、状态
		sprintf((char*) Lcd_Str_Disp, "Main");
		LCD_DisplayStringLine(Line0, Lcd_Str_Disp);
		
		sprintf((char*) Lcd_Str_Disp, "Volt: %4.2fV", R37_Volt_AVE);
		LCD_DisplayStringLine(Line2, Lcd_Str_Disp);
		
		sprintf((char*) Lcd_Str_Disp, "Status:%s", StatusStrings[Status]);
		LCD_DisplayStringLine(Line3, Lcd_Str_Disp);
	}
	else if(L_state == Set_Pama){
		
		//i2c_read(Save_Volt_Max_Min_Led, 0, 4);
		//Volt_Max_Min[0] = Save_Volt_Max_Min_Led[0];
		//Volt_Max_Min[1] = Save_Volt_Max_Min_Led[1];
		
		//ucled_Max = Save_Volt_Max_Min_Led[2];
		//ucled_Min = Save_Volt_Max_Min_Led[3];
		
		sprintf((char*) Lcd_Str_Disp, "Setting");
		LCD_DisplayStringLine(Line0, Lcd_Str_Disp);
		

		
		sprintf((char*) Lcd_Str_Disp, "Max Volt: %3.2f", (float)Save_Volt_Max_Min_Led[0]/10.0);
		if(choose_pama == 1) LCD_SetBackColor(Green);
		LCD_DisplayStringLine(Line1, Lcd_Str_Disp);
		LCD_SetBackColor(White);
		
		sprintf((char*) Lcd_Str_Disp, "Min Volt: %3.2f", (float)Save_Volt_Max_Min_Led[1]/10.0);
		if(choose_pama == 2) LCD_SetBackColor(Blue);
		LCD_DisplayStringLine(Line2, Lcd_Str_Disp);
		LCD_SetBackColor(White);
		
		sprintf((char*) Lcd_Str_Disp, "Upper:LD%1d", (uint8_t)Save_Volt_Max_Min_Led[2]);
		if(choose_pama == 3) LCD_SetBackColor(Blue);
		LCD_DisplayStringLine(Line3, Lcd_Str_Disp);
		LCD_SetBackColor(White);
		
		sprintf((char*) Lcd_Str_Disp, "Lower:LD%1d", (uint8_t)Save_Volt_Max_Min_Led[3]);
		if(choose_pama == 4) LCD_SetBackColor(Blue);
		LCD_DisplayStringLine(Line4, Lcd_Str_Disp);
		LCD_SetBackColor(White);
	}
}

4. 按键功能

void Key_Proc(){
	if((uwTick - uwTick_Set_Key) < 100)
		return;
	uwTick_Set_Key = uwTick;
	Key_val = Key_Scan();
	Key_down = Key_val & (Key_val ^ Key_old);	
	Key_up = ~Key_val & (Key_val ^ Key_old);
	Key_old = Key_val;
	
    if(L_state == Data_Disp){
        if(Key_down == 1){
						LCD_Clear(White);
            L_state = Set_Pama;
        }
    }
    else if(L_state == Set_Pama){
        switch (Key_down)
        {
        case 1:
						LCD_Clear(White);
            i2c_write(Save_Volt_Max_Min_Led, 0 , 4);
            L_state = Data_Disp;
            break;
        case 2:
            if(++choose_pama == 5)
                choose_pama = 1;
						
            break;
        case 3:
					switch(choose_pama){
						case 1:
							Save_Volt_Max_Min_Led[0]+=3;
							if(Save_Volt_Max_Min_Led[0] >=33 && Save_Volt_Max_Min_Led[0] <40)
								Save_Volt_Max_Min_Led[0] = 33;
						break;
							
						case 2:
							if((Save_Volt_Max_Min_Led[1]+3)<Save_Volt_Max_Min_Led[0]){
								Save_Volt_Max_Min_Led[1] += 3;
							}
						break;
							
						case 3:
							//到了8以后,再加就原地不动
							if(++Save_Volt_Max_Min_Led[2] >= 8)
								Save_Volt_Max_Min_Led[2] = 8;
							//如果相同
							if(Save_Volt_Max_Min_Led[2] == Save_Volt_Max_Min_Led[3]){
								if(Save_Volt_Max_Min_Led[3] == 8){
									Save_Volt_Max_Min_Led[2]=7;
								}
								else {
									 Save_Volt_Max_Min_Led[2] += 1;
								}
							}
							break;
						case 4:
							if(++Save_Volt_Max_Min_Led[3] >= 8)
								Save_Volt_Max_Min_Led[2] = 8;
							if(Save_Volt_Max_Min_Led[2] == Save_Volt_Max_Min_Led[3]){
								if(Save_Volt_Max_Min_Led[2] == 8){
									Save_Volt_Max_Min_Led[3]=7;
								}
								else {
									 Save_Volt_Max_Min_Led[3] += 1;
								}
							}
							break;
								
					}
					break;
						
							
        case 4:
            switch(choose_pama){
							case 1:
								if((Save_Volt_Max_Min_Led[1]+3) < Save_Volt_Max_Min_Led[0])
									Save_Volt_Max_Min_Led[0] -= 3;
							break;
								
							case 2:
								Save_Volt_Max_Min_Led[1] -= 3;
								if(Save_Volt_Max_Min_Led[1] >= 200)
									//补码
									Save_Volt_Max_Min_Led[1] = 0;
							break;
								
							case 3:
								if(--Save_Volt_Max_Min_Led[2] == 0){
									Save_Volt_Max_Min_Led[2] = 1;
								}
								if(Save_Volt_Max_Min_Led[2] == Save_Volt_Max_Min_Led[3])
								{
									if(Save_Volt_Max_Min_Led[3] == 1)
									{
										Save_Volt_Max_Min_Led[2] = 2;
									}
									else {
										Save_Volt_Max_Min_Led[2] -= 1;
									}
								}
								break;
								
							case 4:
								if(--Save_Volt_Max_Min_Led[3] == 0){
									Save_Volt_Max_Min_Led[3] = 1;
								}
								if(Save_Volt_Max_Min_Led[3] == Save_Volt_Max_Min_Led[2])
								{
									if(Save_Volt_Max_Min_Led[2] == 1)
									{
										Save_Volt_Max_Min_Led[3] = 2;
									}
									else {
										Save_Volt_Max_Min_Led[3] -= 1;
									}
								}
							break;
								
						}
						break;
        }
    }
}

5. LED 指示灯

void Led_Proc(){
	//ucled_Max = Save_Volt_Max_Min_Led[2];
	//ucled_Min = Save_Volt_Max_Min_Led[3];
	if((uwTick - uwTick_Set_Led) < 200)
		return;
	uwTick_Set_Led = uwTick;
	if(R37_Volt_AVE*10 >= Save_Volt_Max_Min_Led[0]){
		ucled ^= (0x01 << (Save_Volt_Max_Min_Led[2]-1));
		Status = Upper;
	}

	else if(R37_Volt_AVE*10 <= Save_Volt_Max_Min_Led[1])
	{
		ucled ^= (0x01 << (Save_Volt_Max_Min_Led[3]-1));	
		Status = Lower;		
	}

	else if( (Save_Volt_Max_Min_Led[1] <= R37_Volt_AVE*10) && (R37_Volt_AVE*10 <= Save_Volt_Max_Min_Led[0]))
	{
		ucled = 0x00;
		Status = Normal;
	}
	Led_Disp(ucled);
}

小结

这届比赛,需要在数值边界部分要考虑考虑。本届难度一般。

相关文章:

  • 前端知识(vue3)
  • Python 字典和集合(常见的映射方法)
  • 【学Rust写CAD】39 over_in_in 函数(alpha256补充方法)
  • JS中的Promise对象
  • 源代码保密解决方案
  • linux上todesk无法使用问题
  • 避免误用strncmp与memcmp,strcpy与memcpy
  • CSS中的inline-flex与flex的区别
  • 在C++11及后续标准中,auto和decltype是用于类型推导的关键特性,它们的作用和用法。
  • 力扣热题100刷题day62|283.移动零、39.组合总和、94.二叉树的中序遍历
  • 百度开放平台调用动物识别接口
  • 运营商在网状态查询API:精准探测手机号的状态
  • LLM Agent未来研究趋势
  • 前后端开发规范
  • 好数(蓝桥杯2024省赛B组)
  • Win11重新设计开始菜单 变成iOS样式
  • 【Linux】Git的简单使用
  • 刷题 | 牛客 - js简单10题(更ing)1/10知识点解答
  • pdf转latex
  • 关于GEO的100个核心问题
  • 网站如何做浮窗/公司运营策划方案
  • 孟村县做网站价格/排名优化推广
  • 苍南网站建设/如何创建自己的网站平台
  • wordpress 图灵机器人/临沂做网络优化的公司
  • 邯郸做网站的/长春seo排名公司
  • 能免费用服务器的网站/友链交换网站