前言
个人感觉这次的题目想拿高分和满分的拿分的还是有难度的,这届赛题我个人觉得难在车辆出入库之间,解决这两个主要问题,然后就是细节问题。接下来上赛题
解题之前,我觉得需要写一下串口部分的代码思路,方便后面的书写。
首先是车辆三要素,可以用结构体包含,想要车辆出入库,前提是串口发送数据合理,合理后判断车辆出入库,入库需要查询入几号库,出库也是,同时清空库内数据。大致就是以上步骤,其实思路清晰了,后续代码的编写也就是时间问题了,个人觉得这次拿满分很难,主要时间确实有点紧迫。接下来就上代码
全局变量和头文件
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "led.h"
#include "key.h"
#include "stdio.h"
#include "string.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
__IO uint32_t keyTick,ledTick,uartTick;
_Bool uart_flag,tim17_flag; //串口接收22字节标志位和PA7电平标志位
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
u8 lcd_display = 0; //界面 0 1
u8 cnbr_num = 0,vnbr_num = 0; //两种车辆类型的数目
u8 cnbr_rate = 35,vnbr_rate = 20; //两种车辆每小时的停车费用
u8 led_ctrl; //led控制
u8 uart_buf[2]; //串口发送缓存
u8 uart_rx[23]; //串口接收缓存
u8 rx_cnt; //串口接收几个数
u8 year,month,day,hour,min,sec; //首次接收串口数据并验证数据正确性
u8 year1,month1,day1,hour1,min1,sec1; //数据正常赋值给这些变量
u8 year3,month3,day3,hour3,min3,sec3; //最后出车的时候计算停车费用,算总时间
u16 hour_all; //最后停车的总时间
__IO uint32_t money_vnbr,money_cnbr; //两种车辆停车的总费用
u8 name1[4]; //存车辆名字的数组
u8 car_indexes,car_out; //第一个索引停哪个车位,第二个出库车位
typedef struct
{
u8 type[5]; //车辆类型
u8 name[5]; //车辆名字
u8 year2; //入库的时间
u8 month2;
u8 day2;
u8 hour2;
u8 min2;
u8 sec2;
u8 pos; //当前车位的状态0有空位,1没有空位
} CAR;
CAR car_info[8]; //八个停车位
然后是各级任务
//1.lcd显示
void LCD_Process()
{
u8 text[30];
//主界面
if(!lcd_display)
{
sprintf((char*)text," Data ");
LCD_DisplayStringLine(Line2,text);
sprintf((char*)text," CNBR:%d ",cnbr_num);
LCD_DisplayStringLine(Line4,text);
sprintf((char*)text," VNBR:%d ",vnbr_num);
LCD_DisplayStringLine(Line6,text);
sprintf((char*)text," IDLE:%d ",(8-cnbr_num-vnbr_num));
LCD_DisplayStringLine(Line8,text);
}
//参数界面
if(lcd_display==1)
{
sprintf((char*)text," Para ");
LCD_DisplayStringLine(Line2,text);
sprintf((char*)text," CNBR:%0.2f ",(cnbr_rate/10.0f));
LCD_DisplayStringLine(Line4,text);
sprintf((char*)text," VNBR:%0.2f ",(vnbr_rate/10.0f));
LCD_DisplayStringLine(Line6,text);
}
}
//2.按键功能
void KEY_Process()
{
//10ms扫描一次
if(uwTick - keyTick<10) return;
keyTick = uwTick;
Key_Read();
//按键B1
if(Trg & 0x01)
{
LCD_Clear(Black);
lcd_display =(lcd_display+1)%2;
}
//按键B2
if(Trg & 0x02)
{
//参数界面
if(lcd_display ==1)
{
cnbr_rate+=5;
vnbr_rate+=5;
}
}
//按键B3
if(Trg & 0x04)
{
//参数界面
if(lcd_display ==1)
{
cnbr_rate-=5;
vnbr_rate-=5;
}
}
//按键B4
if(Trg & 0x08)
{
tim17_flag = !tim17_flag;
}
}
//4.PWM占空比调节
void PWM_Process()
{
if(tim17_flag)
{
TIM17->CCR1 = 100;
}
else
TIM17->CCR1 = 0; //0占空比即低电平
}
//5.led灯任务
void LED_Process()
{
if((8-cnbr_num-vnbr_num))
led_ctrl |= 0x01;
else
led_ctrl &= ~0x01;
if(tim17_flag)
led_ctrl |= 0x02;
else
led_ctrl &= ~ 0x02;
LED_Control(led_ctrl);
}
串口任务单独写
//3.串口接收数据大小检查和定时清空接收
void RxIde_Process()
{
if(uwTick- uartTick<50) return;
uartTick = uwTick;
//串口接收到数据但是没有22个
if(rx_cnt>0 && (uart_flag ==0))
{
printf("error\r\n");
}
uart_flag = 0;
rx_cnt = 0;
memset(uart_rx,'\0',sizeof(uart_rx)); //清空接收的数据
}
//检查数据合理性
_Bool check_String(u8 *str)
{
u8 i;
if((str[1]=='N') && (str[2]=='B') &&(str[3]=='R') && ((str[0]!='C')||(str[0]!='V'))&&(str[4]==':')&&(str[9]==':') )
{
for(i=10;i<=21;i++)
{
if(str[i]>'9' || str[i]<'0' )
return 0;
}
year = (str[10] -'0')*10+(str[11] -'0');
month = (str[12] -'0')*10+(str[13] -'0');
day = (str[14] -'0')*10+(str[15] -'0');
hour = (str[16] -'0')*10+(str[17] -'0');
min = (str[18] -'0')*10+(str[19] -'0');
sec = (str[20] -'0')*10+(str[21] -'0');
if(year>99 || month >12 || day>31 ||hour >23||min>59||sec>59)
return 0;
year1 = year;
month1 = month;
day1 = day;
hour1 = hour;
min1 = min;
sec1 = sec;
return 1;
}
return 0;
}
//判断是入车还是出车
u8 Judge(u8 *str)
{
u8 i =0;
for(i=0;i<8;i++)
{
if((str[0]==car_info[i].name[0])&&(str[1]==car_info[i].name[1])&&(str[2]==car_info[i].name[2])&&(str[3]==car_info[i].name[3]))
{
return (i+1); //有名字相同的车辆,就返回相应的车库号,库号1-8,表示出库
}
}
return 0; //没有就返回零,表示入库
}
//判断进入第几个车库
u8 Indexes()
{
u8 i =0;
for(i=0;i<8;i++)
{
if(car_info[i].pos == 0) //从低到高查每一个车库的状态
return (i+1);
}
return 0;
}
//车辆入库,把数据写入结构体
void Write_enter()
{
car_info[car_indexes-1].type[0] = uart_rx[0];car_info[car_indexes-1].type[1] = uart_rx[1];car_info[car_indexes-1].type[2] = uart_rx[2];car_info[car_indexes-1].type[3] = uart_rx[3];
car_info[car_indexes-1].name[0] = uart_rx[5];car_info[car_indexes-1].name[1] = uart_rx[6];car_info[car_indexes-1].name[2] = uart_rx[7];car_info[car_indexes-1].name[3] = uart_rx[8];
car_info[car_indexes-1].year2 = year1;
car_info[car_indexes-1].month2 = month1;
car_info[car_indexes-1].day2 = day1;
car_info[car_indexes-1].hour2= hour1;
car_info[car_indexes-1].min2 = min1;
car_info[car_indexes-1].sec2 = sec1;
car_info[car_indexes-1].pos = 1;
}
//停车消耗的时间,不足一小时按一小时计算,不足一分按一分钟计算
void Write_out()
{
year3= ((uart_rx[10]-'0')*10+(uart_rx[11]-'0'))-car_info[car_out-1].year2;
month3 = ((uart_rx[12]-'0')*10+(uart_rx[13]-'0')) -car_info[car_out-1].month2;
day3 = ((uart_rx[14]-'0')*10+(uart_rx[15]-'0'))-car_info[car_out-1].day2;
hour3 = ((uart_rx[16]-'0')*10+(uart_rx[17]-'0'))-car_info[car_out-1].hour2;
min3 = ((uart_rx[18]-'0')*10+(uart_rx[19]-'0'))-car_info[car_out-1].min2;
sec3 = ((uart_rx[20]-'0')*10+(uart_rx[21]-'0'))-car_info[car_out-1].sec2;
hour_all = (year3*365*25)+(month3*30*24)+(day3*24)+hour3;
if(sec3>0)
{
min3++;
}
if(min3>0)
hour_all++;
}
//串口接收回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
uartTick = uwTick;
uart_rx[rx_cnt++] = uart_buf[0];
HAL_UART_Receive_IT(&huart1,uart_buf,1);
if(rx_cnt == 22)
{
if(check_String(uart_rx)==0)
{
printf("error\r\n");
}
if(check_String(uart_rx)==1)
{
name1[0] = uart_rx[5]; //把串口接收的数据放入车辆名字中
name1[1] = uart_rx[6];
name1[2] = uart_rx[7];
name1[3] = uart_rx[8];
car_out = Judge(name1);
if((Judge(name1)==0)) //判断入库
{
car_indexes = Indexes(); //判断第几号车库
if(car_indexes!=0) //有空闲车库
{
if(uart_rx[0] == 'C') //判断那种类型车
{
cnbr_num++;
}
else
{
vnbr_num++;
}
Write_enter(); //入库
printf("car in\r\n"); //题目没有要求
}
else
printf(" car is full\r\n"); //题目要求打印Error
}
else //出库
{
Write_out(); //计算停车的时间
if(uart_rx[0] == 'C')
{
cnbr_num--;
money_cnbr=hour_all*cnbr_rate; //停车费用
printf("%cNBR:%c%c%c%c:%d:%0.2f\r\n",car_info[car_out-1].type[0],car_info[car_out-1].name[0],car_info[car_out-1].name[1],
car_info[car_out-1].name[1],car_info[car_out-1].name[3],hour_all,(money_cnbr/10.0f));
}
else
{
vnbr_num--;
money_vnbr=hour_all*vnbr_rate; //停车费用
printf("%cNBR:%c%c%c%c:%d:%0.2f\r\n",car_info[car_out-1].type[0],car_info[car_out-1].name[0],car_info[car_out-1].name[1],
car_info[car_out-1].name[1],car_info[car_out-1].name[3],hour_all,(money_vnbr/10.0f));
}
memset(&car_info[car_out-1],0,sizeof(car_info[car_out-1])); //清空数组内的数据
}
}
rx_cnt = 0;
uart_flag = 1;
}
}
最后是主函数调用,要开启定时器通道和串口接收
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1); //开启定时器17pwm通道1
TIM17->CCR1 = 0;
HAL_UART_Receive_IT(&huart1,uart_buf,1); //开启串口接收中断
LCD_Init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
LCD_Process();
KEY_Process();
RxIde_Process();
PWM_Process();
LED_Process();
}
上述代码能实现最大部分功能,不过停车收费有bug,没有计算大小月各平年闰年,各位小伙伴有需要可以自行补充。