目录
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的电压在上下限之间则为符合标准,即标准数++,反之不符合则不++,然后按公式计算即可