Files
motor_ili9341/Core/Src/freertos.c
T
2026-07-08 10:30:07 +08:00

305 lines
9.7 KiB
C

/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : freertos.c
* Description : Code for freertos applications
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "uart4.h"
#include "esc.h"
#include "lvgl.h"
#include "ili9341.h"
#include "lv_port_disp.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.stack_size = 1024 * 4,
.priority = (osPriority_t) osPriorityNormal,
};
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
/* USER CODE END FunctionPrototypes */
void StartDefaultTask(void *argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
/* Hook prototypes */
void vApplicationIdleHook(void);
void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName);
void vApplicationMallocFailedHook(void);
/* USER CODE BEGIN 2 */
void vApplicationIdleHook( void )
{
/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
task. It is essential that code added to this hook function never attempts
to block in any way (for example, call xQueueReceive() with a block time
specified, or call vTaskDelay()). If the application makes use of the
vTaskDelete() API function (as this demo application does) then it is also
important that vApplicationIdleHook() is permitted to return to its calling
function, because it is the responsibility of the idle task to clean up
memory allocated by the kernel to any task that has since been deleted. */
}
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName)
{
/* Run time stack overflow checking is performed if
configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is
called if a stack overflow is detected. */
}
/* USER CODE END 4 */
/* USER CODE BEGIN 5 */
void vApplicationMallocFailedHook(void)
{
/* vApplicationMallocFailedHook() will only be called if
configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook
function that will get called if a call to pvPortMalloc() fails.
pvPortMalloc() is called internally by the kernel whenever a task, queue,
timer or semaphore is created. It is also called by various parts of the
demo application. If heap_1.c or heap_2.c are used, then the size of the
heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
to query the size of free heap space that remains (although it does not
provide information on how the remaining heap might be fragmented). */
}
/* USER CODE END 5 */
/**
* @brief FreeRTOS initialization
* @param None
* @retval None
*/
void MX_FREERTOS_Init(void) {
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* creation of defaultTask */
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
}
/* USER CODE BEGIN Header_StartDefaultTask */
/**
* @brief Function implementing the defaultTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/*
* 之前这里是:
* ILI9341_Init();
* ILI9341_SetRotation(1);
* ILI9341_FillScreen(ILI9341_BLACK);
*
* 现在硬件初始化、清屏都收拢到了 lv_port_disp.c 的 disp_init()
* 里统一做(跟随 lv_init()/lv_port_disp_init() 一起调用)。
* 不再单独调用 ILI9341_SetRotation(1):横屏旋转已经改成在
* disp_flush() 里用软件转置实现,如果这里再把 MADCTL 的 MV 位
* 置 1,会跟软件转置逻辑重复叠加,导致画面完全错乱。
*/
lv_init();
lv_port_disp_init();
//延时等待时钟同步防止异常出现
osDelay(100);
lv_obj_t *scr = lv_scr_act();
/*
* 屏幕背景
*/
lv_obj_set_style_bg_color(scr, lv_color_hex(0x101820), LV_PART_MAIN);
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, LV_PART_MAIN);
/*
* 标题
*/
lv_obj_t *title = lv_label_create(scr);
lv_label_set_text(title, "STM32H750 LVGL");
lv_obj_set_style_text_color(title, lv_color_hex(0xFFFFFF), LV_PART_MAIN);
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 12);
/*
* 状态文字
*/
lv_obj_t *status = lv_label_create(scr);
lv_label_set_text(status, "UI + Animation OK");
lv_obj_set_style_text_color(status, lv_color_hex(0x00E5FF), LV_PART_MAIN);
lv_obj_align(status, LV_ALIGN_TOP_MID, 0, 38);
/*
* 进度条背景
*/
lv_obj_t *bar = lv_bar_create(scr);
lv_obj_set_size(bar, 220, 18);
lv_obj_align(bar, LV_ALIGN_TOP_MID, 0, 72);
lv_bar_set_mode(bar, LV_BAR_MODE_NORMAL);
lv_bar_set_range(bar, 0, 100);
lv_bar_set_value(bar, 0, LV_ANIM_OFF);
lv_obj_set_style_bg_color(bar, lv_color_hex(0x303030), LV_PART_MAIN);
lv_obj_set_style_bg_opa(bar, LV_OPA_COVER, LV_PART_MAIN);
lv_obj_set_style_border_width(bar, 1, LV_PART_MAIN);
lv_obj_set_style_border_color(bar, lv_color_hex(0x666666), LV_PART_MAIN);
lv_obj_set_style_pad_all(bar, 0, LV_PART_MAIN);
lv_obj_set_style_bg_color(bar, lv_color_hex(0x00C853), LV_PART_INDICATOR);
lv_obj_set_style_bg_opa(bar, LV_OPA_COVER, LV_PART_INDICATOR);
/*
* 蓝色动画方块
*/
lv_obj_t *box = lv_obj_create(scr);
lv_obj_set_size(box, 40, 40);
lv_obj_set_pos(box, 20, 115);
lv_obj_set_style_bg_color(box, lv_color_hex(0x0091EA), LV_PART_MAIN);
lv_obj_set_style_bg_opa(box, LV_OPA_COVER, LV_PART_MAIN);
lv_obj_set_style_border_width(box, 0, LV_PART_MAIN);
lv_obj_set_style_pad_all(box, 0, LV_PART_MAIN);
/*
* 按钮
*/
lv_obj_t *btn = lv_btn_create(scr);
lv_obj_set_size(btn, 120, 36);
lv_obj_align(btn, LV_ALIGN_BOTTOM_MID, 0, -18);
lv_obj_set_style_bg_color(btn, lv_color_hex(0x263238), LV_PART_MAIN);
lv_obj_set_style_bg_opa(btn, LV_OPA_COVER, LV_PART_MAIN);
lv_obj_set_style_border_width(btn, 1, LV_PART_MAIN);
lv_obj_set_style_border_color(btn, lv_color_hex(0x00E5FF), LV_PART_MAIN);
lv_obj_t *btn_label = lv_label_create(btn);
lv_label_set_text(btn_label, "START");
lv_obj_set_style_text_color(btn_label, lv_color_hex(0xFFFFFF), LV_PART_MAIN);
lv_obj_center(btn_label);
/*
* 方块左右移动动画
*/
lv_anim_t anim;
lv_anim_init(&anim);
lv_anim_set_var(&anim, box);
lv_anim_set_values(&anim, 20, 260);
lv_anim_set_time(&anim, 1200);
lv_anim_set_playback_time(&anim, 1200);
lv_anim_set_repeat_count(&anim, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_exec_cb(&anim, (lv_anim_exec_xcb_t)lv_obj_set_x);
lv_anim_start(&anim);
/*
* 进度条动画,0 到 100 再回到 0
*/
// lv_anim_t bar_anim;
// lv_anim_init(&bar_anim);
// lv_anim_set_var(&bar_anim, bar);
// lv_anim_set_values(&bar_anim, 0, 100);
// lv_anim_set_time(&bar_anim, 3000);
// lv_anim_set_playback_time(&bar_anim, 0);
// lv_anim_set_repeat_count(&bar_anim, LV_ANIM_REPEAT_INFINITE);
// lv_anim_set_exec_cb(&bar_anim, Bar_Anim_CB);
// lv_anim_start(&bar_anim);
for(;;)
{
lv_timer_handler();
/*
* DMA 看门狗:兜底极端情况下 DMA 传输既没有触发完成中断
* 也没有触发错误中断(硬件卡死/中断丢失)时,强制恢复 SPI
* 状态机,避免画面永久冻结。正常情况下 ILI9341_WriteArea_DMA
* 内部的信号量超时已经能处理绝大多数异常,这里只是双保险。
* timeout_ms 要大于 ILI9341_WriteArea_DMA 内部的 100ms 超时,
* 避免两层保护互相打架。
*/
ILI9341_DMA_Watchdog(180);
osDelay(5);
}
/* USER CODE END StartDefaultTask */
}
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
/* USER CODE END Application */