蓝桥杯嵌入式第十五届省赛模拟3

目录

1.题目要求

2.user.h中

3.user.c中

4.main中

5.总结


1.题目要求

2.user.h中

#ifndef __USER_H
#define __USER_H

#include "main.h"
#include "stdio.h"
#include "string.h"

void key_pro(void);
void lcd_pro(void);
void getR37value(void);
void getR38value(void);
void led_pro(void);
void rx_pro(void);
int fputc(int ch, FILE *f);

extern uint8_t rx_data;
extern uint8_t rx_pointer;

#endif

3.user.c中

#include "user.h"

extern ADC_HandleTypeDef hadc2;
double R37_volt = 0,R38_volt = 0;
void getR37value(void)					//ADC2
{
	uint16_t ADC2_Value;
	HAL_ADC_Start(&hadc2);
	ADC2_Value = HAL_ADC_GetValue(&hadc2);
	R37_volt = (ADC2_Value * 3.3f) / 4095.0f;
}

extern ADC_HandleTypeDef hadc1;
void getR38value(void)					//ADC1
{
	uint16_t ADC1_Value;
	HAL_ADC_Start(&hadc1);
	ADC1_Value = HAL_ADC_GetValue(&hadc1);
	R38_volt = (ADC1_Value * 3.3f) / 4095.0f;
}

uint8_t key_value,key_down,key_up,key_old = 0;
void key_scan(void)
{
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0) == RESET)
			key_value = 1;	
	else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) == RESET)
			key_value = 2;
	else if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2) == RESET)
			key_value = 3;
	else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET)
			key_value = 4;
	else key_value = 0;
	
	key_down = key_value & (key_value ^ key_old);
	key_up = ~key_value & (key_value ^ key_old);
	key_old = key_value;
}

uint8_t page_index = 1;
uint8_t line_index = 1;
uint32_t key_tick = 0;
double R37_xia = 1.2,R37_shang = 2.2;		//R37上下限
double R38_xia = 1.4,R38_shang = 3.0;		//R38上下限
uint8_t R37_Sum = 0,R38_Sum = 0;			//记录总检数
uint8_t R37_qualified_quantity = 0,R38_qualified_quantity = 0;	//记录符合标准数
double R37_yield,R38_yield;					//合格率
uint8_t R37_passflag = 0,R38_passflag = 0;
void key_pro(void)
{
	if(uwTick - key_tick < 20)				//消抖
		return;
	key_tick = uwTick;
	key_scan();
	
	if(key_down == 1)				//换页面
	{
		page_index ++;
		LCD_Clear(Black);
		if(page_index > 3)page_index = 1;
	}
	
	if(page_index == 1)
	{
		if(key_down == 2)		//检测R37是否合格
		{
			R37_Sum ++;
			if(R37_volt <= R37_shang && R37_volt >= R37_xia)
			{
				R37_passflag = 1;						//点灯
				R37_qualified_quantity ++;
			}
			
			R37_yield = R37_qualified_quantity * 1.0f / R37_Sum * 100.0f;
		}
		else if(key_down == 3)		//检测R38是否合格
		{
			R38_Sum ++;
			if(R38_volt <= R38_shang && R38_volt >= R38_xia)
			{
				R38_passflag = 1;
				R38_qualified_quantity ++;
			}
			
			R38_yield = R38_qualified_quantity * 1.0f / R38_Sum * 100.0f;
		}
	}
	else if(page_index == 2)			
	{
		if(key_down == 2)			//选择更改的上下限
		{
			line_index ++;
			if(line_index > 4)line_index = 1;
		}
		else if(key_down == 3)
		{
			switch(line_index)			//更改上下限
			{
				case 1:
				{
					if(R37_xia < 2.0)R37_xia += 0.2;
					else if(R37_xia >= 2.0)R37_xia = 1.2;
					
				}break;
				
				case 2:
				{
					if(R37_shang < 3.0)R37_shang += 0.2;
					else if(R37_shang >= 3.0)R37_shang = 2.2;
					
				}break;
				
				case 3:
				{
					if(R38_xia < 2.0)R38_xia += 0.2;
					else if(R38_xia >= 2.0)R38_xia = 1.2;
					
				}break;
				
				case 4:
				{
					if(R38_shang < 3.0)R38_shang += 0.2;
					else if(R38_shang >= 3.0)R38_shang = 2.2;
					
				}break;
			}
		}
		else if(key_down == 4)		//更改上下限
		{
			switch(line_index)
			{
				case 1:
				{
					if(R37_xia > 1.2)R37_xia -= 0.2;
					else if(R37_xia <= 1.2)R37_xia = 2.0;
					
				}break;
				
				case 2:
				{
					if(R37_shang > 2.2)R37_shang -= 0.2;
					else if(R37_shang <= 2.2)R37_shang = 3.0;
					
				}break;
				
				case 3:
				{
					if(R38_xia > 1.2)R38_xia -= 0.2;
					else if(R38_xia <= 1.2)R38_xia = 2.0;
					
				}break;
				
				case 4:
				{
					if(R38_shang > 2.2)R38_shang -= 0.2;
					else if(R38_shang <= 2.2)R38_shang = 3.0;
					
				}break;
			}
		}
		
		if(key_down == 3)			//标准发生改变
		{
			R37_Sum = 0;			
			R37_yield = 0;			
			R37_qualified_quantity = 0;	
		}
		else if(key_down == 4)
		{
			R38_Sum = 0;
			R38_yield = 0;
			R38_qualified_quantity = 0;
		}
		
	}
	else if(page_index == 3)
	{
		if(key_down == 4)
		{
			R37_Sum = 0;
			R38_Sum = 0;
			R37_yield = 0;
			R38_yield = 0;
			R37_qualified_quantity = 0;
			R38_qualified_quantity = 0;
		}
	}
	
}

char buf[30];
u32 lcd_tick = 0;
void lcd_pro(void)
{
	if(uwTick - lcd_tick < 200)
		return;
	lcd_tick = uwTick;
	
	switch(page_index)
	{
		case 1:
		{
			LCD_DisplayStringLine(Line1,(u8 *)"       GOODS        ");
		
			sprintf(buf,"     R37:%.2lfV    ",R37_volt);
			LCD_DisplayStringLine(Line3,(u8 *)buf);
							
			sprintf(buf,"     R38:%.2lfV    ",R38_volt);
			LCD_DisplayStringLine(Line4,(u8 *)buf);
			
		}break;
		case 2:
		{
			LCD_DisplayStringLine(Line1,(u8 *)"      STANDARD        ");
			
			sprintf(buf,"    SR37:%.1f-%.1f    ",R37_xia,R37_shang);
			LCD_DisplayStringLine(Line3,(u8 *)buf);
		
			sprintf(buf,"    SR38:%.1f-%.1f    ",R38_xia,R38_shang);
			LCD_DisplayStringLine(Line4,(u8 *)buf);
					
		}break;
		case 3:
		{
			LCD_DisplayStringLine(Line1,(u8 *)"        PASS        ");
			
			sprintf(buf,"    PR37:%.1f%%    ",R37_yield);
			LCD_DisplayStringLine(Line3,(u8 *)buf);
		
			sprintf(buf,"    PR38:%.1f%%    ",R38_yield);
			LCD_DisplayStringLine(Line4,(u8 *)buf);
			
		}break;
	}
}

extern TIM_HandleTypeDef htim2;
uint32_t led1_tick;
uint32_t led2_tick;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim -> Instance == TIM2)
	{
		if(R37_passflag == 1)
		{
			led1_tick ++;
		}
		else if(R38_passflag == 1)
		{
			led2_tick ++;
		}
		
		if(led1_tick == 1000)
		{
			R37_passflag = 0;
			led1_tick = 0;
		}
		else if(led2_tick == 1000)
		{
			R38_passflag = 0;
			led2_tick = 0;
		}
	}
	HAL_TIM_Base_Start_IT(&htim2);
}


void led_pro(void)
{
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
	
	if(R37_passflag == 1)HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET);//R37检测合格
	else HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);

	if(R38_passflag == 1)HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET);//R38检测合格
	else HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_SET);

	if(page_index == 1)	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,GPIO_PIN_RESET);//页面1
	else HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,GPIO_PIN_SET);
	
	if(page_index == 2)	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_RESET);//页面2
	else HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_SET);
	
	if(page_index == 3)	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_RESET);//页面3
	else HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_SET);
	
	HAL_Delay(1);
	
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

/*数据接收不完整,丢失严重

问题一:无条件重置接收指针
	现象:

void rx_pro(void)
{
  //...
  rx_pointer = 0; // 无条件重置
  memset(rx_buf,0,sizeof(rx_buf));
}
	后果:
		1.每次处理都会清空接收缓冲区
		2.快速发送时部分数据被意外清除
		3.无法处理连续多次命令

问题二:缺乏超时机制
	现象:
		1.接收不完整数据时永久挂起
		2.异常数据阻塞后续处理

问题三:未处理命令结束符
	现象:
		1.无法区分连续命令
		2.实际发送可能包含CR/LF
		
问题四:缓冲区溢出风险

uint8_t rx_buf[6];
void HAL_UART_RxCpltCallback(...)
{
  if(rx_pointer < 5) // 允许写入5字节
}

	隐患:
		1.数组大小为6但允许写5字节
		2.最后一个字节未保留给字符串终结符
*/
                            /*不推荐代码*/
//uint8_t rx_pointer,rx_data,rx_buf[6];
//void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
//{
//	if(rx_pointer < 5)
//	{
//		rx_buf[rx_pointer ++] = rx_data;
//	}
//	HAL_UART_Receive_IT(&huart1,&rx_data,1);
//}

//void rx_pro(void)
//{
//	static  uint32_t rx_tick = 0;
//	if(uwTick - rx_tick < 50)
//		return;
//	rx_tick = uwTick;
//	
//	if(rx_pointer > 0)
//	{
//		if(rx_pointer == 3)
//		{
//			if(rx_buf[0] == 'R' && rx_buf[1] == '3' && (rx_buf[2] == '7' || rx_buf[2] == '8'))
//			{
//				if(rx_buf[2] == '7')
//				{
//					printf("R37:%d,%d,%.1lf%%\r\n",R37_Sum,R37_qualified_quantity,R37_yield);
//				}
//				else if(rx_buf[2] == '8')
//				{
//					printf("R38:%d,%d,%.1lf%%\r\n",R38_Sum,R38_qualified_quantity,R38_yield);
//				}
//			}
//		}
//	}
//		rx_pointer = 0;
//		memset(rx_buf,0,sizeof(rx_buf));
//}

extern UART_HandleTypeDef huart1;
int fputc(int ch, FILE *f) 
{
	uint8_t c = (uint8_t)ch;
	HAL_UART_Transmit(&huart1,&c,1,50);
	return ch;
}

/*
优化效果:
		1.响应延迟从50ms降低到实时响应
		2.支持连续命令处理
		3.抗干扰能力提升(异常数据自动超时清除)
		4.缓冲区溢出风险完全消除
*/

#define RX_BUF_SIZE 64
#define RX_TIMEOUT 100  //100ms延时

uint8_t rx_pointer = 0;
uint8_t rx_data;
uint8_t rx_buf[RX_BUF_SIZE];
uint32_t last_rx_time = 0;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if(rx_pointer < RX_BUF_SIZE-1){
    rx_buf[rx_pointer++] = rx_data;
    last_rx_time = uwTick; // 更新最后接收时间
  }
  HAL_UART_Receive_IT(&huart1, &rx_data, 1);
}

void rx_pro(void)
{
	// 超时处理
    if((uwTick - last_rx_time > RX_TIMEOUT) && rx_pointer >0)
	{
		if(rx_pointer >=3)
		{
			if(memcmp(rx_buf, "R37",3) == 0)
			{
				printf("R37:%d,%d,%.1lf%%\r\n",R37_Sum,R37_qualified_quantity,R37_yield);
			}
			else if(memcmp(rx_buf, "R38",3) == 0)
			{
				printf("R38:%d,%d,%.1lf%%\r\n",R38_Sum,R38_qualified_quantity,R38_yield);
		}
		}
    rx_pointer = 0;
    memset(rx_buf,0,sizeof(rx_buf));
  }
}

4.main中

#include "user.h"

int main(void)
{

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  MX_USART1_UART_Init();
  MX_TIM2_Init();
	
	LCD_Init();
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	
	HAL_TIM_Base_Start_IT(&htim2);			//1s
	HAL_UART_Receive_IT(&huart1,&rx_data,1);
	
	
  while (1)
  {
	  key_pro();
	  lcd_pro();
	  getR38value();
	  getR37value();
	  led_pro();
	 
	  if(rx_pointer != 0)
	  {
		  rx_pro();
	  }  
  }
}

5.总结

1.串口助手点击发送的次数不等于串口助手接受的次数,串口助手接收区相应慢或者不响应。经过代码优化:                                        (具体分析见代码注释)
        优化效果:
                1.响应延迟从50ms降低到实时响应
                2.支持连续命令处理
                3.抗干扰能力提升(异常数据自动超时清除)
               4.缓冲区溢出风险完全消除

2.合格率的计算:

按下按键检测一次,即总检数++,如果此时R37或R38的电压在上下限之间则为符合标准,即标准数++,反之不符合则不++,然后按公式计算即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值