一、题目概览
设计一个小型停车计费系统
二、分模块实现
1、LCD
void disp_proc()
{
if(view==0)
{
char text[30];
sprintf(text," Data");
LCD_DisplayStringLine(Line2,(uint8_t *)text);
sprintf(text," CNBR:%d ",Cnum);
LCD_DisplayStringLine(Line4,(uint8_t *)text);
sprintf(text," VNBR:%d ",Vnum);
LCD_DisplayStringLine(Line6,(uint8_t *)text);
sprintf(text," IDLE:%d ",idle-Cnum-Vnum);
LCD_DisplayStringLine(Line8,(uint8_t *)text);
}
if(view==1)
{
char text[30];
sprintf(text," Para");
LCD_DisplayStringLine(Line2,(uint8_t *)text);
sprintf(text," CNBR:%.2lf ",Crate);
LCD_DisplayStringLine(Line4,(uint8_t *)text);
sprintf(text," VNBR:%.2lf ",Vrate);
LCD_DisplayStringLine(Line6,(uint8_t *)text);
}
}
2、按键
Crate和Vrate分别是CNBR类型和VNBR类型停车的费率,按按键B3的减少我没有设置下限(仔细看了题目没要求),而且设置下限为零的话重新开始加的话两个费率就相等了。
void key_proc()
{
if(key[0].single_flag==1)//B1
{
view=!view;
LCD_Clear(Black);
key[0].single_flag=0;
}
if(key[1].single_flag==1)//B2
{
if(view==1)
{
Crate+=0.5;
Vrate+=0.5;
}
key[1].single_flag=0;
}
if(key[2].single_flag==1)//B3
{
if(view==1)
{
Crate-=0.5;
Vrate-=0.5;
}
key[2].single_flag=0;
}
if(key[3].single_flag==1)//B4
{
state=!state;
if(state==1)
{
HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);
__HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,(20/100)*(80000000/80/2000));
LED_state|=0x02;LED_Disp(LED_state);
}
else
{
HAL_TIM_PWM_Stop(&htim17,TIM_CHANNEL_1);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET);
LED_state&=0xFD;LED_Disp(LED_state);
}
key[3].single_flag=0;
}
}
3、PA7脉冲输出
4、串口通信(重点)
串口通信的基础代码我学习的是B站这个uart串口通信(完结)_哔哩哔哩_bilibili
这个题目最关键的部分就是串口接收数据的处理,即对时间的解析算出停车时间
自定义的变量:
extern struct keys key[];
extern uint frq;
extern float duty;
bool view=0;
bool cnbr_flag=0;
bool vnbr_flag=0;
extern char rxdata[];
extern uint8_t rxdat;
extern int rx_point;//接收位指针
struct CarInfo
{
char car_type[5];
char car_num[5];
char car_time[15];
}CNBRnum[10],VNBRnum[10];
int Cnum=0;
int Vnum=0;
int idle=8;
double Crate=3.50;
double Vrate=2.00;
uchar pa7_duty[2]={0,20};
uchar state=0; //PA7端口输出状态
uchar LED_state=0x01;
// 定义结构体用于保存解析的时间
typedef struct {
uint8_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
} DateTime;
void key_proc(void);
void disp_proc(void);
void uart_rx_proc(void);
void parse_time(char *time_str,DateTime *dt);
void calculate_time_difference(DateTime *start, DateTime *end, int *hours, int *minutes);
自定义的两个处理时间的函数:
// 解析时间字符串
void parse_time(char *time_str,DateTime *dt)
{
dt->year=2000+(time_str[0]-'0')*10+(time_str[1]-'0');
dt->month=(time_str[2]-'0')*10+(time_str[3]-'0');
dt->day=(time_str[4]-'0')*10+(time_str[5]-'0');
dt->hour=(time_str[6]-'0')*10+(time_str[7]-'0');
dt->minute=(time_str[8]-'0')*10+(time_str[9]-'0');
}
// 计算两个时间之间的差值
void calculate_time_difference(DateTime *start, DateTime *end, int *hours, int *minutes) {
// 简化的差值计算,假设输入是有效的
int total_start_minutes = start->year * 525600 + start->month * 43800 + start->day * 1440 + start->hour * 60 + start->minute; // 1年=525600分钟
int total_end_minutes = end->year * 525600 + end->month * 43800 + end->day * 1440 + end->hour * 60 + end->minute;
int diff_minutes = total_end_minutes - total_start_minutes;
*hours = diff_minutes / 60;
*minutes = diff_minutes % 60;
}
串口接收数据的处理函数:
void uart_rx_proc()
{
if(rx_point>0)
{
if(rx_point==22)//接收的字符串定长为22
{
if(rxdata[0]=='C')//开头字母判断停车类型
{
sscanf(rxdata,"%4s:%4s:%12s",CNBRnum[Cnum].car_type,CNBRnum[Cnum].car_num,CNBRnum[Cnum].car_time);
for(int i=0;i<Cnum;i++)
{
if(strcmp(CNBRnum[i].car_num,CNBRnum[Cnum].car_num)==0)//能匹配到一样的车辆编号说明这是出停车场的信息,反之是入停车库
{
DateTime start_time,end_time;
parse_time(CNBRnum[i].car_time,&start_time); //解析时间字符串,拆分成时、分、秒
parse_time(CNBRnum[Cnum].car_time,&end_time);
int hours,minutes;
calculate_time_difference(&start_time,&end_time,&hours,&minutes); //计算时间差
if(minutes>0)hours+=1;
double cost=Crate*hours;
//串口输出计费信息
char temp[30];
sprintf(temp,"CNBR:%4s:%d:%.2lf\r\n",CNBRnum[i].car_num,hours,cost);
HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
Cnum-=1;
for(int j=i;j<Cnum;j++) //前移
{
strncpy(CNBRnum[j].car_num,CNBRnum[j+1].car_num,strlen(CNBRnum[j].car_num));
strncpy(CNBRnum[j].car_time,CNBRnum[j+1].car_time,strlen(CNBRnum[j].car_time));
strncpy(CNBRnum[j].car_type,CNBRnum[j+1].car_type,strlen(CNBRnum[j].car_type));
}
cnbr_flag = 1;
break;
}
}
if(cnbr_flag == 0) //入车库
{
Cnum++;
}
cnbr_flag = 0;
}
if(rxdata[0]=='V')
{
sscanf(rxdata,"%4s:%4s:%12s",VNBRnum[Vnum].car_type,VNBRnum[Vnum].car_num,VNBRnum[Vnum].car_time);
for(int i=0;i<Vnum;i++)
{
if(strcmp(VNBRnum[i].car_num,VNBRnum[Vnum].car_num)==0)
{
DateTime start_time,end_time;
parse_time(VNBRnum[i].car_time,&start_time);
parse_time(VNBRnum[Vnum].car_time,&end_time);
int hours,minutes;
calculate_time_difference(&start_time,&end_time,&hours,&minutes);
if(minutes>0)hours+=1;
double cost=Vrate*hours;
char temp[30];
sprintf(temp,"VNBR:%4s:%d:%.2lf\r\n",VNBRnum[i].car_num,hours,cost);
HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
Vnum-=1;
for(int j=i;j<Vnum;j++) //前移
{
strncpy(VNBRnum[j].car_num,VNBRnum[j+1].car_num,strlen(VNBRnum[j].car_num));
strncpy(VNBRnum[j].car_time,VNBRnum[j+1].car_time,strlen(VNBRnum[j].car_time));
strncpy(VNBRnum[j].car_type,VNBRnum[j+1].car_type,strlen(VNBRnum[j].car_type));
}
vnbr_flag = 1;
break;
}
}
if(vnbr_flag == 0)//入库
{
Vnum++;
}
vnbr_flag = 0;
}
idle = 8-Cnum-Vnum;
if(idle>0){LED_state|=0x01;LED_Disp(LED_state);}
else{LED_state&=0xFE;LED_Disp(LED_state);}
}
else
{
char temp[20];
sprintf(temp,"Error\n");
HAL_UART_Transmit(&huart1,(uint8_t *)temp,strlen(temp),50);
}
rx_point=0;memset(rxdata,0,30);
}
}
5、LED指示灯
LED1:(我写在了串口接收数据处理的函数里)
LED2: (写在了控制按键B3里面)
6、main
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
MX_TIM17_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
LED_Disp(0x00);
LCD_Clear(Black);
LCD_SetBackColor(Black);
LCD_SetTextColor(White);
HAL_TIM_Base_Start_IT(&htim2);
HAL_UART_Receive_IT(&huart1,&rxdat,1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(state == 0)
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,GPIO_PIN_RESET);
LED_Disp(LED_state);
if(rx_point!=0) //防止接收不完整问题
{
int temp=rx_point;
HAL_Delay(1);
if(temp==rx_point) uart_rx_proc();
}
key_proc();
disp_proc();
}
/* USER CODE END 3 */
}
三、总结
我使用的是数组的方式存储车辆信息,有车出停车场的情况我的思路是后面的车位‘往前移’,补空位,感觉这个方法有点笨笨的(T_T),so如果有其他思路请评论!!(*^_^*)