向OSAL系统添加自定义任务|学习笔记

本文涉及的产品
语种识别,语种识别 100万字符
文档翻译,文档翻译 1千页
文本翻译,文本翻译 100万字符
简介: 快速学习向OSAL系统添加自定义任务

开发者学堂课程【嵌入式之RFID开发与应用2020版向OSAL系统添加自定义任务】学习笔记与课程紧密联系,让用户快速学习知识

课程地址https://developer.aliyun.com/learning/course/665/detail/11131


向OSAL系统添加自定义任务

 

OSAL系统例子分析

接下来主要讲述OSAL系统的例子以及其如何使用。

要在OSAL基础上创建自己的任务,基本的流程是,首先来看代码的执行过程,如下:

首先进入到主程序当中,如下:

int main ( void )

// Turn off interrupts

osalint _ disable ( INTS _ ALL );

// Initialization for board related stuff such as LED HAL _ BOARD _ INITO );

// Make sure supply voltage is high enough to run zmain _ vdd _ check ();

// Initialize board I/0

// InitBoard ( OB _ COLD );

InitBoard ( OB _ READY );

// Initialze HAL drivers HalDriverInit ();

// Initialize NV System

osal _ nv _ init ( NULL );

// Initialize the MAC

// Initialize the timers osalTimerInitO )

// Initialize the Power Management System

OsalpWrmgr init )

// Initialize the system tasks .

osalInitTasks ();

// Setup efficient search for the first free block of heap osal _ mem _ kick ();

return ( SUCCESS);

}”end osal_ init _system”

在主程序中有很多有关的初始化,暂时先略过不重要的,首先是OSAL相关的,如关中断、按键相关的,还有一些变压键盘硬件,还有一些需要实时存储的数据。

与操作系统有关的首先是 osal_init_system,如下:

uint8 osalinit _ system ( void )

// Initialize the Memory A1location System Osalmem _ init ()

// Initialize the message queue osal _ qHead = NULL ;

// Initialize the timers OsalTimerInit )()

// Initialize the Power Management System

osalpWrmgrinit()

11 Initialize the system tasks osalInitTasks ();

1/ Setup efficient search for the first free block of heap . osalmem _ kick ()

return ( SUCCESS);

}”end osal_ init _system”

这里面有有关内存的初始化,包括定制器,任务,主要是任务,针对所有的任务,在此进行了统一的初始化,如下:

void osalInitTasks

uint8 taskID =0;

tasksEvents =(uint16*) osal _ mem _ alloc ( sizeof (uint16)* tasksCnt ); osal _ memset ( tasksEvents ,0,( sizeof (uint16)* tasksCnt ));

macTaskInit ( taskID ++); nwk _ init ( taskID ++);

Hal _ Init ( taskID ++);

# if defined ( MT _ TASK )

MT _ TaskInit ( taskID ++);# endif

APS _ Init ( taskID ++);

# if defined ( ZIGBEE _ FRAGMENTATION )

APSF _ Init ( taskID ++);

# endif

ZDApp _ Init (

taskID ++);

# if defined ( ZIGBEELFREQAGILITY ) II defined ( zIGBEE _ PANID _ coNFLICT )

ZDNwkMgr _ Init ( taskID ++);

# endif

1/SampleApp_ Init ( taskID ++);

my _ Init ( taskID ++);

这些任务是来自于一个数组 typeof unsigned short (*PTaskEventHandIerFn)(unsiged char task_id,unsiged short event):

这个数组是一个函数指针数,函数类型它包含任务的ID,任务的事件,以及返回未处理完的事件。

如下前面的一些任务是系统自带的:

macEVentLOop ,

nwk _ event _ loop , Hal _ ProcessEvent ,# if defined ( MT _ TASK

MTPrOcessEvent ,# endif

APS _ eventloop ,

# if defined ( ZIGBEE _ FRAGMENTATION

APSFProcessEvent ,# endif

ZDApp _ event _ loop ,

# if defined ( ZIGBEELFREQ AGILITY

ZDNwkMgr _ event _1oop,

# endif

其点进去看不到,只有一个声明,看不到它的实现,它的源代码被封装成库,后面还有很多是这样的。

下面是官方提供的参考案例,就是说明如何去写一个任务,如下:

uint16 SampleApp ProcessEVent (uint8 task _ id ,uint16 events ){

afIncomingMSGPacket _ t * MSGpkt ;

( void ) task _ id ;1/ Intentionally unreferenced parameter if ( events & SYS _ EVENT _ MSG )

{

MSGpkt =( afIncomingMSGPacket _ t *) osal _ msg _ receive ( SampleApp _ TaskID ); while ( MSGpkt )

switch ( MSGpkt -> hdr . event )

{

// Received when a key is pressed case KEY _ CHANGE :

SampleApp _ HandleKeys ((( keyChange _ t *) MSGpkt )-> state ,(( keyChange

break ;

// Received when a messages is received ( OTA ) for this endpoint case AF _ INCOMING _ MSG _ CMD :

SampleApp _ MessageMSGCB ( MSGpkt );

break ;

// Received whenever the device changes state in the network case ZDO_ STATE _ CHANGE ;

因为它本身是一个 forexample,可以在官方源码把它注释起来,可以去添加一个自己的任务,添加任务的本质就是创建一个函数,

如下My_process就是创建的属于自己的函数:

Uint16 My_ProcessEvent(uint8 task_id,uint16 event)

{

afIncomingMSGPacket _ t * MSGpkt = NULL ; if ( events & SYS _ EVENT MSG )

MSGpkt =( afIncomingMSGPacket _ t *) osal _ msg _ receive ( my _ TaskID ); while ( MSGpkt l = NULL ){

Switch ( MSGpkt -> hdr . event )

case ZDO _ STATE _ CHANGE :

identity _ nwk =( devStates _ t )( MSGpkt -> hdr . status );

if ( identitynwk = DEV _ END _ DEVICE ){

debug ("入网成功\ n ");

debug ("获得地址=0x%× In ", NLME _ GetShortAddr ();

# if CTRL _ OR _ GATHER //控制节点/采集节点入网成功后先发一个数据给协调器以确认

send _ coord _ affirm ( SAMPLEAPP _ CTRL _ CLUSTERID );//这是不同

# else

send _ coord _ affirm ( SAMPLEAPP _ SENSOR _ cLuSTERID );//这是不同终端

# endif

break ;

case AF _ INCOMING _ MSGCMD ;

my _ MessageMSGCB ( MSGpkt );

break ;

注意的是函数的返回值和参数要尊重数组的类型、定义。在这个函数中具体要做什么事?这个不是特别重要,只要有一个函数,如果发生了什么事,这个函数就会被执行,

这个函数之后接着往下看:

void osalInitTasks ( void )

{

uint8 taskID =0;

tasksEvents =(uint16) osalmem _ alloc ( sizeof (uint16)* tasksCnt ). osal _ memset tasksEvents ,, sizeof (uint15)* tasksCnt ));

macTaskInit ( taskID ++ nwk _ init (

taskID ++);

Hal _ Init (

taskID ++);

# if defined ( MLTASK )

MT _ TaskInit ( taskTD ++);

# endif

APS Init # if defined

APSF _ Init (taskTD ++);

# endif

ZDApp _ Init (# if defined

ZDNwkMgrInitKtaskID ++);

# endif

nwk _ init (

Hal Init (

# if defined ( MTLTASK

MT _ TaskInit ( taskID ++);

# endif

APS _ Init

taskID++;

#1f defined

ZIGBEEL FRAGMENTATION

APSF _ Init (

taskTD ++);

# endif

ZDApp _ Init (taskTD ++);

#1f defined ( ZIGBEELFREQAGILITY defined ( ZIGBEE _ PANID _ CONFLICT

ZDNwkMgr _ Init ( taskID ++);

# endif

//SampleApp_ Init ( taskID ++);

my _ hit ( taskID ++);

首先在这个初始化中,会把所有的任务都去找一遍,会根据任务的个数去申请一块空间,这个空间就作为每一个任务所对应的完整型的事件,比如有10个任务就会申请10个完整型的数据,给到task events,首先把所有的事件全部清零,现在开始对所有的任务进行初始化,初始化非常重要的事情是,把每个任务的ID自己保存起来,

就是初始化函数中,给你分配了一个ID,比如这个是0,这个是1,这个是2…一直到后面,要自己把它存起来,不管  my_Init此ID是多少,要么存在静态中,要么是my _Task升级的,要么是全局变量。此处为了简操作单定义成全局变量,先把它保存到里面,后面是跟当前要做的事情相关的初始化,就是说创建这个任务是为了做什么?完成这些工作之后,将来任务被调动的时候能正常运行。

OSAL 任务创建:

定义自己的任务函数

定义任务初始化函数并保存任务ID

定义完成之后如何声明,不知道其源文件是什么,可以参考申报APP,这是官方提供的,可复制粘贴,简单修改一下

接下来等待任务何时被调度,这个是不一定的,任务何时被调动,是取决于对应的事件是否被置危,可能给任务发送了一个消息:

每个任务最多可以同时设置16个事件,但有

些位已经被系统定义事件占用,所以自定义事件时最好不要与其冲突,如:任务间消息收发事件 SYS EVENTMSG =0x8000

taskEvents 事件要和后面 zigbee 协议栈中的

afIncomingMSGPackett -> hdr . event 这个

8bit的消息事件加以区别

指定任务添加事件:

osal _ set _ event (uint8 task _ id ,uint16 eventflag )

tasksEvents [ task _ id ]= event _ flag ;指定任务清除事件:

osal _ clear _ event (uint8 task _ id ,

uint16 event _ flag )

tasksEventsLtask _ id ]&=( event flag);

通过 osal set event 给某一个任务ID置危,那可能就被调度了,此处为了操作简单,演示,比如以串口输出去为例:

myTaskID = taskid ;

MTUartnit ();//串口初始化

MTUartRegisterTaskID ( task _ id )<>咨记任务号GPI0初始化*7

P1DIR

P1DIR

P2INP&=~(1<<6);//打开上拉 LOCAL _LED1= SWITCH _ LED _ CLOSE <>LOCALLED2

= SWITCHLED _ CLOSE

//P1_0定义为输出

//P11定义为输出

P1INP&=~(1<<3)()

P1SEL&=~((1<<)1(1<<1)(1<<3)

P1DIR=(1<<)(1<<1)(1<<3)()

SWITCHLED = SWITCHLED _ CLOSE ()

/*端点初始化*/

my _ epDesc . endPoint = MY _ ENDPOINT ; my _ epDesc . task _ id =8my_ TaskID ; my _ epDesc . simpleDesc

my _ epDesc . latencyReq = noLatencyReqs ;

if ( afRegister (8my_ epDesc )= afStatus _ INVALID _ PARANETER )

( SimpleDescmiptionFormat _ t *)& my _ SimpleDesc ;

debug ("端点注册失败\ n ");

else

首先来看初始化当中, UART串口已经做好,已经可以发送消息,直接搜索任务名,给了任务名消息,收到了一个串口的数据 psmg,

如下:

SampleApp

HalUARTRead ( port ,& buf [ i ],1);j++;

flag =1;

/把数据接收放到 buf 中/记录字符数

//已经从串口接收到信息

if ( flag ==1)

//已经从串口接收到信息

/AIl0Cate memory for the data 产/

//分配内存空间,为机构体内容+数据内容+1个记录长度的数据=( mtOSALSerialDatat ") osal _ msg _ allocate ( sizeof

DMSg

( mtOSALSerialData _ t )+ j +3);

//事件号用原来的 CMD SERIAL MSG pMSg -> hdr . event = CMD _ SERIAL _ MSG ; pMsg -> msg =(uint8*)( pMsg +1);11

pMsg

> msB

= port <>

pMsg -> msg [1]= J ;buf10]=0;

strcpy (( char *)&( pMsg -> msg [2]),( const char *) buf );

for ( i =0; i < j ; i ++)

pMsg -> msg [ i +2]= buf ];

osal msg _ send ( my _ TaskID ,( byte *) pMsg );1/登记任务,发往上层

/* deallocate the msg “/

osal _ msg _ deallocate ((uint8*) pMSg );/

把数据定位到结构体数据部分

//给上层的数据第一个是串口号

//给上层的数据第二个是长度

//从第二个开始记录数据

//释放内存

发送完成之后任务才会被调用,然后判断这个消息,在其中要去掉一些无用的东西,Zigbee在此处是可有可无的,因为现在不讨论Zigbee的问题,将收到消息的case保留,前面的去掉,如下是表示串口的数据:

while ( MSGpkt != NULL ){

Switch ( MSGpkt -> hdr . event )

case CMD _ SERIAL _ MSG :

uint8 str [ UART _ RECV _ LEN ];

uint8 port =*((( mtoSALSerialData _ t *) MSGpkt )-> msg );uint8 len =*((( mtOSALSerialData _ t *) MSGpkt )-> msg +1) if ( len < UART _ RECV _ LEN )

osal _ memcpy ( str ,(( mtOSALSerialData _ t *) MSGpkt )-

elSe

break ;

if ( len >1){

*( str + len )=0;

debug (" uart % d (% d ):% s In ", port , len , str ); serial _ dispos ( port , len , str );

break ;

这个处理可以暂时不去调用,只需把串口的数据打印出来,

此循环的前面是接受第1次,如果不等于null,则表示接收到了消息,后面这个表示如果还有消息可以在未退出之前再接收一次,若接收到可直接退出,接收到之后继续处理,如下:

Osal _ memcpy ( str ,(( mtOSALSerialData _ t *) MSGpkt )-> ms

e1Se 

break ;

if ( len >1){

*( str + len )=0;

debug (" uart % d (% d ):% s In ", port , len , str );

// serial _ dispos ( port , len , str );

break ;

Osalmsg _deal1ocate((uint8*) MSGpkt );

MSGpkt =( afIncomingMSGPacket _ t *) osal _ msg _ receive ( my _ TaskID );

}《 end while MSGpkt !=NULL》

return ( events ^ SYS_EVENT_MSG );

else if

end if events8SYS EVENT_MSG  else if events & DEMO _ KEYBOARD _1){

debug ("key1 down In ");

my _ SendPointToPointMessage ( SAMPLEAPPSENSOR _ CLUSTERID , SET _ TEMP _ADJ1 mySendPointToPointMessage ( SAMPLEAPPSENSOR CLUSTERID , SET HUMI ADJI my _ SendPointToPointMessage ( SAMPLEAPP _ CTRL _ CLUSTERID , SET _ TEMP _ ADJUS my _ SendPointToPointMessage ( SAMPLEAPP _ CTRL _ CLUSTERID , SET _ HUMI _ ADJUS LOCAL _LED1= SWITCHLED _ OPEN ;

LOCAL _LED2

SWITCHLED _ OPEN ;

SWITCH _ LED =

SWITCH _ LED _ OPEN ;

后面的其他事件可暂时去掉,只处理如下一个事件,当有消息过来时,当有事件触发时,去判断是否发消息,如果发送消息则判断它是否是串口消息。

判断它是否是串口消息,借助构造时运用的CMD_SWRIAL_MSG,如果是串口消息,则直接打印,其他的不做处理

初始化中关于Zigbee的东西无关紧要,操作完成之后,接下编写程序,

程序编写完成之后,当线串好之后,直接下载,下载完成之后,点击全速运行,此时需要打开串口,串口打开之后,试一下是否输出信息,此时目的不是运用Zigbee,只是通过串口发送数据,看是否能打印出来,打印的内容是“uart%d(%d):%s\n,port,len,str” 关口、长度和内容。

image.png

如下是试验:

如果发送一个hello,会在383行,第0个串口,长度为5,内容为hello。因此如果不给它发送任何消息,任务是不会执行的,或者是需通过其他方式设置事件标志,任务才能被执行。

image.png

如上就是整个osal要完成自己任务的添加,基本上要遵循的原则:创建自己的任务、初始化,确定ID,确定何时去调用设置事件的接口,也就是osal _set_event让任务具备执行的条件,那么这个任务就会被执行。

相关文章
|
5月前
|
运维 Linux 调度
Linux定时器的配置与管理方法
Linux定时器的配置与管理方法
|
7月前
|
消息中间件 调度
FreeRTOS入门教程(任务状态)
FreeRTOS入门教程(任务状态)
252 0
|
7月前
|
安全 测试技术
【ZYNQ】ZYNQ7000 全局定时器及其驱动示例
【ZYNQ】ZYNQ7000 全局定时器及其驱动示例
168 0
|
7月前
|
API
FreeRTOS软件定时器的原理以及使用实例
FreeRTOS软件定时器的原理以及使用实例
147 0
|
7月前
|
存储
FreeRTOS入门教程(事件组概念和函数使用)
FreeRTOS入门教程(事件组概念和函数使用)
136 0
|
7月前
|
消息中间件 存储 数据采集
FreeRTOS入门教程(任务通知)
FreeRTOS入门教程(任务通知)
140 0
|
7月前
|
数据采集 API 数据处理
FreeRTOS入门教程(软件定时器)
FreeRTOS入门教程(软件定时器)
182 0
|
API 调度
FreeRTOS学习笔记—任务创建和删除
本文学习了如何创建和删除任务。最后,分析解决了遇到的问题。
175 0
|
传感器 移动开发 Linux
RT-Thread UART设备驱动框架初体验(中断方式接收带\r\n的数据)
RT-Thread UART设备驱动框架初体验(中断方式接收带\r\n的数据)
223 0
MSP430F5529库函数定时器A——捕获实验
MSP430F5529库函数定时器A——捕获实验
252 0