蓝桥杯嵌入式STM32G431——第六届省赛真题电压测量监控设备

第六届省赛真题电压测量监控设备

第六届省赛真题

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

main.c

#include "main.h"
//使用CubeMX配置以下头文件下的模块初始化
#include "rcc.h" //时钟初始化
#include "led_key.h"
#include "lcd.h"
#include "i2c.h"
#include "uart.h"
#include "adc.h"
#include "rtc.h"

//***全局变量区
//*扫描时间速度控制变量
__IO uint32_t uwTick_LED_Set_Point; //控制LED执行一次的时间
__IO uint32_t uwTick_KEY_Set_Point;	//控制KEY执行一次的时间
__IO uint32_t uwTick_LCD_Set_Point;	//控制LCD执行一次的时间
__IO uint32_t uwTick_UART_Set_Point;	//控制UART执行一次的时间
//*LED变量
uint8_t ucLed;
//*按键变量
uint8_t key_value,key_up,key_down;	//按键的三行代码所使用的变量
static uint8_t key_old;
//*LCD变量
uint8_t LCD_Disp_String[21];	
//*串口变量
uint8_t UART_Str[40]; //串口发送时用于存储发送数据的缓冲区
uint8_t rx_buffer;	//串口接收数据的中间缓冲变量
//*ADC2变量
float ADC2_Voltage;	//R37的电压值
//*RTC变量
RTC_TimeTypeDef T;
RTC_DateTypeDef D;

//***用户自定义变量区
uint8_t Interface_ctrl;// 0x00-界面选择 0x11-小时控制 0x12-分钟控制 0x13-秒控制
uint8_t k_value = 1;	//k初始值为1
uint8_t LED_ctrl;; //0x00-打开 0x01-关闭
uint8_t Clock_Comp_Disp[3]={0,0,0}; //时钟对比值 显示
uint8_t Clock_Comp_Ctrl[3]; //时钟对比值 控制
__IO uint32_t uwTick_Clock_Time_Set_Point;	//时钟时间控制变量
uint8_t Time_Set_Ctrl; //0不灭 1灭
uint8_t Uart_Transmit_Times_Ctrl; //串口发送次数控制
uint8_t rx_Buf[100];	//接收数据缓存区
uint8_t rx_Buf_index;	//接收数据的位置
__IO uint32_t uwTick_RX_Dealy_Time;	//用于对接收时间的判断
_Bool Start_Flag = 0; //起始位判断
__IO uint32_t uwTick_LED_Light_Time;	//用于控制LED闪烁时间

//***子函数声明区
void SystemClock_Config(void);
void LED_Proc(void);
void KEY_Proc(void);
void LCD_Proc(void);
void UART_Proc(void);



//***主函数区
int main(void)
{
  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
  /* Configure the system clock */
  SystemClock_Config();
	
	
	//*初始化区
	//LED和按键的初始化
	LED_KEY_Init();
	
	//LCD的初始化
	LCD_Init();
	LCD_Clear(Black);	//清屏
	LCD_SetBackColor(Black);	//设置背景颜色
	LCD_SetTextColor(Magenta);	//设置文本颜色
	
	//I2C初始化
	I2CInit();
	
	I2C_24c02_read(&k_value , 0 , 1);	//EEPROM读数据
	
	//串口初始化
	UART1_Init();
	HAL_UART_Receive_IT(&huart1 , (uint8_t *)(&rx_buffer) , 1);	//打开串口接收中断 进入串口中断回调函数
	
	//ADC2初始化
	ADC2_Init();
	//RTC实时时钟初始化
	RTC_Init();
	
  while (1)
  {
		LED_Proc();
		KEY_Proc();
		LCD_Proc();
		UART_Proc();
  }
}


//***子函数区

//*LED处理函数
void LED_Proc(void)
{
	if((uwTick - uwTick_LED_Set_Point)<50) return;
		uwTick_LED_Set_Point = uwTick;	//每50ms执行一次
	
	if(LED_ctrl == 0x00)	//打开LED每200ms闪烁功能
	{
		if(ADC2_Voltage > (3.3*k_value*0.1)) //V1>VDD*k VDD=3.3V
		{
			if((uwTick - uwTick_LED_Light_Time)>=200)	//LED每200ms闪烁一次
			{
				uwTick_LED_Light_Time = uwTick;
				
				ucLed ^= 0x01;
			}
		}
		else
			ucLed = 0x00;	//V1<=3.3*k 关闭LED
	}
	else
	{
		ucLed = 0x00;	//LED为OFF 关闭LED
	}
	LED_Disp(ucLed);	//LED显示函数
	
	
}
//*按键处理函数
void KEY_Proc(void)
{
	if((uwTick - uwTick_KEY_Set_Point)<100) return;
		uwTick_KEY_Set_Point = uwTick;	//每100ms执行一次
	
	//按键的三行代码
	key_value = KEY_Scan();
	key_up = ~key_value & (key_value ^ key_old);
	key_down = key_value & (key_value ^ key_old);
	key_old = key_value;
	
	if(key_down == 1)	//按键B1控制LED打开或关闭
	{
		LED_ctrl ^= 0x01;
		
	}
	
	if(key_down == 2)	//按键2控制界面的切换
	{
		Interface_ctrl ^= 0x10;
		LCD_Clear(Black);	//每次切换界面时需清屏
		
		if((Interface_ctrl>>4) == 0)	//当返回主界面时,将将设定的闹钟值赋给闹钟控制值用于判断是否上报
		{
			Clock_Comp_Ctrl[0]=Clock_Comp_Disp[0];
			Clock_Comp_Ctrl[1]=Clock_Comp_Disp[1];
			Clock_Comp_Ctrl[2]=Clock_Comp_Disp[2];
		}
	}
	
	if((Interface_ctrl>>4) == 0x1)	//在设置上报时间界面下
	{
		if(key_down == 3) //按键B3实现时分秒的切换
		{
			Interface_ctrl +=1;
			if(Interface_ctrl == 0x14)
				Interface_ctrl = 0x10;
		}
	}

			
	if(key_down ==4)	//按键B4实现时分秒时间的调整
	{
		if(Interface_ctrl == 0x11)
		{
			Clock_Comp_Disp[0]++;
			if(Clock_Comp_Disp[0] == 24)
			{
				Clock_Comp_Disp[0] = 0;
			}
		}
			
		
		if(Interface_ctrl == 0x12)
		{
			Clock_Comp_Disp[1]++;
			if(Clock_Comp_Disp[1] == 60)
			{
				Clock_Comp_Disp[1] = 0;
			}
		}
		
		if(Interface_ctrl == 0x13)
		{
			Clock_Comp_Disp[2]++;
			if(Clock_Comp_Disp[2] == 60)
			{
				Clock_Comp_Disp[2] = 0;
			}
		}
	}

	
}

//*LCD处理函数
void LCD_Proc(void)
{
	if((uwTick - uwTick_LCD_Set_Point)<100) return;
		uwTick_LCD_Set_Point = uwTick;	//每100ms执行一次
	
	if((Interface_ctrl>>4) == 0x0)	//主界面显示下
	{
		ADC2_Voltage = ADC2_Get_Value()*(3.3/4096);	//ADC2的电压值转换
		HAL_RTC_GetTime(&hrtc , &T ,RTC_FORMAT_BIN);	//打开RTC实时时钟 需要同时获取时间与日期才有效
		HAL_RTC_GetDate(&hrtc , &D ,RTC_FORMAT_BIN);
		
		//*LCD显示
		memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String)); 	//清空字符串
		sprintf((char*)LCD_Disp_String , "     V1:%4.2fV  ", ADC2_Voltage);	//打印字符串
		LCD_DisplayStringLine(Line2 , LCD_Disp_String);	//将字符串中的数据打印到屏幕上对应位置
		
		memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
		sprintf((char*)LCD_Disp_String , "     k:%3.1f ", k_value*0.1);
		LCD_DisplayStringLine(Line4 , LCD_Disp_String);
		
		if(LED_ctrl == 0x00)	//打开LED
		{
				memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
				sprintf((char*)LCD_Disp_String , "     LED:ON ");
				LCD_DisplayStringLine(Line6 , LCD_Disp_String);
		}
		else	//关闭LED
		{
				memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
				sprintf((char*)LCD_Disp_String , "     LED:OFF");
				LCD_DisplayStringLine(Line6 , LCD_Disp_String);
		}
		
		memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
		sprintf((char*)LCD_Disp_String , "     T:%02d-%02d-%02d",T.Hours,T.Minutes,T.Seconds);
		LCD_DisplayStringLine(Line8 , LCD_Disp_String);
		
	}
	else if((Interface_ctrl>>4) == 0x01)	//上报时间设置界面
	{
		
		memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
		sprintf((char*)LCD_Disp_String , "       Setting");
		LCD_DisplayStringLine(Line2 , LCD_Disp_String);
		
		if(Time_Set_Ctrl == 0x00)
		{
			memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
			sprintf((char*)LCD_Disp_String , "      %02d-%02d-%02d",Clock_Comp_Disp[0],Clock_Comp_Disp[1],Clock_Comp_Disp[2]);
			LCD_DisplayStringLine(Line5 , LCD_Disp_String);
		}
		
		if((uwTick - uwTick_Clock_Time_Set_Point)>=500) //实现设置时或分或秒时的闪烁功能 每500ms闪烁
		{
			uwTick_Clock_Time_Set_Point = uwTick;
			Time_Set_Ctrl ^= 0x01;
		}
		if(Time_Set_Ctrl == 0x01)	//时间设置控制为0x01为关闭对应位
		{
			if(Interface_ctrl == 0x11)	//小时控制
			{
				memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
				sprintf((char*)LCD_Disp_String , "        -%02d-%02d",Clock_Comp_Disp[1],Clock_Comp_Disp[2]);
			}
			else if(Interface_ctrl == 0x12)	//分钟控制
			{
				memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
				sprintf((char*)LCD_Disp_String , "      %02d-  -%02d",Clock_Comp_Disp[0],Clock_Comp_Disp[2]);
			}
			else if(Interface_ctrl == 0x13)	//秒控制
			{
				memset(LCD_Disp_String , 0 ,sizeof(LCD_Disp_String));
				sprintf((char*)LCD_Disp_String , "      %02d-%02d-  ",Clock_Comp_Disp[0],Clock_Comp_Disp[1]);
			}
			else	//时间设置完成 都不闪烁
			{
				sprintf((char*)LCD_Disp_String , "      %02d-%02d-%02d",Clock_Comp_Disp[0],Clock_Comp_Disp[1],Clock_Comp_Disp[2]);
			}
			LCD_DisplayStringLine(Line5 , LCD_Disp_String);		
		}	
	}
}

//*串口处理
void UART_Proc(void)
{
	if((uwTick - uwTick_UART_Set_Point)<50) return;
		uwTick_UART_Set_Point = uwTick;	//每50ms执行一次
	
	//当实时时钟的数值与设置的上报时间相等
	if((T.Hours==Clock_Comp_Ctrl[0])&&(T.Minutes==Clock_Comp_Ctrl[1])&&(T.Seconds==Clock_Comp_Ctrl[2]))
	{
		if(Uart_Transmit_Times_Ctrl == 0)
		{
			Uart_Transmit_Times_Ctrl = 1;		//对每秒钟只上报一次数据的处理 每秒钟只传送一次数据 如果不做处理每秒钟会发送20次
			sprintf((char*)UART_Str , "%4.2f+%3.1f+%02d%02d%02d\n",ADC2_Voltage,k_value*0.1,T.Hours,T.Minutes,T.Seconds);
			HAL_UART_Transmit(&huart1 , UART_Str , strlen((char*)UART_Str) ,50);
		}
	}
	else
	{
		Uart_Transmit_Times_Ctrl = 0;	//串口每秒钟输出数据次数标志位清零以便于修改完上报时间后再次做上面的处理
	}
	
	
	//*串口接收数据处理
	if((uwTick - uwTick_RX_Dealy_Time)>=200 && (uwTick - uwTick_RX_Dealy_Time)<=300) //200ms~300ms之内处理一次
	{
		if(rx_Buf_index == 6)//接收到6个数据
		{
			//判断接收的数据是否正确 如果正确通过串口发送OK 不正确不发送
			if((rx_Buf[0]==0x6B) && (rx_Buf[1]==0x30) && (rx_Buf[2]==0x2E) && (rx_Buf[4]==0x5C) && (rx_Buf[5]==0x6E))
			{
				if((rx_Buf[3]<=0x39) && (rx_Buf[3]>=0x31))
				{					
					k_value = rx_Buf[3] - 0x30;	//串口修改后k_value的值
					sprintf((char*)UART_Str , "ok\n");
					HAL_UART_Transmit(&huart1 , UART_Str , strlen((char*)UART_Str) ,50);
					I2C_24c02_write(&k_value , 0 , 1); //EEPROM写数据 将通过串口修改的k_value的值存入EEPROM中					
				}
				
			}
		}
		rx_Buf_index = 0;
		Start_Flag = 0;
	}
		
	
}

//*串口中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if((rx_buffer == 0x6B) && (rx_Buf_index == 0))
	{
		uwTick_RX_Dealy_Time = uwTick;	//接收到第一个数据开始计数的时间
		Start_Flag = 1;	//接收开始标志位
	}
	if(Start_Flag == 1)
	{
		rx_Buf[rx_Buf_index] = rx_buffer;	//每一位接收到的数存入接收缓冲区中
		rx_Buf_index++;
	
	}
	HAL_UART_Receive_IT(&huart1 , (uint8_t *)(&rx_buffer) , 1);	
}
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lzya.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值