lulugl 发表于 2023-10-28 17:03

【AT-START-F423测评】基于freeRTOS的流水呼吸灯

AT32F23呼吸流水灯
【工程简介】
传统都是用GPIO的高低电平来实现流水灯。这次用PWM来实现呼吸的流水灯。
【实现步骤】
新建freertos工程,复一份官方的freertos的工程,重命名,并打开工程,并确保编译通过。
打开雅特力的图形配置工具,配置板载的三个LED为PWM输出。


复制配置工具生成的代码到工程中。

代码为:
void wk_tmr4_init(void)
{
/* add user code begin tmr4_init 0 */

/* add user code end tmr4_init 0 */

gpio_init_type gpio_init_struct;
tmr_output_config_type tmr_output_struct;

gpio_default_para_init(&gpio_init_struct);

/* add user code begin tmr4_init 1 */
       /* enable gpiod periph clock */
crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);

/* enable tmr4 periph clock */
crm_periph_clock_enable(CRM_TMR4_PERIPH_CLOCK, TRUE);
/* add user code end tmr4_init 1 */

/* configure the tmr4 CH2 pin */
gpio_init_struct.gpio_pins = GPIO_PINS_13;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init(GPIOD, &gpio_init_struct);

gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE13, GPIO_MUX_2);

/* configure the tmr4 CH3 pin */
gpio_init_struct.gpio_pins = GPIO_PINS_14;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init(GPIOD, &gpio_init_struct);

gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE14, GPIO_MUX_2);

/* configure the tmr4 CH4 pin */
gpio_init_struct.gpio_pins = GPIO_PINS_15;
gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
gpio_init(GPIOD, &gpio_init_struct);

gpio_pin_mux_config(GPIOD, GPIO_PINS_SOURCE15, GPIO_MUX_2);

/* configure counter settings */
tmr_base_init(TMR4, 14999, 0);
tmr_cnt_dir_set(TMR4, TMR_COUNT_UP);
tmr_clock_source_div_set(TMR4, TMR_CLOCK_DIV1);
tmr_period_buffer_enable(TMR4, FALSE);

/* configure primary mode settings */
tmr_sub_sync_mode_set(TMR4, FALSE);
tmr_primary_mode_select(TMR4, TMR_PRIMARY_SEL_RESET);

/* configure channel 2 output settings */
tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
tmr_output_struct.oc_output_state = TRUE;
tmr_output_struct.occ_output_state = FALSE;
tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_LOW;
tmr_output_struct.occ_polarity = TMR_OUTPUT_ACTIVE_LOW;
tmr_output_struct.oc_idle_state = FALSE;
tmr_output_struct.occ_idle_state = FALSE;
tmr_output_channel_config(TMR4, TMR_SELECT_CHANNEL_2, &tmr_output_struct);
tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_2, 0);
tmr_output_channel_buffer_enable(TMR4, TMR_SELECT_CHANNEL_2, FALSE);

tmr_output_channel_immediately_set(TMR4, TMR_SELECT_CHANNEL_2, FALSE);

/* configure channel 3 output settings */
tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
tmr_output_struct.oc_output_state = TRUE;
tmr_output_struct.occ_output_state = FALSE;
tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_LOW;
tmr_output_struct.occ_polarity = TMR_OUTPUT_ACTIVE_LOW;
tmr_output_struct.oc_idle_state = FALSE;
tmr_output_struct.occ_idle_state = FALSE;
tmr_output_channel_config(TMR4, TMR_SELECT_CHANNEL_3, &tmr_output_struct);
tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_3, 0);
tmr_output_channel_buffer_enable(TMR4, TMR_SELECT_CHANNEL_3, FALSE);

tmr_output_channel_immediately_set(TMR4, TMR_SELECT_CHANNEL_3, FALSE);

/* configure channel 4 output settings */
tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
tmr_output_struct.oc_output_state = TRUE;
tmr_output_struct.occ_output_state = FALSE;
tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_LOW;
tmr_output_struct.occ_polarity = TMR_OUTPUT_ACTIVE_LOW;
tmr_output_struct.oc_idle_state = FALSE;
tmr_output_struct.occ_idle_state = FALSE;
tmr_output_channel_config(TMR4, TMR_SELECT_CHANNEL_4, &tmr_output_struct);
tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_4, 0);
tmr_output_channel_buffer_enable(TMR4, TMR_SELECT_CHANNEL_4, FALSE);

tmr_output_channel_immediately_set(TMR4, TMR_SELECT_CHANNEL_4, FALSE);


tmr_counter_enable(TMR4, TRUE);

/* add user code begin tmr4_init 2 */

/* add user code end tmr4_init 2 */
}
创建三个任务,实现三个灯的交替呼吸。创建三个信量,实现三个PWM呼着灯的交替工作。
/* led2 task function */
void led2_task_function(void *pvParameters)
{
        uint32_t tmr_channel_value;
        uint8_t f;
        BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
        xSemaphoreGive( xBinarySemaphorePWM1 );//给出二值信号量
while(1)
{
                //获取二值信号量 xSemaphore,没获取到则一直等待
    xReturn = xSemaphoreTake(xBinarySemaphorePWM1,/* 二值信号量句柄 */
                              portMAX_DELAY); /* 等待时间 */
    for(f=0; f<180; f++)
                {
                        tmr_channel_value = (uint32_t)(14999*cos(f*3.14/180));
                        tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_2, tmr_channel_value);
                        vTaskDelay(10);
                }
                tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_2, tmr_channel_value);
                xSemaphoreGive( xBinarySemaphorePWM2 );//给出二值信号量
}
}

/* led3 task function */
void led3_task_function(void *pvParameters)
{
        BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
        uint32_t tmr_channel_value;
        uint8_t f;
while(1)
{
                //获取二值信号量 xSemaphore,没获取到则一直等待
                      
    xReturn = xSemaphoreTake(xBinarySemaphorePWM2,/* 二值信号量句柄 */
                              portMAX_DELAY); /* 等待时间 */
    for(f=0; f<180; f++)
                {
                        tmr_channel_value = (uint32_t)(14999*sin(f*3.14/180));
                        tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_3, tmr_channel_value);
                        vTaskDelay(10);
                }
                tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_3, 0);
                xSemaphoreGive( xBinarySemaphorePWM3 );//给出二值信号量
}
}

/* led3 task function */
void led4_task_function(void *pvParameters)
{
        BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
        uint32_t tmr_channel_value;
        uint8_t f;
while(1)
{
                //获取二值信号量 xSemaphore,没获取到则一直等待
                      
    xReturn = xSemaphoreTake(xBinarySemaphorePWM3,/* 二值信号量句柄 */
                              portMAX_DELAY); /* 等待时间 */
    for(f=0; f<180; f++)
                {
                        tmr_channel_value = (uint32_t)(14999*sin(f*3.14/180));
                        tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_4, tmr_channel_value);
                        vTaskDelay(10);
                }
                tmr_channel_value_set(TMR4, TMR_SELECT_CHANNEL_4, 0);
                xSemaphoreGive( xBinarySemaphorePWM1 );//给出二值信号量
}
}
在主程序中开始三个任务,任务中等待其的任务发出信号量,来实现工作。
/**
* @briefmain function.
* @paramnone
* @retval none
*/
int main(void)
{
system_clock_config();

nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);

        wk_tmr4_init();
/* init usart1 */
uart_print_init(115200);
        xBinarySemaphorePWM1 = xSemaphoreCreateBinary();//创建信号量
        if (NULL != xBinarySemaphorePWM1)
    {
      printf("BinarySem_Handle 二值信号量1创建成功!\r\n");
    }
        xBinarySemaphorePWM2 = xSemaphoreCreateBinary();//创建信号量
        if (NULL != xBinarySemaphorePWM2)
    {
      printf("BinarySem_Handle 二值信号量2创建成功!\r\n");
    }
        xBinarySemaphorePWM3 = xSemaphoreCreateBinary();//创建信号量
        if (NULL != xBinarySemaphorePWM3)
    {
      printf("BinarySem_Handle 二值信号量3创建成功!\r\n");
    }
/* enter critical */
taskENTER_CRITICAL();

/* create led2 task */
if(xTaskCreate((TaskFunction_t )led2_task_function,
               (const char*    )"LED2_task",
               (uint16_t       )512,
               (void*          )NULL,
               (UBaseType_t    )2,
               (TaskHandle_t*)&led2_handler) != pdPASS)
{
    printf("LED2 task could not be created as there was insufficient heap memory remaining.\r\n");
}
else
{
    printf("LED2 task was created successfully.\r\n");
}
/* create led3 task */
if(xTaskCreate((TaskFunction_t )led3_task_function,
               (const char*    )"LED3_task",
               (uint16_t       )512,
               (void*          )NULL,
               (UBaseType_t    )2,
               (TaskHandle_t*)&led3_handler) != pdPASS)
{
    printf("LED3 task could not be created as there was insufficient heap memory remaining.\r\n");
}
else
{
    printf("LED3 task was created successfully.\r\n");
}
/* create led3 task */
if(xTaskCreate((TaskFunction_t )led4_task_function,
               (const char*    )"LED4_task",
               (uint16_t       )512,
               (void*          )NULL,
               (UBaseType_t    )2,
               (TaskHandle_t*)&led4_handler) != pdPASS)
{
    printf("LED4 task could not be created as there was insufficient heap memory remaining.\r\n");
}
else
{
    printf("LED4 task was created successfully.\r\n");
}
/* exit critical */
taskEXIT_CRITICAL();

/* start scheduler */
vTaskStartScheduler();
}
实现交替的呼吸流水灯:
https://www.bilibili.com/video/BV1pB4y1d7ay/?vd_source=e1bd226340c8b87027d5dcfc6b0c3344
【小结】
此工程实现了定时器的驱动,同时应用信号量来实现三个任务的交替运行呼吸灯。开程提供了FreeRTOS的移植、信号量的创建,任务之间的信号传递,实现了不一样的流水灯效果。

页: [1]
查看完整版本: 【AT-START-F423测评】基于freeRTOS的流水呼吸灯