一、题目概览
设计一个小型停车计费系统


二、分模块实现
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如果有其他思路请评论!!(*^_^*)



















