本篇在上篇的基础上,进行实时操作系统移植,所使用到的系统是FreeRTOS v10.3.0,系统源码与测试代码都将以附件形式在文末分享。
由于我一直使用v10.3.0版本的系统,因此就不在git上下载最新的系统了,这个版本的系统我已经在多个产品上使用过了,稳定性与可靠性都不错。本篇只说系统如何使用。
首先添加源码文件到工程,如下图。除FreeRTOSConfig.h文件外,其余文件都是官方文件,不要自己更改其中的内容。FreeRTOSConfig.h这个文件是非常重要的,是用于剪裁FreeRTOS这个系统的,比如是否使用信号量、是否使用软件定时器等。
其次,还有一个重要文件为port.c,这个文件根据内核或编译平台的不同,要选择不同的文件,我们这里使用ARM_CM4F文件夹下的port.c,如图所示。
在添加完相关文件后,我们需要添加头文件路径,如下图。
由于HC32F4A0的svc中断和pendsv中断本身没有函数写好,都需要我们自己去实现,而FreeRTOS是需要接管这两个函数的,所以我们就不需要创建也不需要删除相关内容。但是,我们需要实现Systick_Handler函数,因为之前我们使用过精确定时,所以,我们将这个函数放在delay.c中,像ST或GD单片机,一般都放在stm(gd)32f4xx_it.c中。Systick_Handler函数实现如下。在delay.c中,还需要包含相关FreeRTOS的头文件,我们新建了一个os_inclusdes.h的头文件,包含了所有操作系统相关的头文件,其内容有#include "FreeRTOS.h"、#include "task.h"、#include "queue.h"、#include "timers.h"、#include "semphr.h"。
/**************************************************************
* [url=home.php?mod=space&uid=32621]@name[/url] SysTick_Handler
* [url=home.php?mod=space&uid=159083]@brief[/url] * @param None
* @retval
* [url=home.php?mod=space&uid=1315547]@author[/url] Zachary
* [url=home.php?mod=space&uid=34591]@data[/url] 2023-02-13
**************************************************************/
extern void xPortSysTickHandler( void );
void SysTick_Handler( void )
{
uint32_t ulReturn;
if ( xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED ) /* ---任务调度已开启--- */
{
ulReturn = taskENTER_CRITICAL_FROM_ISR();
xPortSysTickHandler();
taskEXIT_CRITICAL_FROM_ISR( ulReturn );
}
}
接着我们编写多任务函数,我们一共创建3个任务来测试操作系统是否一直成功,分别是static void xTaskStart( void *pvParameters )开始任务、static void xTask1( void *pvParameters )任务1和static void xTask2( void *pvParameters )任务2。
首先,需要创建任务句柄,任务句柄每个任务都是唯一的,任务的创建、挂起、删除等操作,都需要任务句柄。有了任务句柄,就可以使用xTaskCreate函数创建任务了。下面是我们在main.c中创建的任务。任务创建函数的说明均以注释的形式,进行说明。开始任务中创建了任务1与任务2,开始任务本身优先级为最低0,任务内容为控制LED1每500ms闪烁一次;任务1优先级为1,任务内容是控制LCD液晶屏刷屏;任务2优先级最高,任务内容是控制LED2每250ms闪烁一次。
static TaskHandle_t xTaskHandleStart = NULL; /* ---任务句柄--- */
static TaskHandle_t xTaskHandleTask1 = NULL;
static TaskHandle_t xTaskHandleTask2 = NULL;
static void xTaskStart( void *pvParameters ); /* ---任务函数--- */
static void xTask1( void *pvParameters );
static void xTask2( void *pvParameters );
/**************************************************************
* @Name StartTaskCreate
* @brief 创建开始任务
* @param None
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
void StartTaskCreate( void )
{
xTaskCreate( xTaskStart, /* ---任务函数--- */
"xTaskStart", /* ---任务名称--- */
1024, /* ---任务堆栈--- */
NULL, /* ---传入参数--- */
0, /* ---任务优先级--- */
&xTaskHandleStart ); /* ---任务句柄--- */
}
/**************************************************************
* @Name xTaskStart
* @brief
* @param pvParameters: [输入/出]
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
static void xTaskStart( void *pvParameters )
{
xTaskCreate( xTask1, /* ---任务函数--- */
"xTask1", /* ---任务名称--- */
512, /* ---任务堆栈--- */
NULL, /* ---传入参数--- */
1, /* ---任务优先级--- */
&xTaskHandleTask1 ); /* ---任务句柄--- */
xTaskCreate( xTask2, /* ---任务函数--- */
"xTask2", /* ---任务名称--- */
512, /* ---任务堆栈--- */
NULL, /* ---传入参数--- */
2, /* ---任务优先级--- */
&xTaskHandleTask2 ); /* ---任务句柄--- */
for( ;; )
{
TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN6, TCA9539_PIN_SET );
vTaskDelay( 500 );
TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN6, TCA9539_PIN_RESET );
vTaskDelay( 500 );
}
}
/**************************************************************
* @Name xTask1
* @brief
* @param pvParameters: [输入/出]
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
static void xTask1( void *pvParameters )
{
for( ;; )
{
LCD_Clear( RED );
vTaskDelay( 200 );
LCD_Clear( GREEN );
vTaskDelay( 200 );
LCD_Clear( BLACK );
vTaskDelay( 200 );
LCD_Clear( BLUE );
vTaskDelay( 200 );
LCD_Clear( YELLOW );
vTaskDelay( 200 );
LCD_Clear( MAGENTA );
vTaskDelay( 200 );
LCD_Draw_Circle( 200, 200, 100, BLACK );
LCD_ShowString( 300, 300, lcddev.width, lcddev.height, 24, ( uint8_t * )"hello world", BLACK, MAGENTA );
vTaskDelay( 1000 );
}
}
/**************************************************************
* @Name xTask2
* @brief
* @param pvParameters: [输入/出]
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
static void xTask2( void *pvParameters )
{
for( ;; )
{
TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_PIN_SET );
vTaskDelay( 250 );
TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_PIN_RESET );
vTaskDelay( 250 );
}
}
下面是main.c中的内容:
/**
************************************* Copyright ******************************
*
* (C) Copyright 2022,Zachary ,HPU, China.
* All Rights Reserved
*
* FileName : main.c
* Version : v1.0
* Author : Zachary
* Date : 2023-02-13
* Description: This is a template project of HC32F4A0
---Zachary,in Zhejiang Hanpu.
******************************************************************************
*/
/* Includes --------------------------------------------------------------*/
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "os_includes.h"
#include "bsp_Gpio.h"
#include "bsp_TCA9539.h"
#include "bsp_NT35510.h"
#include "bsp_XPT2046.h"
#include "bsp_AT24Cxx.h"
/* --- Typedef -----------------------------------------------------------*/
/* --- Define ------------------------------------------------------------*/
/* --- Macro -------------------------------------------------------------*/
/* --- Variables ---------------------------------------------------------*/
stc_clock_freq_t sysclk;
uint8_t Reg = 0x20;
uint8_t ReadBuf[8];
uint8_t WriteBuf[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
char DispBuf1[50], DispBuf2[50];
static TaskHandle_t xTaskHandleStart = NULL;
static TaskHandle_t xTaskHandleTask1 = NULL;
static TaskHandle_t xTaskHandleTask2 = NULL;
/* --- Functions ---------------------------------------------------------*/
static void SysInit( void );
static void bsp_SetSysClk( void );
static void LCD_Test( void );
static void xTaskStart( void *pvParameters );
static void xTask1( void *pvParameters );
static void xTask2( void *pvParameters );
/*------------------------------------------------------------------------*/
/**************************************************************
* @Name Load_Drow_Dialog
* @brief
* @param None
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
void Load_Drow_Dialog( void )
{
LCD_Clear( WHITE );//清屏
LCD_ShowString( lcddev.width - 24, 0, lcddev.width, lcddev.height, 16, ( uint8_t * )"RST", BLACK, WHITE ); //显示清屏区域
}
/**************************************************************
* @Name rtp_test
* @brief 电阻触摸屏测试函数
* @param None
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
void rtp_test( void )
{
Load_Drow_Dialog();
while( 1 )
{
tp_dev.scan( 0 );
if( tp_dev.sta & TP_PRES_DOWN ) //触摸屏被按下
{
if( tp_dev.x[0] < lcddev.width && tp_dev.y[0] < lcddev.height )
{
if( tp_dev.x[0] > ( lcddev.width - 24 ) && tp_dev.y[0] < 16 )
Load_Drow_Dialog();//清除
else
TP_Draw_Big_Point( tp_dev.x[0], tp_dev.y[0], RED ); //画图
}
}
else
delay_ms( 1 ); //没有按键按下的时候
}
}
/**************************************************************
* @Name xTask1
* @brief
* @param pvParameters: [输入/出]
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
static void xTask1( void *pvParameters )
{
for( ;; )
{
LCD_Clear( RED );
vTaskDelay( 200 );
LCD_Clear( GREEN );
vTaskDelay( 200 );
LCD_Clear( BLACK );
vTaskDelay( 200 );
LCD_Clear( BLUE );
vTaskDelay( 200 );
LCD_Clear( YELLOW );
vTaskDelay( 200 );
LCD_Clear( MAGENTA );
vTaskDelay( 200 );
LCD_Draw_Circle( 200, 200, 100, BLACK );
LCD_ShowString( 300, 300, lcddev.width, lcddev.height, 24, ( uint8_t * )"hello world", BLACK, MAGENTA );
vTaskDelay( 1000 );
}
}
/**************************************************************
* @Name xTask2
* @brief
* @param pvParameters: [输入/出]
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
static void xTask2( void *pvParameters )
{
for( ;; )
{
TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_PIN_SET );
vTaskDelay( 250 );
TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_PIN_RESET );
vTaskDelay( 250 );
}
}
/**************************************************************
* @Name xTaskStart
* @brief
* @param pvParameters: [输入/出]
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
static void xTaskStart( void *pvParameters )
{
xTaskCreate( xTask1, /* ---任务函数--- */
"xTask1", /* ---任务名称--- */
512, /* ---任务堆栈--- */
NULL, /* ---传入参数--- */
1, /* ---任务优先级--- */
&xTaskHandleTask1 ); /* ---任务句柄--- */
xTaskCreate( xTask2, /* ---任务函数--- */
"xTask2", /* ---任务名称--- */
512, /* ---任务堆栈--- */
NULL, /* ---传入参数--- */
2, /* ---任务优先级--- */
&xTaskHandleTask2 ); /* ---任务句柄--- */
for( ;; )
{
TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN6, TCA9539_PIN_SET );
vTaskDelay( 500 );
TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN6, TCA9539_PIN_RESET );
vTaskDelay( 500 );
}
}
/**************************************************************
* @Name StartTaskCreate
* @brief 创建开始任务
* @param None
* @retval
* @author Zachary
* @Data 2023-03-23
**************************************************************/
void StartTaskCreate( void )
{
xTaskCreate( xTaskStart, /* ---任务函数--- */
"xTaskStart", /* ---任务名称--- */
1024, /* ---任务堆栈--- */
NULL, /* ---传入参数--- */
0, /* ---任务优先级--- */
&xTaskHandleStart ); /* ---任务句柄--- */
}
/**************************************************************
* @Name main
* @brief
* @param None
* @retval
* @author Zachary
* @Data 2023-03-22
**************************************************************/
int32_t main( void )
{
SysInit();
// sprintf( DispBuf1, "WirteBuf:%d,%d,%d,%d,%d,%d,%d,%d", WriteBuf[0], WriteBuf[1], \
// WriteBuf[2], WriteBuf[3], WriteBuf[4], WriteBuf[5], WriteBuf[6], WriteBuf[7] );
// LCD_ShowString( 10, 500, lcddev.width, lcddev.height, 24, ( uint8_t *)DispBuf1, WHITE, BLACK );
// AT24Cxx_I2C_Write( AT24Cxx_Addr, &Reg, 0x01, WriteBuf, 0x08 );
// delay_ms( 10 );
// AT24Cxx_I2C_Read( AT24Cxx_Addr, &Reg, 0x01, ReadBuf, 0x08 );
// sprintf( DispBuf2, "ReadBuf:%d,%d,%d,%d,%d,%d,%d,%d", ReadBuf[0], ReadBuf[1], \
// ReadBuf[2], ReadBuf[3], ReadBuf[4], ReadBuf[5], ReadBuf[6], ReadBuf[7] );
// LCD_ShowString( 10, 550, lcddev.width, lcddev.height, 24, ( uint8_t *)DispBuf2, WHITE, BLACK );
// delay_ms( 1000 );
// rtp_test();
StartTaskCreate();
vTaskStartScheduler();
while( 1 )
{
// LED10_TOGGLE();
// LED11_TOGGLE();
// TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_PIN_SET );
// delay_ms( 500 );
// TCA9539_WritePin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_PIN_RESET );
// delay_ms( 500 );
}
}
/**************************************************************
* @Name SysInit
* @brief
* @param None
* @retval
* @author Zachary
* @Data 2023-02-13
**************************************************************/
static void SysInit( void )
{
bsp_SetSysClk();
CLK_GetClockFreq( &sysclk ); /* ---检查时钟是否正确--- */
delay_init( 240 ); /* ---系统滴答定时器初始化--- */
bsp_Gpio_Init(); /* ---初始化Gpio--- */
bsp_TCA9539_Init();
// TCA9539_ConfigPin( TCA9539_IO_PORT1, TCA9539_IO_PIN5, TCA9539_DIR_OUT );
TCA9539_ConfigPin( TCA9539_IO_PORT1, TCA9539_IO_PIN6, TCA9539_DIR_OUT );
TCA9539_ConfigPin( TCA9539_IO_PORT1, TCA9539_IO_PIN7, TCA9539_DIR_OUT );
bsp_NT35510_Init();
// LCD_Test();
bsp_XPT2046_Init();
}
/**************************************************************
* @Name LCD_Test
* @brief
* @param None
* @retval
* @author Zachary
* @Data 2023-03-04
**************************************************************/
static void LCD_Test( void )
{
LCD_Clear( RED );
delay_ms( 500 );
LCD_Clear( GREEN );
delay_ms( 500 );
LCD_Clear( BLACK );
delay_ms( 500 );
LCD_Clear( BLUE );
delay_ms( 500 );
LCD_Clear( YELLOW );
delay_ms( 500 );
LCD_Clear( MAGENTA );
delay_ms( 500 );
LCD_Draw_Circle( 200, 200, 100, BLACK );
LCD_ShowString( 300, 300, lcddev.width, lcddev.height, 24, ( uint8_t * )"hello world", BLACK, MAGENTA );
}
/**************************************************************
* @Name SetSysClk
* @brief 参考自官方工程
* @param None
* @retval
* @author Zachary
* @Data 2023-02-13
**************************************************************/
static void bsp_SetSysClk( void )
{
stc_clock_xtal_init_t stcXtalInit;
stc_clock_pll_init_t stcPLLHInit;
LL_PERIPH_WE( LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | \
LL_PERIPH_EFM | LL_PERIPH_SRAM ); /* ---解保护相关外设--- */
/* PCLK0, HCLK Max 240MHz */
/* PCLK1, PCLK4 Max 120MHz */
/* PCLK2, PCLK3 Max 60MHz */
/* EX BUS Max 120MHz */
CLK_SetClockDiv( CLK_BUS_CLK_ALL, \
( CLK_PCLK0_DIV1 | CLK_PCLK1_DIV2 | CLK_PCLK2_DIV4 | \
CLK_PCLK3_DIV4 | CLK_PCLK4_DIV2 | CLK_EXCLK_DIV2 | \
CLK_HCLK_DIV1 ) ); /* ---外设总线分频--- */
CLK_XtalStructInit( &stcXtalInit );
/* Config Xtal and enable Xtal */
stcXtalInit.u8Mode = CLK_XTAL_MD_OSC; /* ---选择外部晶振--- */
stcXtalInit.u8Drv = CLK_XTAL_DRV_ULOW; /* ---晶振驱动能力 有源晶振驱动能力强--- */
stcXtalInit.u8State = CLK_XTAL_ON;
stcXtalInit.u8StableTime = CLK_XTAL_STB_2MS; /* ---晶振稳定等待周期--- */
CLK_XtalInit( &stcXtalInit );
CLK_PLLStructInit( &stcPLLHInit ); /* ---锁相环寄存器初始化--- */
/* VCO = (8/1)*120 = 960MHz*/
stcPLLHInit.u8PLLState = CLK_PLL_ON;
stcPLLHInit.PLLCFGR = 0UL;
stcPLLHInit.PLLCFGR_f.PLLM = 1UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLN = 120UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLP = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLQ = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLR = 4UL - 1UL;
stcPLLHInit.PLLCFGR_f.PLLSRC = CLK_PLL_SRC_XTAL;
CLK_PLLInit( &stcPLLHInit );
/* Highspeed SRAM set to 0 Read/Write wait cycle */
SRAM_SetWaitCycle( SRAM_SRAMH, SRAM_WAIT_CYCLE0, SRAM_WAIT_CYCLE0 );
/* SRAM1_2_3_4_backup set to 1 Read/Write wait cycle */
SRAM_SetWaitCycle( ( SRAM_SRAM123 | SRAM_SRAM4 | SRAM_SRAMB ), SRAM_WAIT_CYCLE1, SRAM_WAIT_CYCLE1 );
/* 0-wait @ 40MHz */
EFM_SetWaitCycle( EFM_WAIT_CYCLE5 );
/* 4 cycles for 200 ~ 250MHz */
GPIO_SetReadWaitCycle( GPIO_RD_WAIT4 );
CLK_SetSysClockSrc( CLK_SYSCLK_SRC_PLL );
LL_PERIPH_WP( LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU | \
LL_PERIPH_EFM | LL_PERIPH_SRAM ); /* ---保护相关外设--- */
}
视频展示:
633b71556d384ccc70ddc300ca837c3c
FreeRTOS源码与测试工程代码:
|