TKIT : Task kit
V566 简介
这是一个基于ARM微控制器平台的多种工具集合,所有代码均为C语言构成(基于KEIL工具开发)。与具体硬件环境无关联,符合标准C语言规则,通过少量外部函数与实际硬件对接。其核心架构为前后台任务管理。
早期的嵌入式系统中没有操作系统的概念,程序员编写嵌入式程序通常直接面对裸机。在这种情况下,通常把嵌入式程序分成两部分,即前台程序和后台程序。
应用程序是一个无限的循环,循环中调用相应的函数完成相应的操作,这部分可以看成后台行为。前台程序通过中断来处理事件;后台程序则掌管整个嵌入式系统软、硬件资源的分配、管理以及任务的调度,是一个系统管理调度程序。这就是通常所说的前后台系统。一般情况下,后台程序也叫任务级程序,前台程序也叫事件处理级程序。在程序运行时,后台程序检查每个任务是否具备运行条件,通过一定的调度算法来完成相应的操作。对于实时性要求特别严格的操作通常由中断来完成,仅在中断服务程序中标记事件的发生,不再做任何工作就退出中断,经过后台程序的调度,转由前台程序完成事件的处理,这样就不会造成在中断服务程序中处理费时的事件而影响后续和其他中断。
实际上,后台程序是一个无限循环的结构,一旦在这个循环体中正在处理的任务崩溃,使得整个任务队列中的其他任务得不到机会被处理,从而造成整个系统的崩溃。由于这类系统结构简单,几乎不需要RAM/ROM的额外开销,因而在简单的嵌入式应用被广泛使用。前后台系统设计简单,其最小的系统框图如下,所有应用被归纳在一个无穷的循环结构和中断服务里。所有关键敏感操作应该放在前台来保证处理的实时性,同样意味着所有前台程序不能消耗太长时间,以免导致中断溢出。被称之为任务级的后台任务的特点是必须等待上一条任务的返回后才能执行,依赖于上一次的执行结果。一个后台执行周期取决于各个任务的执行时间和,无法准确统一计算,这一点是和前台任务很大的区别。
一、主要特征
- 前后台任务管理。主要负责前台任务调度(start\delete\create\suspend\resume),后台任务设计者自组织
- 时间管理。包括时间片计时、延时,系统时间片自动变量,超时变量,日历更新
- 消息或事件管理(create\delete\post\pend\accept\clear)
- 其他中间件:例如fatfs文件系统;文件校验算法;矩阵变换;图像分割;傅里叶变换\Kalman滤波\Lagrange插值计算\多项式拟合运算;自适应PID算法;内存管理;IO端口呼吸、脉冲模拟输出;Terminal终端控制台;RTC看门狗授权算法;等等
non-boot模式main():
/* Layer specfication ------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------- 2018.07.09 : Liu Jie : AM00V20500 ----------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------*/ #include "includes.h" /************************************************************************************************ * * Description: * * Arguments : * Returns : ************************************************************************************************/ int main(void) { INT8U receive_buf[128],para_buf[128];
INT8U buffer[4096]; u_BusFrame frame; TKIT_MSG Msg; //TKIT APP模式初始化 TKIT_Init( TKITMODE_APP ); //启动所有前台任务 TKIT_TaskStart();//创建一个消息,并且由系统每隔1S自动触发 Msg = TKIT_MsgCreate( NULL,TKIT_DLY_1S); while( 1 ) { if( TKIT_MsgPend(Msg,NULL,0) ) { TKIT_IO_SetBurstCnt(IO_LED,1); }
//Terminal
if( ReadsExt(receive_buf,para_buf) ) { Terminal_Handler(receive_buf,para_buf); }
//接收一个帧 frame.Port = BUS_PORT_USB; if( b_ProBus_ReadFrame(&frame,buffer,TKIT_DLY_10MS) ) { t_ProBus_CmdHandler( frame,buffer, NULL ); } }//end while }
二、文件组成
TKIT_Header是该工具的发布文件,主要包括.h和.lib文件。一般是对库函数的说明以及相关的配置,外部使用时不允许对此进行更改。
三、使用案例
*************************************** TKIT library 使用说明 ************************************************
1.包含头文件 TKIT.H 以及配置堆栈
#include "TKIT_Header\TKIT.h"
如果使用到了heap等,建议堆栈>=0x4000
2.向工程添加 TKIT_XXXX.lib文件
3.配置TKIT_Header里面的Config_*****.c文件
3.1 Config_BoardSrc.c TKIT使用到的资源配置文件。 //重点配置以下函数,板载资源初始化 //TKIT 启动时自动调用以下函数 //如果已经使能串口终端,会在调用此函数之前初始化串口 //此时串口、定时器功能已完成初始化 extern TKIT_ErrType TKIT_BoardSrcInit (void) //设置设备ID编号 //4*32bit ID //建议上电设置设备ID编号 (Call) void TKIT_SetId (INT32U const* p); //固件版本号的设置和读取 (Call) char const* TKIT_GetFirmVer (void); (Call) void TKIT_SetFirmVer (char const* ver); (Call) TKIT_SetNumbVer(10500 ,201805); 3.2 Config_ExternFun.c TKIT外部功能函数实例化,文件内的函数被TKIT自动调用 例如用户自定义的命令响应等 extern TKIT_ErrType t_ProBus_CmdUser (u_BusFrame frm,INT8U *data) //IO处理消息 extern void TKIT_IO_IRQHook (void) //终端输入test调用函数 extern void TerminalHandler_TestHook (INT8U *p) 3.3 Config_Timer.c 与MCU相关的定时器功能配置,外部实例化此函数 extern void TKIT_TimerInit (INT32U Ticks); extern INT32U TKIT_TimerCounter (void); //禁止所有中断响应 extern void TKIT_ENTER_CRITICAL (void); //恢复所有中断响应 extern void TKIT_EXIT_CRITICAL (void); 定时器中断调用下面的函数 (Call) void TKIT_TimerHandler (void); 3.4其他外部函数实现 Config_BoardSrc.c //内存读写等板载资源初始化 实例化 extern TKIT_ErrType TKIT_BoardSrcInit (void); extern void TKIT_ResetBoard (void); extern void TKIT_SysJump (INT32U addr); extern void TKIT_VectorRemap (INT32U addr);
4.例程
**************************************************************** 示例:main() 启动TKIT **************************************************************** INT8U receive_buf[128],para_buf[128]; FP64 *fx,*fy; TYPE_KM X,P,Q,R; INT8S x[30],y[30]; INT16U i; u_BusFrame frame; u_BusPacketL pkt_l; TKIT_MSG Msg; //TKIT APP模式初始化 #ifdef __APP_CODE__ TKIT_Init( TKITMODE_APP ); TKIT_Key(0xAC880303); t_LicenseCheck(NULL,TRUE); #else //TKIT BOOT模式初始化 TKIT_Init( TKITMODE_BOOT ); #endif //Check app code >>>>>>>>>>>>>>>>>>>>>>>>>>>> #if TKIT_FATFS_EN && KIT_SDCARD_EN while( SD_Exist ) { //建立系统文件夹 err = t_FatSysCheck(FAT_ROOT); if( TKIT_SUCCESS==err )err = t_fat_PathCheck(FAT_ROOT_PATH,TRUE); if( TKIT_SUCCESS==err )err = t_fat_PathCheck(FAT_PATH_DEVICE,TRUE); if( TKIT_SUCCESS==err )err = t_fat_PathCheck(FAT_PATH_SYS,TRUE); //检测升级文件 if( TRUE==b_FileFirmwareCheck(FAT_PATH_SYS,"AM-AM",FALSE,FALSE) ) { Printf("<FirmwareCheck>Find available app code in disk[%s]\r\n",FAT_PATH_SYS); #ifndef __APP_CODE__ b_FileFirmwareCheck(FAT_PATH_SYS,"AM-AM10",TRUE,TRUE); #endif } else { Printf("<FirmwareCheck>Can't find available app code in disk[%s]\r\n",FAT_PATH_SYS); } break; } #endif //TKIT_FATFS_EN //Bootloader检测是否需要跳转 #ifndef __APP_CODE__ Printf("<boot>Check app code and jump...\r\n"); TKIT_ErrUpdate( t_TKIT_AppCheck( TKIT_DLY_3S,BUS_PORT_ALL ) ); #endif //__APP_CODE__ #ifdef __APP_CODE__ Printf("<app>app code start.\r\n"); #else Printf("<boot>Bootloader start.\r\n"); #endif //启动所有前台任务 TKIT_TaskStart(); //Task_Init(); //创建一个消息,并且由系统每隔1S自动触发 Msg = TKIT_MsgCreate( NULL,TKIT_DLY_1S); //功能演示 #ifdef __APP_CODE__ //申请动态内存 fx = (FP64 *)malloc((40+1) * sizeof(FP64)); fy = (FP64 *)malloc((40+1) * sizeof(FP64)); //printf 演示 TKIT_DlyTicks(TKIT_DLY_200MS); printf("<app>If you see this string,printf function success!\r\n"); printf(" %.5f \r\n",0.123 ); //>>0.12300 printf(" %2.5f \r\n",0.123 ); //>>0.12300 printf(" %2.5f \r\n",321.123 ); //>>321.12300 printf(" %02.5f \r\n",0.123 ); //>>0.12300 printf(" %.5lf \r\n",(double)0.123 ); //>>0.12300 printf(" %05d \r\n",123); //>>00123 printf(" %5d \r\n",123); //>> 123 printf(" %s \r\n","string"); //>>string printf(" %c \r\n",'X'); //>>X printf(" 0x%x \r\n",0x123); //>>0x123 printf(" 0x%6x \r\n",0x123); //>>0x 123 printf(" 0x%06x \r\n",0x123); //>>0x000123 printf(" %d%% \r\n",99); //>>99% printf(" %d \r\n",-99); //>>-99 printf(" %d \r\n", 99); //>>99 printf(" %0.5f,%f,%f \r\n",0.123,0.456,1.789 ); //>>0.12300,0.456000,1.789000 printf(" %0.5f # %1.3f \r\n",0.123,12.3456 ); //>>0.12300 # 12.346 Printf(" %05d \r\n",123); //>>00123 Printf(" %05ud \r\n",123); //>> 00123 Printf(" %5ud \r\n",123); //>> 123 Printf(" %5ud \r\n",-123); //>> -123 Printf(" %0.5uf \r\n",0.123 ); //>> 0.12300 Printf(" %0.5uf \r\n",-0.123 ); //>>-0.12300 Printf(" %2.5uf \r\n",-0.123 ); //>> -0.12300 Printf(" %3.5uf \r\n",32.123 ); //>> 32.12300 Printf(" %3.5uf \r\n",-32.123 ); //>> -32.12300 //拉格朗日插值计算 TKIT_DlyTicks(TKIT_DLY_200MS); x[0] = 0; y[0] = 0; x[1] = 1; y[1] = 10; x[2] = 2; y[2] = 40; x[3] = 3; y[3] = 80; Alg_LagrangePrintDemo ("INT8S",x,y,4,0.1); TKIT_DlyTicks(TKIT_DLY_200MS); x[0] =-1; y[0] = 0; x[1] = 0; y[1] = 20; x[2] = 1; y[2] = 30; x[3] = 2; y[3] = 20; x[4] = 3; y[4] = 0; Alg_LagrangePrintDemo ("INT8S",x,y,5,0.1); //Kalman filter TKIT_DlyTicks(TKIT_DLY_200MS); fx[ 0] = 20.0 + 1.5; fx[ 1] = 20.0 - 1.1; fx[ 2] = 20.0 - 2.8; fx[ 3] = 20.0 + 1.6; fx[ 4] = 20.0 - 1.5; fx[ 5] = 20.0 - 2.4; fx[ 6] = 20.0 - 1.7; fx[ 7] = 20.0 + 1.9; fx[ 8] = 20.0 - 0.6; fx[ 9] = 20.0 + 2.3; fx[10] = 20.0 + 2.5; fx[11] = 20.0 - 1.1; fx[12] = 20.0 - 1.8; fx[13] = 20.0 + 2.2; fx[14] = 20.0 + 1.5; fx[15] = 20.0 - 1.4; fx[16] = 20.0 - 2.7; fx[17] = 20.0 + 2.1; fx[18] = 20.0 - 1.6; fx[19] = 20.0 - 0.3; fx[20] = 20.0 + 2.5; fx[21] = 20.0 - 1.1; fx[22] = 20.0 + 1.8; fx[23] = 20.0 - 2.2; fx[24] = 20.0 - 1.5; fx[25] = 20.0 + 1.4; fx[26] = 20.0 - 2.7; fx[27] = 20.0 + 1.1; fx[28] = 20.0 - 1.6; fx[29] = 20.0 + 0.3; fx[30] = 20.0 + 2.5; fx[31] = 20.0 - 1.1; fx[32] = 20.0 + 1.8; fx[33] = 20.0 - 2.2; fx[34] = 20.0 - 1.5; fx[35] = 20.0 + 1.4; fx[36] = 20.0 - 2.7; fx[37] = 20.0 + 1.1; fx[38] = 20.0 - 1.6; fx[39] = 20.0 + 0.3; Q = 1.0; R = 0.1; X=0; P=0; for(i=0;i<40;i++){fy[ i] = fAlg_KalmanFilter(fx[ i],Q,R,&X,&P);} printf("Kalman filter.fx input. Q=%.2f,R=%.2f, X=%.2f,P=%.2f\r\n",Q,R,X,P); PrintPlot_XY("Kalman filter",TRUE,fx,fy,40); Printf("\r\n"); Q = 1.0; R = 1.0; X=0; P=0; for(i=0;i<40;i++){fy[ i] = fAlg_KalmanFilter(fx[ i],Q,R,&X,&P);} printf("Kalman filter.fx input. Q=%.2f,R=%.2f, X=%.2f,P=%.2f\r\n",Q,R,X,P); PrintPlot_XY("Kalman filter",TRUE,fx,fy,40); Printf("\r\n"); Q = 0.1; R = 1.0; X=0; P=0; for(i=0;i<40;i++){fy[ i] = fAlg_KalmanFilter(fx[ i],Q,R,&X,&P);} printf("Kalman filter.fx input. Q=%.2f,R=%.2f, X=%.2f,P=%.2f\r\n",Q,R,X,P); PrintPlot_XY("Kalman filter",TRUE,fx,fy,40); Printf("\r\n"); Q = 0.01; R = 1.0; X=0; P=0; for(i=0;i<40;i++){fy[ i] = fAlg_KalmanFilter(fx[ i],Q,R,&X,&P);} printf("Kalman filter.fx input. Q=%.2f,R=%.2f, X=%.2f,P=%.2f\r\n",Q,R,X,P); PrintPlot_XY("Kalman filter",TRUE,fx,fy,40); Printf("\r\n"); Alg_FFTDemo( 0.0,1.0,5.0,0); //5Hz sin test Alg_FFTDemo( 0.0,1.0,5.0,5); //5Hz triangle //释放动态内存 free(fx); free(fy); #endif // __APP_CODE__ while( 1 ) { //Task(); if( TKIT_MsgPend(Msg,NULL,0) ) { //Pend message success TKIT_IO_SetBurstCnt(IO_LED,1); } //If terminal enable if( Terminal_EnableCheck() ) { if( ReadsExt(receive_buf,para_buf) ) { Terminal_Handler(receive_buf,para_buf); } } //选择通信接口 //接收一个帧 if( Terminal_EnableCheck() ) { frame.Port = BUS_PORT_USB; } else { frame.Port = BUS_PORT_USB | BUS_PORT_UART; } //frame.Port |= BUS_PORT_WIFI; if( b_ProBus_ReadFrame(&frame,pkt_l.byte,TKIT_DLY_10MS) ) { //Printf("<main>Received command:%04X\r\n",frame.Cmd.u16); t_ProBus_CmdHandler( frame,pkt_l.byte, NULL ); TKIT_IO_SetBurstCnt(IO_LED,1); } else if( BUS_PORT_UART==frame.Port ) { if( 0==std_StringCmpExt("admin%ADMIN",(char*)pkt_l.Alt.Data ) ) { Terminal_Enable(TRUE); PrintWelcome(); } } //接收一个长数据包 pkt_l.Alt.Port = BUS_PORT_WIFI; if( i_ProBus_ReadLPkt( &pkt_l , &frame ,TKIT_DLY_10MS) ) { Printf("<main>Wifi received command:0x%04X\r\n",frame.Cmd.u16); t_ProBus_CmdHandler( frame,pkt_l.Alt.Data,&pkt_l ); TKIT_IO_SetBurstCnt(IO_LED,1); } ////////END FOR ///////////////// }//end while
**************************************************************** 示例:超时检测功能 **************************************************************** INT32U TimerCount; //初始化超时变量 TKIT_TimeOutInit( &TimerCount ); //如果超时3秒 while( 1 ) { if( TKIT_TimeOutCheck( TimerCount,TKIT_DLY_3S) ) { Printf("Function time out ! \r\n"); break; } } **************************************************************** 示例:声明并发送一个消息 **************************************************************** //Create message TKIT_MSG Msg; //Auto post message by system tiks. every 2 seconds Msg = TKIT_MsgCreate(&err,TKIT_DLY_2S); //Check message if( TRUE==TKIT_MsgPend(Msg,NULL,0) ) { //Pend message success } //Dlete message TKIT_MsgDel(Msg); //Create message Msg = TKIT_MsgCreate(&err,0); //Post message TKIT_MsgPost(Msg, 0x12345678 ); //Wait message if( TRUE==TKIT_MsgPend(Msg,&msg_data,TKIT_DLY_100MS) ) { if( msg_data==0x12345678 )//success } **************************************************************** 示例:声明并发送一个事件 **************************************************************** //Create event TKIT_EVENT Event; TKIT_EventPost( &Event,0X00000001); if( 0x00000001 == TKIT_EventPend(&Event,0x00000001,0) ) { } **************************************************************** 示例:创建系统时间片自动调用的函数 **************************************************************** //任务函数 void UserTaskIsr(void) { time++; } //创建任务 TKIT_ErrType err; err = TKIT_TaskCreate( UserTaskIsr,NULL ); **************************************************************** 示例:创建一个变量,并且变量由系统时间片周期自动累加 **************************************************************** INT32U UpdateTimer; TKIT_TimerValCreate( &UpdateTimer ); //函数使用该变量 if( UpdateTimer >= TKIT_DLY_1S ) { UpdateTimer = 0; //Do something } **************************************************************** 示例:创建一个输出管脚,配置为模拟PWM模式 **************************************************************** //配置 P2.12为输出IO TKIT_IO_Cfg(IO_LED0,(1<<12),&LPC_GPIO2->FIODIR,&LPC_GPIO2->FIOSET,&LPC_GPIO2->FIOCLR,NULL); //输出PWM模式,初始电平HIGH PWM周期500ms,占空比50ms TKIT_IO_Set(IO_LED0,STD_PWM,IO_DIR_OUT,IO_LEV_HIGH,0,FALSE,TKIT_DLY_500MS,TKIT_DLY_50MS); **************************************************************** 示例:创建一个输入管脚,并处理输入的消息 **************************************************************** //初始化流程配置管脚信息 //输入滤波延时50ms TKIT_IO_Cfg(IO_KEY,IOBIT13_MASK,&LPC_GPIO2->FIODIR,&LPC_GPIO2->FIOSET,&LPC_GPIO2->FIOCLR,&LPC_GPIO2->FIOPIN); TKIT_IO_Set(IO_KEY,STD_GPIO,IO_DIR_IN,IO_LEV_LOW,TKIT_DLY_50MS,FALSE,0,0); //在 TKIT_IO_IRQHook 处理消息 //500ms 以内的短按触发 if( TKIT_IO_GetMesg(IO_KEY) == HIGH_FLASH && TKIT_IO_GetLastMesgTimer(IO_KEY)<TKIT_DLY_500MS ) { //TKIT_EventPost(&TaskEvent,EVENT_KEYTRIG); } //1S 长按触发 if( TKIT_IO_GetMesg(IO_KEY) == LOW_TRIG && TKIT_DLY_1S==TKIT_IO_GetMesgTimer(IO_KEY) ) { //TKIT_EventPost(&TaskEvent,EVENT_KEYTRIGLONG); } **************************************************************** 示例:Terminal 读取用户的输入 **************************************************************** char *endp; u_Val32 val; char Buf[64]; char Arg[64]; //阻塞等待用户输入例如 IP 1.2.3.4 GetsExt((INT8U*)Buf,Arg); if(0 == std_StringCmpExt("ip%IP",Buf)) { val.u8[3] = std_StringToulExt((char*)Arg,&endp,0,' '); val.u8[2] = std_StringToulExt(endp+1,&endp,0,' '); val.u8[1] = std_StringToulExt(endp+1,&endp,0,' '); val.u8[0] = std_StringToulExt(endp+1,&endp,0,' '); Printf(" IP=%d.%d.%d.%d\r\n",val.u8[3],val.u8[2],val.u8[1],val.u8[0]); } **************************************************************** 示例:增加一个内存变量 定义一个变量地址 > ARG_USER_MEMCHK #define ARG_USER_MEMCHK 40 #define ARG_IP 41 **************************************************************** //读取变量值 val = u_ArgGet(ARG_IP); //设置变量值 err = t_ArgSet(ARG_IP,0x12345678); **************************************************************** 示例:对数组排序、返回平均值、返回中位值等 **************************************************************** INT32U DATA[200]; //DATA[0]大--小 排序 std_BubbleSort32(DATA,200,TRUE); //DATA[0]小--大 排序 std_BubbleSort32(DATA,200,FALSE); //递推并返回均值 //向数组递推存入NewData //返回数组均值val val = std_AlgMovingMean(DATA,NewData,200); //返回数组中位值 val = std_AlgMedian(DATA,200); **************************************************************** 示例:搜寻数组中相近的两个数 **************************************************************** INT32U Buf[]={ 6,3,5,7,10}; INT32U BufRe[2]; len = Alg_Search32U(Buf,5,3,BufRe); //例中将返回 len = 1, BufRe[0]=3,BufRe[1]=3, len = Alg_Search32U(Buf,5,9,BufRe); //例中将返回 len = 3, BufRe[0]=7,BufRe[1]=10, **************************************************************** ****************************************************************