IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 第七届蓝桥杯嵌入式省赛真题 -> 正文阅读

[嵌入式]第七届蓝桥杯嵌入式省赛真题

第七届蓝桥杯嵌入式省赛真题

真题-设计任务

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

STM32CubeMx配置

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

代码撰写

1.按键

uint8_t key1_flag=0;
uint8_t key2_flag=0;
uint8_t key3_flag=0;
uint8_t key4_flag=0;

uint8_t key1_state=1;
uint8_t key2_state=1;
uint8_t key3_state=1;
uint8_t key4_state=1;

uint8_t key1_state_last=1;
uint8_t key2_state_last=1;
uint8_t key3_state_last=1;
uint8_t key4_state_last=1;
/*
 * @函 数: KEY_SCAN
 * @功 能: 按键扫描
 */
void KEY_SCAN(void)
{
	key1_state = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
	key2_state = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
	key3_state = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
	key4_state = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
	
	if(key1_state_last && !key1_state ) key1_flag = 1;
	if(key2_state_last && !key2_state ) key2_flag = 1;
	if(key3_state_last && !key3_state ) key3_flag = 1;
	if(key4_state_last && !key4_state ) key4_flag = 1;
	
	key1_state_last=key1_state;
	key2_state_last=key2_state;
	key3_state_last=key3_state;
	key4_state_last=key4_state;	
}

2.LED

/*
 * @函 数: KEY_SCAN
 * @功 能: 按键扫描
 */
void LED_Disp(uint8_t ucled)
{
	//将所有的灯熄灭
	HAL_GPIO_WritePin(GPIOC, 0xff<<8, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);		
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);

	//根据ucLed的数值点亮相应的灯
	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);
}

3.I2C读写

void I2C_Write_EEPROM(uint8_t addr,uint8_t *data,uint8_t len)
{
	I2CStart();
	I2CSendByte(0XA0);
	I2CWaitAck();
	
	I2CSendByte(addr);
	I2CWaitAck();
	while(len--)
	{
		I2CSendByte(*data);
		I2CWaitAck();
		data++;
	}
	I2CStop();
	delay1(500);
}
void I2C_Read_EEPROM(uint8_t addr,uint8_t *data,uint8_t len)
{
	I2CStart();
	I2CSendByte(0XA0);
	I2CWaitAck();
	
	I2CSendByte(addr);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0XA1);
	I2CWaitAck();
	
	while(len--)
	{
		*data = I2CReceiveByte();
		data++;
		if(len)
			I2CSendAck();	
		else
			I2CSendNotAck();
	}
	I2CStop();
}

4.全局变量和函数声明

#define UP 1
#define DOWN 2

//LED相关变量
__IO uint32_t uwTick_LED_Set_Point=0;
uint8_t LED1_Flag=0,LED2_Flag=0,LED3_Flag=0;
//按键相关变量
uint8_t Param_Threshold_Change = 0;

//串口相关变量
uint8_t UART_Receive_Right_Flag = 0;//正确接收为1
uint8_t UART_Receive_Flag = 0;
uint8_t UART_Receive_Buff = 0;
uint8_t UART_Transmit_Buff_C[10]="C:H00+L0\r\n";
uint8_t UART_Transmit_Buff_S[18]="S:TL00+TM00+TH00\r\n";
uint8_t UART_Transmit_Buff_A[12]="A:H00+L0+U\r\n";
//LCD 相关变量
uint8_t LCD_Buff[40];
uint8_t LCD_Page = 0;
uint8_t LCD_Parameter=1;

//ADC 相关变量
uint16_t ADC_REG_Value=0;
uint32_t ADC_REG_Value_Sum=0;
float ADC_Value_R37=0;
__IO uint32_t uwTick_ADC_Set_Point=0;

uint8_t Liquid_Height = 0;
uint8_t Liquid_Level = 0;
uint8_t Liquid_Level_last;
uint8_t Liquid_Level_Change=0;
//阈值结构体
typedef struct
{
	uint8_t Threshold1;
	uint8_t Threshold2;
	uint8_t Threshold3;
}Threshold;	

//声明一个阈值结构体
Threshold Thres={30,50,70};
//按键相关变量
__IO uint32_t uwTick_Key_Pro = 0;
//函数声明
void LCD_UI(void);
void Get_ADC_Value(void);
void Key_Process(void);
void UART_Process(void);
void Write_Threshold_To_EEPROM(void);
void Read_Threshold_From_EEPROM(void);
void LED_Process(void);

5.主函数编写

	/* 关闭所有LED */
	LED_Disp(0X00);
	/* 屏幕初始化 */
	LCD_Init();
	LCD_SetTextColor(White);
	LCD_SetBackColor(Black);
	LCD_Clear(Black);
	//I2C初始化
	I2CInit();
	//从EEPROM读取数据,也有更好的操作在后几篇中会提到
	//Write_Threshold_To_EEPROM();//第一次运行的时候可以先执行写入
	Read_Threshold_From_EEPROM();//写入过才能读取
	//开启串口接收中断
	HAL_UART_Receive_IT(&huart1,(uint8_t*)&UART_Receive_Buff,1);

  while (1)
  {
	  //按键处理
	  Key_Process();
	  //获取电压值
	  Get_ADC_Value();
	  //LED处理
	  LED_Process();
	  //串口处理
	  UART_Process();
	  //LCD UI控制
	  LCD_UI();
	  //写数据到EEPROM
	  Write_Threshold_To_EEPROM();
  }

6、LCD显示

/*
 * @函 数: LCD_UI
 * @功 能: 屏幕显示界面
 */
void LCD_UI(void)
{
	if(!LCD_Page)
	{
		LCD_SetBackColor(Black);
		LCD_DisplayStringLine(Line0,(uint8_t*)"    Liquid Level   ");
		sprintf((char*)LCD_Buff,"   Height: %d              ",Liquid_Height);
		LCD_DisplayStringLine(Line3,(uint8_t*)LCD_Buff);
		sprintf((char*)LCD_Buff,"   ADC: %.2f               ",ADC_Value_R37);
		LCD_DisplayStringLine(Line5,(uint8_t*)LCD_Buff);
		sprintf((char*)LCD_Buff,"   Level: %d               ",Liquid_Level);
		LCD_DisplayStringLine(Line7,(uint8_t*)LCD_Buff);
	}
	else
	{
		LCD_SetBackColor(Black);
		LCD_DisplayStringLine(Line0,(uint8_t*)"  Parameter Setup");
		
		if(LCD_Parameter==1)	{ LCD_SetBackColor(Red);  }
		else					{ LCD_SetBackColor(Black);}
		sprintf((char*)LCD_Buff,"  Threshold 1: %d   ",Thres.Threshold1);
		LCD_DisplayStringLine(Line3,(uint8_t*)LCD_Buff);
		if(LCD_Parameter==2)	{ LCD_SetBackColor(Red);  }
		else					{ LCD_SetBackColor(Black);}
		sprintf((char*)LCD_Buff,"  Threshold 2: %d    ",Thres.Threshold2);
		LCD_DisplayStringLine(Line5,(uint8_t*)LCD_Buff);
		if(LCD_Parameter==3)	{ LCD_SetBackColor(Red);  }
		else					{ LCD_SetBackColor(Black);}
		sprintf((char*)LCD_Buff,"  Threshold 3: %d    ",Thres.Threshold3);
		LCD_DisplayStringLine(Line7,(uint8_t*)LCD_Buff);
	}
}

7、ADC读取

/*
 * @函 数: Get_ADC_Value
 * @功 能: 获取 R37 的电压值并判断
 */
void Get_ADC_Value(void)
{
	if(uwTick - uwTick_ADC_Set_Point<1000) return;
	uwTick_ADC_Set_Point = uwTick;
	/* 启动 ADC */
	HAL_ADC_Start(&hadc2);
	//中值滤波
	ADC_REG_Value_Sum = 0;
	for(int i=0;i<10;i++)
	{//采集10次电压值
		ADC_REG_Value_Sum += HAL_ADC_GetValue(&hadc2);
	}
	//对采集的10次的原始数据求均值
	ADC_REG_Value = ADC_REG_Value_Sum/10;
	//计算实际电压值
	ADC_Value_R37 = ADC_REG_Value*3.3/4096;
	
/*************数据处理***************/
	//液体高度
	Liquid_Height =  100.0*ADC_Value_R37/3.3;
	if(Liquid_Height>100) Liquid_Height = 100;//限幅
	//液位等级判断 30 50 70
	if     (Liquid_Height<=Thres.Threshold1) Liquid_Level = 0;
	else if(Liquid_Height<=Thres.Threshold2) Liquid_Level = 1;
	else if(Liquid_Height<=Thres.Threshold3) Liquid_Level = 2;
	else  									 Liquid_Level = 3;
	//判断液位等级是否发生变换
	if(Liquid_Level>Liquid_Level_last) 		Liquid_Level_Change = UP;
	else if(Liquid_Level_last>Liquid_Level) Liquid_Level_Change = DOWN;	
	
	//保存前一次液位等级
	Liquid_Level_last = Liquid_Level;			
}

8、LED处理

/*
 * @函 数: LED_Process
 * @功 能: LED处理
 */
void LED_Process(void)
{
	if(Liquid_Level_Change)//当液位等级发生改变时,LED2_Flag=1
	{
		LED2_Flag = 1;
	}
	if(UART_Receive_Right_Flag)//当串口接收到正确数据时,LED3_Flag=1
	{
		UART_Receive_Right_Flag = 0;
		LED3_Flag = 1;
	}
	
	if((uwTick-uwTick_LED_Set_Point)<200) return;//每隔200ms进入一次
	uwTick_LED_Set_Point = uwTick;
	
	static uint8_t LED_Ctrl = 0;
	static uint8_t LED1_1S=0,LED2_200MS=0,LED3_200MS=0;
	
	LED1_1S++;
	if(LED2_Flag) //控制10次取反
	{
		LED2_200MS++; 
		if(LED2_200MS==11)//10次取反,不需要第11次,第十一次的时候全部置零
		{
			LED2_200MS = 0;
			LED2_Flag = 0;
		}
	}
	if(LED3_Flag) //同上
	{
		LED3_200MS++; 
		if(LED3_200MS==11)
		{
			LED3_200MS = 0;
			LED3_Flag = 0;
		}
	}
	
	if(LED1_1S==5){ LED1_1S=0;LED_Ctrl^=0x01;}//每隔1s取一次反
	if(LED2_200MS){ LED_Ctrl^=0x02; } //每隔200ms取一次反
	if(LED3_200MS){ LED_Ctrl^=0X04; } //每隔200ms取一次反
	LED_Disp(LED_Ctrl);
}

9、按键处理

/*
 * @函 数: Key_Process
 * @功 能: 获取按键状态进行相并处理
 */
void Key_Process(void)
{
	if((uwTick-uwTick_Key_Pro)<100) return;
	uwTick_Key_Pro = uwTick;
	//进行按键扫描
	KEY_SCAN();
	
	//通过扫描获得的状态进行按键处理
	if(key1_flag)
	{
		key1_flag = 0;
		LCD_Page = !LCD_Page;
	}
	else if(key2_flag)
	{
		key2_flag = 0;
		if(LCD_Page)
		LCD_Parameter++;
		if(LCD_Parameter>3)LCD_Parameter=1;
	}
	else if(key3_flag)
	{
		key3_flag = 0;
		if(LCD_Page) Param_Threshold_Change = 1;
		if(LCD_Parameter==1)
		{ 
			Thres.Threshold1 +=5; Thres.Threshold1 = (Thres.Threshold1>95)?95:Thres.Threshold1;
		}
		else if(LCD_Parameter==2)
		{
			Thres.Threshold2 +=5; Thres.Threshold2 = (Thres.Threshold2>95)?95:Thres.Threshold2;
		}
		else if(LCD_Parameter==3)
		{
			Thres.Threshold3 +=5; Thres.Threshold3 = (Thres.Threshold3>95)?95:Thres.Threshold3;
		}
	}
	else if(key4_flag)
	{
		if(LCD_Page) Param_Threshold_Change = 1;
		key4_flag = 0;
		if(LCD_Parameter==1)
		{ 
			Thres.Threshold1 -=5; Thres.Threshold1 = (Thres.Threshold1<5)?5:Thres.Threshold1;
		}
		else if(LCD_Parameter==2)
		{
			Thres.Threshold2 -=5; Thres.Threshold2 = (Thres.Threshold2<5)?5:Thres.Threshold2;
		}
		else if(LCD_Parameter==3)
		{
			Thres.Threshold3 -=5; Thres.Threshold3 = (Thres.Threshold3<5)?5:Thres.Threshold3;
		}
	}
}

10、当阈值变化时写入EEPROM

/*
 * @函 数: Write_Threshold_To_EEPROM
 * @功 能: 将阈值存到EEPROM里面
 */
void Write_Threshold_To_EEPROM(void)
{
	if(Param_Threshold_Change)
	{
		//满足改液位阈值条件才写入EEPROM
		if(Thres.Threshold1<Thres.Threshold2 && 
			 Thres.Threshold1<Thres.Threshold3 &&Thres.Threshold2<Thres.Threshold3 )
		{
			uint8_t temp[3]={Thres.Threshold1,Thres.Threshold2,Thres.Threshold3};
			I2C_Write_EEPROM(0,temp,3);
			HAL_Delay(10);
			Param_Threshold_Change = 0;
		}
	}
}

11、读取EEPROM的值

/*
 * @函 数: Read_Threshold_From_EEPROM
 * @功 能: 单片机上电后从RRPROM中读取数据
 */
void Read_Threshold_From_EEPROM(void)
{
	uint8_t temp[3];
	I2C_Read_EEPROM(0,temp,3);
	Thres.Threshold1= temp[0];
	Thres.Threshold2= temp[1];
	Thres.Threshold3= temp[2];
}

12、串口相关处理

/*
 * @函 数: UART_Process
 * @功 能: 串口处理
 */
void UART_Process(void)
{
	if(Liquid_Level_Change)//判断液位等级发生变换
	{
		UART_Transmit_Buff_A[3] = Liquid_Height /10%10+ '0';
		UART_Transmit_Buff_A[4] = Liquid_Height %10 + '0';
		UART_Transmit_Buff_A[7] = Liquid_Level + '0';
		
		if(Liquid_Level_Change == UP)        { UART_Transmit_Buff_A[9] = 'U'; }
		else if(Liquid_Level_Change == DOWN) { UART_Transmit_Buff_A[9] = 'D'; }
		
		HAL_UART_Transmit(&huart1,(uint8_t*)&UART_Transmit_Buff_A,12,5000);
		Liquid_Level_Change = 0;
		
	}
	if(UART_Receive_Flag==1) //判断串口是否接收到数据
	{
		UART_Receive_Flag = 0;
		if(UART_Receive_Buff=='C')
		{
			UART_Receive_Right_Flag = 1;
			UART_Transmit_Buff_C[3] = Liquid_Height /10%10+ '0';
			UART_Transmit_Buff_C[4] = Liquid_Height %10 + '0';
			UART_Transmit_Buff_C[7] = Liquid_Level + '0';
			HAL_UART_Transmit(&huart1,(uint8_t*)&UART_Transmit_Buff_C,10,5000);
		}
		if(UART_Receive_Buff=='S')
		{
			UART_Receive_Right_Flag = 1;
			UART_Transmit_Buff_S[4]  = Thres.Threshold1  /10%10+ '0';
			UART_Transmit_Buff_S[5]  = Thres.Threshold1 %10 + '0';
			UART_Transmit_Buff_S[9]  = Thres.Threshold2 /10%10+ '0';
			UART_Transmit_Buff_S[10] = Thres.Threshold2 %10 + '0';
			UART_Transmit_Buff_S[14] = Thres.Threshold3 /10%10+ '0';
			UART_Transmit_Buff_S[15] = Thres.Threshold3 %10 + '0';
			HAL_UART_Transmit(&huart1,(uint8_t*)&UART_Transmit_Buff_S,18,5000);
		}
	}
}
/*
 * @函 数: HAL_UART_RxCpltCallback
 * @功 能: 串口中断回调函数
 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	UART_Receive_Flag = 1;
	HAL_UART_Receive_IT(&huart1,(uint8_t*)&UART_Receive_Buff,1);
}
  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-11 16:35:53  更:2022-05-11 16:36:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 13:48:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码