蓝桥杯嵌入式第七届省赛模拟题-电压测量监控系统,看完这篇保证你蓝桥杯嵌入式赛轻轻松松过省赛。

蓝桥杯嵌入式第七届模拟题-电压测量监控系统

1.题目

设计一个电压测量监控设备,定时通过串口向 PC 机发送电压值,通过串口接收系统配
置参数并保存到 E2PROM 中。设备硬件部分主要由电源部分、控制器单元、串口部分、存储
单元组成,系统框图如图 1 所示:

在这里插入图片描述
图 1 系统框图

设计任务及要求

  1. RTC 实时时钟
    使用 STM32 内部 RTC 完成相关功能,设备上电后,时间初始化为 23 时 59 分 55 秒,
    默认定时上报电压时间为 0 时 0 点 0 分。
  2. ADC 测量功能
    设备采集电位器 R37 输出的电压信号 V1,并通过 LCD 显示。当 V1>VDD*k 时,指示灯
    LD1 以 0.2 秒为间隔闪烁,闪烁功能可以通过按键关闭;VDD为 3.3V;k 默认值为 0.1,
    保存在 E2PROM 中并可以通过串口修改配置。
  3. 串行功能
    3.1 设定 k 值,可设置范围 0.1 ~ 0.9
    格式:【命令类型】【数值】【命令结束标志】
    举例:
    “k0.1\n”
    设置 k 值为 0.1;
    设备接收到命令执行后,回复“ok\n”。
    3.2 定时上报电压 V1
    格式:【V1 电压值】+【k 值】+【时间】【命令结束标志】
    举例:
    “2.21+0.1+123030\n”
    12 时 30 分 30 秒上报电压值为 2.21V,k 值为 0.1
    说明:串口设定 9600 波特,数据位 8,停止位 1,无校验位;没有发送或发送错误
    的控制命令时,设备不做回应。
  4. LCD 显示
    设备上电默认通过 LCD 显示电位器输出电压 V1(保留小数点后两位有效数字)、k 值、
    指示灯闪烁报警功能状态和系统时间,显示界面如图 1 所示:
    在这里插入图片描述

图 2. LCD 显示界面(参考)

  1. 按键功能
    “B1”按键设定为“功能”按键,打开/关闭指示灯闪烁报警功能,默认为打开状态;
    “B2”按键设定为“设置”按键,设置设备自动上报电压时间,按下 B2 后,LCD 显示
    界面如图 2 所示,此时通过按键 B3 切换选择时、分、秒,通过按键 B4 进行调整,完成调
    整后,按下 B2 按键,更新自动上报时间,并返回图 1 所示的 LCD 显示界面。
    在这里插入图片描述

图 3. 定时上报时间设置界面(参考)

2.主要思路

(1)确定需要使用的模块
本题需要使用如下模块
LED模块
按键模块
ADC模块
RTC模块
LCD模块
USART模块
I2C模块
分别把它们初始化
(2)编写各模块的功能实现函数
如:Key_Read( )函数实现按键功能
Read_ADC()函数获得模拟输入值
USART2_SendString()函数用来向串口2传输数据
(3)显示函数的编写
(4)查缺补漏

3.代码实现

模块初始化
这个不必多说了,相信大家已经写的滚瓜烂熟了。看代码:

#define KEY1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)
#define KEY2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8)
#define KEY3 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)
#define KEY4 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2)
#define HH 23
#define MM 59
#define SS 54
void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOC, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = 0xff00;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
	
	GPIOC->ODR=0xff00;
	GPIOD->ODR|=(1<<2);
	GPIOD->ODR&=~(1<<2);
}
void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void ADC1_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode=DISABLE;
	ADC_InitStructure.ADC_NbrOfChannel=1;
	ADC_Init(ADC1,&ADC_InitStructure);
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_239Cycles5);
	ADC_Cmd(ADC1,ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	ADC_StartCalibration(ADC1);
  while(ADC_GetCalibrationStatus(ADC1));
}
void USART2_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_InitStructure.USART_BaudRate = 9600;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	
	USART_Init(USART2,&USART_InitStructure);
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	USART_Cmd(USART2,ENABLE);
}

void _24c02_Write(u8 adress,u8 data)
{
	I2CStart();
	
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(adress);
	I2CWaitAck();
	I2CSendByte(data);
	I2CWaitAck();
	
	I2CStop();
}

u8 _24c02_Read(u8 adress)
{
	u8 temp;
	
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(adress);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	temp=I2CReceiveByte();
	I2CWaitAck();
	
	I2CStop();
	return temp;
}

void RTC_Init(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
  PWR_BackupAccessCmd(ENABLE);
  BKP_DeInit();
  RCC_LSICmd(ENABLE);
	RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
  RCC_RTCCLKCmd(ENABLE);
	
	NVIC_InitStructure.NVIC_IRQChannel=RTC_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
  RTC_WaitForSynchro();
  RTC_WaitForLastTask();
	
  RTC_ITConfig(RTC_IT_SEC, ENABLE);
  RTC_WaitForLastTask();
	
  RTC_SetPrescaler(40000);
  RTC_WaitForLastTask();
	
	RTC_SetCounter(3600*23+60*59+SS);
	RTC_WaitForLastTask();

	

}

编写各模块的功能实现函数

u8 LED_Status=1;//LED1状态默认打开
u8 Set_Flag;		//主界面与设置界面切换标志
u8 Change_Flag=1;//RTC时分秒高显标志
u8 System_Flag=0;
u8 hour_f;
u8 min_f;
u8 sec_f;
u32 times_f;
float READ_ADC(void)
{
	float temp;
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	Delay_Ms(5);
	temp=ADC_GetConversionValue(ADC1)*3.30/0xfff;
	return temp;
}

void USART2_SendString(u8 *str)
{
	u8 index=0;
	do
	{
		USART_SendData(USART2,str[index]);
		while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)!=SET);
		index++;
	}while(str[index]!=0);
}
void KEY_Read(void)
{
	static u8 Key1_Num=0,Key2_Num=0,Key3_Num=0,Key4_Num=0;
	if(KEY1==0)
	{
		Key1_Num++;
		if(Key1_Num==1)
		{
			LED_Status^=1;
		}
	}else{
		Key1_Num=0;
	}
	if(KEY2==0)
	{
		Key2_Num++;
		if(Key2_Num==1)
		{
			Set_Flag^=1;
			if(System_Flag==1)
			{
				System_Flag=0;
				times_f=hour_f*3600+min_f*60+sec_f;
				RTC_SetCounter(times_f);
				RTC_WaitForLastTask();
			}
			LCD_ClearLine(Line2);
			LCD_ClearLine(Line4);
			LCD_ClearLine(Line6);
			LCD_ClearLine(Line8);
		}
	}else{
		Key2_Num=0;
	}
	if(KEY3==0)
	{
		Key3_Num++;
		if(Key3_Num==1)
		{
			Change_Flag++;
			if(Change_Flag>3){ Change_Flag=1;}
		}
	}else{
		Key3_Num=0;
	}
	if(KEY4==0)
	{
		Key4_Num++;
		if(Key4_Num==1)
		{
			switch(Change_Flag)
			{
				case 1:	hour_f++;if(hour_f>23) hour_f=0;
								break;
				case 2: min_f++;if(min_f>59) min_f=0;
								break;
				case 3: sec_f++;if(sec_f>59) sec_f=0;
								break;
			}
			System_Flag=1;
		}
	}else{
		Key4_Num=0;
	}
	
}

stm32f10x_it.c 各类中断函数编写

extern u32 TimingDelay;
extern u8 LED_Flag;
extern u8 KEY_Flag;
extern u8 ADC_Flag;
extern u8 Display_Flag;
void USART2_IRQHandler(void)
{
	u8 temp;
	if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)
	{
		USART_ClearITPendingBit(USART2,USART_IT_RXNE);
		temp=USART_ReceiveData(USART2);
		if(temp=='\n')
		{
			RXCOUNT=0;
			RXOVER=1;
		}else{
			RXBUF[RXCOUNT++]=temp;
		}
	}
}
void RTC_IRQHandler(void)
{
	u32 times;
	if(RTC_GetITStatus(RTC_IT_SEC)==SET)
	{
		RTC_ClearITPendingBit(RTC_IT_SEC);
		RTC_Flag=1;
		times=RTC_GetCounter();
		if(times==24*3600-1)
		{
			RTC_SetCounter(0x0);
		}
	}
}
void SysTick_Handler(void)
{
	static u8 LED_Sum=0;
	static u8 KEY_Sum=0;
	static u8 ADC_Sum=0;
	static u8 Display_Sum=0;
	TimingDelay--;
	if(++ADC_Sum==200)
	{
		ADC_Sum=0;
		ADC_Flag=1;
	}
	if(++KEY_Sum==50)
	{
		KEY_Sum=0;
		KEY_Flag=1;
	}
	if(++Display_Sum==50)
	{
		Display_Sum=0;
		Display_Flag=1;
	}
	if(++LED_Sum==200)
	{
		LED_Sum=0;
		LED_Flag=1;
	}
	
}

最后就是主函数的编写(重中之重)

u8 RTC_Flag=0;
u8 LED_Flag=0;
u8 KEY_Flag=0;
u8 ADC_Flag=0;
u8 Display_Flag=0;
int k;
int main(void)
{
	float temp;
	u16 LED_MODE=0xff00;
	u8 string[20];
	STM3210B_LCD_Init();
	LCD_Clear(Blue);
	LCD_SetBackColor(Blue);
	LCD_SetTextColor(White);
	LED_Init();
	KEY_Init();
	USART2_Init();
	ADC1_Init();
	RTC_Init();
	SysTick_Config(SystemCoreClock/1000);
	i2c_init();
	Delay_Ms(200);
	if(_24c02_Read(0x11)!=5)
	{
		_24c02_Write(0x11,5);
		Delay_Ms(5);
		_24c02_Write(0x21,1);
		Delay_Ms(5);
	}
	k=(int)_24c02_Read(0x21);
	Delay_Ms(5);
	
	
	while(1)
	{

		if(RXOVER)
		{
			RXOVER=0;
			if(RXBUF[0]=='k'&&(RXBUF[3]>'1'&&RXBUF[3]<'9'))
			{
				k=RXBUF[3]-0x30;
				USART2_SendString("OK\r\n");
				_24c02_Write(0x21,k);
			}
		}
		
		if(RTC_Flag)
		{
			RTC_Flag=0;
			times=RTC_GetCounter();
			hour=times/3600;
			min=times%3600/60;
			sec=times%3600%60;
			if(hour==0&&min==0&&sec==0)
			{
				sprintf((char*)string,"%.2fV+0.%d+%.2d%.2d%.2d\n",temp,k,hour,min,sec);
				USART2_SendString(string);
			}
		}
		if(ADC_Flag)
		{
			ADC_Flag=0;
			temp=READ_ADC();
		}
		if(LED_Flag)
		{
			LED_Flag=0;
			if(LED_Status)
			{
					if(temp>(float)3.3*k/10)
				{
					LED_MODE^=(1<<8);
				}else{
					LED_MODE|=(1<<8);
				}
				GPIOC->ODR=LED_MODE;
				GPIOD->ODR|=(1<<2);
				GPIOD->ODR&=~(1<<2);
			}else{
				GPIOC->ODR=0xff00;
				GPIOD->ODR|=(1<<2);
				GPIOD->ODR&=~(1<<2);
			}
			
		}
		if(KEY_Flag)
		{
			KEY_Flag=0;
			KEY_Read();
		}
		if(Display_Flag)
		{
			Display_Flag=0;
			if(Set_Flag==0)
				{
					sprintf((char*)string,"  V1:%.2fV",temp);
					LCD_DisplayStringLine(Line2,string);
					sprintf((char*)string,"  k:0.%d",k);
					LCD_DisplayStringLine(Line4,string);
					if(LED_Status)
					{
						sprintf((char*)string,"  LED: ON");
					}else{
						sprintf((char*)string,"  LED:OFF");
					}
					LCD_DisplayStringLine(Line6,string);
					sprintf((char*)string,"  %.2d:%.2d:%.2d",hour,min,sec);
					LCD_DisplayStringLine(Line8,string);
					sprintf((char*)string,"                  1");
					LCD_DisplayStringLine(Line9,string);
				}else if(Set_Flag==1)
				{
					sprintf((char*)string,"     Settings");
					LCD_DisplayStringLine(Line2,string);
					if(Change_Flag==1)
					{
						LCD_SetTextColor(Red);
					}else{
						LCD_SetTextColor(White);
					}
					LCD_DisplayChar(Line4,270,hour_f/10+0x30);
					LCD_DisplayChar(Line4,255,hour_f%10+0x30);
					LCD_SetTextColor(White);
					LCD_DisplayChar(Line4,240,'-');
					if(Change_Flag==2)
					{
						LCD_SetTextColor(Red);
					}else{
						LCD_SetTextColor(White);
					}
					LCD_DisplayChar(Line4,225,min_f/10+0x30);
					LCD_DisplayChar(Line4,210,min_f%10+0x30);
					LCD_SetTextColor(White);
					LCD_DisplayChar(Line4,195,'-');
					if(Change_Flag==3)
					{
						LCD_SetTextColor(Red);
					}else{
						LCD_SetTextColor(White);
					}
					LCD_DisplayChar(Line4,180,sec_f/10+0x30);
					LCD_DisplayChar(Line4,165,sec_f%10+0x30);
					LCD_SetTextColor(White);
					sprintf((char*)string,"                  2");
					LCD_DisplayStringLine(Line9,string);
				}
			
			
		}
	}
}

本文除标注写在stm32f10x_it.c中的文件,其余全部在main.c中
关于I2C为什么要这样设置,可以看我的这篇博客
蓝桥杯嵌入式I2C使用EEPROM教程(内附初始值设定)
亲测实现
在这里插入图片描述
在这里插入图片描述
蓝桥杯嵌入式第七届模拟题-电压测量监控系统
蓝桥杯嵌入式第十届省赛题代码
蓝桥杯嵌入式第十一届省赛模拟题
有收获?希望老铁们来个三连击,给更多的同学看到这篇文章
给大力点个赞呗,可以让更多的人看到这篇文章,顺便激励下我,嘻嘻!
有不懂的可以私信我呦!

原创文章 2 获赞 7 访问量 242

猜你喜欢

转载自blog.csdn.net/qq_41649861/article/details/105882181