【APM32F402R Micro-EVB开发板测评】8、FreeRTOS外部中断触发任务通过PWM调整亮度
本帖最后由 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,
通用定时器4支持PWM输出,由此可以实现基于PWM占空比的亮度或速度调节。其周期由自动重装载寄存器(TMR4_AUTORLD)的值决定,
信号脉宽由比较寄存器(TMR4_CC2)的值决定。其向上、向下计数和中央对齐模式及PWM模式1/2对亮度调整影响不大,本次测试使用PWM模式1向上计数。
根据数据手册的时钟树及频率配置可知,TMR4时钟为APB1 x 2 = 120MHz。PWM的配置基于官方例程PWM输出代码进行修改。
当前配置PWM为10KHz,按照正弦序列将亮度从0 - 100%分了10份共11个比较寄存器值。具体代码如下:
void TMR_Config(void)
{
TMR_BaseConfig_T tmrBaseConfig;
TMR_OCConfig_T tmrOCConfig;
RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR4);
/* TMR4 clock source frequency = 120MHz */
tmrBaseConfig.countMode = TMR_COUNTER_MODE_UP;
tmrBaseConfig.clockDivision = TMR_CLOCK_DIV_1;
tmrBaseConfig.period = 999;//tmr update rate = 10M / (999 + 1) = 10K
tmrBaseConfig.division = 19; //tmr4 clk 10M
tmrBaseConfig.repetitionCounter = 0;
TMR_ConfigTimeBase(TMR4, &tmrBaseConfig);
/* 50% PWM */
tmrOCConfig.mode = TMR_OC_MODE_PWM1;
tmrOCConfig.outputState = TMR_OC_STATE_ENABLE;
tmrOCConfig.outputNState = TMR_OC_NSTATE_DISABLE;
tmrOCConfig.polarity = TMR_OC_POLARITY_HIGH;
tmrOCConfig.nPolarity = TMR_OC_NPOLARITY_HIGH;
tmrOCConfig.idleState = TMR_OC_IDLE_STATE_RESET;
tmrOCConfig.nIdleState = TMR_OC_NIDLE_STATE_RESET;
tmrOCConfig.pulse = PWM_Arry;
TMR_ConfigOC2(TMR4, &tmrOCConfig);
TMR_EnablePWMOutputs(TMR4);
TMR_Enable(TMR4);
}3.按键触发中断
通过查阅原理图可知用户按键连接到了PA1上,按下时为低电平。在用户手册中查到PA1内部连接到了EINT1,可以在程序中配置PA1为上拉输入,开放EINT_LINE_1的中断请求,并设置为下降沿触发,然后设置中断优先级,开启中断。最后在中断处理函数中清除中断标志位,并给Led_Thread任务发送事件。
按键中断的配置使用例程中的void BOARD_BUTTON_Config(BOARD_BUTTON_T button, BOARD_BUTTON_MODE_T mode)函数,为适应FreeRTOS环境,需要把配置NVIC的代码修改为支持RTOS的接口:
void BOARD_BUTTON_Config(BOARD_BUTTON_T button, BOARD_BUTTON_MODE_T mode)
{
GPIO_Config_T GPIO_ConfigStruct = {0U};
EINT_Config_T EINT_ConfigStruct = {0U};
/* Enable the BUTTON Clock */
RCM_EnableAPB2PeriphClock(BUTTON_CLK | RCM_APB2_PERIPH_AFIO);
/* Configure Button pin as input floating */
GPIO_ConfigStruct.mode = GPIO_MODE_IN_PU;
GPIO_ConfigStruct.pin = BUTTON_PIN;
GPIO_Config(BUTTON_PORT, &GPIO_ConfigStruct);
if (mode == BUTTON_MODE_EINT)
{
/* Connect Button EINT Line to Button GPIO Pin */
GPIO_ConfigEINTLine(BUTTON_PORT_SOURCE, BUTTON_PIN_SOURCE);
/* Configure Button EINT line */
EINT_ConfigStruct.line = BUTTON_EINT_LINE;
EINT_ConfigStruct.mode = EINT_MODE_INTERRUPT;
EINT_ConfigStruct.trigger = EINT_TRIGGER_FALLING;
EINT_ConfigStruct.lineCmd = ENABLE;
EINT_Config(&EINT_ConfigStruct);
/* Enable and set Button EINT Interrupt to the lowest priority */
// NVIC_EnableIRQRequest(BUTTON_IRQn, 0x0F, 0x0F);
NVIC_SetPriority (BUTTON_IRQn, 1U);
NVIC_EnableIRQ(BUTTON_IRQn);
}
}并在apm32f402_403_int.c中编写中断服务函数:
void EINT1_IRQHandler(void)
{
if (EINT_ReadIntFlag(EINT_LINE_1))
{
EINT_ClearIntFlag(EINT_LINE_1);
osEventFlagsSet(testEveGroupID, 0x1);
}
}
为使中断服务函数能够调用RTOS接口,需要包含cmsis_os2.h头文件,并把调用到的任务和事件相关变量声明为外部变量。
4.PWM调光任务
PWM调光任务修改自FreeRTOS例程中的Led_Thread,任务中等待按键中断的事件,收到事件后切换LED2的状态,并打印按键消息,之后根据接收到的事件次数依次调用PWM_Arry数组中预定义的值切换PWM占空比来实现亮度调节的目的。具体代码如下:
uint16_t PWM_Arry = {999, 712, 590, 493, 409, 333, 262, 194, 128, 64, 0};
void Led_Thread(void *argument)
{
UNUSED(argument);
uint32_t cnt = 0;
while (1)
{
/* Toggle LED2 */
osEventFlagsWait(testEveGroupID, 0x1, osFlagsWaitAll, osWaitForever);
BOARD_LED_Toggle(LED2);
// osDelay(600);
printf("get key push\r\n");
cnt++;
if(cnt > 11) {
cnt = 0;
}
TMR_ConfigCompare2(TMR4, PWM_Arry);
}
}
5.演示
代码编译完成烧录后,可以在日志中看到环境信息采集任务定时打印的气压、温湿度数据,按下Key1后可以看到获取按键消息的打印,开发板上的LED3随着按下次数循环改变亮度。
页:
[1]