【蓝桥杯嵌入式】第十四届蓝桥杯嵌入式省赛

  1. PWM输出:通过PA1引脚输出频率可调(4kHz或8kHz)的PWM信号,占空比通过电位器R37调节。
  2. 频率测量:通过PAY引脚捕获输入信号的频率,并转换为速度值。
  3. ADC检测:检测电位器R37的模拟电压信号。
  4. LCD显示:显示数据界面、参数界面和统计界面。
  5. 按键功能:通过按键切换界面、调整参数、锁定/解锁占空比等。
  6. LED指示灯:根据系统状态控制LED指示灯。

以下是基于STM32 HAL库的代码实现和详细解释。


CubeMX 配置

  1. 系统时钟配置

    • 配置系统时钟为最大频率(例如80MHz)。
  2. 配置TIM2为PWM输出

    • TIM2Channel 2 → PWM Generation CH2。
    • Parameter Settings
      • Prescaler: 0
      • Counter Mode: Up
      • Period (ARR): 19999(初始频率4kHz)
      • Pulse (CCR): 初始占空比(例如5000,对应25%)
    • GPIO:确认PA1配置为复用推挽输出。
  3. 配置TIM3为输入捕获

    • TIM3Channel 1 → Input Capture Direct Mode。
    • Parameter Settings
      • Prescaler: 79(得到1MHz时钟)
      • Counter Mode: Up
      • Period (ARR): 65535
    • GPIO:确认PAY引脚配置为输入捕获。
  4. 配置ADC

    • ADC1Channel 0 → 选择电位器R37的引脚。
    • Parameter Settings
      • Resolution: 12位
      • Data Alignment: Right
      • Continuous Conversion Mode: Enabled
    • NVIC Settings:启用ADC中断。
  5. 配置按键和LED

    • GPIO:配置B1、B2、B3、B4为输入,LD1-LD8为输出。
  6. 配置LCD

    • 根据LCD型号配置SPI或I2C接口。
  7. 生成代码

    • 生成项目代码并打开工程。

代码实现

1. PWM输出和频率调整
// 定义全局变量
typedef enum {
    PWM_LOW_FREQ_MODE,
    PWM_HIGH_FREQ_MODE
} PWMMode;

PWMMode current_mode = PWM_LOW_FREQ_MODE;
float current_duty_cycle = 0.0f;
uint32_t target_freq = 0;
int32_t remaining_steps = 0;
int32_t freq_step = 0;
uint32_t timer_clock = 80000000; // 根据实际时钟调整

// 初始化PWM
void PWM_Init() {
    HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
    current_duty_cycle = (float)__HAL_TIM_GET_COMPARE(&htim2, TIM_CHANNEL_2) / (__HAL_TIM_GET_AUTORELOAD(&htim2) + 1);
}

// 模式切换函数
void SwitchPWMMode(PWMMode new_mode) {
    if(new_mode == current_mode) return;

    target_freq = (new_mode == PWM_HIGH_FREQ_MODE) ? 8000 : 4000;
    int32_t delta_f = (int32_t)target_freq - (int32_t)(current_mode == PWM_HIGH_FREQ_MODE ? 8000 : 4000);

    freq_step = (delta_f > 0) ? 100 : -100;
    remaining_steps = abs(delta_f) / 100;

    HAL_TIM_Base_Start_IT(&htim6); // 启动TIM6中断
}

// TIM6中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if(htim == &htim6 && remaining_steps > 0) {
        uint32_t new_freq = (current_mode == PWM_LOW_FREQ_MODE) ? 
                           (4000 + (100 * (remaining_steps - (abs(target_freq - 4000)/100 - remaining_steps)))) : 
                           (8000 - (100 * (remaining_steps - (abs(target_freq - 8000)/100 - remaining_steps))));

        uint32_t new_arr = (timer_clock / new_freq) - 1;
        uint32_t new_ccr = current_duty_cycle * (new_arr + 1);

        __HAL_TIM_SET_AUTORELOAD(&htim2, new_arr);
        __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, new_ccr);
        TIM_GenerateEvent(&htim2, TIM_EVENTSOURCE_UPDATE);

        remaining_steps--;

        if(remaining_steps == 0) {
            HAL_TIM_Base_Stop_IT(&htim6);
            current_mode = (target_freq == 8000) ? PWM_HIGH_FREQ_MODE : PWM_LOW_FREQ_MODE;
        }
    }
}
2. 频率测量
// 定义全局变量
uint32_t captured_freq = 0;
float speed = 0.0f;
uint8_t R = 1, K = 1;

// TIM3输入捕获回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
    if(htim == &htim3) {
        captured_freq = HAL_TIM_ReadCapturedValue(&htim3, TIM_CHANNEL_1);
        speed = (captured_freq * 2 * 3.14 * R) / (100 * K); // 计算速度
    }
}
3. ADC检测
// 定义全局变量
uint32_t adc_value = 0;
float voltage = 0.0f;

// ADC转换完成回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
    if(hadc == &hadc1) {
        adc_value = HAL_ADC_GetValue(&hadc1);
        voltage = (adc_value * 3.3) / 4095; // 转换为电压值
        current_duty_cycle = voltage / 3.3; // 更新占空比
        __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, current_duty_cycle * (__HAL_TIM_GET_AUTORELOAD(&htim2) + 1));
    }
}
4. LCD显示
// 显示数据界面
void DisplayDataScreen() {
    char buffer[50];
    sprintf(buffer, "DATA M=%c P=%.1f V=%.1f", (current_mode == PWM_HIGH_FREQ_MODE) ? 'H' : 'L', current_duty_cycle * 100, speed);
    LCD_DisplayString(0, 0, buffer);
}

// 显示参数界面
void DisplayParameterScreen() {
    char buffer[50];
    sprintf(buffer, "PARA R=%d K=%d", R, K);
    LCD_DisplayString(0, 0, buffer);
}

// 显示统计界面
void DisplayStatisticsScreen() {
    char buffer[50];
    sprintf(buffer, "RECD N=%d MH=%.1f ML=%.1f", switch_count, max_speed_high, max_speed_low);
    LCD_DisplayString(0, 0, buffer);
}
5. 按键处理
// 按键处理函数
void HandleButtons() {
    if (HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin) == GPIO_PIN_RESET) {
        // 切换界面
        current_screen = (current_screen + 1) % 3;
        HAL_Delay(200); // 防抖
    }
    if (HAL_GPIO_ReadPin(B2_GPIO_Port, B2_Pin) == GPIO_PIN_RESET) {
        // 切换模式或参数
        if (current_screen == DATA_SCREEN) {
            SwitchPWMMode((current_mode == PWM_LOW_FREQ_MODE) ? PWM_HIGH_FREQ_MODE : PWM_LOW_FREQ_MODE);
        } else if (current_screen == PARA_SCREEN) {
            selected_param = (selected_param == PARAM_R) ? PARAM_K : PARAM_R;
        }
        HAL_Delay(200); // 防抖
    }
    if (HAL_GPIO_ReadPin(B3_GPIO_Port, B3_Pin) == GPIO_PIN_RESET) {
        // 增加参数
        if (current_screen == PARA_SCREEN) {
            if (selected_param == PARAM_R) R = (R % 10) + 1;
            else K = (K % 10) + 1;
        }
        HAL_Delay(200); // 防抖
    }
    if (HAL_GPIO_ReadPin(B4_GPIO_Port, B4_Pin) == GPIO_PIN_RESET) {
        // 长按锁定/解锁占空比
        uint32_t start_time = HAL_GetTick();
        while (HAL_GPIO_ReadPin(B4_GPIO_Port, B4_Pin) == GPIO_PIN_RESET) {
            if (HAL_GetTick() - start_time > 2000) {
                is_duty_locked = !is_duty_locked;
                HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, is_duty_locked ? GPIO_PIN_SET : GPIO_PIN_RESET);
                break;
            }
        }
        HAL_Delay(200); // 防抖
    }
}
6. 主函数
int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_TIM2_Init();
    MX_TIM3_Init();
    MX_ADC1_Init();
    MX_LCD_Init();

    PWM_Init();
    HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_1);
    HAL_ADC_Start_IT(&hadc1);

    while (1) {
        HandleButtons();
        switch (current_screen) {
            case DATA_SCREEN: DisplayDataScreen(); break;
            case PARA_SCREEN: DisplayParameterScreen(); break;
            case STAT_SCREEN: DisplayStatisticsScreen(); break;
        }
        HAL_Delay(100);
    }
}

代码解释

  1. PWM输出

    • 使用TIM2生成PWM信号,通过调整ARR和CCR实现频率和占空比控制。
    • 模式切换时,频率在5秒内均匀变化,步进值小于200Hz。
  2. 频率测量

    • 使用TIM3的输入捕获功能测量输入信号的频率,并转换为速度值。
  3. ADC检测

    • 使用ADC1检测电位器R37的电压,实时更新PWM占空比。
  4. LCD显示

    • 根据当前界面显示数据、参数或统计信息。
  5. 按键处理

    • 实现界面切换、模式切换、参数调整和占空比锁定/解锁功能。
  6. 主函数

    • 初始化硬件和外设,进入主循环处理按键和更新显示。

注意事项

  • 时钟配置:确保系统时钟和定时器时钟正确。
  • 中断优先级:合理配置中断优先级,避免冲突。
  • 防抖处理:按键处理时加入防抖逻辑。
  • 边界检查:参数调整时检查边界值,避免无效参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

马职音人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值