蓝桥杯嵌入式省赛第十届——模版编程,超级简单!

原题展示

考点精练

按键输入、LED、LCD显示、脉冲捕获PWM、ADC、按键长按(红色为难点,橙色为较难)

CubeMax 配置

SYS配置:Serial Wire(串行调试)

RCC配置:内部时钟

时钟配置

按键配置:PC0~PC3设置为GPIO_Input

LED配置:PC8~PC15 GPIO_Ouput

PWM配置:PA1 TIM2_CH2

脉冲捕获:PA7 TIM3_CH2

ADC配置:PB15 ADC_IN15

原题题解

相关变量

#define pi 3.14
//lcd
uint8_t jiemian,lcd_buf[21]; //初始化界面
uint8_t r=1,k=1; //参数初始化
uint8_t i_flag;//标志位
//led
uint8_t led_buf1,led_buf2,led_buf3; //赋值led
uint32_t ledTick=0xffffff,led_flag;//led计时
//key
uint8_t pm[2]={'L','H'},Frq_Mode,n;//按键切换高低频
u32 KeyTick,ModeTick;//按键防抖
uint8_t rk;//R&K数值切换
uint8_t modekey; // 判断是否是首次按下
uint8_t flag_b4;  //长按标志位
uint16_t timer2s; //延时超过两秒;
//pwm
uint8_t pc[2];  //
float v[2],v1[2];
uint8_t b4c;
uint32_t pwm_f=4000 ;//频率值
//adc
uint32_t value;
float volt;
uint8_t lock;
uint32_t AdcTick0=0,AdcTick1=0;
uint32_t tim3_cnt =0,tim3_frq;

ADC模块

void ADC_Proc(void)
{
	HAL_ADC_Start (&hadc2 );  //开启ADC2
	
    value= HAL_ADC_GetValue (&hadc2 );  //获取ADC2的值
	
	volt = value/4096.0f*3.3f;  //转换模拟值
	
	if(b4c == 0&jiemian==0)  //R37调节占空比
	{
		if(volt < 1)  //ADC输出小于1V,保持10%占空比
		{
		  Pwm_Control[Frq_Mode]=10;
		}
		if(volt>=1&volt<=3)  //ADC输出在1~3V内,占空比线性增长
		{
		  Pwm_Control[Frq_Mode]=(volt-1)*37.5f+10;
		}
		if(volt>3)  //ADC输出大于3V,保持85%占空比
		{
		  Pwm_Control[Frq_Mode]=85;
		}
    }
}

PWM模块

void PWM_Proc(void)
{
    if(Frq_Mode==0)  //低频模式
	{
    //调整频率
	__HAL_TIM_SET_AUTORELOAD (&htim2 ,1000000/pwm_f-1);  
    //调节占空比
    __HAL_TIM_SET_COMPARE (&htim2 ,TIM_CHANNEL_2 ,(uint8_t)(250*(Pwm_Control[Frq_Mode]/100.0f))); 
	}
	if(Frq_Mode==1)  //高频模式
	{
    //调整频率
	__HAL_TIM_SET_AUTORELOAD (&htim2 ,1000000/pwm_f -1); 
    //调节占空比
	__HAL_TIM_SET_COMPARE (&htim2 ,TIM_CHANNEL_2 ,(uint8_t)(125*(Pwm_Control[Frq_Mode]/100.0f)));
	}
}

脉冲捕获

void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    //PA7引脚捕获脉冲
	if(htim->Instance ==TIM3 )
	{
       tim3_cnt = HAL_TIM_ReadCapturedValue (htim,TIM_CHANNEL_2); 
       TIM3->CNT=0;
       tim3_frq = 80000000/(80*tim3_cnt);		
	}
    
    if(Frq_Mode==0)
	{  
		v1[0]= tim3_frq *2*pi*r/100.0f/k;
	}
	if(v[0]<v1[0]&&uwTick-AdcTick0 >2000) //统计大于2S赋值
		{
			v[0]=v1[0];
		}
	if(Frq_Mode==1)
	{  
		v1[1]= tim3_frq*2*pi*r/100.0f/k;
	}
	if(v[1]<v1[1]&&uwTick-AdcTick1 >2000) //统计大于2S赋值
		{
			v[1]=v1[1];
		}
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2 );
}


 

LCD模块

1.初始化背景
void LCD_Setting(void)
{
	//设置LCD的背景色
	LCD_Clear(Black);
	//设置LCD字体颜色
	LCD_SetTextColor(White);
	//设置LCD字体的背景色
	LCD_SetBackColor(Black);
}
2.显示功能
void LCD_Proc(void)
{

	if(jiemian == 0) ///数据界面
	{
		LCD_DisplayStringLine (Line1,(u8 *)"        DATA");
		sprintf((char*)lcd_buf ,"     M=%c",pm[i_flag]);
		LCD_DisplayStringLine (Line3,(u8 *)lcd_buf );
		sprintf((char*)lcd_buf ,"     P=%d%%",Pwm_Control[Frq_Mode]);
		LCD_DisplayStringLine (Line4,(u8 *)lcd_buf );
		sprintf((char*)lcd_buf ,"     V=%.1f",v1[Frq_Mode]);
		LCD_DisplayStringLine (Line5,(u8 *)lcd_buf );
		
	}
	if(jiemian == 1)  //参数界面
	{
		LCD_DisplayStringLine (Line1,(u8 *)"        PARA");
		sprintf((char*)lcd_buf ,"     R=%d",r);
		LCD_DisplayStringLine (Line3,(u8 *)lcd_buf );
		sprintf((char*)lcd_buf ,"     K=%d",k);
		LCD_DisplayStringLine (Line4,(u8 *)lcd_buf );
	}
	if(jiemian == 2) //统计界面
	{
		LCD_DisplayStringLine (Line1,(u8 *)"        RECD");
		sprintf((char*)lcd_buf ,"     N=%d",n);
		LCD_DisplayStringLine (Line3,(u8 *)lcd_buf );
		sprintf((char*)lcd_buf ,"     MH=%.1f",v[1]);
		LCD_DisplayStringLine (Line4,(u8 *)lcd_buf );
		sprintf((char*)lcd_buf ,"     ML=%.1f",v[0]);
		LCD_DisplayStringLine (Line5,(u8 *)lcd_buf );
		
	}
}

按键模块

1.Key_Read()子程序
#include "key.h"

#define KB1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define KB2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KB3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define KB4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
#define KEYPORT KB1 | (KB2<<1) | (KB3<<2) | (KB4<<3) | 0xf0  

uint8_t Trg;
uint8_t Cont;

void Key_Read()
{
	uint8_t DataRead = (KEYPORT)^0xff;
	Trg = DataRead & (DataRead ^ Cont);
	Cont = DataRead;
}
2.Key_Proc()函数
void Key_Proc(void)
{
	if(uwTick-KeyTick <10)return;  //按键防抖
	KeyTick = uwTick;
	
    Key_Read ();  //调用KEY_Read子程序
	
    //B4按键控制PWM占空比
	if(Trg&0x08 && Cont == 0x08 && jiemian==0)  //在数据界面下,短按解锁PWM状态
	{
		flag_b4 = 1;
	}
	else if(Trg!=0x08 && Cont == 0x08 && jiemian==0)  //数据界面下,长按锁定PWM状态
	{
		flag_b4 = 2;
	}
	else  //其他情况,状态保持
	{
		flag_b4 = 0;
	}

	//B1按键功能
	if(Trg & 0x01)  
	{
		if(jiemian>1)  //界面切换
			jiemian=0;
		else
			jiemian++;
		
		if(jiemian ==1) //从数据界面进入参数界面默认可调整参数为R
			rk=0;

		LCD_Clear (Black); //界面切换后自动清屏
	}
	
    //B2按键功能
	if(Trg & 0x02)  
	{
		if(jiemian==0)  //切换高低频
		{
		   if(modekey == 1)
		      {
			 
				if(Frq_Mode==0&&uwTick-ModeTick>=5000) //五秒内不能再次按下
				{
					Frq_Mode=1;  //切换高频率
					ModeTick = uwTick;   //重置ModeTick
					n++;  //高低频率切换次数加一
					ledTick=uwTick;    //重置led
					LCD_Clear (Black);  
				}
				else if(Frq_Mode==1&&uwTick-ModeTick>=5000)
				{
					Frq_Mode=0;  //切换低频率
					ModeTick = uwTick;  //重置MoedTick
					n++;  //高低频率切换次数加一
					ledTick=uwTick;   //重置LedTick
					LCD_Clear (Black);
				}
		    }

		    if(modekey==0) //首次切换
	        {   
				Frq_Mode=1;
				modekey = 1;
				ModeTick = uwTick;
				n=1;
				ledTick=uwTick; 
				LCD_Clear (Black);
			}
			led2_flag =1;
		}
		
	   if(jiemian==1) //切换R&K调整参数
	   {
			
			if(rk==0)
			{
				rk=1;  //K可调
				
			}
			else
				rk=0;  //R可调
		}
	}
    
    //B3按键功能
	if(Trg & 0x04) 
	{
		if(jiemian ==1)  //参数界面下R&K加一
		{
		if(rk==0)
		{
			if(r<10)
				r++;
			else  //循环置为1,清屏一次
			{
				r=1;
				LCD_Clear (Black);
			}
			AdcTick0 =uwTick;
			AdcTick1 =uwTick;
		}
		if(rk==1)
		{
			if(k<10)
				k++;
			else  //循环置为1,清屏一次
			{
				k=1;
				LCD_Clear (Black);
			}
			AdcTick1 =uwTick;
			AdcTick0 =uwTick;
		}
	   }
	}

    //B4按键功能
	if(Trg & 0x08)  
	{
		if(jiemian == 1) //参数界面下R&K减一
		{
		  if(rk==0)
			{
			  if(r>1&&r<10)
			  {
				  r--; 
			  }
			  else if(r==10) //R减为9,清屏一次
			  {
				  r--;
				  LCD_Clear (Black);
			  }
			  else  //循环置为10
			  {  
				  r=10;
			  }
			  AdcTick0 =uwTick;
			  AdcTick1 =uwTick;
			}
		  if(rk==1)
			{
			if(k>1&&k<10)
			{
		     	k--;
			}
			else if(k==10)  //K减为9,清屏一次
			{
				k--;
				LCD_Clear (Black);
			}
			else  //循环置为10
			{
				k=10;
			}
			AdcTick1 =uwTick;
			AdcTick0 =uwTick;
			}
		}
	}
}

LED模块

1.Led_Read子程序
#include "led.h"

void Led_Read(uint8_t led_control1)
{
	HAL_GPIO_WritePin(GPIOC,0xffff,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOC,led_control1<<8,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
void Led_Read2(uint8_t led_control2)
{
	HAL_GPIO_WritePin(GPIOC,led_control2<<8,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
void Led_Read3(uint8_t led_control3)
{
	HAL_GPIO_WritePin(GPIOC,led_control3<<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.Led_Proc函数
void Led_Proc()
{	
    //DATA界面,长亮LD1
	if(jiemian==0)  
	{
		led_buf1 =0x01;
	}
	else            //熄灭LD1
		led_buf1 &=~0x01;
	
    //高低频率切换5秒内,LD2间隔0.1秒闪烁
	if(n>0&&uwTick-ModeTick<=5000) 
	{
		if(uwTick-ledTick <=100)  //点亮
		{
			led_buf2 = 0x02;
		}
		if(uwTick-ledTick2>100&&uwTick-ledTick<=200)  //熄灭
		{
			led_buf2 &=~ 0x02;
			
		}
		if(uwTick-ledTick>200)  //重置ledTick
		{
			ledTick=uwTick;
		}
	}
	else   //5秒后关闭LD2
		led_buf2 &=~0x02;  
	
    //PWM锁住,常亮LD3
	if(b4c==1)  
	{
		led_buf3 = 0x04;
	}
	else
	{
		led_buf3 &=~0x04;
	}
		
	Led_Read(led_buf1);
	Led_Read2(led_buf2 );
	Led_Read3 (led_buf3 );
	
}

计时设计

void Timer_Proc()
{
    //计时数据界面下,按下B4
	if(flag_b4 ==2)
	{
        timer2s+=50;
		if(timer2s >2000&jiemian==0) //数据界面,长按2s锁定PWM占空比状态
		{
			if(lock==0)
			lock=1;
			b4c=1;
		}
		else  
		{
			if (jiemian == 0 & lock==1)  //数据界面,短按解锁PWM占空比状态
			{ 
				lock=0;
			    b4c=0;
			}
		}
	}
	else if(flag_b4 == 0)  
	{ 
		timer2s = 0;   //置位timer2s
	}
	
    //PWM高低频率切换
	if(n%2==0)  
	{
		if(pwm_f >4000) //5秒内PWM输出频率均匀增加
		{
		  pwm_f -=16;
		  AdcTick0 =uwTick;
		  AdcTick1 =uwTick;
		}
	}
	else
	{
		if(pwm_f <8000) //5秒内PWM输出频率均匀降低
		{ 
		  pwm_f+=16;
		  AdcTick1 =uwTick;
		  AdcTick0 =uwTick;
		}
	}
	if(pwm_f ==8000)
			i_flag = 1;
	if(pwm_f==4000)
			i_flag=0;
     
	 TIM2->ARR=1E6/pwm_f-1;   //捕获脉冲频率
     TIM2->CCR2 = (TIM2->ARR+1)*pc[i]/100;  //捕获脉冲占空比
}

主函数

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_ADC2_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  /* USER CODE BEGIN 2 */
	
	LCD_Init();
	LCD_Setting();
    //设置自动重载值
    TIM2->ARR=245;
    //设置定时器比较值
    TIM2->CCR2=125; 	
    //启动TIM2里的PWM
	HAL_TIM_PWM_Start (&htim2 ,TIM_CHANNEL_2 );
    //启动TIM3里的脉冲捕获	
	HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_2 );
    //初次上电
	modekey=0;
	//初始AdcTick0和AdcTick1
	AdcTick0 =uwTick;
	AdcTick1 = uwTick;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	
  while (1)
  {
    /* USER CODE END WHILE */
      LCD_Proc();
	  ADC_Proc();
	  Key_Proc();
	  Timer_Proc();
	  Led_Proc();
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

总结

       蓝桥杯第十四届题目相对较难,考点之间的联系比较紧密。脉冲捕获和按键长按是比较新的考点,很容易让人摸不同头脑,但最重要的还是有扎实的基础和清晰的逻辑。   

   好了,以上就是蓝桥杯嵌入式第十四届省赛的编程题目解析,如果有什么问题和建议都欢迎在评论区提出来喔。

### 蓝桥杯嵌入式模板与示例代码 在蓝桥杯嵌入式中,构建一个高效的工程模板对于快速解决问题至关重要。以下是一个基于STM32 HAL库的UART通信模板示例[^1]: #### UART串口初始化模板 此模板展示了如何使用HAL库完成基本的UART配置。 ```c #include "stm32f4xx_hal.h" UART_HandleTypeDef huart2; void MX_USART2_UART_Init(void) { huart2.Instance = USART2; huart2.Init.BaudRate = 9600; // 波特率设置为9600 huart2.Init.WordLength = UART_WORDLENGTH_8B; // 数据位长度为8位 huart2.Init.StopBits = UART_STOPBITS_1; // 停止位为1 huart2.Init.Parity = UART_PARITY_NONE; // 无校验 huart2.Init.Mode = UART_MODE_TX_RX; // 发送接收模式 huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; // 关闭硬件流控 huart2.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart2) != HAL_OK) { // 初始化USART2 Error_Handler(); // 错误处理函数 } } // 发送字符串函数 void SendString(const char *str) { while (*str) { HAL_UART_Transmit(&huart2, (uint8_t *)str, strlen(str), HAL_MAX_DELAY); str++; } } ``` 上述代码片段实现了UART外设的基本初始化,并提供了发送字符串的功能。这可以作为解决涉及串口通信问题的基础框架。 --- #### BSP驱动层设计 为了提高程序可维护性和扩展性,通常会在项目中引入BSP(Board Support Package)架构。以下是创建BSP文件夹并将其集成到Keil工程的具体操作步骤[^4]: 1. **新建文件夹**:在工程根目录下创建名为`bsp`的文件夹。 2. **添加组至Keil工程**:右键点击Keil工程窗口中的“Groups”,选择“Add Group...”,命名为`bsp`。 3. **配置头文件路径**:进入“Options for Target -> C/C++”页面,在“Includes”字段加入`\bsp\`. 通过这种方式分离底层硬件接口逻辑和上层应用业务逻辑,有助于团队协作开发以及后期功能迭代升级。 --- #### 输入输出标准化实践 根据蓝桥杯评分准则[^3],参者需严格按照题目指定的数据格式读取输入参数并通过标准输出返回计算结果。下面是一段用于验证用户按键状态变化的小例子[^5]: ```c #include "main.h" #include "gpio.h" #define DELAY_TIME_MS 500 int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); uint8_t prev_state = GPIO_PIN_RESET; while (1) { uint8_t current_state = HAL_GPIO_ReadPin(USER_BUTTON_GPIO_Port, USER_BUTTON_Pin); if ((current_state == GPIO_PIN_SET) && (prev_state == GPIO_PIN_RESET)) { printf("Button Pressed\n"); } prev_state = current_state; HAL_Delay(DELAY_TIME_MS); // 防抖动延迟时间设定 } } ``` 该实例演示了检测按钮按下事件的过程,同时利用printf语句模拟向控制台打印消息的行为。实际比中可能需要替换为特定设备上的显示组件更新动作。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值