蓝桥杯嵌入式赛题思路总结(自用)持续更新

ADC相关

如何读取ADC电压的上升沿和下降沿

如图:

思路:

定义两个变量volt_prev 和 volt_now,一个读取当前电压值,另一个保存上一次的电压值并设定一个参考电压volt_refer。

( volt_prev > volt_refer ) && ( volt_now < volt_refer )  电压下降沿

 ( volt_prev < volt_refer ) && ( volt_now > volt_refer )  电压上升沿

代码部分(选自11届第1套)

1.

/* ADC */
u16 adc_val;
float volt_r37_prev;
void ADC_Process()
{
    HAL_ADC_Start(&hadc2);
    adc_val = HAL_ADC_GetValue(&hadc2);
    volt_r37_prev = volt_r37;//保存上一个时刻的电压
    volt_r37  = adc_val/4095.0f*3.30f;//获取当前电压值
}

2.

if( (volt_r37_prev <= volt_min_val) && volt_r37 > volt_min_val)//判断为电压上升沿
{
        
}
    

if(volt_r37_prev >= volt_min_val && volt_r37 < volt_max_val)//判断为电压下降沿
{


}
        

LCD显示的高亮选中

如图,我们要在界面实现选中高亮。

程序思路

定义一个高亮索引,select_index。通过按键增减select_index的值,控制高亮的行。

LCD_SetBackColor(Green);//高亮使用的颜色
LCD_DisplayStringLine(Line4,display_buf);
LCD_SetBackColor(White);//最终的背景色

代码部分

sprintf((char*)display_buf,"        Seting          ");
        LCD_DisplayStringLine(Line1,display_buf);
        
        //选中上限电压 高亮显示
        sprintf((char*)display_buf,"   Max Volt:%.1fV       ",max_volt);
        if(select_index == 1)
        {
            LCD_SetBackColor(Green);
            LCD_DisplayStringLine(Line2,display_buf);
            LCD_SetBackColor(White);
        }
        else//正常显示
        {
            LCD_DisplayStringLine(Line2,display_buf);
        }
        
        //选中下限电压 高亮显示
        sprintf((char*)display_buf,"   Min Volt:%.1fV       ",min_volt);
        if(select_index == 2)
        {
            LCD_SetBackColor(Green);
            LCD_DisplayStringLine(Line4,display_buf);
            LCD_SetBackColor(White);
        }
        else//正常显示
        {
            LCD_DisplayStringLine(Line4,display_buf);
        }

设计编程细节

修改参数后的生效时间

  • 修改后的参数是在从参数设置界面切换到数据显示界面后生效
  • 修改后的参数即时生效(比上面的代码要复杂很多)

参数电压的显示

参数的电压变量推荐用u8类型表示,显示的时候再进行类型转换。这样的设置会方便后续的编程。如果有参数进行比较,float的精度过多容易影响判断。

如果电压参数要保存在EEPROM中,那么更加推荐电压参数设置为u8,因为EEPROM函数默认保存u8类型的数据。

LED进阶

LED闪烁指定时间闪烁

(1)让LED以0.5S(500ms)为间隔闪烁

程序思路:让LED_Process()每100ms执行一次。500ms亮,100ms灭

//LED
u8 led_ctrl = 0x00;
u32 ledTick = 0;
u16 cnt_led = 0;
void LED_Process()
{
  if(uwTick - ledTick < 100) return;//每100ms执行一次led功能
  ledTick = uwTick;
  

/*  //亮灭时间不同时的解决办法:
  //以下程序举例为亮500ms,灭100ms  
  if(volt_r37 > 1.0f)
  {
    cnt_led = (cnt_led + 1)%6;//cnt_led范围为0-5
    if(cnt_led <= 4)//500ms亮
      led_ctrl |= 0x02;
    else if(cnt_led <= 5)//100ms灭
      led_ctrl &= ~0x02;
  }
  else
    led_ctrl &= ~0x02; 
*/ 
 
  LED_Control(led_ctrl);
}

LED指定时间后熄灭

例:confirm_5s_flag = 1后,LED1亮5S后熄灭。

u16 led_cnt1 = 0;
//1ms中断函数
void SysTick_Handler(void)
{
  
  HAL_IncTick();
  if(confirm_5s_flag == 1)
  {
      led_cnt1++;
      if(led_cnt1 == 5000)
      {
          led_cnt1 = 0;
          confirm_5s_flag = 0;
      }
  }
 
  
}

* LED */
u8 led_ctrl = 0x00;
void LED_Process()
{
    if(confirm_5s_flag == 1)
        led_ctrl |= 0x01;
    else
        led_ctrl &= ~0x01;
    
    LED_Control(led_ctrl);
}

按键按下后指定时间后生效

例:按下B2后,5S后切换PWM模式,即pwm_mode+1;

基本思路

定义计时变量b2Tick,计时标志位pwm_mode_flag。按下B2,b2Tick = uwTick,pwm_mode_flag =1 ;当(uwTick - b2Tick)>= 5000 && pwm_mode_flag == 1 时,切换模式,同时计时标志位pwm_mode_flag清零。

代码部分

/* 按键 */
u32 keyTick;
_Bool pwm_mode_flag;
u32 b2Tick;
void KEY_Process()
{
    if(uwTick - keyTick < 20) return;
    keyTick = uwTick;
    
    Key_Read();
    if(uwTick - b2Tick >= 5000 && pwm_mode_flag == 1)//pwm_mode_flag=1后,5000ms后执行一次
    {
        pwm_change_num++;
        pwm_mode = (pwm_mode+1)%2;
        pwm_mode_flag = 0;
    }
}

if(Trg & 0x02)//B2 选择按键
    {
        switch(display_mode)
        {
            case DATA:
            {
                if(pwm_mode_flag == 0)
                {
                    b2Tick = uwTick;
                    pwm_mode_flag = 1;//5S后该标志位清零
                }
                break;
            }
        }
    }

PWM的步进频率

需求:PWM输出频率在指定时间内均匀的升高或者降低。

基本思路

已知条件:PWM输出模式未切换时,pwmstepTick = uwTick;pwm_mode_flag置1,5s后又清零。5s后,(uwTick - pwmstepTick) = 5000

高频模式下,按下切换键5S后,ARR值从124变为249

低频模式下,按下切换键5S后,ARR值从249变为124

代码部分

/* PWM */
u32 pwmstepTick = 0;
void PWM_Process()
{
    if(pwm_mode_flag == 0)//不在切换过程中
    {
        pwmstepTick = uwTick;//初始化步进频率的定时
        if(pwm_mode == 0)//低频模式
        {
            TIM2->ARR = 250-1;
            TIM2->CCR2 = (u16)(250.0f * pwm_duty / 100.0f);
        }
        else if(pwm_mode == 1)//高频模式
        {
            TIM2->ARR = 125-1;
            TIM2->CCR2 = (u16)(125.0f * pwm_duty / 100.0f);
        }
    }
    else//步进频率
    {
        if(pwm_mode == 0)//低频变高频
        {
            TIM2->ARR = 249 - (uwTick - pwmstepTick)/40;//5S后变成124
            TIM2->CCR2 = (u16)( (250.0f - (uwTick - pwmstepTick) / 40) * pwm_duty / 100.0f );
        }
        else if(pwm_mode == 1)//高频变低频
        {
            TIM2->ARR = 124 + (uwTick - pwmstepTick)/40;//5S后变成249
            TIM2->CCR2 = (u16)( (125 + (uwTick - pwmstepTick)/40) * pwm_duty / 100.0f);
        }
    }
    
    
}

只保存稳定在2S以上的频率

基本思路:

当freq_prev - freq的绝对值小于200,且freq > freq_prev | freq < freq_prev,开始计时,计时超过2s,则freq = freq_prev。

代码部分:

/* PWM捕获 */
u32 tim17_cnt;
u32 freq;
float v_prev = 0;
u32 lmvTick;
_Bool lmv_flag;//更新最大速度计时标志位
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    tim17_cnt = __HAL_TIM_GetCounter(&htim17);
    __HAL_TIM_SetCounter(&htim17,0);
    
    freq = 1e6/tim17_cnt;
    v_prev = velocity;
    velocity = (freq * 2.0 * 3.14f * para_r)/(100 * para_k);
    
    
    HAL_TIM_IC_Start_IT(&htim17,TIM_CHANNEL_1);
}

/* PWM_Data */
void PWM_Data_Process()
{
    if(pwm_mode == 0)
    {
        //保持时间不足2S的速度值纳入不计
        if(  abs( (int)(v_prev - velocity) ) < 200)//速度基本保持不变
        {
            if((u16)velocity > (u16)lmax_v)
            {
                if(lmv_flag == 0)
                {
                    lmvTick = uwTick;//开始计时
                    lmv_flag = 1;
                }
                
                if( (uwTick - lmvTick >= 2000) && (lmv_flag == 1)) 
                {
                    lmax_v = velocity;
                    lmv_flag = 0;//计时标志位
                }
            }
            else
            {
                lmv_flag = 0;
            } 
        }
        else
        {
            lmv_flag = 0;
        }
    }
    else
    {
        //保持时间不足2S的速度值纳入不计
        if(  abs( (int)(v_prev - velocity) ) < 200)//速度基本保持不变
        {
            if((u16)velocity > (u16)hmax_v)
            {
                if(lmv_flag == 0)
                {
                    lmvTick = uwTick;//开始计时
                    lmv_flag = 1;
                }
                
                if( (uwTick - lmvTick >= 2000) && (lmv_flag == 1)) 
                {
                    hmax_v = velocity;
                    lmv_flag = 0;//计时标志位
                }
            }
            else
            {
                lmv_flag = 0;
            } 
        }
        else
        {
            lmv_flag = 0;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值