diff --git a/controler/CMakeLists.txt b/controler/CMakeLists.txt index 3406a90..e6675ad 100644 --- a/controler/CMakeLists.txt +++ b/controler/CMakeLists.txt @@ -55,6 +55,10 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE ./User/bsp/time.c ./User/component/user_math.c ./User/module/config.c + ./User/task/init.c + ./User/task/display.c + ./User/task/user_task.c + ./User/LCD/lcd.c @@ -64,6 +68,7 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE ./User/LCD/touch.c ./User/lvgl/examples/porting/lv_port_disp_template.c ./User/lvgl/examples/porting/lv_port_indev_template.c + ./User/lvgl/stress/lv_demo_stress.c ${LVGL_C} diff --git a/controler/Core/Inc/stm32f4xx_hal_conf.h b/controler/Core/Inc/stm32f4xx_hal_conf.h index f2de69d..d9635fa 100644 --- a/controler/Core/Inc/stm32f4xx_hal_conf.h +++ b/controler/Core/Inc/stm32f4xx_hal_conf.h @@ -96,7 +96,7 @@ * (when HSE is used as system clock source, directly or through the PLL). */ #if !defined (HSE_VALUE) - #define HSE_VALUE 25000000U /*!< Value of the External oscillator in Hz */ + #define HSE_VALUE 8000000U /*!< Value of the External oscillator in Hz */ #endif /* HSE_VALUE */ #if !defined (HSE_STARTUP_TIMEOUT) diff --git a/controler/Core/Inc/stm32f4xx_it.h b/controler/Core/Inc/stm32f4xx_it.h index 13a27cc..651a4f5 100644 --- a/controler/Core/Inc/stm32f4xx_it.h +++ b/controler/Core/Inc/stm32f4xx_it.h @@ -56,6 +56,7 @@ void CAN1_RX0_IRQHandler(void); void CAN1_RX1_IRQHandler(void); void USART1_IRQHandler(void); void TIM8_TRG_COM_TIM14_IRQHandler(void); +void DMA2_Stream0_IRQHandler(void); /* USER CODE BEGIN EFP */ /* USER CODE END EFP */ diff --git a/controler/Core/Src/dma.c b/controler/Core/Src/dma.c index b2c6b3c..c76b13e 100644 --- a/controler/Core/Src/dma.c +++ b/controler/Core/Src/dma.c @@ -64,6 +64,11 @@ void MX_DMA_Init(void) Error_Handler(); } + /* DMA interrupt init */ + /* DMA2_Stream0_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 5, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); + } /* USER CODE BEGIN 2 */ diff --git a/controler/Core/Src/freertos.c b/controler/Core/Src/freertos.c index 8a81b40..0e14a91 100644 --- a/controler/Core/Src/freertos.c +++ b/controler/Core/Src/freertos.c @@ -26,6 +26,7 @@ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ +#include "task/user_task.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -96,6 +97,7 @@ void MX_FREERTOS_Init(void) { /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ + osThreadNew(Task_Init, NULL, &attr_init); // 创建初始化任务 /* USER CODE END RTOS_THREADS */ /* USER CODE BEGIN RTOS_EVENTS */ @@ -114,11 +116,7 @@ void MX_FREERTOS_Init(void) { void StartDefaultTask(void *argument) { /* USER CODE BEGIN StartDefaultTask */ - /* Infinite loop */ - for(;;) - { - osDelay(1); - } + osThreadTerminate(osThreadGetId()); /* USER CODE END StartDefaultTask */ } diff --git a/controler/Core/Src/gpio.c b/controler/Core/Src/gpio.c index ca62f51..152d490 100644 --- a/controler/Core/Src/gpio.c +++ b/controler/Core/Src/gpio.c @@ -42,12 +42,25 @@ void MX_GPIO_Init(void) { + GPIO_InitTypeDef GPIO_InitStruct = {0}; + /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); + __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); + /*Configure GPIO pin Output Level */ + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); + + /*Configure GPIO pin : PB0 */ + GPIO_InitStruct.Pin = GPIO_PIN_0; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + } /* USER CODE BEGIN 2 */ diff --git a/controler/Core/Src/main.c b/controler/Core/Src/main.c index 7c1fbdb..06a7f79 100644 --- a/controler/Core/Src/main.c +++ b/controler/Core/Src/main.c @@ -141,8 +141,8 @@ void SystemClock_Config(void) RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; - RCC_OscInitStruct.PLL.PLLM = 25; - RCC_OscInitStruct.PLL.PLLN = 336; + RCC_OscInitStruct.PLL.PLLM = 4; + RCC_OscInitStruct.PLL.PLLN = 168; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 4; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) diff --git a/controler/Core/Src/stm32f4xx_it.c b/controler/Core/Src/stm32f4xx_it.c index 289a29d..8724e5a 100644 --- a/controler/Core/Src/stm32f4xx_it.c +++ b/controler/Core/Src/stm32f4xx_it.c @@ -60,6 +60,7 @@ void SysTick_Port (void); /* External variables --------------------------------------------------------*/ extern CAN_HandleTypeDef hcan1; +extern DMA_HandleTypeDef hdma_memtomem_dma2_stream0; extern UART_HandleTypeDef huart1; extern TIM_HandleTypeDef htim14; @@ -221,6 +222,20 @@ void TIM8_TRG_COM_TIM14_IRQHandler(void) /* USER CODE END TIM8_TRG_COM_TIM14_IRQn 1 */ } +/** + * @brief This function handles DMA2 stream0 global interrupt. + */ +void DMA2_Stream0_IRQHandler(void) +{ + /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */ + + /* USER CODE END DMA2_Stream0_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_memtomem_dma2_stream0); + /* USER CODE BEGIN DMA2_Stream0_IRQn 1 */ + + /* USER CODE END DMA2_Stream0_IRQn 1 */ +} + /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ diff --git a/controler/User/LCD/lcd.c b/controler/User/LCD/lcd.c index d6e221d..97ec424 100644 --- a/controler/User/LCD/lcd.c +++ b/controler/User/LCD/lcd.c @@ -604,68 +604,77 @@ void lcd_set_window(uint16_t sx, uint16_t sy, uint16_t width, uint16_t height) * @param 无 * @retval 无 */ -void lcd_init(void) + +__weak void lcd_init(void) { - GPIO_InitTypeDef gpio_init_struct; - FSMC_NORSRAM_TimingTypeDef fsmc_read_handle; - FSMC_NORSRAM_TimingTypeDef fsmc_write_handle; - LCD_CS_GPIO_CLK_ENABLE(); /* LCD_CS脚时钟使能 */ - LCD_WR_GPIO_CLK_ENABLE(); /* LCD_WR脚时钟使能 */ - LCD_RD_GPIO_CLK_ENABLE(); /* LCD_RD脚时钟使能 */ - LCD_RS_GPIO_CLK_ENABLE(); /* LCD_RS脚时钟使能 */ - LCD_BL_GPIO_CLK_ENABLE(); /* LCD_BL脚时钟使能 */ - - gpio_init_struct.Pin = LCD_CS_GPIO_PIN; - gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 推挽复用 */ - gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ - gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */ - gpio_init_struct.Alternate = GPIO_AF12_FSMC; /* 复用为FSMC */ - HAL_GPIO_Init(LCD_CS_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_CS引脚 */ - - gpio_init_struct.Pin = LCD_WR_GPIO_PIN; - HAL_GPIO_Init(LCD_WR_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_WR引脚 */ - - gpio_init_struct.Pin = LCD_RD_GPIO_PIN; - HAL_GPIO_Init(LCD_RD_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_RD引脚 */ - - gpio_init_struct.Pin = LCD_RS_GPIO_PIN; - HAL_GPIO_Init(LCD_RS_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_RS引脚 */ - - gpio_init_struct.Pin = LCD_BL_GPIO_PIN; - gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */ - HAL_GPIO_Init(LCD_BL_GPIO_PORT, &gpio_init_struct); /* LCD_BL引脚模式设置(推挽输出) */ - - g_sram_handle.Instance = FSMC_NORSRAM_DEVICE; - g_sram_handle.Extended = FSMC_NORSRAM_EXTENDED_DEVICE; - - g_sram_handle.Init.NSBank = FSMC_NORSRAM_BANK4; /* 使用NE4 */ - g_sram_handle.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; /* 地址/数据线不复用 */ - g_sram_handle.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; /* 16位数据宽度 */ - g_sram_handle.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; /* 是否使能突发访问,仅对同步突发存储器有效,此处未用到 */ - g_sram_handle.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; /* 等待信号的极性,仅在突发模式访问下有用 */ - g_sram_handle.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; /* 存储器是在等待周期之前的一个时钟周期还是等待周期期间使能NWAIT */ - g_sram_handle.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; /* 存储器写使能 */ - g_sram_handle.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; /* 等待使能位,此处未用到 */ - g_sram_handle.Init.ExtendedMode = FSMC_EXTENDED_MODE_ENABLE; /* 读写使用不同的时序 */ - g_sram_handle.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE; /* 是否使能同步传输模式下的等待信号,此处未用到 */ - g_sram_handle.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; /* 禁止突发写 */ - - /* FSMC读时序控制寄存器 */ - fsmc_read_handle.AddressSetupTime = 0x0F; /* 地址建立时间(ADDSET)为15个fsmc_ker_ck(1/168=6)即6*15=90ns */ - fsmc_read_handle.AddressHoldTime = 0x00; /* 地址保持时间(ADDHLD) 模式A是没有用到 */ - fsmc_read_handle.DataSetupTime = 60; /* 数据保存时间(DATAST)为60个fsmc_ker_ck=6*60=360ns */ - /* 因为液晶驱动IC的读数据的时候,速度不能太快,尤其是个别奇葩芯片 */ - fsmc_read_handle.AccessMode = FSMC_ACCESS_MODE_A; /* 模式A */ - - /* FSMC写时序控制寄存器 */ - fsmc_write_handle.AddressSetupTime = 9; /* 地址建立时间(ADDSET)为9个fsmc_ker_ck=6*9=54ns */ - fsmc_write_handle.AddressHoldTime = 0x00; /* 地址保持时间(ADDHLD) 模式A是没有用到 */ - fsmc_write_handle.DataSetupTime = 9; /* 数据保存时间(DATAST)为9个fsmc_ker_ck=6*9=54ns */ - /* 注意:某些液晶驱动IC的写信号脉宽,最少也得50ns */ - fsmc_write_handle.AccessMode = FSMC_ACCESS_MODE_A; /* 模式A */ - - HAL_SRAM_Init(&g_sram_handle, &fsmc_read_handle, &fsmc_write_handle); + // lcddev.id =0x7789; + // lcd_ex_st7789_reginit(); + // lcd_display_dir(1); + // LCD_BL(1); + // lcd_clear(WHITE); + // return; + + // GPIO_InitTypeDef gpio_init_struct; + // FSMC_NORSRAM_TimingTypeDef fsmc_read_handle; + // FSMC_NORSRAM_TimingTypeDef fsmc_write_handle; + // + // LCD_CS_GPIO_CLK_ENABLE(); /* LCD_CS脚时钟使能 */ + // LCD_WR_GPIO_CLK_ENABLE(); /* LCD_WR脚时钟使能 */ + // LCD_RD_GPIO_CLK_ENABLE(); /* LCD_RD脚时钟使能 */ + // LCD_RS_GPIO_CLK_ENABLE(); /* LCD_RS脚时钟使能 */ + // LCD_BL_GPIO_CLK_ENABLE(); /* LCD_BL脚时钟使能 */ + // + // gpio_init_struct.Pin = LCD_CS_GPIO_PIN; + // gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* 推挽复用 */ + // gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ + // gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */ + // gpio_init_struct.Alternate = GPIO_AF12_FSMC; /* 复用为FSMC */ + // HAL_GPIO_Init(LCD_CS_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_CS引脚 */ + // + // gpio_init_struct.Pin = LCD_WR_GPIO_PIN; + // HAL_GPIO_Init(LCD_WR_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_WR引脚 */ + // + // gpio_init_struct.Pin = LCD_RD_GPIO_PIN; + // HAL_GPIO_Init(LCD_RD_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_RD引脚 */ + // + // gpio_init_struct.Pin = LCD_RS_GPIO_PIN; + // HAL_GPIO_Init(LCD_RS_GPIO_PORT, &gpio_init_struct); /* 初始化LCD_RS引脚 */ + // + // gpio_init_struct.Pin = LCD_BL_GPIO_PIN; + // gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */ + // HAL_GPIO_Init(LCD_BL_GPIO_PORT, &gpio_init_struct); /* LCD_BL引脚模式设置(推挽输出) */ + // + // g_sram_handle.Instance = FSMC_NORSRAM_DEVICE; + // g_sram_handle.Extended = FSMC_NORSRAM_EXTENDED_DEVICE; + // + // g_sram_handle.Init.NSBank = FSMC_NORSRAM_BANK4; /* 使用NE4 */ + // g_sram_handle.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; /* 地址/数据线不复用 */ + // g_sram_handle.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; /* 16位数据宽度 */ + // g_sram_handle.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; /* 是否使能突发访问,仅对同步突发存储器有效,此处未用到 */ + // g_sram_handle.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; /* 等待信号的极性,仅在突发模式访问下有用 */ + // g_sram_handle.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; /* 存储器是在等待周期之前的一个时钟周期还是等待周期期间使能NWAIT */ + // g_sram_handle.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; /* 存储器写使能 */ + // g_sram_handle.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; /* 等待使能位,此处未用到 */ + // g_sram_handle.Init.ExtendedMode = FSMC_EXTENDED_MODE_ENABLE; /* 读写使用不同的时序 */ + // g_sram_handle.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE; /* 是否使能同步传输模式下的等待信号,此处未用到 */ + // g_sram_handle.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; /* 禁止突发写 */ + // + // /* FSMC读时序控制寄存器 */ + // fsmc_read_handle.AddressSetupTime = 0x0F; /* 地址建立时间(ADDSET)为15个fsmc_ker_ck(1/168=6)即6*15=90ns */ + // fsmc_read_handle.AddressHoldTime = 0x00; /* 地址保持时间(ADDHLD) 模式A是没有用到 */ + // fsmc_read_handle.DataSetupTime = 60; /* 数据保存时间(DATAST)为60个fsmc_ker_ck=6*60=360ns */ + // /* 因为液晶驱动IC的读数据的时候,速度不能太快,尤其是个别奇葩芯片 */ + // fsmc_read_handle.AccessMode = FSMC_ACCESS_MODE_A; /* 模式A */ + // + // /* FSMC写时序控制寄存器 */ + // fsmc_write_handle.AddressSetupTime = 9; /* 地址建立时间(ADDSET)为9个fsmc_ker_ck=6*9=54ns */ + // fsmc_write_handle.AddressHoldTime = 0x00; /* 地址保持时间(ADDHLD) 模式A是没有用到 */ + // fsmc_write_handle.DataSetupTime = 9; /* 数据保存时间(DATAST)为9个fsmc_ker_ck=6*9=54ns */ + // /* 注意:某些液晶驱动IC的写信号脉宽,最少也得50ns */ + // fsmc_write_handle.AccessMode = FSMC_ACCESS_MODE_A; /* 模式A */ + // + // HAL_SRAM_Init(&g_sram_handle, &fsmc_read_handle, &fsmc_write_handle); delay_ms(50); /* 尝试9341 ID的读取 */ @@ -786,21 +795,21 @@ void lcd_init(void) lcd_ssd_backlight_set(100); /* 背光设置为最亮 */ } - /* 初始化完成以后,提速 */ - if (lcddev.id == 0x7789 || lcddev.id == 0x9341 || lcddev.id == 0x1963) /* 7789/9341/1963 提速 */ - { - /* 重新配置写时序控制寄存器的时序 */ - fsmc_write_handle.AddressSetupTime = 3; /* 地址建立时间(ADDSET)为3个fsmc_ker_ck=6*3=18ns */ - fsmc_write_handle.DataSetupTime = 3; /* 数据保持时间(DATAST)为3个fsmc_ker_ck=6*3=18ns */ - FSMC_NORSRAM_Extended_Timing_Init(g_sram_handle.Extended, &fsmc_write_handle, g_sram_handle.Init.NSBank, g_sram_handle.Init.ExtendedMode); - } - else if (lcddev.id == 0x5310 || lcddev.id == 0x7796 || lcddev.id == 0x5510 || lcddev.id == 0x9806) /* 如果是这几个IC, 则设置WR时序为最快 */ - { - /* 重新配置写时序控制寄存器的时序 */ - fsmc_write_handle.AddressSetupTime = 2; /* 地址建立时间(ADDSET)为2个fsmc_ker_ck=6*2=12ns */ - fsmc_write_handle.DataSetupTime = 2; /* 数据保持时间(DATAST)为2个fsmc_ker_ck=6*2=12ns */ - FSMC_NORSRAM_Extended_Timing_Init(g_sram_handle.Extended, &fsmc_write_handle, g_sram_handle.Init.NSBank, g_sram_handle.Init.ExtendedMode); - } + // /* 初始化完成以后,提速 */ + // if (lcddev.id == 0x7789 || lcddev.id == 0x9341 || lcddev.id == 0x1963) /* 7789/9341/1963 提速 */ + // { + // /* 重新配置写时序控制寄存器的时序 */ + // fsmc_write_handle.AddressSetupTime = 3; /* 地址建立时间(ADDSET)为3个fsmc_ker_ck=6*3=18ns */ + // fsmc_write_handle.DataSetupTime = 3; /* 数据保持时间(DATAST)为3个fsmc_ker_ck=6*3=18ns */ + // FSMC_NORSRAM_Extended_Timing_Init(g_sram_handle.Extended, &fsmc_write_handle, g_sram_handle.Init.NSBank, g_sram_handle.Init.ExtendedMode); + // } + // else if (lcddev.id == 0x5310 || lcddev.id == 0x7796 || lcddev.id == 0x5510 || lcddev.id == 0x9806) /* 如果是这几个IC, 则设置WR时序为最快 */ + // { + // /* 重新配置写时序控制寄存器的时序 */ + // fsmc_write_handle.AddressSetupTime = 2; /* 地址建立时间(ADDSET)为2个fsmc_ker_ck=6*2=12ns */ + // fsmc_write_handle.DataSetupTime = 2; /* 数据保持时间(DATAST)为2个fsmc_ker_ck=6*2=12ns */ + // FSMC_NORSRAM_Extended_Timing_Init(g_sram_handle.Extended, &fsmc_write_handle, g_sram_handle.Init.NSBank, g_sram_handle.Init.ExtendedMode); + // } lcd_display_dir(0); /* 默认为竖屏 */ LCD_BL(1); /* 点亮背光 */ diff --git a/controler/User/LCD/lcd.h b/controler/User/LCD/lcd.h index dd9f2f2..0013240 100644 --- a/controler/User/LCD/lcd.h +++ b/controler/User/LCD/lcd.h @@ -71,8 +71,8 @@ * 修改LCD_FSMC_NEX, 对应的LCD_CS_GPIO相关设置也得改 * 修改LCD_FSMC_AX , 对应的LCD_RS_GPIO相关设置也得改 */ -#define LCD_FSMC_NEX 4 /* 使用FSMC_NE4接LCD_CS,取值范围只能是: 1~4 */ -#define LCD_FSMC_AX 6 /* 使用FSMC_A6接LCD_RS,取值范围是: 0 ~ 25 */ +#define LCD_FSMC_NEX 1 /* 使用FSMC_NE4接LCD_CS,取值范围只能是: 1~4 */ +#define LCD_FSMC_AX 16 /* 使用FSMC_A6接LCD_RS,取值范围是: 0 ~ 25 */ #define LCD_FSMC_BCRX FSMC_Bank1->BTCR[(LCD_FSMC_NEX - 1) * 2] /* BCR寄存器,根据LCD_FSMC_NEX自动计算 */ #define LCD_FSMC_BTRX FSMC_Bank1->BTCR[(LCD_FSMC_NEX - 1) * 2 + 1] /* BTR寄存器,根据LCD_FSMC_NEX自动计算 */ @@ -101,8 +101,8 @@ extern uint32_t g_back_color; /* 背景颜色.默认为白色 */ /* LCD背光控制 */ #define LCD_BL(x) do{ x ? \ - HAL_GPIO_WritePin(LCD_BL_GPIO_PORT, LCD_BL_GPIO_PIN, GPIO_PIN_SET) : \ - HAL_GPIO_WritePin(LCD_BL_GPIO_PORT, LCD_BL_GPIO_PIN, GPIO_PIN_RESET); \ + HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0, GPIO_PIN_SET) : \ + HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0, GPIO_PIN_RESET); \ }while(0) /* LCD地址结构体 */ diff --git a/controler/User/lvgl/examples/porting/lv_port_disp_template.c b/controler/User/lvgl/examples/porting/lv_port_disp_template.c index b60bf0b..1b98507 100755 --- a/controler/User/lvgl/examples/porting/lv_port_disp_template.c +++ b/controler/User/lvgl/examples/porting/lv_port_disp_template.c @@ -18,12 +18,12 @@ *********************/ #ifndef MY_DISP_HOR_RES #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen width, default value 320 is used for now. - #define MY_DISP_HOR_RES 480 + #define MY_DISP_HOR_RES 320 #endif #ifndef MY_DISP_VER_RES #warning Please define or replace the macro MY_DISP_HOR_RES with the actual screen height, default value 240 is used for now. - #define MY_DISP_VER_RES 320 + #define MY_DISP_VER_RES 240 #endif @@ -115,8 +115,8 @@ void lv_port_disp_init(void) // /* Example for 2) */ static lv_disp_draw_buf_t draw_buf_dsc_2; - static lv_color_t buf_2_1[MY_DISP_HOR_RES * 40]; /*A buffer for 10 rows*/ - static lv_color_t buf_2_2[MY_DISP_HOR_RES * 40]; /*An other buffer for 10 rows*/ + static lv_color_t buf_2_1[MY_DISP_HOR_RES * 20]; /*A buffer for 10 rows*/ + static lv_color_t buf_2_2[MY_DISP_HOR_RES * 20]; /*An other buffer for 10 rows*/ lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 40); /*Initialize the display buffer*/ // /* Example for 3) also set disp_drv.full_refresh = 1 below*/ diff --git a/controler/User/lvgl/lv_demos.h b/controler/User/lvgl/lv_demos.h index 46053e1..36a3e13 100755 --- a/controler/User/lvgl/lv_demos.h +++ b/controler/User/lvgl/lv_demos.h @@ -13,10 +13,10 @@ extern "C" { /********************* * INCLUDES *********************/ -#include "../lvgl.h" +#include "lvgl.h" #if LV_USE_DEMO_WIDGETS -#include "widgets/lv_demo_widgets.h" +#include "lvgl/examples/lv_examples.h" #endif #if LV_USE_DEMO_BENCHMARK diff --git a/controler/User/task/config.yaml b/controler/User/task/config.yaml new file mode 100644 index 0000000..ec932fa --- /dev/null +++ b/controler/User/task/config.yaml @@ -0,0 +1,6 @@ +- delay: 0 + description: '' + freq_control: false + function: Task_lvgl + name: lvgl + stack: 1024 diff --git a/controler/User/task/display.c b/controler/User/task/display.c new file mode 100644 index 0000000..358b5b6 --- /dev/null +++ b/controler/User/task/display.c @@ -0,0 +1,49 @@ +/* + lvgl Task + +*/ + +/* Includes ----------------------------------------------------------------- */ +#include "task/user_task.h" +/* USER INCLUDE BEGIN */ +#include "lvgl/lvgl.h" +#include "lvgl/stress/lv_demo_stress.h" +#include "lvgl/examples/porting/lv_port_disp_template.h" +#include "LCD/lcd.h" +/* USER INCLUDE END */ + +/* Private typedef ---------------------------------------------------------- */ +/* Private define ----------------------------------------------------------- */ +/* Private macro ------------------------------------------------------------ */ +/* Private variables -------------------------------------------------------- */ +/* USER STRUCT BEGIN */ + +/* USER STRUCT END */ + +/* Private function --------------------------------------------------------- */ +/* Exported functions ------------------------------------------------------- */ +void Task_lvgl(void *argument) { + (void)argument; /* 未使用argument,消除警告 */ + + lcd_init(); + lv_init(); + + lv_port_disp_init(); + + lv_demo_stress(); + // osDelay(LVGL_INIT_DELAY); /* 延时一段时间再开启任务 */ + + /* USER CODE INIT BEGIN */ + + /* USER CODE INIT END */ + + while (1) { + // lcd_fill(100, 100,200,200,RED); +lv_task_handler(); + // lv_timer_handler(); + /* USER CODE BEGIN */ + + /* USER CODE END */ + } + +} diff --git a/controler/User/task/init.c b/controler/User/task/init.c new file mode 100644 index 0000000..1c0d5ec --- /dev/null +++ b/controler/User/task/init.c @@ -0,0 +1,42 @@ +/* + Init Task + 任务初始化,创建各个线程任务和消息队列 +*/ + +/* Includes ----------------------------------------------------------------- */ +#include "task/user_task.h" + +/* USER INCLUDE BEGIN */ + +/* USER INCLUDE END */ + +/* Private typedef ---------------------------------------------------------- */ +/* Private define ----------------------------------------------------------- */ +/* Private macro ------------------------------------------------------------ */ +/* Private variables -------------------------------------------------------- */ +/* Private function --------------------------------------------------------- */ +/* Exported functions ------------------------------------------------------- */ + +/** + * \brief 初始化 + * + * \param argument 未使用 + */ +void Task_Init(void *argument) { + (void)argument; /* 未使用argument,消除警告 */ + /* USER CODE INIT BEGIN */ + + /* USER CODE INIT END */ + osKernelLock(); /* 锁定内核,防止任务切换 */ + + /* 创建任务线程 */ + task_runtime.thread.lvgl = osThreadNew(Task_lvgl, NULL, &attr_lvgl); + + // 创建消息队列 + /* USER MESSAGE BEGIN */ + task_runtime.msgq.user_msg= osMessageQueueNew(2u, 10, NULL); + /* USER MESSAGE END */ + + osKernelUnlock(); // 解锁内核 + osThreadTerminate(osThreadGetId()); // 任务完成后结束自身 +} \ No newline at end of file diff --git a/controler/User/task/user_task.c b/controler/User/task/user_task.c new file mode 100644 index 0000000..93e0d4f --- /dev/null +++ b/controler/User/task/user_task.c @@ -0,0 +1,16 @@ +#include "task/user_task.h" + +Task_Runtime_t task_runtime; + +const osThreadAttr_t attr_init = { + .name = "Task_Init", + .priority = osPriorityRealtime, + .stack_size = 256 * 4, +}; + +/* User_task */ +const osThreadAttr_t attr_lvgl = { + .name = "lvgl", + .priority = osPriorityNormal, + .stack_size = 1024 * 8, +}; diff --git a/controler/User/task/user_task.h b/controler/User/task/user_task.h new file mode 100644 index 0000000..1b06217 --- /dev/null +++ b/controler/User/task/user_task.h @@ -0,0 +1,80 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif +/* Includes ----------------------------------------------------------------- */ +#include +#include "FreeRTOS.h" +#include "task.h" + +/* USER INCLUDE BEGIN */ + +/* USER INCLUDE END */ +/* Exported constants ------------------------------------------------------- */ +/* 任务运行频率 */ + + +/* 任务初始化延时ms */ +#define TASK_INIT_DELAY (100u) +#define LVGL_INIT_DELAY (0) + +/* Exported defines --------------------------------------------------------- */ +/* Exported macro ----------------------------------------------------------- */ +/* Exported types ----------------------------------------------------------- */ + +/* 任务运行时结构体 */ +typedef struct { + /* 各任务,也可以叫做线程 */ + struct { + osThreadId_t lvgl; + } thread; + + /* USER MESSAGE BEGIN */ + struct { + osMessageQueueId_t user_msg; /* 用户自定义任务消息队列 */ + } msgq; + /* USER MESSAGE END */ + + /* 机器人状态 */ + struct { + float battery; /* 电池电量百分比 */ + float vbat; /* 电池电压 */ + float cpu_temp; /* CPU温度 */ + } status; + + /* USER CONFIG BEGIN */ + + /* USER CONFIG END */ + + /* 各任务的stack使用 */ + struct { + UBaseType_t lvgl; + } stack_water_mark; + + /* 各任务运行频率 */ + struct { + + } freq; + + /* 任务最近运行时间 */ + struct { + + } last_up_time; + +} Task_Runtime_t; + +/* 任务运行时结构体 */ +extern Task_Runtime_t task_runtime; + +/* 初始化任务句柄 */ +extern const osThreadAttr_t attr_init; +extern const osThreadAttr_t attr_lvgl; + +/* 任务函数声明 */ +void Task_Init(void *argument); +void Task_lvgl(void *argument); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/controler/controler.ioc b/controler/controler.ioc index 193d265..d8e39fb 100644 --- a/controler/controler.ioc +++ b/controler/controler.ioc @@ -43,35 +43,36 @@ Mcu.Name=STM32F407V(E-G)Tx Mcu.Package=LQFP100 Mcu.Pin0=PH0-OSC_IN Mcu.Pin1=PH1-OSC_OUT -Mcu.Pin10=PE15 -Mcu.Pin11=PD8 -Mcu.Pin12=PD9 -Mcu.Pin13=PD10 -Mcu.Pin14=PD11 -Mcu.Pin15=PD14 -Mcu.Pin16=PD15 -Mcu.Pin17=PA9 -Mcu.Pin18=PA10 -Mcu.Pin19=PA11 -Mcu.Pin2=PE7 -Mcu.Pin20=PA12 -Mcu.Pin21=PA13 -Mcu.Pin22=PA14 -Mcu.Pin23=PD0 -Mcu.Pin24=PD1 -Mcu.Pin25=PD4 -Mcu.Pin26=PD5 -Mcu.Pin27=PD7 -Mcu.Pin28=VP_FREERTOS_VS_CMSIS_V2 -Mcu.Pin29=VP_SYS_VS_tim14 -Mcu.Pin3=PE8 -Mcu.Pin4=PE9 -Mcu.Pin5=PE10 -Mcu.Pin6=PE11 -Mcu.Pin7=PE12 -Mcu.Pin8=PE13 -Mcu.Pin9=PE14 -Mcu.PinsNb=30 +Mcu.Pin10=PE14 +Mcu.Pin11=PE15 +Mcu.Pin12=PD8 +Mcu.Pin13=PD9 +Mcu.Pin14=PD10 +Mcu.Pin15=PD11 +Mcu.Pin16=PD14 +Mcu.Pin17=PD15 +Mcu.Pin18=PA9 +Mcu.Pin19=PA10 +Mcu.Pin2=PB0 +Mcu.Pin20=PA11 +Mcu.Pin21=PA12 +Mcu.Pin22=PA13 +Mcu.Pin23=PA14 +Mcu.Pin24=PD0 +Mcu.Pin25=PD1 +Mcu.Pin26=PD4 +Mcu.Pin27=PD5 +Mcu.Pin28=PD7 +Mcu.Pin29=VP_FREERTOS_VS_CMSIS_V2 +Mcu.Pin3=PE7 +Mcu.Pin30=VP_SYS_VS_tim14 +Mcu.Pin4=PE8 +Mcu.Pin5=PE9 +Mcu.Pin6=PE10 +Mcu.Pin7=PE11 +Mcu.Pin8=PE12 +Mcu.Pin9=PE13 +Mcu.PinsNb=31 Mcu.ThirdPartyNb=0 Mcu.UserConstants= Mcu.UserName=STM32F407VGTx @@ -80,6 +81,7 @@ MxDb.Version=DB.6.0.150 NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false NVIC.CAN1_RX0_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true NVIC.CAN1_RX1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true +NVIC.DMA2_Stream0_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false NVIC.ForceEnableDMAVector=true NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false @@ -109,6 +111,8 @@ PA14.Mode=Serial_Wire PA14.Signal=SYS_JTCK-SWCLK PA9.Mode=Asynchronous PA9.Signal=USART1_TX +PB0.Locked=true +PB0.Signal=GPIO_Output PD0.Mode=16b-d1 PD0.Signal=FSMC_D2 PD1.Mode=16b-d1 @@ -199,26 +203,26 @@ RCC.EthernetFreq_Value=168000000 RCC.FCLKCortexFreq_Value=168000000 RCC.FamilyName=M RCC.HCLKFreq_Value=168000000 -RCC.HSE_VALUE=25000000 +RCC.HSE_VALUE=8000000 RCC.HSI_VALUE=16000000 -RCC.I2SClocksFreq_Value=96000000 +RCC.I2SClocksFreq_Value=192000000 RCC.IPParameters=48MHZClocksFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2SClocksFreq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLM,PLLN,PLLQCLKFreq_Value,PLLSourceVirtual,RTCFreq_Value,RTCHSEDivFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VcooutputI2S RCC.LSE_VALUE=32768 RCC.LSI_VALUE=32000 RCC.MCO2PinFreq_Value=168000000 RCC.PLLCLKFreq_Value=168000000 -RCC.PLLM=25 -RCC.PLLN=336 +RCC.PLLM=4 +RCC.PLLN=168 RCC.PLLQCLKFreq_Value=84000000 RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE RCC.RTCFreq_Value=32000 -RCC.RTCHSEDivFreq_Value=12500000 +RCC.RTCHSEDivFreq_Value=4000000 RCC.SYSCLKFreq_VALUE=168000000 RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK -RCC.VCOI2SOutputFreq_Value=192000000 -RCC.VCOInputFreq_Value=1000000 +RCC.VCOI2SOutputFreq_Value=384000000 +RCC.VCOInputFreq_Value=2000000 RCC.VCOOutputFreq_Value=336000000 -RCC.VcooutputI2S=96000000 +RCC.VcooutputI2S=192000000 USART1.IPParameters=VirtualMode USART1.VirtualMode=VM_ASYNC VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2 @@ -226,3 +230,4 @@ VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2 VP_SYS_VS_tim14.Mode=TIM14 VP_SYS_VS_tim14.Signal=SYS_VS_tim14 board=custom +rtos.0.ip=FREERTOS diff --git a/engineer/CMakeLists.txt b/engineer/CMakeLists.txt index b14d013..7b92b00 100644 --- a/engineer/CMakeLists.txt +++ b/engineer/CMakeLists.txt @@ -57,6 +57,7 @@ target_sources(${CMAKE_PROJECT_NAME} PRIVATE User/component/kinematics.c User/component/pid.c User/component/user_math.c + ./User/component/mixer.c # User/device sources User/device/motor.c diff --git a/engineer/User/component/component_config.yaml b/engineer/User/component/component_config.yaml index 0d07966..70feb54 100644 --- a/engineer/User/component/component_config.yaml +++ b/engineer/User/component/component_config.yaml @@ -6,6 +6,10 @@ filter: dependencies: - component/ahrs enabled: true +mixer: + dependencies: + - component/user_math.h + enabled: true pid: dependencies: - component/filter diff --git a/engineer/User/component/mixer.c b/engineer/User/component/mixer.c new file mode 100644 index 0000000..554b92e --- /dev/null +++ b/engineer/User/component/mixer.c @@ -0,0 +1,94 @@ +/* + 混合器 +*/ + +#include "mixer.h" + +#include "math.h" + +/** + * @brief 初始化混合器 + * + * @param mixer 混合器 + * @param mode 混合器模式 + * @return int8_t 0对应没有错误 + */ +int8_t Mixer_Init(Mixer_t *mixer, Mixer_Mode_t mode) { + if (mixer == NULL) return -1; + + mixer->mode = mode; + return 0; +} + +/** + * @brief 计算输出 + * + * @param mixer 混合器 + * @param move_vec 运动向量 + * @param out 输出数组 + * @param len 输出数组长短 + * @param scale 输出放大因子 + * @return int8_t 0对应没有错误 + */ +int8_t Mixer_Apply(Mixer_t *mixer, MoveVector_t *move_vec, float *out, + int8_t len, float scale) { + if (mixer == NULL) return -1; + + switch (mixer->mode) { + case MIXER_MECANUM: + if (len == 4) { + out[0] = move_vec->vx - move_vec->vy + move_vec->wz; + out[1] = move_vec->vx + move_vec->vy + move_vec->wz; + out[2] = -move_vec->vx + move_vec->vy + move_vec->wz; + out[3] = -move_vec->vx - move_vec->vy + move_vec->wz; + } else { + goto error; + } + break; + + case MIXER_PARLFIX4: + if (len == 4) { + out[0] = -move_vec->vx; + out[1] = move_vec->vx; + out[2] = move_vec->vx; + out[3] = -move_vec->vx; + } else { + goto error; + } + case MIXER_PARLFIX2: + if (len == 2) { + out[0] = -move_vec->vx; + out[1] = move_vec->vx; + } else { + goto error; + } + case MIXER_SINGLE: + if (len == 1) { + out[0] = move_vec->vx; + } else { + goto error; + } + case MIXER_OMNICROSS: + case MIXER_OMNIPLUS: + goto error; + } + + float abs_max = 0.f; + for (int8_t i = 0; i < len; i++) { + const float abs_val = fabsf(out[i]); + abs_max = (abs_val > abs_max) ? abs_val : abs_max; + } + if (abs_max > 1.f) { + for (int8_t i = 0; i < len; i++) { + out[i] /= abs_max; + } + } + for (int8_t i = 0; i < len; i++) { + out[i] *= scale; + } + return 0; + +error: + for (uint8_t i = 0; i < len; i++) out[i] = 0; + return -1; +} diff --git a/engineer/User/component/mixer.h b/engineer/User/component/mixer.h new file mode 100644 index 0000000..b8e4401 --- /dev/null +++ b/engineer/User/component/mixer.h @@ -0,0 +1,76 @@ +/* + 混合器 +*/ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "user_math.h" + +/* USER INCLUDE BEGIN */ + +/* USER INCLUDE END */ + +/* USER DEFINE BEGIN */ + +/* USER DEFINE END */ + +/** 四轮布局 */ +/* 前 */ +/* 2 1 */ +/* 3 4 */ + +/* 两轮布局 */ +/* 前 */ +/* 2 1 */ + +/* 混合器模式 */ +typedef enum { + MIXER_MECANUM, /* 麦克纳姆轮 */ + MIXER_PARLFIX4, /* 平行四驱动轮 */ + MIXER_PARLFIX2, /* 平行对侧两驱动轮 */ + MIXER_OMNICROSS, /* 叉形全向轮 */ + MIXER_OMNIPLUS, /* 十字全向轮 */ + MIXER_SINGLE, /* 单个摩擦轮 */ +} Mixer_Mode_t; + +typedef struct { + Mixer_Mode_t mode; +} Mixer_t; /* 混合器主结构体 */ + +/* USER STRUCT BEGIN */ + +/* USER STRUCT END */ + +/** + * @brief 初始化混合器 + * + * @param mixer 混合器 + * @param mode 混合器模式 + * @return int8_t 0对应没有错误 + */ +int8_t Mixer_Init(Mixer_t *mixer, Mixer_Mode_t mode); + +/** + * @brief 计算输出 + * + * @param mixer 混合器 + * @param move_vec 运动向量 + * @param out 输出数组 + * @param len 输出数组长短 + * @param scale 输出放大因子 + * @return int8_t 0对应没有错误 + */ +int8_t Mixer_Apply(Mixer_t *mixer, MoveVector_t *move_vec, float *out, + int8_t len, float scale); + +/* USER FUNCTION BEGIN */ + +/* USER FUNCTION END */ + +#ifdef __cplusplus +} +#endif diff --git a/engineer/User/module/chassis.c b/engineer/User/module/chassis.c new file mode 100644 index 0000000..ab030ad --- /dev/null +++ b/engineer/User/module/chassis.c @@ -0,0 +1,418 @@ +/* + * 底盘模组 + */ + +/* Includes ----------------------------------------------------------------- */ +#include "chassis.h" + +#include + +#include "bsp/mm.h" +#include "cmsis_os2.h" +#include "component/limiter.h" +#include "device/can.h" +#include "module/cap.h" + +/* Private typedef ---------------------------------------------------------- */ +/* Private define ----------------------------------------------------------- */ +#define _CAP_PERCENTAGE_WORK 100 /* 底盘不再限制功率的电容电量 */ +#define _CAP_PERCENTAGE_CHARGE 30 /* 电容开始工作的电容电量 */ + +#define CHASSIS_MAX_CAP_POWER 100 /* 电容能够提供的最大功率 */ + +#define CHASSIS_ROTOR_WZ_MIN 0.6f /* 小陀螺旋转位移下界 */ +#define CHASSIS_ROTOR_WZ_MAX 0.8f /* 小陀螺旋转位移上界 */ +#define M_7OVER72PI (M_2PI * 7.0f / 72.0f) /* 三十五度对应弧度值 */ +// #define CHASSIS_ROTOR_OMEGA 0.15f /* 小陀螺转动频率 */ +// 随机产生小陀螺转动频率,范围0.001-0.05 +//#define CHASSIS_ROTOR_OMEGA rand() % 50 / 10000.0f + 0.001f +#define CHASSIS_ROTOR_OMEGA 0.001 +/* Private macro ------------------------------------------------------------ */ + +/* 保证电容电量宏定义在正确范围内 */ +#if ((_CAP_PERCENTAGE_WORK < 0) || (_CAP_PERCENTAGE_WORK > 100) || \ + (_CAP_PERCENTAGE_CHARGE < 0) || (_CAP_PERCENTAGE_CHARGE > 100)) +#error "Cap percentage should be in the range from 0 to 100." +#endif + +/* 保证电容功率宏定义在正确范围内 */ +#if ((CHASSIS_MAX_CAP_POWER < 60) || (CHASSIS_MAX_CAP_POWER > 200)) +#error "The capacitor power should be in in the range from 60 to 200." +#endif + +/* Private variables -------------------------------------------------------- */ + +static const float CAP_PERCENTAGE_WORK = (float)_CAP_PERCENTAGE_WORK / 100.0f; +static const float CAP_PERCENTAGE_CHARGE = + (float)_CAP_PERCENTAGE_CHARGE / 100.0f; + +/* Private function -------------------------------------------------------- */ +/** + * \brief 设置底盘模式 + * + * \param c 包含底盘数据的结构体 + * \param mode 要设置的模式 + * + * \return 函数运行结果 + */ +static int8_t Chassis_SetMode(Chassis_t *c, CMD_ChassisMode_t mode, + uint32_t now) { + if (c == NULL) return CHASSIS_ERR_NULL; /* 主结构体不能为空 */ + if (mode == c->mode) return CHASSIS_OK; /* 模式未改变直接返回 */ + + if (mode == CHASSIS_MODE_ROTOR && c->mode != CHASSIS_MODE_ROTOR) { + srand(now); + c->wz_multi = (rand() % 2) ? -1 : 1; + } + /* 切换模式后重置PID和滤波器 */ + for (uint8_t i = 0; i < c->num_wheel; i++) { + PID_Reset(c->pid.motor + i); + LowPassFilter2p_Reset(c->filter.in + i, 0.0f); + LowPassFilter2p_Reset(c->filter.out + i, 0.0f); + } + c->mode = mode; + + return CHASSIS_OK; +} +/** + * @brief 产生小陀螺wz随机速度 + * + * @param min wz产生最小速度 + * @param max wz产生最大速度 + * @param now ctrl_chassis的tick数 + * @return float + */ +static float Chassis_CalcWz(const float min, const float max, uint32_t now) { + /* wz在min和max之间,上限0.6f */ + float wz_vary = fabs(0.2f * sinf(CHASSIS_ROTOR_OMEGA * (float)now)) + min; + return wz_vary > 0.8f ? max : wz_vary; +} + +/* Exported functions ------------------------------------------------------- */ + +/** + * \brief 初始化底盘 + * + * \param c 包含底盘数据的结构体 + * \param param 包含底盘参数的结构体指针 + * \param target_freq 任务预期的运行频率 + * + * \return 函数运行结果 + */ +int8_t Chassis_Init(Chassis_t *c, const Chassis_Params_t *param, + AHRS_Eulr_t *mech_zero, float target_freq) { + if (c == NULL) return CHASSIS_ERR_NULL; + + c->param = param; /* 初始化参数 */ + c->mode = CHASSIS_MODE_RELAX; /* 设置上电后底盘默认模式 */ + c->mech_zero = mech_zero; /* 设置底盘机械零点 */ + + /* 如果电机反装重新计算机械零点 */ + if (param->reverse.yaw) CircleReverse(&(c->mech_zero->yaw)); + + /* 根据参数(param)中的底盘型号初始化Mixer */ + Mixer_Mode_t mixer_mode; + switch (c->param->type) { + case CHASSIS_TYPE_MECANUM: + c->num_wheel = 4; + mixer_mode = MIXER_MECANUM; + break; + + case CHASSIS_TYPE_PARLFIX4: + c->num_wheel = 4; + mixer_mode = MIXER_PARLFIX4; + break; + + case CHASSIS_TYPE_PARLFIX2: + c->num_wheel = 2; + mixer_mode = MIXER_PARLFIX2; + break; + + case CHASSIS_TYPE_OMNI_CROSS: + c->num_wheel = 4; + mixer_mode = MIXER_OMNICROSS; + break; + + case CHASSIS_TYPE_OMNI_PLUS: + c->num_wheel = 4; + mixer_mode = MIXER_OMNIPLUS; + break; + + case CHASSIS_TYPE_SINGLE: + c->num_wheel = 1; + mixer_mode = MIXER_SINGLE; + break; + + case CHASSIS_TYPE_DRONE: + /* onboard sdk. */ + return CHASSIS_ERR_TYPE; + } + + /* 根据底盘型号动态分配控制时使用的变量 */ + c->feedback.motor_rpm = + BSP_Malloc((size_t)c->num_wheel * sizeof(*c->feedback.motor_rpm)); + if (c->feedback.motor_rpm == NULL) goto error; /* 变量未分配,返回错误 */ + + c->feedback.motor_current = + BSP_Malloc((size_t)c->num_wheel * sizeof(*c->feedback.motor_current)); + if (c->feedback.motor_current == NULL) goto error; + + c->setpoint.motor_rpm = + BSP_Malloc((size_t)c->num_wheel * sizeof(*c->setpoint.motor_rpm)); + if (c->setpoint.motor_rpm == NULL) goto error; + + c->pid.motor = BSP_Malloc((size_t)c->num_wheel * sizeof(*c->pid.motor)); + if (c->pid.motor == NULL) goto error; + + c->out = BSP_Malloc((size_t)c->num_wheel * sizeof(*c->out)); + if (c->out == NULL) goto error; + + c->filter.in = BSP_Malloc((size_t)c->num_wheel * sizeof(*c->filter.in)); + if (c->filter.in == NULL) goto error; + + c->filter.out = BSP_Malloc((size_t)c->num_wheel * sizeof(*c->filter.out)); + if (c->filter.out == NULL) goto error; + + /* 初始化轮子电机控制PID和LPF */ + for (uint8_t i = 0; i < c->num_wheel; i++) { + PID_Init(c->pid.motor + i, KPID_MODE_NO_D, target_freq, + &(c->param->motor_pid_param)); + + LowPassFilter2p_Init(c->filter.in + i, target_freq, + c->param->low_pass_cutoff_freq.in); + LowPassFilter2p_Init(c->filter.out + i, target_freq, + c->param->low_pass_cutoff_freq.out); + } + + /* 初始化跟随云台的控制PID */ + PID_Init(&(c->pid.follow), KPID_MODE_NO_D, target_freq, + &(c->param->follow_pid_param)); + + Mixer_Init(&(c->mixer), mixer_mode); /* 初始化混合器 */ + return CHASSIS_OK; + +error: + /* 动态内存分配错误时,释放已经分配的内存,返回错误值 */ + BSP_Free(c->feedback.motor_rpm); + BSP_Free(c->setpoint.motor_rpm); + BSP_Free(c->pid.motor); + BSP_Free(c->out); + BSP_Free(c->filter.in); + BSP_Free(c->filter.out); + return CHASSIS_ERR_NULL; +} + +/** + * \brief 更新底盘的反馈信息 + * + * \param c 包含底盘数据的结构体 + * \param can CAN设备结构体 + * + * \return 函数运行结果 + */ +int8_t Chassis_UpdateFeedback(Chassis_t *c, const CAN_t *can) { + /* 底盘数据和CAN结构体不能为空 */ + if (c == NULL) return CHASSIS_ERR_NULL; + if (can == NULL) return CHASSIS_ERR_NULL; + + /* 如果电机反装重新计算正确的反馈值 */ + if (c->param->reverse.yaw) { + c->feedback.gimbal_yaw_encoder = + -can->motor.gimbal.named.yaw.rotor_angle + M_2PI; + } else { + c->feedback.gimbal_yaw_encoder = can->motor.gimbal.named.yaw.rotor_angle; + } + + /* 将CAN中的反馈数据写入到feedback中 */ + for (uint8_t i = 0; i < c->num_wheel; i++) { + c->feedback.motor_rpm[i] = can->motor.chassis.as_array[i].rotor_speed; + c->feedback.motor_current[i] = + can->motor.chassis.as_array[i].torque_current; + } + + return CHASSIS_OK; +} + +/** + * \brief 运行底盘控制逻辑 + * + * \param c 包含底盘数据的结构体 + * \param c_cmd 底盘控制指令 + * \param dt_sec 两次调用的时间间隔 + * + * \return 函数运行结果 + */ +int8_t Chassis_Control(Chassis_t *c, const CMD_ChassisCmd_t *c_cmd, + uint32_t now) { + /* 底盘数据和控制指令结构体不能为空 */ + if (c == NULL) return CHASSIS_ERR_NULL; + if (c_cmd == NULL) return CHASSIS_ERR_NULL; + + c->dt = (float)(now - c->lask_wakeup) / 1000.0f; + c->lask_wakeup = now; + + /* 根据遥控器命令更改底盘模式 */ + Chassis_SetMode(c, c_cmd->mode, now); + + /* ctrl_vec -> move_vec 控制向量和真实的移动向量之间有一个换算关系 */ + /* 计算vx、vy */ + switch (c->mode) { + case CHASSIS_MODE_BREAK: /* 刹车模式电机停止 */ + c->move_vec.vx = 0.0f; + c->move_vec.vy = 0.0f; + break; + + case CHASSIS_MODE_INDENPENDENT: /* 独立模式控制向量与运动向量相等 */ + c->move_vec.vx = c_cmd->ctrl_vec.vx; + c->move_vec.vy = c_cmd->ctrl_vec.vx; + break; + + case CHASSIS_MODE_OPEN: + case CHASSIS_MODE_RELAX: + case CHASSIS_MODE_FOLLOW_GIMBAL: /* 按照云台方向换算运动向量 */ + case CHASSIS_MODE_FOLLOW_GIMBAL_35: + case CHASSIS_MODE_ROTOR: { + float beta = c->feedback.gimbal_yaw_encoder - c->mech_zero->yaw; + float cos_beta = cosf(beta); + float sin_beta = sinf(beta); + c->move_vec.vx = + cos_beta * c_cmd->ctrl_vec.vx - sin_beta * c_cmd->ctrl_vec.vy; + c->move_vec.vy = + sin_beta * c_cmd->ctrl_vec.vx + cos_beta * c_cmd->ctrl_vec.vy; + } + } + + /* 计算wz */ + switch (c->mode) { + case CHASSIS_MODE_RELAX: + case CHASSIS_MODE_BREAK: + case CHASSIS_MODE_INDENPENDENT: /* 独立模式wz为0 */ + c->move_vec.wz = 0.0f; + break; + + case CHASSIS_MODE_OPEN: + case CHASSIS_MODE_FOLLOW_GIMBAL: /* 跟随模式通过PID控制使车头跟随云台 */ + c->move_vec.wz = PID_Calc(&(c->pid.follow), c->mech_zero->yaw, + c->feedback.gimbal_yaw_encoder, 0.0f, c->dt); + break; + case CHASSIS_MODE_FOLLOW_GIMBAL_35: + c->move_vec.wz = + PID_Calc(&(c->pid.follow), c->mech_zero->yaw + M_7OVER72PI, + c->feedback.gimbal_yaw_encoder, 0.0f, c->dt); + break; + case CHASSIS_MODE_ROTOR: { /* 小陀螺模式使底盘以一定速度旋转 */ + c->move_vec.wz = c->wz_multi * Chassis_CalcWz(CHASSIS_ROTOR_WZ_MIN, + CHASSIS_ROTOR_WZ_MAX, now); + } + } + + /* move_vec -> motor_rpm_set. 通过运动向量计算轮子转速目标值 */ + Mixer_Apply(&(c->mixer), &(c->move_vec), c->setpoint.motor_rpm, c->num_wheel, + 7000.0f); + + /* 根据轮子转速目标值,利用PID计算电机输出值 */ + for (uint8_t i = 0; i < c->num_wheel; i++) { + /* 输入滤波. */ + c->feedback.motor_rpm[i] = + LowPassFilter2p_Apply(c->filter.in + i, c->feedback.motor_rpm[i]); + + /* 根据底盘模式计算输出值 */ + switch (c->mode) { + case CHASSIS_MODE_BREAK: + case CHASSIS_MODE_FOLLOW_GIMBAL: + case CHASSIS_MODE_FOLLOW_GIMBAL_35: + case CHASSIS_MODE_ROTOR: + case CHASSIS_MODE_INDENPENDENT: /* 独立模式,受PID控制 */ + c->out[i] = PID_Calc(c->pid.motor + i, c->setpoint.motor_rpm[i], + c->feedback.motor_rpm[i], 0.0f, c->dt); + break; + + case CHASSIS_MODE_OPEN: /* 开环模式,不受PID控制 */ + c->out[i] = c->setpoint.motor_rpm[i] / 9000.0f; + break; + + case CHASSIS_MODE_RELAX: /* 放松模式,不输出 */ + c->out[i] = 0; + break; + } + /* 输出滤波. */ + c->out[i] = LowPassFilter2p_Apply(c->filter.out + i, c->out[i]); + } + + return CHASSIS_OK; +} + +/** + * @brief 底盘功率限制 + * + * @param c 底盘数据 + * @param cap 电容数据 + * @param ref 裁判系统数据 + * @return 函数运行结果 + */ +int8_t Chassis_PowerLimit(Chassis_t *c, const CAN_Capacitor_t *cap, + const Referee_ForChassis_t *ref) { + float power_limit = 0.0f; + if (ref->ref_status != REF_STATUS_RUNNING) { + /* 裁判系统离线,将功率限制为固定值 */ + power_limit = CHASSIS_POWER_MAX_WITHOUT_REF; + } else { + if (cap->cap_status == CAN_CAP_STATUS_RUNNING && + cap->percentage > CAP_PERCENTAGE_CHARGE) { + /* 电容在线且电量足够,使用电容 */ + if (cap->percentage > CAP_PERCENTAGE_WORK) { + /* 电容接近充满时不再限制功率 */ + power_limit = -1.0f; + } else { + /* 按照电容能量百分比计算输出功率 */ + power_limit = ref->chassis_power_limit + + (cap->percentage - CAP_PERCENTAGE_CHARGE) / + (CAP_PERCENTAGE_WORK - CAP_PERCENTAGE_CHARGE) * + (float)CHASSIS_MAX_CAP_POWER; + } + } else { + /* 电容不在工作,根据缓冲能量计算输出功率限制 */ + power_limit = PowerLimit_TargetPower(ref->chassis_power_limit, + ref->chassis_pwr_buff); + } + } + /* 应用功率限制 */ + PowerLimit_ChassicOutput(power_limit, c->out, c->feedback.motor_rpm, + c->num_wheel); + + return CHASSIS_OK; +} + +/** + * \brief 复制底盘输出值 + * + * \param s 包含底盘数据的结构体 + * \param out CAN设备底盘输出结构体 + */ +void Chassis_DumpOutput(Chassis_t *c, CAN_ChassisOutput_t *out) { + for (uint8_t i = 0; i < c->num_wheel; i++) { + out->as_array[i] = c->out[i]; + } +} + +/** + * \brief 清空Chassis输出数据 + * + * \param out CAN设备底盘输出结构体 + */ +void Chassis_ResetOutput(CAN_ChassisOutput_t *out) { + for (uint8_t i = 0; i < 4; i++) { + out->as_array[i] = 0.0f; + } +} + +/** + * @brief 导出底盘数据 + * + * @param chassis 底盘数据结构体 + * @param ui UI数据结构体 + */ +void Chassis_DumpUI(const Chassis_t *c, Referee_ChassisUI_t *ui) { + ui->mode = c->mode; + ui->angle = c->feedback.gimbal_yaw_encoder - c->mech_zero->yaw; +} diff --git a/engineer/User/module/chassis.h b/engineer/User/module/chassis.h new file mode 100644 index 0000000..ad991cd --- /dev/null +++ b/engineer/User/module/chassis.h @@ -0,0 +1,179 @@ +/* + * 底盘模组 + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ----------------------------------------------------------------- */ +#include "component/filter.h" +#include "component/mixer.h" +#include "component/pid.h" +#include "bsp/can.h" +#include "device/referee.h" + +/* Exported constants ------------------------------------------------------- */ +#define CHASSIS_OK (0) /* 运行正常 */ +#define CHASSIS_ERR (-1) /* 运行时发现了其他错误 */ +#define CHASSIS_ERR_NULL (-2) /* 运行时发现NULL指针 */ +#define CHASSIS_ERR_MODE (-3) /* 运行时配置了错误的CMD_ChassisMode_t */ +#define CHASSIS_ERR_TYPE (-4) /* 运行时配置了错误的Chassis_Type_t */ + +/* Exported macro ----------------------------------------------------------- */ +/* Exported types ----------------------------------------------------------- */ + +/* 底盘类型(底盘的物理设计) */ +typedef enum { + CHASSIS_TYPE_MECANUM, /* 麦克纳姆轮 */ + CHASSIS_TYPE_PARLFIX4, /* 平行摆设的四个驱动轮 */ + CHASSIS_TYPE_PARLFIX2, /* 平行摆设的两个驱动轮 */ + CHASSIS_TYPE_OMNI_CROSS, /* 叉型摆设的四个全向轮 */ + CHASSIS_TYPE_OMNI_PLUS, /* 十字型摆设的四个全向轮 */ + CHASSIS_TYPE_DRONE, /* 底盘为无人机 */ + CHASSIS_TYPE_SINGLE, /* 单个摩擦轮 */ +} Chassis_Type_t; + +/* 底盘参数的结构体,包含所有初始化用的参数,通常是const,存好几组 */ +typedef struct { + Chassis_Type_t type; /* 底盘类型,底盘的机械设计和轮子选型 */ + KPID_Params_t motor_pid_param; /* 轮子控制PID的参数 */ + KPID_Params_t follow_pid_param; /* 跟随云台PID的参数 */ + + /* 低通滤波器截止频率 */ + struct { + float in; /* 输入 */ + float out; /* 输出 */ + } low_pass_cutoff_freq; + + /* 电机反装 应该和云台设置相同*/ + struct { + bool yaw; + } reverse; + +} Chassis_Params_t; + +/* + * 运行的主结构体,所有这个文件里的函数都在操作这个结构体 + * 包含了初始化参数,中间变量,输出变量 + */ +typedef struct { + uint32_t lask_wakeup; + float dt; + + const Chassis_Params_t *param; /* 底盘的参数,用Chassis_Init设定 */ + AHRS_Eulr_t *mech_zero; + + /* 模块通用 */ + CMD_ChassisMode_t mode; /* 底盘模式 */ + + /* 底盘设计 */ + int8_t num_wheel; /* 底盘轮子数量 */ + Mixer_t mixer; /* 混合器,移动向量->电机目标值 */ + + MoveVector_t move_vec; /* 底盘实际的运动向量 */ + + /* 反馈信息 */ + struct { + float gimbal_yaw_encoder; /* 云台Yaw轴编码器角度 */ + float *motor_rpm; /* 电机转速的动态数组,单位:RPM */ + float *motor_current; /* 转矩电流 单位:A */ + } feedback; + + float wz_multi; /* 小陀螺模式旋转方向 */ + + /* PID计算的目标值 */ + struct { + float *motor_rpm; /* 电机转速的动态数组,单位:RPM */ + } setpoint; + + /* 反馈控制用的PID */ + struct { + KPID_t *motor; /* 控制轮子电机用的PID的动态数组 */ + KPID_t follow; /* 跟随云台用的PID */ + } pid; + + /* 滤波器 */ + struct { + LowPassFilter2p_t *in; /* 反馈值滤波器 */ + LowPassFilter2p_t *out; /* 输出值滤波器 */ + } filter; + + float *out; /* 电机最终的输出值的动态数组 */ +} Chassis_t; + +/* Exported functions prototypes -------------------------------------------- */ + +/** + * \brief 初始化底盘 + * + * \param c 包含底盘数据的结构体 + * \param param 包含底盘参数的结构体指针 + * \param target_freq 任务预期的运行频率 + * + * \return 函数运行结果 + */ +int8_t Chassis_Init(Chassis_t *c, const Chassis_Params_t *param, + AHRS_Eulr_t *mech_zero, float target_freq); + +/** + * \brief 更新底盘的反馈信息 + * + * \param c 包含底盘数据的结构体 + * \param can CAN设备结构体 + * + * \return 函数运行结果 + */ +int8_t Chassis_UpdateFeedback(Chassis_t *c, const CAN_t *can); + +/** + * \brief 运行底盘控制逻辑 + * + * \param c 包含底盘数据的结构体 + * \param c_cmd 底盘控制指令 + * \param dt_sec 两次调用的时间间隔 + * + * \return 函数运行结果 + */ +int8_t Chassis_Control(Chassis_t *c, const CMD_ChassisCmd_t *c_cmd, + uint32_t now); + +/** + * @brief 底盘功率限制 + * + * @param c 底盘数据 + * @param cap 电容数据 + * @param ref 裁判系统数据 + * @return 函数运行结果 + */ +int8_t Chassis_PowerLimit(Chassis_t *c, const CAN_Capacitor_t *cap, + const Referee_ForChassis_t *ref); + +/** + * \brief 复制底盘输出值 + * + * \param s 包含底盘数据的结构体 + * \param out CAN设备底盘输出结构体 + */ +void Chassis_DumpOutput(Chassis_t *c, CAN_ChassisOutput_t *out); + +/** + * \brief 清空Chassis输出数据 + * + * \param out CAN设备底盘输出结构体 + */ +void Chassis_ResetOutput(CAN_ChassisOutput_t *out); + +/** + * @brief 导出底盘数据 + * + * @param chassis 底盘数据结构体 + * @param ui UI数据结构体 + */ +void Chassis_DumpUI(const Chassis_t *c, Referee_ChassisUI_t *ui); + +#ifdef __cplusplus +} +#endif diff --git a/engineer/User/task/config.yaml b/engineer/User/task/config.yaml index dfde961..91a568f 100644 --- a/engineer/User/task/config.yaml +++ b/engineer/User/task/config.yaml @@ -5,3 +5,9 @@ function: Task_control name: control stack: 1024 +- delay: 0 + description: '' + freq_control: false + function: Task_display + name: display + stack: 1024 diff --git a/engineer/User/task/control.c b/engineer/User/task/control.c index 7d5ff20..3121532 100644 --- a/engineer/User/task/control.c +++ b/engineer/User/task/control.c @@ -1,12 +1,9 @@ /* control Task - + */ /* Includes ----------------------------------------------------------------- */ -#include "component/filter.h" -#include "component/pid.h" -#include "device/motor_dm.h" #include "task/user_task.h" /* USER INCLUDE BEGIN */ #include "component/kinematics.h" @@ -99,39 +96,20 @@ MOTOR_LZ_t* a; void Task_control(void *argument) { (void)argument; /* 未使用argument,消除警告 */ + /* 计算任务运行到指定频率需要等待的tick数 */ const uint32_t delay_tick = osKernelGetTickFreq() / CONTROL_FREQ; osDelay(CONTROL_INIT_DELAY); /* 延时一段时间再开启任务 */ - BSP_CAN_Init(); - MOTOR_LZ_Init(); - MOTOR_LZ_Register(&lzmotor.param); -MOTOR_LZ_Enable(&lzmotor.param); -a = MOTOR_LZ_GetMotor(&lzmotor.param); - // MOTOR_DM_Register(&motor.param); - // MOTOR_DM_Enable(&motor.param); - // PID_Init(&pid, KPID_MODE_SET_D, 1000, &pid_pram); - // LowPassFilter2p_Init(&filter, 1000, 20); - // LPF_Init(&ff, 1, 5); - // - // motor_out.angle = tp; - // motor_out.velocity = 0; - // motor_out.kp = 0; - // motor_out.kd = 0; - // motor_out.torque = 0; - // float sp = 0; - - robot_init(&hand, LINK, T_mat, mat_pdata, 5); - fkine(&hand); uint32_t tick = osKernelGetTickCount(); /* 控制任务运行频率的计时 */ - /* USER CODE INIT BEGIN * + /* USER CODE INIT BEGIN */ /* USER CODE INIT END */ - + while (1) { tick += delay_tick; /* 计算下一个唤醒时刻 */ - /* USER CODE BEGIN */ + /* USER CODE BEGIN */ // MOTOR_LZ_UpdateAll(); MOTOR_LZ_Update(&lzmotor.param); @@ -151,4 +129,5 @@ a = MOTOR_LZ_GetMotor(&lzmotor.param); /* USER CODE END */ osDelayUntil(tick); /* 运行结束,等待下一次唤醒 */ } -} + +} \ No newline at end of file diff --git a/engineer/User/task/display.c b/engineer/User/task/display.c new file mode 100644 index 0000000..7debeac --- /dev/null +++ b/engineer/User/task/display.c @@ -0,0 +1,38 @@ +/* + display Task + +*/ + +/* Includes ----------------------------------------------------------------- */ +#include "task/user_task.h" +/* USER INCLUDE BEGIN */ + +/* USER INCLUDE END */ + +/* Private typedef ---------------------------------------------------------- */ +/* Private define ----------------------------------------------------------- */ +/* Private macro ------------------------------------------------------------ */ +/* Private variables -------------------------------------------------------- */ +/* USER STRUCT BEGIN */ + +/* USER STRUCT END */ + +/* Private function --------------------------------------------------------- */ +/* Exported functions ------------------------------------------------------- */ +void Task_display(void *argument) { + (void)argument; /* 未使用argument,消除警告 */ + + + osDelay(DISPLAY_INIT_DELAY); /* 延时一段时间再开启任务 */ + + /* USER CODE INIT BEGIN */ + + /* USER CODE INIT END */ + + while (1) { + /* USER CODE BEGIN */ + + /* USER CODE END */ + } + +} \ No newline at end of file diff --git a/engineer/User/task/init.c b/engineer/User/task/init.c index 7f27372..9028559 100644 --- a/engineer/User/task/init.c +++ b/engineer/User/task/init.c @@ -31,6 +31,7 @@ void Task_Init(void *argument) { /* 创建任务线程 */ task_runtime.thread.control = osThreadNew(Task_control, NULL, &attr_control); + task_runtime.thread.display = osThreadNew(Task_display, NULL, &attr_display); // 创建消息队列 /* USER MESSAGE BEGIN */ diff --git a/engineer/User/task/user_task.c b/engineer/User/task/user_task.c index 74ab41d..31b8cfd 100644 --- a/engineer/User/task/user_task.c +++ b/engineer/User/task/user_task.c @@ -13,4 +13,9 @@ const osThreadAttr_t attr_control = { .name = "control", .priority = osPriorityNormal, .stack_size = 1024 * 4, +}; +const osThreadAttr_t attr_display = { + .name = "display", + .priority = osPriorityNormal, + .stack_size = 1024 * 4, }; \ No newline at end of file diff --git a/engineer/User/task/user_task.h b/engineer/User/task/user_task.h index 49b10c0..62fe86e 100644 --- a/engineer/User/task/user_task.h +++ b/engineer/User/task/user_task.h @@ -18,6 +18,7 @@ extern "C" { /* 任务初始化延时ms */ #define TASK_INIT_DELAY (100u) #define CONTROL_INIT_DELAY (0) +#define DISPLAY_INIT_DELAY (0) /* Exported defines --------------------------------------------------------- */ /* Exported macro ----------------------------------------------------------- */ @@ -28,6 +29,7 @@ typedef struct { /* 各任务,也可以叫做线程 */ struct { osThreadId_t control; + osThreadId_t display; } thread; /* USER MESSAGE BEGIN */ @@ -50,6 +52,7 @@ typedef struct { /* 各任务的stack使用 */ struct { UBaseType_t control; + UBaseType_t display; } stack_water_mark; /* 各任务运行频率 */ @@ -70,10 +73,12 @@ extern Task_Runtime_t task_runtime; /* 初始化任务句柄 */ extern const osThreadAttr_t attr_init; extern const osThreadAttr_t attr_control; +extern const osThreadAttr_t attr_display; /* 任务函数声明 */ void Task_Init(void *argument); void Task_control(void *argument); +void Task_display(void *argument); #ifdef __cplusplus }