您当前的位置: 首页 >  嵌入式

风间琉璃•

暂无认证

  • 2浏览

    0关注

    337博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

2015年嵌入式第六届省赛真题解析

风间琉璃• 发布时间:2022-02-12 21:51:32 ,浏览量:2

一、题目

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16

 watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16

二、题目分析

题目要求做一个电压测量监控设备,各个模块的使用都比较简单,但是当要利用各个模块完成一个简单的小项目,就要理清楚整个程序的大致框架。这里将整个功能分为三大部分显示界面,设置界面,串口接发。

1.界面

显示界面由外设读取显示,设置界面设置自动上报时间的。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16 

 界面的控制用一个变量LCD_GUI来控制。 若变量为0x00表示显示界面;若变量为0x1_,则为设置界面,并且0x10设置时,0x11设置分,0x12设置秒。

if(unKey_Down == 2)  //界面控制
	{
		if(LCD_GUI == 0x00)  //若是显示界面切换为设置界面
		{
			LCD_Clear(White); // 清屏
			LCD_GUI = 0x10;
		}
		else    //返回显示界面
		{
			LCD_Clear(White);
			LCD_GUI=0x00;
			time_ctrl[0] = time_disp[0]; //再次返回时,设置更新上报时间
			time_ctrl[1] = time_disp[1];
			time_ctrl[2] = time_disp[2];
		}
	}

在设置界面时,选择时分秒,并且闪烁选中的。这里用一个变量set_ctrl,当为1是将要显示字符串对于的时分秒设置为空字符,为0就为原来的。并且该变量在一定时间类翻转来达到闪烁效果。

	if(LCD_GUI>>4==1 && unKey_Down ==3) //进入设置界面并且按下按键3
	{
		if(LCD_GUI==0x12)
		{
			LCD_GUI=0x10;
		}
		else
			LCD_GUI++;
	}

//设置界面
		sprintf((char *)Lcd_Disp_String, "Setting");
		LCD_DisplayStringLine(Line2, Lcd_Disp_String);	
		sprintf((char *)Lcd_Disp_String, "T:%02d-%02d-%02d",time_disp[0],time_disp[1],time_disp[2]);
		LCD_DisplayStringLine(Line6, Lcd_Disp_String);	
		if((uwTick -  uwTick_Set_time_Set_Point)>=500) //控制设置时分秒的闪烁时间
		{
			uwTick_Set_time_Set_Point = uwTick;
			set_ctrl ^= 0x01;
		}
		if(set_ctrl == 0x01)  // 将相应的时分秒设置为空字符
		{
			if(LCD_GUI == 0X10)
			{
				Lcd_Disp_String[2] = ' ';
				Lcd_Disp_String[3] = ' ';
			}
			else if(LCD_GUI == 0X11)
			{
				Lcd_Disp_String[5] = ' ';
				Lcd_Disp_String[6] = ' ';
			}
			else if(LCD_GUI == 0X12)
			{
				Lcd_Disp_String[8] = ' ';
				Lcd_Disp_String[9] = ' ';
			}
		}
		LCD_DisplayStringLine(Line6, Lcd_Disp_String);	

设置更新时间,用两个数值来存储(用一个其实就够了的),一个专门用来显示,一个用来控制上报时间的。当按键4按下时,修改显示变量即可,然后再界面返回时,将显示变量值赋给控制变量

uint8_t time_disp[3]={0}; 
uint8_t time_ctrl[3]={0}; 
if(unKey_Down == 4)  //值修改
	{
		if(LCD_GUI == 0X10) // hour
		{
			if(time_disp[0] >=23)time_disp[0] = 0;
			else
				time_disp[0]++;
		}
		else if(LCD_GUI == 0X11) // min
		{
			if(time_disp[1] >=59)time_disp[1] = 0;
			else 
				time_disp[1]++;
		}
		else if(LCD_GUI == 0X12) // sed
		{
			if(time_disp[2]>=59)time_disp[2] = 0;
			else
				time_disp[2]++;
		}

....


else    //返回显示界面
		{
			LCD_Clear(White);
			LCD_GUI=0x00;
			time_ctrl[0] = time_disp[0]; //再次返回时,设置更新上报时间
			time_ctrl[1] = time_disp[1];
			time_ctrl[2] = time_disp[2];
		}
....

界面的难点基本上就是上面的了,其他细节看后面的完整程序。

2.串口的接发

自动上报,直接在相等时刻发给串口即可,这里要控制在相等时刻只发一次,用一个变量来控制即可。(直接在发送字符后面适当的延时即可)

// 自动上报
	if(time_ctrl[0]==sTime.Hours && time_ctrl[1]==sTime.Minutes && time_ctrl[2]==sTime.Seconds)
	{
		if(Ctrl_Uart_Send_Time_Data_Times ==0)
		{
			Ctrl_Uart_Send_Time_Data_Times=1;
			sprintf(str, "%4.2f+%2.1f+%02d%02d%02d\n",v1, (k_int/10.),sTime.Hours,sTime.Minutes,sTime.Seconds);
			HAL_UART_Transmit(&huart1,(unsigned char *)str, strlen(str), 50);
		}
	}
	else
		Ctrl_Uart_Send_Time_Data_Times = 0;	//当时间变化或者控制值变化,两者不等的时候,恢复下一次数据发送允许。

本题的难点就是串口的接收,在发生错误的时候,设备不相应。发生的数据格式k0.x\n。转换为十六进制为:k0.1\n  ==>6B 30 2E 31 5C 6E 。这里在串口中"\n"会被当成两个字符处理

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA57yW56iL5bCP54aK,size_20,color_FFFFFF,t_70,g_se,x_16

 发生错误可以从两种角度考虑:数据内容不匹配和数据长度不为6。

因此,可以在中断接收函数里面以字节为单位接收数据,若是第一个字节并且为6b,于是才开始接收下一个字节。

//串口接收中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(rx_buf == 0x6b && rx_buf_index ==0)//若数据为6b,并且是第一个数据
	{
		uwTick_Uart_TI_time_Set_Point= uwTick;//接收到第一个数据启动计时
		Start_Flag = 1;  //接收下一个字节
	}
	if(Start_Flag == 1) //满足则把数据接收完
	{
		rx_buffer[rx_buf_index++] = rx_buf;
	}
	HAL_UART_Receive_IT(&huart1, (uint8_t *)&rx_buf, 1);
}

但是如果上一串数据是错的,但是下一串数据是对的,我们必须又恢复为原来还没开始接收数据前的样子,即需要在一个时间段内将数组的索引归0和开始接收标志归0,为一下接收做准备。所以用一个时间变量来控制串口接收处理时间,数据错误或者数据正确并处理完,时间到了就清0,为下一次接收做准备

// 设置k
	// k0.1\n ==>6B 30 2E 31 5C 6E 
	200ms~300ms之内处理数据
	if((uwTick - uwTick_Uart_TI_time_Set_Point) = 200) 
	{
		if(rx_buf_index==6)  //判断命令长度
		{
			// 比较内容处第三个
			if(rx_buffer[0] == 0x6b && rx_buffer[1] == 0x30 && rx_buffer[2] == 0x2e && rx_buffer[4] == 0x5c && rx_buffer[5] == 0x6e)
			{
				// 第三个字节范围 1-9
				if(rx_buffer[3]>=0x30 && rx_buffer[3]4==1 && unKey_Down ==3) //进入设置界面并且按下按键3
	{
		if(LCD_GUI==0x12)
		{
			LCD_GUI=0x10;
		}
		else
			LCD_GUI++;
	}
	
	if(unKey_Down == 4)  //值修改
	{
		if(LCD_GUI == 0X10) // hour
		{
			if(time_disp[0] >=23)time_disp[0] = 0;
			else
				time_disp[0]++;
		}
		else if(LCD_GUI == 0X11) // min
		{
			if(time_disp[1] >=59)time_disp[1] = 0;
			else 
				time_disp[1]++;
		}
		else if(LCD_GUI == 0X12) // sed
		{
			if(time_disp[2]>=59)time_disp[2] = 0;
			else
				time_disp[2]++;
		}
		
	}

}


//***LED扫描子函数
void Led_Proc(void)
{
	if((uwTick -  uwTick_Led_Set_Point)3.3*k_int*0.1)  //亮
		{
			if((uwTick -  uwTick_Led_Point)>=200)
			{
				uwTick_Led_Point = uwTick;
				ucLed ^= 0x01;
			}		
		}
		else
			ucLed = 0;
	}
	LED_Disp(ucLed);
}


void Lcd_Proc(void)
{
	if((uwTick -  uwTick_Lcd_Set_Point)=500) //控制设置时分秒的闪烁时间
		{
			uwTick_Set_time_Set_Point = uwTick;
			set_ctrl ^= 0x01;
		}
		if(set_ctrl == 0x01)  // 将相应的时分秒设置为空字符
		{
			if(LCD_GUI == 0X10)
			{
				Lcd_Disp_String[2] = ' ';
				Lcd_Disp_String[3] = ' ';
			}
			else if(LCD_GUI == 0X11)
			{
				Lcd_Disp_String[5] = ' ';
				Lcd_Disp_String[6] = ' ';
			}
			else if(LCD_GUI == 0X12)
			{
				Lcd_Disp_String[8] = ' ';
				Lcd_Disp_String[9] = ' ';
			}
		}
		LCD_DisplayStringLine(Line6, Lcd_Disp_String);	
	}
}

void Usart_Proc(void)
{
	if((uwTick -  uwTick_Usart_Set_Point)6B 30 2E 31 5C 6E 
	200ms~300ms之内处理数据
	if((uwTick - uwTick_Uart_TI_time_Set_Point) = 200) 
	{
		if(rx_buf_index==6)  //判断命令长度
		{
			// 比较内容处第三个
			if(rx_buffer[0] == 0x6b && rx_buffer[1] == 0x30 && rx_buffer[2] == 0x2e && rx_buffer[4] == 0x5c && rx_buffer[5] == 0x6e)
			{
				// 第三个字节范围 1-9
				if(rx_buffer[3]>=0x30 && rx_buffer[3]            
关注
打赏
1665385461
查看更多评论
0.1857s