第十二届 蓝桥杯 嵌入式设计与开发项目 省赛

一、硬件框图以及要求

 二、模块代码与功能实现

 2.1、STM32CubeMX配置

2、模块配置与代码

2.2.1、LED模块

        将PC8~PC15配置为GPIO_Output;将PD2配置GPIO_Output。LED驱动代码如下:

//LED驱动代码
void LED_Display(uchar led)
{
	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_All, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC, led << 8, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

2.2.2、LCD模块

        lcd不需要配置,只需将官方给的lcd.c与lcd.h拷贝到自己项目文件夹下,在main函数中使用LCD_Init();初始化即可使用。

2.2.4、键盘模块

将PB0、PB1、PB2、PA0、配置成GPIO_Input,设置为Pull-up上拉模式。在配置定时器TIM4每10ms中断一次,即将预分频系数psc设置为80-1,重装载值设置为10000-1。

        使用定时器TIM4来扫描键盘状态,每隔10ms扫描一次;

       key.h文件内容 

struct keys
{
	uchar key_sta;
	uchar key_judge;
	bool key_flag;
};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

        key.c文件内容

struct keys key[4]={0};

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM4)
	{
		key[0].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
		key[1].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
		key[2].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
		key[3].key_sta = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
		
		for(int i=0;i<4;i++)
		{
			switch(key[i].key_judge)
			{
				case 0:
				{
					if(key[i].key_sta == 0) key[i].key_judge = 1;
				}
				break;
				case 1:
				{	
					if(key[i].key_sta == 0) key[i].key_judge = 2;
				}
				break;
				case 2:
				{	
					if(key[i].key_sta == 0) 
					{
						key[i].key_judge = 3;
						key[i].key_flag = true;
					}
				}
				break;
				case 3:
				{
					if(key[i].key_sta == 1) 
					{
						key[i].key_judge = 0;
					}
				}
				break;
			}
		}
	}
}

2.2.5、PWM

  将PPA7分别配置为TIM17_CH1, PSC为80-1;PA7为2kHz;重装载值分别为10000-1和500-1即可产生2kHz的频率。

2.2.6、串口通信

配置PA9与PA10分别为USART1_Tx与USART1_Rx,波特率9600,打开中断。

        串口接收函数,使用void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)回调函数接收信息。

uint8_t rx;
uint8_t rx_data[50];
uint8_t pt = 0;
bool uart_flag = false;

//接收数据,每次只能接收1个字节
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	HAL_UART_Receive_IT(&huart1,&rx,1);
	rx_data[pt++] = rx;				
}

//判断是否接收完成
void usart_proc()
{
	if(pt != 0)
	{
		uint8_t temp = pt;
		HAL_Delay(5);
		if(temp == pt)
		{
			if(pt > 0)
			{
				uart_flag = true;
			}
		}
	}
}

三、功能实现

3.1、LCD显示界面

1) 车位显示界面
在车位显示界面下,通过LCD显示界面名称(Data).停车场内目前的停车数量和空闲车位,CNBR 和VNBR代表两类不同的停车类型。

图2所示停车数量共6辆,CNBR类2辆,VNBR类4辆,空闲车位2个。
2) 费率设置界面
在费率设置界面下,通过LCD显示界面名称(Para). CNBR类型和VNBR类型停车的费率,单位为元/小时,保留小数点后2位有效数字。

图3所示CNBR类停车费率位3.50元/小时,VNBR类型停车费率位2.00元/小时。
3) LCD通用显示要求
●显示背景 色(BackColor):黑色
●显示前景色(TextColor): 白色
●请严格按照图示2.3要求设计各个信息项的名称(区分字母大小写)和行列位置。

void show(void)
{
	char text[25];
	
	if(view == 0)
	{
		sprintf(text,"       Data         ");
		LCD_DisplayStringLine(Line1,(uint8_t *)text);
		sprintf(text,"   CNBR: %d         ",CNBR);
		LCD_DisplayStringLine(Line3,(uint8_t *)text);
		sprintf(text,"   VNBR: %d         ",VNBR);
		LCD_DisplayStringLine(Line5,(uint8_t *)text);
		sprintf(text,"   IDLE: %d         ",IDLE);
		LCD_DisplayStringLine(Line7,(uint8_t *)text);
	}
	else//设置界面
	{
		sprintf(text,"       Para         ");
		LCD_DisplayStringLine(Line1,(uint8_t *)text);
		sprintf(text,"   CNBR: %.2f         ",Price_CNBR);
		LCD_DisplayStringLine(Line3,(uint8_t *)text);
		sprintf(text,"   VNBR: %.2f         ",Price_VNBR);
		LCD_DisplayStringLine(Line5,(uint8_t *)text);
	}
}

3.2、按键功能

1) B1:定义为“界面切换”按键,切换LCD显示“车位显示界面”和“费率设置界面”。
2) B2:定义为 “加”按键,每次按下B2按键,CNBR、VNBR费率增加0.5元。
3) B3:定义为 “减”按键,每次按下B3按键,CNBR、VNBR费率减少0.5元。
4) B4:定义为 “控制”按键,按下后,切换PA7端口输出状态(2KHz,20%占 空比的脉冲信号或持续低电平),切换要求如图4所示。

5) 通用按键设计要求
●按键应进行有效的防抖处理, 避免出现一次按下、多次触发等情形。
●按键B2、 B3仅在费率设置界面有效。


void key_proc(void)
{
	if(key[0].key_flag)
	{
		key[0].key_flag = false;
		view = !view;
		LCD_Clear(Black);
	}
	
	if(view == 1)
	{
		if(key[1].key_flag)
		{
			key[1].key_flag = false;
			Price_CNBR += 0.5;
			Price_VNBR += 0.5;
		}
		if(key[2].key_flag)
		{
			key[2].key_flag = false;
			Price_CNBR -= 0.5;
			if(Price_CNBR <= 0.5) Price_CNBR = 0.5;
			Price_VNBR -= 0.5;
			if(Price_VNBR <= 0.0) Price_VNBR = 0.0;
		}
	}
	
	
	if(key[3].key_flag)
	{
		key[3].key_flag = false;

		PA7 = !PA7;
		if(PA7)
		{
			int arr = 1000000/2000;
			int crr = 20*arr/100;
			__HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,crr);
			led = led | LED2;
		}
		else
		{
			__HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,0);
			
			led = led & (~LED2);
		}
		LED_Display(led);
	}
}

3.3、串口功能

void handle_proc(void)
{
	if(uart_flag)
	{
		uart_flag = false;
		if(pt == 22)//判断信息是否正确
		{
			char text[30];
			sscanf((char*)rx_data,"%4s:%4s:%12s",car_type,car_id,car_time);//分离数据

			bool flag = false;
			//判断数据库中是否有该车辆的数据,有则表示出停车场,否则进停车场
			int i = 0;
			for(;i<CAR_NUM;i++)
			{
				if(car[i].flag&&(strcmp(car_id,car[i].id) == 0))//有则表示出停车场
				{
					flag = true;//
					break;
				}
			}
			if(flag)//找到车辆信息
			{
				char in_year[3],in_month[3],in_day[3],in_hour[3],in_min[3],in_sec[3];
				char out_year[3],out_month[3],out_day[3],out_hour[3],out_min[3],out_sec[3];
					
				//提出时间
				sscanf(car[i].time,"%2s%2s%2s%2s%2s%2s",in_year,in_month,in_day,in_hour,in_min,in_sec);
				sscanf(car_time,"%2s%2s%2s%2s%2s%2s",out_year,out_month,out_day,out_hour,out_min,out_sec);
					
				sprintf(text,"in   : %s:%s:%s\r\n",car[i].type,car[i].id,car[i].time);
				HAL_UART_Transmit(&huart1,(uint8_t*)text,strlen(text),50);
				HAL_Delay(10);
				sprintf(text,"out: %s:%s:%s\r\n",car_type,car_id,car_time);
				HAL_UART_Transmit(&huart1,(uint8_t*)text,strlen(text),50);	
				HAL_Delay(10);
				
				//分析及处理
				int time = 0;
				double rmb = 0;
				//将字符串转成数字
				int day_in = atoi(in_day);
				int hour_in = atoi(in_hour);
				int min_in = atoi(in_min);
				
				int day_out = atoi(out_day);
				int hour_out = atoi(out_hour);
				int min_out = atoi(out_min);
			
				time = (day_out - day_in)*24 + (hour_out - hour_in);
				if(min_out - min_in > 0) time++;
				
				if(strcmp(car_type,"CNBR")  == 0)
				{
					CNBR--;
					rmb = time*Price_CNBR;
				}
				else if(strcmp(car_type,"VNBR")  == 0)
				{
					VNBR--;
					rmb = time*Price_VNBR;
				}
				IDLE++;	
				
				sprintf(text,"c    : %s:%s:%d:%.2f\r\n",car[i].type,car[i].id,time,rmb);
				HAL_UART_Transmit(&huart1,(uint8_t*)text,strlen(text),50);
				
				strcpy(car[i].type,"0");	
				strcpy(car[i].id,"0");	
				strcpy(car[i].time,"0");	
				car[i].flag = false;
			}
			else//进停车场
			{
				//寻找空位
				int i= 0;
				flag = false;
				for(;i<CAR_NUM;i++)
				{
					if(car[i].flag == false)//表示车位未被占用
					{
						flag = true;
						break;
					}
				}
				if(flag)
				{
					//判断车辆类型
					if(strcmp(car_type,"CNBR")  == 0)
					{
						if(IDLE > 0)
						{
							CNBR += 1;
							IDLE--;
						}
					}
					else if(strcmp(car_type,"VNBR")  == 0)
					{
						if(IDLE > 0)
						{
							VNBR += 1;
							IDLE--;
						}
					}
					
					strcpy(car[i].type,car_type);	
					strcpy(car[i].id,car_id);	
					strcpy(car[i].time,car_time);	
					car[i].flag = true;
				}
			}
		}
		else
		{
			HAL_UART_Transmit(&huart1,(uint8_t*)"Erorr\r\n",strlen("Erorr\r\n"),50);
			HAL_Delay(5);
		}
		pt = 0;
		memset(rx_data,0,sizeof(rx_data));
	}
}


3.5、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_TIM4_Init();
  MX_TIM17_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

	LCD_Init();
	HAL_TIM_Base_Start_IT(&htim4);
	HAL_TIM_PWM_Start(&htim17,TIM_CHANNEL_1);
	__HAL_TIM_SetCompare(&htim17,TIM_CHANNEL_1,0);//默认占空比为0
	HAL_UART_Receive_IT(&huart1,&rx,1);//打开中断
		
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(White);
	LED_Display(0);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	
	//初始化
	for(int i=0;i < CAR_NUM;i++)
	{
		strcpy(car[i].type,"0");	
		strcpy(car[i].id,"0");	
		strcpy(car[i].time,"0");	
		car[i].flag = false;
	}
	
  while (1)
  {
		key_proc();
		show();
		usart_proc();
	  handle_proc();
	
		if(IDLE == 0)
		{
			led = led & (~LED1);
		}
		else
		{
			led = led | LED1;
		}
		LED_Display(led);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

有不对或不恰当的地方,请您批评指正,主打一个听劝;也可以一起讨论讨论,互相学习,共同进步,比心比心。

  • 20
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值