前言

近年来,蓝桥杯嵌入式竞赛的题目设计逐渐向思维深度和创新性倾斜,传统“刷题式”备考的效果正在减弱。面对这一趋势,借鉴他人的解题思路和分析方法,往往能帮助参赛者更快抓住问题核心,实现事半功倍。

本次分享聚焦蓝桥杯第15届第二套省赛的这道典型题目,这些题目有一定难度。通过拆解题目背景、关键思路和优化技巧,希望能为读者提供一种可参考的思考范式。需说明的是,所有观点仅为个人经验总结,未必完全适用所有场景,欢迎交流指正。

(注:若需具体题目解析或进一步讨论,可随时补充细节。)
————————————————

题目

在这里插入图片描述

Cubemx配置

在这里插入图片描述
在这里插入图片描述
定时器2的配置
在这里插入图片描述
定时器15的配置
在这里插入图片描述
定时器6的配置
在这里插入图片描述
定时器6,我作为按键消抖用的,定时器2和15,你们可以在PA1、PA2引脚上任选其中可以配置的定时器。
预分配我习惯设为8-1,这样有时候频率比较大的时候的精确度可以大一些,看你个人习惯。
ARR:一般选设为题目的初始条件来设定;
在这里插入图片描述
在这里插入图片描述
题目初始条件为低速,也就是200Hz。
所以ARR=时钟频率/预分配系数/频率
ARR=80M/8/200=50000,我这里设成5000了,你们修改一下就好了。
或者你们可以像我一样在程序里面改。

 TIM2->ARR = 50000;               // 设置TIM2自动重装载值(决定PWM频率)
 TIM15->ARR = 50000;              // 设置TIM15自动重装载值

代码实现

LCD显示

void lcd_proc()
{
    char text[30];
    if (view == 0)// 数据视图
    {
        sprintf(text, "       DATA         ");
        LCD_DisplayStringLine(Line1, (uint8_t *)text);
        sprintf(text, "     A=%0.1fV         ", adc_f);// 显示ADC电压
        LCD_DisplayStringLine(Line3, (uint8_t *)text);
        sprintf(text, "     P=%d%%-%d%%         ", duty1, duty2);// 显示双路占空比
        LCD_DisplayStringLine(Line4, (uint8_t *)text);
        if (mode == 0)sprintf(text, "     MODE=L         ");
        else sprintf(text, "     MODE=H         ");// 模式指示
        LCD_DisplayStringLine(Line5, (uint8_t *)text);
        if (lock == 0)sprintf(text, "     LOCK=N         ");
        else if (lock == 1)sprintf(text, "     LOCK=Y         "); // 锁定状态
        LCD_DisplayStringLine(Line6, (uint8_t *)text);
    }
    if (view == 1) // 参数设置视图
    {
        sprintf(text, "       PARA         ");
        LCD_DisplayStringLine(Line1, (uint8_t *)text);
        sprintf(text, "     PU=%0.1fV         ", Pu);
        LCD_DisplayStringLine(Line3, (uint8_t *)text);
        sprintf(text, "     PD=%0.1fV         ", Pd);
        LCD_DisplayStringLine(Line4, (uint8_t *)text);
        sprintf(text, "                   ");
        LCD_DisplayStringLine(Line5, (uint8_t *)text);
        sprintf(text, "                   ");
        LCD_DisplayStringLine(Line6, (uint8_t *)text);

    }
    if (view == 2)// 错误视图
    {
        sprintf(text, "                       ");
        LCD_DisplayStringLine(Line1, (uint8_t *)text);
        sprintf(text, "                       ");
        LCD_DisplayStringLine(Line3, (uint8_t *)text);

        sprintf(text, "       ERROR         ");
        LCD_DisplayStringLine(Line4, (uint8_t *)text);
        sprintf(text, "                   ");
        LCD_DisplayStringLine(Line5, (uint8_t *)text);
        sprintf(text, "                   ");
        LCD_DisplayStringLine(Line6, (uint8_t *)text);


    }
}

按键操作

void key_proc()
{
	if (bkey[1].flag == 1) {
        view = (view + 1) % 2;  // 在0/1视图间切换
        choose_ud = 0;          // 重置参数选择
        /* 检查阈值有效性 */
        if ((int)(Pu * 10) <= (int)(Pd * 10)) { 
            error = 1;          // 触发错误状态
            view = 2;           // 跳转到错误视图
        }
        if (error == 0) {       // 有效时更新阈值
            Pu_r = Pu;
            Pd_r = Pd;
        }
        bkey[1].flag = 0;       // 清除按键标志
    }
    
    // 按键2短按:模式切换/参数选择
    if (bkey[2].flag == 1) {
        if (view == 1) choose_ud = !choose_ud; // 在参数视图切换选择对象
        if (lock == 0) {         // 未锁定时可改模式
            if (view == 0) mode = !mode;  // 在数据视图切换工作模式
            // 根据模式调整PWM频率
            if (mode == 0) {      // 低频模式
                TIM2->ARR = 50000;
                TIM15->ARR = 50000;
            } else if (mode == 1) { // 高频模式
                TIM2->ARR = 5000;
                TIM15->ARR = 5000;
            }
        }
        bkey[2].flag = 0;
    }
    
    // 按键3短按:增加选定参数值
    if (bkey[3].flag == 1) {
        if (view == 1) {
            if (choose_ud == 0) {  // 增加上限
                Pu += 0.3f;
                if (Pu > 3.4f) Pu = 3.3f; // 限制最大值
            } else {                // 增加下限
                Pd += 0.3f;
                if (Pd > 3.4f) Pd = 3.3f;
            }
        }
        bkey[3].flag = 0;
    }
    
    // 按键4短按:减小选定参数值/解锁
    if (bkey[4].flag == 1) {
        if (view == 1) {
            if (choose_ud == 0) {  // 减小上限
                Pu -= 0.3f;
                if (Pu < -0.1f) Pu = 0.0f;
            } else {                // 减小下限
                Pd -= 0.3f;
                if (Pd < -0.1f) Pd = 0.0f;
            }
        }
        if (lock == 1 && view == 0) lock = 0; // 在数据视图解锁
        bkey[4].flag = 0;
    }
    
    // 按键4长按:锁定参数
    if (bkey[4].long_flag == 1) {
        if(view == 0) lock = 1;  // 在数据视图锁定
        bkey[4].long_flag = 0;
    }
//给其他长按清零,不清掉的话有时候测评点会出问题
    if (bkey[3].long_flag == 1)
    {
        bkey[3].long_flag = 0;
    }
    if (bkey[2].long_flag == 1)
    {
        bkey[2].long_flag = 0;
    }
    if (bkey[1].long_flag == 1)
    {
        bkey[1].long_flag = 0;
    }
}

定时器中断

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == TIM6) {   // 处理TIM6中断(10ms周期)
        key_serv();                 // 按键扫描服务
        if (error == 1) {           // 错误状态处理
            time_3s++;              // 递增计数器
            if (time_3s > 299) {    // 3秒超时(300 * 10ms)
                time_3s = 0;
                error = 0;           // 清除错误
                Pu = Pu_r;          // 恢复原阈值
                Pd = Pd_r;
                view = 1;           // 返回参数视图
            }
        }
    }
}

4t测试满分:
在这里插入图片描述

总结

此文仅代表个人愚见。
15届第二套省赛满分工程链接
视频讲解

其他届满分工程及解析

第8届省赛工程及解析
第12届省赛满分工程及解析
第15届国赛解题思路及完整工程

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐