【蓝桥杯嵌入式】14届程序题刷题记录及反思

一、题目分析

考察内容:

  • led
  • 按键(长按/短按)
  • adc(模拟输入)
  • PWM输出(PA1)
  • 脉冲捕获(PA7)

根据PWM输出进行占空比调节,高频与低频切换(步进)

频率测量转换为速度值

三个显示界面

锁定解锁

任务多次执行时长间隔要求

二、按键部分

//放在定时器中断函数

    if(htim->Instance == TIM6)          //0.01s进入一次
    {
        key[0].key_sta = HAL_GPIO_ReadPin(B1_PORT,B1_PIN);
        key[1].key_sta = HAL_GPIO_ReadPin(B2_PORT,B2_PIN);
        key[2].key_sta = HAL_GPIO_ReadPin(B3_PORT,B3_PIN);
        key[3].key_sta = HAL_GPIO_ReadPin(B4_PORT,B4_PIN);       
        for(uint8_t i = 0;i < 4;i ++){
            switch(key[i].judge_sta){
                case 0:{        //判断按键是否按下
                    if(key[i].key_sta == 0){
                        key[i].judge_sta = 1;
                        key[i].key_time = 0;    //按键时间清零
                    }else{
                        key[i].judge_sta = 0;
                    }
                }break;
                case 1:{        //消抖
                    if(key[i].key_sta == 0){
                        key[i].judge_sta = 2;
                    }else{
                        key[i].judge_sta = 0;
                    }
                }break;
                case 2:{        //判断按键松开
                    if(key[i].key_sta == 1){
                        key[i].judge_sta = 0;
                        if(key[i].key_time < Short_time){
                            key[i].single_flag = 1;      //短按键
                            key[i].key_time = 0;
                        }
                    }else{                              //按键没松开
                        key[i].key_time++;              //继续计时
                        if(key[i].key_time > Long_time){
                           key[i].long_flag = 1; 
                           key[i].key_time = 0;   
                        }       
                    }
                }break;

            }
        }
    }
struct keys{
    uint8_t judge_sta;                        //按键状态判断
    uint8_t key_sta;                          //按键状态
    uint8_t single_flag;                      //按键单击成功1
    uint8_t long_flag;                        //按键长按成功1
    uint16_t key_time;                       //按键按下时长记录
};
/*define-----------------------------------------------------------------------*/
#define B1_PORT GPIOB
#define B2_PORT GPIOB
#define B3_PORT GPIOB
#define B4_PORT GPIOA

#define B1_PIN  GPIO_PIN_0
#define B2_PIN  GPIO_PIN_1
#define B3_PIN  GPIO_PIN_2
#define B4_PIN  GPIO_PIN_0
/*define------------------------------------------------------------------------*/
#define Long_time  200    //200*0.1 = 1s   //2s进入一次
#define Short_time 30     //单击在0.3s以内
/*include-----------------------------------------------------------------------*/
extern struct keys key[4];

三、LED灯部分

#include "led.h"

void led_set(uint8_t led_dis)
{
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,led_dis<<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_toggle(void)
{
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_10,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOC,GPIO_PIN_15,GPIO_PIN_SET);  
    
    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_9);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);    
}

四、ADC部分

#include "base_adc.h"

double getADC_val(ADC_HandleTypeDef* hadc)
{
    HAL_ADC_Start(hadc);
    uint32_t val = HAL_ADC_GetValue(hadc);
    return val*3.3/4096;
}

五、输入捕获

读取自己捕获寄存器的值称为直接模式

读取另一个通道的捕获寄存器的值称为间接模式

PSC 80-1  得到1us 计数值不用改动

开启中断

/-----------------------------------------------------------------------------------------------------------------------------/

在STM32中,HAL_TIM_ACTIVE_CHANNEL_1通常是指定定时器(TIM)的第一个通道(Channel 1)处于活动状态。HAL是指STM32Cube库中的硬件抽象层(Hardware Abstraction Layer),它提供了一组API函数,用于与STM32微控制器的外设进行交互。TIM是定时器/计数器模块的缩写,它可以用于产生定时中断、测量脉冲宽度、以及生成PWM信号等应用。

HAL_TIM_ACTIVE_CHANNEL_1是在使用STM32Cube库时的一个宏定义,用于指示TIM的第一个通道是否处于活动状态。这通常用于轮询或中断处理程序中,以确定特定通道是否触发了事件。

//单通道频率测量--双通道占空比测量

uint16_t cnt_rising=0, cnt_falling=0;
uint16_t freq=0;
float IC_duty;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
	if(htim -> Instance == TIM3)
	{
		if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_2)
		{
			cnt_rising = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2)+1;
			freq = (80000000/80) / cnt_rising;
			IC_duty = ((float)cnt_falling/cnt_rising)*100;
		}
		if(htim -> Channel == HAL_TIM_ACTIVE_CHANNEL_1)
		{
			cnt_falling = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1)+1;
		}
	}
}

六、PWM输出

本题要求改变频率但不改变占空比,改变频率的时候改变PSC比较方便

改变频率

__HAL_TIM_SET_PRESCALER(&htim2,40-1+bujin_time);

改变占空比

__HAL_TIM_SetCompare(&htim2,TIM_CHANNEL_2,P*0.01*1000 - 1); 

 七、定时器部分

定时器中断函数

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)

//定时器和中断记得在while(1)前面开启

锁定--解锁

任务执行间隔

以上两点我的处理方法是设置flag或者valid信号

    if(htim->Instance == TIM7)  //0.125s进入一次
    {  
        if(bujin_flag == 1){
            
            bujin_time ++;
            if(M == L){
                if(bujin_time == 40){
                    bujin_time = 0;
                    bujin_flag = 0;
                    __HAL_TIM_SET_PRESCALER(&htim2,80-1);
                }else{
                   __HAL_TIM_SET_PRESCALER(&htim2,40-1+bujin_time);
                }        
            }else if(M == H){
                if(bujin_time == 40){
                    bujin_time = 0;
                    bujin_flag = 0;
                    __HAL_TIM_SET_PRESCALER(&htim2,40-1);
                }else{
                   __HAL_TIM_SET_PRESCALER(&htim2,80-1-bujin_time);
                }  
            }
        }
    }
    
    if(htim->Instance == TIM17)  //0.1s进入一次   
    {
        static uint16_t i = 0;
        static uint16_t j = 0;
        if(bujin_flag == 1){
            led_toggle();           
        }
        if(sel_en_flag == 0)
        {
            i++;
            if(i >= 490){
                i = 0;           
                sel_en_flag = 1;
            }
        }
        V_2s = V;
        j++;
        if(j>=19){               //2s_V 要求
            j=0;
            if(V_2s == V){
                V_2s_valid = 1; 
            }else{
                V_2s_valid = 0;
            }
        }else{
            V_2s_valid = 0;
        }
    }      

八、显示页面

初始化

void display_init(void)
{
    LCD_Clear(Black);
    LCD_SetBackColor(Black);
    LCD_SetTextColor(White);
}

显示页面 

//阶段2--步进设置100hz -- 40次中断 5s内 
//0.125s中断一次

void H_fre_set(void){
    __HAL_TIM_SET_PRESCALER(&htim2,40-1);
}
void L_fre_set(void){
    __HAL_TIM_SET_PRESCALER(&htim2,80-1);
}

void displaying(uint8_t menu)
{
    uint8_t text[30];
    if(menu == DATA_menu)
    {
        sprintf((char *)text,"        DATA    ");
        LCD_DisplayStringLine(Line2,text);
        if(M == H){
            sprintf((char *)text,"     M=H     ");

           // H_fre_set();
            LCD_DisplayStringLine(Line4,text);    
        }else if(M == L){
            sprintf((char *)text,"     M=L        ");

           // L_fre_set();
            LCD_DisplayStringLine(Line4,text);  
        }
        P = IC_duty;
        sprintf((char *)text,"     P=%d%%    ",P);
        LCD_DisplayStringLine(Line5,text);  
        V = freq*2*3.14*R/(100.0*K);
        sprintf((char *)text,"     V=%.1f     ",V);
        LCD_DisplayStringLine(Line6,text); 

        if(M ==H){
            if(V_2s_valid){
                if(V> MH) {
                    MH = V;   
                }  
            }
        }else if(M ==L){
            if(V_2s_valid){
                ML = V;            
            }  
        }

    }else if(menu == PARA_menu){

        sprintf((char *)text,"        PARA    ");
        if(key[1].single_flag == 1){
            key[1].single_flag = 0;
        }
        LCD_DisplayStringLine(Line2,text);
        sprintf((char *)text,"     R=%d       ",R);
        LCD_DisplayStringLine(Line4,text);
        sprintf((char *)text,"     K=%d       ",K);
        LCD_DisplayStringLine(Line5,text);
        LCD_ClearLine(Line6);
    }else if(menu == RECD_menu){
        
        if(M ==H){
            if(V_2s_valid){
                if(V> MH) {
                    MH = V;   
                }  
            }
        }else if(M ==L){
            if(V_2s_valid){
                ML = V;            
            }  
        }
        sprintf((char *)text,"        RECD    ");
        LCD_DisplayStringLine(Line2,text);
        sprintf((char *)text,"     N=%d     ",N);
        LCD_DisplayStringLine(Line4,text);
        sprintf((char *)text,"     MH=%.1f    ",MH);
        LCD_DisplayStringLine(Line5,text);
        sprintf((char *)text,"     ML=%.1f   ",ML);
        LCD_DisplayStringLine(Line6,text);
        V = freq*2*3.14*R/(100.0*K);   //R和K参数在其他页面生效
    }
}

九、 总结

 后面打算只写一个usr.c usr.h

如果自己新建工程的话,记得把配置,我最初按键测试的时候不行,发现是cubemx里没有分配引脚。

每个模块独立会导致extern很多变量——在比赛过程中时间耗费较长

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值