蓝桥杯嵌入式开发经验分享(第九届省赛——“电子定时器”)

作者:马一飞                                                         QQ:791729359       

在学习过程中有什么问题可以联系

 

这套题也是我当你省赛时候做的题,也是通过这套题进入拿到省一进入国赛。总体来说,这套题是比较简单的,尤其是在配置上基本没涉及一些比较难的模块,考的方向偏向逻辑,大部分人都在长短按键处被卡死,这套题也是蓝桥杯第一次考长短按键;并且我去参加国赛的时候以为省赛考过长短按键国赛应该就不会再考了,想不到国赛又考了一次长短按键,也算是蓝桥杯对于赛题的一个创新吧。

一、题目

                                              “电子定时器”的程序设计与调试 

基本要求

        1.1 使用 CT117E 嵌入式竞赛板,完成试题功能的程序设计与调试;
        1.2 设计与调试过程中,可参考组委会提供的“资源数据包”;
        1.3 Keil 工程文件以准考证号命名,完成设计后,提交完整、可编译的 Keil工程文件到服务器。

 硬件框图

        通过按键设置定时时间,启动定时器后,开始倒计时;计时过程中,可以暂停、取消定时器。在定时时间内,按要求输出 PWM 信号和控制 LED 指示灯。系统框图如图 1 所示:

                                     

 功能描述

1、LCD 显示

        LCD 显示存储位置、定时时间和当前状态。系统预留 5 个存储位置用于存储常用的定时时间。当定时器停止时,当前状态为 Standby;当系统正在设置时间时,当前状态为 Setting;当定时器运行时,当前状态为 Running,定时器暂停时,当前状态为 Pause。

                                                                        

2、按键功能

        系统使用 4 个按键,B1、B2、B3 和 B4。

        按键 B1 为存储位置切换键。每按一次,存储位置依次以 1、2、3、4、5循环切换,切换后定时时间设定为当前位置存储的时间。

        按键 B2 为时间位置(时、分、秒)切换键和存储键。短按 B2 键进入时间设置状态。每次短按 B2 键,设置位置以时、分、秒循环切换,并突出显示(高亮)当前位置;设置完后,长按 B2 键(超过 0.8 秒)把设置的时间存储到当前的存储位置,并推出设置状态。如果是临时设置定时时间,则不需存储,直接按定时器启动按键。

        按键 B3 为时、分、秒(按键 B2 确定当前位置)数字增加键。每短按B3 一次,数字递增一次;按住 B3 超过 0.8 秒,则数字快速递增,直到松开B3 按键。数字递增时,超出范围则从头循环。

        按键 B4 为定时器启动键。短按 B4,定时器启动,开始运行;运行期间短按 B4,暂停定时器,再短按 B4,恢复定时器运行;长按 B4(超过 0.8 秒),则取消定时器运行,回到 Standby 状态。

3、PWM 输出和 LED 显示

        定时器运行时,PA6 口输出 PWM 信号,同时 LED 灯(LD1)以 0.5 秒的频率闪烁。PWM 信号频率为 1KHz,占空比为 80%。

        定时器停止或暂停时,停止输入 PWM 信号,LED 灯灭。

4、定时时间存储

        设定好的定时时间存储在 EEPROM 中。

        掉电重启后,显示存储位置 1 的定时时间。
 

二、模块化代码分析

建议在做这题的时候,在变量的使用上多写点注释,负责自己也会弄混乱。因为这道题目注重于在逻辑上的处理,而不在于模块的配置。

1、初始化部分

本题目需要使用到AT24C02,那么在最开始应该做一个iic的初始化工作;同时初始化LED、按键、定时器3;这里我的定时器3用的是输出比较的方式来产生pwm的,也建议大家多练习一下输出比较的方式。本题目用PWM模式也是ok的。同时还得读取存在24c02中5个定时时间值。 由于AT24C02的一个地址只能存入0-255的数,因此我们在储存的时候要把时间拆分成时、分、秒进行储存,同时读的时候也一样,按照时、分、秒分别读取,然后再进行合并。

STM3210B_LCD_Init();
LCD_Clear(Blue);
LCD_SetBackColor(Blue);
LCD_SetTextColor(White);
	
SysTick_Config(SystemCoreClock/1000);
i2c_init();
LED_Init();
KEY_Init();
TIM3_PWM_OUTPUT(1000,80,1,0);
Timer[0] = _24c02_Read(0x00) * 3600 + _24c02_Read(0x01) * 60 + _24c02_Read(0x02);
Delay_Ms(10);
Timer[1] = _24c02_Read(0x10) * 3600 + _24c02_Read(0x11) * 60 + _24c02_Read(0x12);
Delay_Ms(10);
Timer[2] = _24c02_Read(0x20) * 3600 + _24c02_Read(0x21) * 60 + _24c02_Read(0x22);
Delay_Ms(10);
Timer[3] = _24c02_Read(0x30) * 3600 + _24c02_Read(0x31) * 60 + _24c02_Read(0x32);
Delay_Ms(10);
Timer[4] = _24c02_Read(0x40) * 3600 + _24c02_Read(0x41) * 60 + _24c02_Read(0x42);
Delay_Ms(10);

2、按键处理部分

          每50ms扫描一次按键判断按键是否有操作,同时也需要根据题目的需求设定各个按键所对应的功能。

if(KEY_Flag)
{
	KEY_Flag = 0;
	KEY_Read();
}
void KEY_Read(void)
{
	static u16 key1_sum = 0,key2_sum = 0,key3_sum = 0,key4_sum = 0;
	// KEY1  
	if(KEY1 == 0)
	{
		key1_sum++;
		if(key1_sum == 1) // 单次触发
		{
			if(system_mode == 0 || system_mode == 1)//在stanby模式和setting模式下进行通道的切换
			{
				Channel_num++;
				if(Channel_num > 4) Channel_num = 0; //一共5个通道
			}
		}
	}else
	{
		key1_sum = 0;
	}
	// KEY2  
	if(KEY2 == 0)
	{
		key2_sum++;
		if(key2_sum == 1) //  短按
		{
			if(system_mode == 0) //在stanby模式下单次按下进入setting模式
			{
				system_mode = 1;  //进入 Setting
				Timer_Buf = Timer[Channel_num];//把当前相应的定时值读取到缓冲区
				LCD_ClearLine(Line0); //清屏操作
				LCD_ClearLine(Line1);
				LCD_ClearLine(Line2);
				LCD_ClearLine(Line3);
				LCD_ClearLine(Line4);
				LCD_ClearLine(Line5);
				LCD_ClearLine(Line6);
				LCD_ClearLine(Line7);
				LCD_ClearLine(Line8);
				LCD_ClearLine(Line9);
			}
			if(system_mode == 1)//如果当前模式是在setting模式下那么就进行切换时、分、秒的操作
			{
				Set_Select++; // 2、1、0 对应时、分、秒
				if(Set_Select > 2) Set_Select = 0;
			}
		}
		if(key2_sum == 16) // 800ms 长按触发
		{
			if(system_mode == 1) //在setting模式下长按代表保存数据
			{
				system_mode = 0;//模式切换回stanby
				Timer[Channel_num] = Timer_Buf; //保存当前设置的定时值
				switch(Channel_num) //根据通道情况保存当前时、分、秒数据到AT24C02响应的位置
				{
					case 0: _24c02_Write(0x00,hour);
							Delay_Ms(10);
							_24c02_Write(0x01,min);
							Delay_Ms(10);
							_24c02_Write(0x02,sec);
							break;
					case 1:	_24c02_Write(0x10,hour);
							Delay_Ms(10);
							_24c02_Write(0x11,min);
							Delay_Ms(10);
							_24c02_Write(0x12,sec);
							break;
					case 2:	_24c02_Write(0x20,hour);
							Delay_Ms(10);
							_24c02_Write(0x21,min);
							Delay_Ms(10);
							_24c02_Write(0x22,sec);
							break;
					case 3:	_24c02_Write(0x30,hour);
					        Delay_Ms(10);
							_24c02_Write(0x31,min);
							Delay_Ms(10);
			     			_24c02_Write(0x32,sec);
							break;
					case 4:	_24c02_Write(0x40,hour);
							Delay_Ms(10);
							_24c02_Write(0x41,min);
							Delay_Ms(10);
						    _24c02_Write(0x42,sec);
							break;
				}
				LCD_ClearLine(Line0);//清屏
				LCD_ClearLine(Line1);
				LCD_ClearLine(Line2);
				LCD_ClearLine(Line3);
				LCD_ClearLine(Line4);
				LCD_ClearLine(Line5);
				LCD_ClearLine(Line6);
				LCD_ClearLine(Line7);
				LCD_ClearLine(Line8);
				LCD_ClearLine(Line9);
			}
		}
		}else
		{
			key2_sum = 0;
		}
		// KEY3 
		if(KEY3 == 0)
		{
			key3_sum++;
			if(key3_sum == 1) // 短按
			{
				if(system_mode == 1) // Setting模式
				{
					switch(Set_Select) //判断当前操作的位置
					{
						case 0: sec++;
								if(sec > 59) sec = 0;
								break;
						case 1: min++;
								if(min > 59) min = 0;
								break;
						case 2: hour++;
								if(hour > 23) hour = 0;
								break;
					}
					Timer_Buf = hour * 3600 + min * 60 + sec; //计算完成还把时分秒还原回总的秒数存到缓冲区中
				}
			}
				
			if(key3_sum == 16) // 长按 快速增加
			{
				if(system_mode == 1) // Setting 模式
				{
					switch(Set_Select)
					{
						case 0: sec++;
								if(sec > 59) sec = 0;
								break;
						case 1: min++;
								if(min > 59) min = 0;
								break;
						case 2: hour++;
								if(hour > 23) hour = 0;
								break;
					}
					Timer_Buf = hour * 3600 + min * 60 + sec;
					key3_sum = 15;
				}
			}
		}else
		{
			key3_sum = 0;
		}
		// KEY4 
		if(KEY4 == 0)
		{
			key4_sum++;
			if(key4_sum == 1) //短按  
			{
				if(system_mode == 0)  //在stanby模式下短按定时器启动
				{
					DingShi = Timer[Channel_num]; //获取定时值进行定时
				}else
				if(system_mode == 1)  //在setting模式下则从缓冲区获取定时值
				{
					DingShi = hour * 3600 + min * 60 + sec;
				}
				system_mode = 2; // 进入Running,pause  模式
				if(system_mode == 2)  //判断当前是running还是pause模式
				{
					switch(Run_Stop)
					{
						case 0: Run_Stop = 1;break;
						case 1: Run_Stop = 0;break;
					}
				}
			}
				
			if(key4_sum == 16)  //长按触发  
			{
				system_mode = 0; //返回stanby模式
				DingShi = 0;  //清除定时
			    Run_Stop = 0;  //回到pause模式
			}
		}else
		{
			key4_sum = 0;
		}
		
}

3、显示部分

       显示部分还是直接看代码吧,在代码里特意添加了比较多的注释辅助网友们理解。

 

if(Display_Flag)
{
	Display_Flag = 0;//清除标志位
	if(system_mode == 0)  // Stanby 模式
	{
		sprintf((char*)string," NO:%d            ",Channel_num + 1);
		LCD_DisplayStringLine(Line1,string);//LCD显示数据
		hour = Timer[Channel_num] / 3600;  //时
		min  = Timer[Channel_num] % 3600 / 60; //分
		sec  = Timer[Channel_num] % 3600 % 60;  //秒
		sprintf((char*)string,"      %.2d:%.2d:%.2d     ",hour,min,sec);
		LCD_DisplayStringLine(Line4,string); //显示时间信息
		LCD_DisplayStringLine(Line7,(u8*)"      Standby   ");
	}
	if(system_mode == 1)  // Setting模式
	{
		sprintf((char*)string," NO:%d            ",Channel_num + 1); //显示通道
		LCD_DisplayStringLine(Line1,string); //
		if(Set_Select == 2) //显示颜色  如果被选中则显示红色  未选中显示蓝色
		{
			LCD_SetTextColor(Red);
		}else
		{
			LCD_SetTextColor(White);
		}
		LCD_DisplayChar(Line4,210, hour / 10 + 0x30); //由于只能修改一行中某个数字的颜色,不能使用行显示 ;数字显示要转换成ascii码
		LCD_DisplayChar(Line4,195, hour % 10 + 0x30);  //同上  下面的显示操作也一样
		LCD_SetTextColor(White);
		LCD_DisplayChar(Line4,180, ':');
		if(Set_Select == 1) //同上
		{
			LCD_SetTextColor(Red);
		}else
		{
			LCD_SetTextColor(White);
		}
		LCD_DisplayChar(Line4,165, min / 10 + 0x30);
		LCD_DisplayChar(Line4,150, min % 10 + 0x30);
		LCD_SetTextColor(White);
		LCD_DisplayChar(Line4,135, ':');
		if(Set_Select == 0)//同上
		{
			LCD_SetTextColor(Red);
		}else
		{
			LCD_SetTextColor(White);
		}
    	LCD_DisplayChar(Line4,120, sec / 10 + 0x30);
		LCD_DisplayChar(Line4,105, sec % 10 + 0x30);
		LCD_SetTextColor(White);
												
		LCD_DisplayStringLine(Line7,(u8*)"      Setting   ");
	}
	if(system_mode == 2)  // running和pause模式
	{
		sprintf((char*)string," NO:%d            ",Channel_num + 1);
		LCD_DisplayStringLine(Line1,string);
		hour = Timer[Channel_num] / 3600;  //获取当前计数值 时 、分 、秒
		min  = Timer[Channel_num] % 3600 / 60;
		sec  = Timer[Channel_num] % 3600 % 60;
		sprintf((char*)string,"      %.2d:%.2d:%.2d     ",hour,min,sec); //显示时间值
		LCD_DisplayStringLine(Line4,string);
		if(Run_Stop)
		{
			LCD_DisplayStringLine(Line7,(u8*)"      Running   "); //当前处于running模式,继续计时
		}else
		{
			LCD_DisplayStringLine(Line7,(u8*)"      Pause     "); //当前处于pause模式,暂停计时
		}
	}
}

4、定时部分 

        在对于这套题的话,我专门设置了一个定时的部分,同时定时的话1s扫描一次,判断当前是否有定时时间,如果有则输出PWM波,如果没有则关闭输出。1s的定时效果右滴答定时器进行计算,不需要专门开一个RTC这么繁琐。 检测到DingShi变量有值,那么就代表获取到了定时的时间,PWM就会开始输出。

if(_1s_Flag) //每秒进入一次
{
	_1s_Flag = 0;  // 清除标志位
	if(system_mode == 2)  //当前在running和pause模式下
	{ 
		if(Run_Stop)  //为真当前的状态是running
		{
			if(DingShi)  //有定时值
			{
				DingShi--;  //定时值每秒-1
			}
		    if(DingShi != 0) // 有定时值 
			{
				TIM3_PWM_OUTPUT(1000,80,0,1); //输出pwm
			}else
		    {
				system_mode = 0;  //  无定时值或者已经计数完毕  则回到stanby模式
				Run_Stop = 0;  
				TIM3_PWM_OUTPUT(1000,80,0,0); //停止输出pwm
			}
		}else
		{
			TIM3_PWM_OUTPUT(1000,80,0,0);  // 如果当前状态不是在running态,也停止输出pwm
		}
	}
}

5、LED部分

        LED部分就比较简单了,只需要判断当前有没有输出PWM就ok了

if(LED_Flag)
{
	LED_Flag = 0;
	if(system_mode == 2 && Run_Stop == 1)
	{
		LED_MODE ^= (1<<8);
	}else
	{
		LED_MODE |= (1<<8);
	}
	GPIOC->ODR = LED_MODE;
	GPIOD->ODR |= (1<<2);
	GPIOD->ODR &=~(1<<2);
}

6、滴答定时器计时以及中断部分

        基本上相差不大

extern u8 KEY_Flag;
extern u8 Display_Flag ;
extern u16 TIM3_CH1_Val;
extern u16 TIM3_CH1_Duty;
u8 TIM3_CH1_Flag;
extern u8 _1s_Flag;
extern u8 LED_Flag;
void SysTick_Handler(void)
{
	static u8 key_sum = 0;
	static u8 display_sum = 0;
	static u16 _1s_sum = 0;
	static u16 led_sum = 0;
	TimingDelay--;
	if(++led_sum == 500)
	{
		led_sum = 0;
		LED_Flag = 1;
	}
	if(++_1s_sum == 1000)
	{
		_1s_sum = 0;
		_1s_Flag = 1;
	}
	if(++key_sum == 50) // 50ms
	{
		key_sum = 0;
		KEY_Flag = 1;
	}
	if(++display_sum == 100) 
	{
		display_sum = 0;
		Display_Flag = 1;
	}
}

void TIM3_IRQHandler(void)
{
	u16 capture;
	if(TIM_GetITStatus(TIM3,TIM_IT_CC1) == 1)
	{
		TIM_ClearITPendingBit(TIM3,TIM_IT_CC1);
		capture = TIM_GetCapture1(TIM3);
		if(TIM3_CH1_Flag)
		{
			TIM_SetCompare1(TIM3,capture + TIM3_CH1_Duty);
		}else
		{
			TIM_SetCompare1(TIM3,capture + TIM3_CH1_Val - TIM3_CH1_Duty);
		}	
		TIM3_CH1_Flag ^= 1;
	}
}

三、通用初始化部分

#include "io.h"
#include "i2c.h"
#include "lcd.h"

extern void Delay_Ms(u32 nTime);
u16 LED_MODE = 0xffff;
u16 TIM3_CH1_Val;
u16 TIM3_CH1_Duty;
extern u8 system_mode;   // 系统当前状态  0:Stanby  1:Setting  2:running¡¢pause
extern u8 Channel_num;   // 储存位置选择  0 ~ 4
u8 Set_Select = 0;    // 选择设置的时间   时  分  秒
extern u32 Timer[5];  // 定时存储区域
u32 Timer_Buf;   //  修改缓冲区
extern u8 hour; //显示分解:时
extern u8 min ; //显示分解:分
extern u8 sec ; //显示分解:秒
u8 Run_Stop = 0;  //1:运行   0:停止
extern u32 DingShi; //定时

  24C02   //
void _24c02_Write(u8 address,u8 data)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(address);
	I2CWaitAck();
	I2CSendByte(data);
	I2CWaitAck();
	I2CStop();
}
u8 _24c02_Read(u8 address)
{
	u8 temp;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(address);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	temp = I2CReceiveByte();
	I2CWaitAck();
	I2CStop();
	return temp;
}


   LED   ///
void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOD, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = 0xff00;
	GPIO_Init(GPIOC, &GPIO_InitStructure);
		
	GPIOC->ODR = LED_MODE;
	GPIOD->ODR |= (1<<2);
	GPIOD->ODR &=~(1<<2);
}

   PWM_OUTPUT   ///
void TIM3_PWM_OUTPUT(u16 Frequency,u8 duty,u8 status,u8 enable)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	if(status)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
			
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &GPIO_InitStructure);
			
		NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
		NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
		NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStructure);
			
		TIM_TimeBaseInitStructure.TIM_Period = 0xffff;
		TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
		TIM_TimeBaseInitStructure.TIM_CounterMode = 0x0;
		TIM_TimeBaseInitStructure.TIM_ClockDivision = 0x0;
		TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	}
	TIM3_CH1_Val = 1000000 / Frequency;
	TIM3_CH1_Duty = TIM3_CH1_Val * duty / 100;
		
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
	if(enable)
	{
				TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	}else
	{
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
	}
	TIM_OCInitStructure.TIM_Pulse = TIM3_CH1_Val;
	TIM_OC1Init(TIM3, &TIM_OCInitStructure);
		
	//TIM_SetCounter(TIM3, 0x0);
	//TIM_SetCompare1(TIM3,0x0);
	if(status)
	{
		TIM_Cmd(TIM3, ENABLE);
		TIM_ITConfig( TIM3, TIM_IT_CC1,ENABLE);
	}
}

///   KEY   
void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

 

### 回答1: 蓝桥杯是全国性的计算机大赛,旨在提高大学生的计算机技术水平和创新能力。嵌入式STM32G431是一款嵌入式芯片,具有高性能和低功耗的特点。第十二届第一场省赛停车计费系统是蓝桥杯的一道工程题目,要求参赛选手设计一个停车场计费系统。 停车计费系统是指通过嵌入式技术实现对车辆进入和离开停车场的自动检测、计时和计费的系统。对于这个题目,参赛选手可以根据题目要求,使用STM32G431芯片设计一个具有以下功能的系统: 1. 车辆进入检测:使用车辆传感器检测车辆的进入,触发计时。 2. 车辆离开检测:使用车辆传感器检测车辆的离开,停止计时。 3. 计时功能:使用内部时钟模块获取进入和离开的时间,并计算停车时间。 4. 计费功能:根据停车时间,按照一定的计费规则进行计费。 5. 显示功能:使用液晶显示屏显示当前的停车信息,如车牌号、停车时间、费用等。 6. 数据存储功能:使用闪存等储存介质将停车数据进行存储,以便后续的数据分析和查询。 设计一个停车计费系统涉及到硬件设计和软件编程两个方面。硬件方面,参赛选手需要选择合适的传感器、显示屏、存储介质等,以及设计电路和接口进行连接。软件方面,需要使用C语言或者汇编语言编写程序,对芯片进行编程,实现各项功能。 通过此次比赛,选手们可以锻炼嵌入式系统的设计能力和编程能力,了解实际应用中嵌入式系统的工作原理和应用场景。同时,也能提升对STM32G431芯片的理解和运用能力。这对于培养嵌入式技术人才,推动物联网技术的发展都具有积极意义。 ### 回答2: 蓝桥杯是面向计算机爱好者的智力竞赛,而嵌入式STM32G431是一款嵌入式系统开发板。第十二届第一场省赛的停车计费系统真题工程,则是要求参赛选手设计并实现一个能够进行停车计费的系统。 停车计费系统是一种用于自动计费和管理停车场的系统。这个系统可以通过识别车辆的进出以及停车的时间,自动计算并收费。在这个工程中,选手需要使用嵌入式STM32G431开发板以及相关的硬件和软件,来设计一个能够实现停车计费功能的系统。 首先,选手需要使用传感器或摄像头来实现车辆进出的检测。当车辆进入或离开停车场时,传感器会发出信号并通过STM32G431进行检测。接着,选手需要编程实现识别车辆的算法,以便能够识别不同的车辆。当车辆停放时,系统会通过计时器记录停车的时间。 然后,选手需要编写计费算法,根据停车的时间来计算费用。这个算法可以根据停车场的规则来确定费用的计算方式,例如按小时计费或按照不同的时间段采用不同的费率。 最后,选手还需要设计一个界面,使得系统能够与用户进行交互。用户可以通过该界面查询停车费用,并进行付款。同时,选手还需要保证系统的稳定性和安全性,确保数据的准确性和保密性。 总而言之,蓝桥杯嵌入式STM32G431第十二届第一场省赛停车计费系统真题工程要求选手使用硬件和软件开发能力,设计并实现一个完整的停车计费系统。这需要选手具备嵌入式系统开发、传感器技术、算法设计和界面设计等多方面的知识和技能。 ### 回答3: 蓝桥杯嵌入式stm32g431——第十二届第一场省赛停车计费系统真题工程是一个基于STM32G431开发板的停车计费系统设计题目。该系统的主要功能是实现停车场的车辆进入、出场的计费管理。 首先,该系统需要实现一个车辆进入检测的功能。当车辆进入停车场时,系统会通过传感器检测到车辆的到达,并记录下进入的时间。 然后,系统需要实现一个车辆出场的功能。当车辆准备离开停车场时,系统会通过传感器检测到车辆的离开,并记录下离开的时间。 接下来,系统需要计算车辆停留的时间。通过进入时间和离开时间的差值计算得出车辆停留的时长。 最后,系统需要计算停车费用。根据停车场的计费规则,根据车辆停留的时长计算出停车费用,并将费用显示在屏幕上。 在实现上述功能的过程中,需要运用STM32G431开发板的各种功能和模块,包括GPIO口、定时器、中断、串口通信等。通过编写相应的代码,实现按钮的控制、传感器检测、时间的计算以及屏幕的显示等功能。 该项目的设计需要考虑多种情况,比如车辆重复进入出场、车辆进入出场顺序错乱等,要充分考虑这些异常情况并进行相应的处理。在代码编写过程中,还需注意代码的优化和资源的合理利用,以提高系统的性能和效率。 通过完成这个项目的设计与实现,可以加深对STM32G431嵌入式系统的了解和应用,并提升嵌入式系统开发的能力。同时,也能锻炼自己的逻辑思维、问题解决能力和团队合作精神。
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fei...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值