[APM32F4] 【APM32F402R Micro-EVB开发板测评】8、FreeRTOS外部中断触发任务通过PWM调整亮度

[复制链接]
31|0
slytherinsun 发表于 2025-8-29 17:38 | 显示全部楼层 |阅读模式
本帖最后由 slytherinsun 于 2025-8-29 23:55 编辑

1.简介
本次测评在前两篇的FreeRTOS的基础上,通过开发板的Key1按键触发外部中断,在中断中给Led_Thread任务发送事件。Led_Thread任务等待事件,并在事件发生后改变LED2的状态,同时通过调整定时器4的比较值来改变PWM的占空比。定时器4的PWM的输出连接到LED3,根据正弦序列从0 - 100%生成了11个占空比,通过按键触发不同的占空比来实现调整亮度的目的,同时可用于PWM风扇的调速控制。
2.定时器4通道2输出PWM
通过查阅原理图可知APM32F402R开发板的LED3连接的是PB7引脚,在数据手册中此引脚的其中一个默认复用功能是TMR4_CH2,

pwm01

pwm01

pwm02

pwm02

通用定时器4支持PWM输出,由此可以实现基于PWM占空比的亮度或速度调节。其周期由自动重装载寄存器(TMR4_AUTORLD)的值决定,
信号脉宽由比较寄存器(TMR4_CC2)的值决定。其向上、向下计数和中央对齐模式及PWM模式1/2对亮度调整影响不大,本次测试使用PWM模式1向上计数。
根据数据手册的时钟树及频率配置可知,TMR4时钟为APB1 x 2 = 120MHz。PWM的配置基于官方例程PWM输出代码进行修改。

pwm03

pwm03

pwm04

pwm04

当前配置PWM为10KHz,按照正弦序列将亮度从0 - 100%分了10份共11个比较寄存器值。具体代码如下:
  1. void TMR_Config(void)
  2. {
  3.     TMR_BaseConfig_T tmrBaseConfig;
  4.     TMR_OCConfig_T tmrOCConfig;

  5.     RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR4);

  6.     /* TMR4 clock source frequency = 120MHz */
  7.     tmrBaseConfig.countMode = TMR_COUNTER_MODE_UP;
  8.     tmrBaseConfig.clockDivision = TMR_CLOCK_DIV_1;
  9.     tmrBaseConfig.period = 999;  //tmr update rate = 10M / (999 + 1) = 10K
  10.     tmrBaseConfig.division = 19; //tmr4 clk 10M
  11.     tmrBaseConfig.repetitionCounter = 0;
  12.     TMR_ConfigTimeBase(TMR4, &tmrBaseConfig);

  13.     /* 50% PWM */
  14.     tmrOCConfig.mode = TMR_OC_MODE_PWM1;
  15.     tmrOCConfig.outputState = TMR_OC_STATE_ENABLE;
  16.     tmrOCConfig.outputNState = TMR_OC_NSTATE_DISABLE;
  17.     tmrOCConfig.polarity = TMR_OC_POLARITY_HIGH;
  18.     tmrOCConfig.nPolarity = TMR_OC_NPOLARITY_HIGH;
  19.     tmrOCConfig.idleState = TMR_OC_IDLE_STATE_RESET;
  20.     tmrOCConfig.nIdleState = TMR_OC_NIDLE_STATE_RESET;
  21.     tmrOCConfig.pulse = PWM_Arry[0];
  22.     TMR_ConfigOC2(TMR4, &tmrOCConfig);

  23.     TMR_EnablePWMOutputs(TMR4);
  24.     TMR_Enable(TMR4);
  25. }
3.按键触发中断
通过查阅原理图可知用户按键连接到了PA1上,按下时为低电平。在用户手册中查到PA1内部连接到了EINT1,可以在程序中配置PA1为上拉输入,开放EINT_LINE_1的中断请求,并设置为下降沿触发,然后设置中断优先级,开启中断。最后在中断处理函数中清除中断标志位,并给Led_Thread任务发送事件。

pwm05

pwm05

pwm06

pwm06

按键中断的配置使用例程中的void BOARD_BUTTON_Config(BOARD_BUTTON_T button, BOARD_BUTTON_MODE_T mode)函数,为适应FreeRTOS环境,需要把配置NVIC的代码修改为支持RTOS的接口:
  1. void BOARD_BUTTON_Config(BOARD_BUTTON_T button, BOARD_BUTTON_MODE_T mode)
  2. {
  3.     GPIO_Config_T GPIO_ConfigStruct = {0U};
  4.     EINT_Config_T EINT_ConfigStruct = {0U};
  5.    
  6.     /* Enable the BUTTON Clock */
  7.     RCM_EnableAPB2PeriphClock(BUTTON_CLK[button] | RCM_APB2_PERIPH_AFIO);
  8.    
  9.     /* Configure Button pin as input floating */
  10.     GPIO_ConfigStruct.mode = GPIO_MODE_IN_PU;
  11.     GPIO_ConfigStruct.pin = BUTTON_PIN[button];
  12.     GPIO_Config(BUTTON_PORT[button], &GPIO_ConfigStruct);
  13.    
  14.     if (mode == BUTTON_MODE_EINT)
  15.     {
  16.         /* Connect Button EINT Line to Button GPIO Pin */
  17.         GPIO_ConfigEINTLine(BUTTON_PORT_SOURCE[button], BUTTON_PIN_SOURCE[button]);

  18.         /* Configure Button EINT line */
  19.         EINT_ConfigStruct.line = BUTTON_EINT_LINE[button];
  20.         EINT_ConfigStruct.mode = EINT_MODE_INTERRUPT;
  21.         EINT_ConfigStruct.trigger = EINT_TRIGGER_FALLING;
  22.         EINT_ConfigStruct.lineCmd = ENABLE;
  23.         EINT_Config(&EINT_ConfigStruct);

  24.         /* Enable and set Button EINT Interrupt to the lowest priority */
  25.         // NVIC_EnableIRQRequest(BUTTON_IRQn[button], 0x0F, 0x0F);
  26.         NVIC_SetPriority (BUTTON_IRQn[button], 1U);
  27.         NVIC_EnableIRQ(BUTTON_IRQn[button]);
  28.     }
  29. }
并在apm32f402_403_int.c中编写中断服务函数:
  1. void EINT1_IRQHandler(void)
  2. {
  3.     if (EINT_ReadIntFlag(EINT_LINE_1))
  4.     {
  5.         EINT_ClearIntFlag(EINT_LINE_1);
  6.         osEventFlagsSet(testEveGroupID, 0x1);
  7.     }
  8. }
为使中断服务函数能够调用RTOS接口,需要包含cmsis_os2.h头文件,并把调用到的任务和事件相关变量声明为外部变量。

4.PWM调光任务
PWM调光任务修改自FreeRTOS例程中的Led_Thread,任务中等待按键中断的事件,收到事件后切换LED2的状态,并打印按键消息,之后根据接收到的事件次数依次调用PWM_Arry数组中预定义的值切换PWM占空比来实现亮度调节的目的。具体代码如下:
  1. uint16_t PWM_Arry[11] = {999, 712, 590, 493, 409, 333, 262, 194, 128, 64, 0};
  2. void Led_Thread(void *argument)
  3. {
  4.     UNUSED(argument);
  5.     uint32_t cnt = 0;
  6.     while (1)
  7.     {
  8.         /* Toggle LED2 */
  9.         osEventFlagsWait(testEveGroupID, 0x1, osFlagsWaitAll, osWaitForever);
  10.         BOARD_LED_Toggle(LED2);
  11.         // osDelay(600);
  12.         printf("get key push\r\n");
  13.         cnt++;
  14.         if(cnt > 11) {
  15.             cnt = 0;
  16.         }
  17.         TMR_ConfigCompare2(TMR4, PWM_Arry[cnt]);
  18.     }
  19. }

5.演示
代码编译完成烧录后,可以在日志中看到环境信息采集任务定时打印的气压、温湿度数据,按下Key1后可以看到获取按键消息的打印,开发板上的LED3随着按下次数循环改变亮度。

pwm07

pwm07


55068b1c6718f7f7.png
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

29

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部