版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
RAW-OSRTOS,RAW-OSForFun的产物。其丰富的内核特计,以及创新的设计足以和目前任何主流商业RTOS可睥睨。特性,中断下半部特性(work_queue工作队列),基于idle任务的触发机制,block,byte,page,malloc,slab五种方式的内存对于本文档内容和例程,不懂,请到下面提问: : Raw-os 硬件平台 正点原子STM32F4探索者开发开发环境 :存放ST标准的固件库。 下面又有extension :用户程序,下面的s子 存放所有用户的s命令实现。 :存放FATFS,LWIP等第协议栈源码。(RAW_U8INIT_TASK_STK_SIZE,voidInit_Task_Func(voidOK,创建一个任务基本上就这些东西了,注意,上面代码是了任务执行函数,当然还需要实现它。完整代码参见例程1。RTOSRTOS启动之前不允许产生任何硬api,api在初始化硬件中voidInit_Task_Func(void{//1.InitialalltheusedHardware//2.Createother}置Systick的中断频率:SysTick_Config(SystemCoreClock/ 表示OS的时钟周期为10ms。Raw-os支持时间片轮转调度,多个任务可以设置相同的优先级,从理论上的USART1(PA9,PA10两个引脚)到电脑串口,波特率为115200。另外,本文档后面的例程,包括s,都需要在SecureCRT这个软件下使各打印10次语句,当任务的时间片到时,即被系统CPU使用权转而运行////voidFirst_Task(void*{intfor(i=0;i<10;i{ //翻转LED1}}//voidSecond_Task(void*{intfor(i=0;i<10;i{ //翻转LED2}}10次语句,两个任务都没有主动去放弃CPU使用权,但由于具有相同的优先级,那么当第一个任务在执行过程中其时间片到时,会被系统CPU控制权,转而运行第二个任务,第二个任务在执 tasktime 实验结果:LED进行多次翻转,按理说是按下一次,释放一次信号量,LED只翻转一次的,那是什么原因呢?当然是因为按务执行了多次,所以LED也翻转多次。//// {2.3.}raw_enter_interrupt()和raw_finish_int()是在中断服务程序的开始和退出处s详RAW-OSS使用一种简单、易用、高效的机制使得应用程序支持命令行护一个单向链表,新加入令依次挂help这个链表头后面,当在应用层面,比如串口终端中,输入命令时,执行s 解析的任务会这个命令,并通过mand()函数从单链表头开始查找这个命令是否已(挂接到命统令列表中进行比对,从而识别这个命令。S机制的实现需要依赖串口,所以在本例中,工程如下你用时候,你会爱上s的。首先分析下一个命令体所对应的数据结构类型,rsh.htypedeftypedefstruct{constRAW_S8*const constRAW_S8*const RAW_S8} 第二项pcHelpString是这个命令对应的使用说明。 typedeftypedefRAW_S32xWriteBufferLen,constRAW_S8mandString pcWriteBuffermandString:用户输入的整个命令行(参数从此命令行中提取eg:添加一个打印Raw-os内核版本version命令: {(constRAW_S8(constRAW_S8*)"version: gettheRaw-oskernelversion.",0命令名为version.gettheRaw-oskernel命令的执行函数实现如下version命令回调:RAW-OSKernelstaticRAW_S32get_os_version(RAW_S8*pcWriteBuffer,RAW_U32xWriteBufferLen,constRAW_S8*const {RAW_U8version[6]=//raw_strcat((char*)pcWriteBuffer,(char*)"RAW-OSVersion:");version[0]=RAW_OS_VERSION/1000+0X30;version[1]=version[2]=RAW_OS_VERSION%1000/100+0X30;version[3]=RAW_OS_VERSION%100/10+0X30;version[4]=RAW_OS_VERSION%10+0X30;version[5]=return//}((RAW_S8*pcWriteBuffer,RAW_U32xWriteBufferLen,constRAW_S8*const pcWriteBuffer 2.这个新mand(constxCommandLineInput*mandToRegister,xCommandLineInputListItem点到系统中,代码如下: 会打印出这个命令,当然,仅是以此例作为s使用说明,在本例程中,实际上我们是以控制LED为例,添加了另外四个命令,输入help如下:以此四个命令为例说明了不带参数令使用方法和带参数令注册使用方法,上面命令中的led命令有两个参数,其命令体如下:led开关, const{(constRAW_S8(constRAW_S8*)"led:<lednumber><onoroff>lednumber(1,2),on(1),off(0).", 2pParameter=(RAW_S8 pParameter=(RAW_S8 rsh_get_parameter函数的第一个参数就是你输入令字符串,第二个参数 关于s 机制令体定义,命令部分更具体的内容请读者查看源码定义一个链表结点结构体类型和几个API函数的使用啦,外加一点点链表知识。在本节继续向系统了几个命令,包括打印内核版本号,打印MCU查看内核版本令version和查看MCUID令chip_id命令执行还有个stack命令则是本节重点要介绍的,先输入执行下试试看:可以看到系统此时只有两个任务:idle_task和s_taskidle_task是系统必须有的一个任务,而stask即为我们创建的s任务。RTOS使用当中经常遇到的问题,有时候莫名其妙的程序就跑飞HardFault_Handler中,这种情况很有可能就是栈空间溢出了,解决问题的方一个命令stack则可以动态实时的查看系统中所有运行的任务的栈空间使用情台一个字是4个字节)。/*enable/*enablesystemzero#define#defineCONFIG_RAW_TASK_0111即统计任务,然后重新编译程序,,然后重新执行stack命令,查看结果如级为0的task_0任务和统计任务。同时可查看他们的任务栈空间剩余。述,对stack命令令体定义,等不在列出,下面分析下其代码实现:staticstaticRAW_S32 mand(RAW_S8*pcWriteBuffer,size_txWriteBufferLen,constRAW_S8* {LISTRAW_U32 1.task_debugiter=/*doituntillistpointerisbacktotheoriginalwhile(iter!=&(raw_task_debug.task_head))2.task_debug =iter-3.task_debugtask_iter=raw_list_entry(iter,RAW_TASK_OBJ,//4.获取该任务的剩余栈空间,存在 5.Uart_Printf("tasknameis%15s***task stacksizeis%d\r\n",task_iter->task_name,stack_ /*move/*movetolistnext*/iter=iter_temp;}return}stack1,2,3,4,5写的很清stack命令的时候,就会遍历这个链表,获得每一raw_task_stack_check函数,分析源码发现该函数支持两种增长模while(*task_stack++==0) }用,_stk变量即最终得到的剩余栈大小。RAW-OS系统中实现栈空间检测的原理,更深入的研究分析请查看本节例程原码和RAW-OS源码。然而,raw-os4种任务栈溢出的检测,大部分时候防患于未然,是最好的方式。只要在raw_config.h里面打开宏定义12%的整体空间的raw-os一家提供了这种任务栈的检测机制。具体的代码可以参考raw_idle.c不再细述。Raw-os提供了定时器给用户去使用。软件定时器的代码在raw_timer.c里面。使用的时候需要打开raw_config.h中的CONFIG_RAW_TIMER和定时器的精度有raw_config.h里的RAW_TIMER_RATE去定义使用,具体的软件定时器的频率可以有:举一个例子,RAW_TICKS_PER_SECOND为100,10,那说明软件定时器的频率是一秒10次,即一次是100ms软件定时器的实现有一个系统开启的任务去实现,这个任务就是#if#if(CONFIG_RAW_TIMER>/*settimertaskstacksize,adjustasyouneed*/#defineTIMER_STACK_SIZE#define5tick时间,有的人把系统定时器的频率开得很大,比如1000Hz,这样对于系统损耗很大,对于100MHz以下的cpu,推荐50Hz或者更小。如果系统中不存rawos//// 创建软件定时器,安装回调函数,////周期为2个ticks,即20msKey_Timer_Function,0,100,2,{{case{//0,1,2////{Key_State //}}case{//{释放信号量(唤醒阻塞在该信号量上的最高优先级任务)Key_State OK状态(等待松开}{释放信号量(唤醒阻塞在该信号量上的最高优先级任务Key_State OK状态(等待松开}{释放信号量(唤醒所有阻塞在该信号量上的任务)Key_StateState_Press_OKOK状态(等待松开}{Key_State //}}case{//if(GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_2)&&GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_4)){Key_State //}}}return}个LED都翻转。Raw-os消息系统提供的机制有很多:queue,mqueue,queue_size,queue是最基本的消息模块了(消息在程序中的体现为一个指向用户数据的两种机制是可以合起来的,在发送消息的同时也发送消息大小嘛,Raw-os分开queue_buffercopy到其内部缓冲(FIFO),copy出来,这适用于某些特殊的情况mqueuequeue的特殊改进,即是对发送的消息进行优先级排序,紧急还是所有的任务?Post唤醒一个任务具体又是什么情况?/*enable/*enableSCHED_FIFOandSCHED_RR#define1提供不同的API供用户选用。LED的不同状态,实际的程序引入了等待u8 voidTask_Queue_Fun(void*{RAW_U16RAW_U32timeout_value=500;signedchar*msg;{res=raw_queue_receive(&Key_Queue,timeout_value,ifRAW_BLOCK_TIMEOUTres {}elseifRAW_SUCCESS {if(0==raw_strncmp((constchar*)msg,"KEY0",4){}elseif(0==raw_strncmp((constchar*)msg,"KEY1",4){}elseif(0==raw_strncmp((constchar*)msg,"KEY2",4){}}}}消息到队列中,任务接收后打印出消息内容,并根据内容控制LED翻转。queue_sizequeue这个新的数组结构名为RAW_MSG_SIZE,其定义如下:typedeftypedefstructRAW_MSG_SIZEstruct }指向用户发送数据段的指针void*msg_ptr,和用户数据段的大小msg_size。RAW_QUEUE_SIZERAW_QUEUE_SIZE raw_queue_size_createraw_queue_size_create(&Key_Queue,"KEY_QUEUE",key_queue,voidvoidMSG_SIZE_TYPE“KEY2123”三则消息到队列中,创建一个任务平时阻塞在消息上,一旦有消voidTask_Queue_Size_Fun(void*{RAW_U16RAW_U32timeout_value=500; void*msg; //消息指针MSG_SIZE_TYPE {if(RAW_BLOCK_TIMEOUT==res{}elseifRAW_SUCCESS {if(0==raw_strncmp((constchar*)msg,"KEY0",4){}elseif(0==raw_strncmp((constchar*)msg,"KEY1",4){}elseif(0==raw_strncmp((constchar*)msg,"KEY2",4){}}}}针,queue_sizequeue_buffer不在转存消息的指针,而是将消息copy一份到用户空间,也即转发消息内容和消息大小。RAW_QUEUE_BUFFERRAW_QUEUE_BUFFER 其中queue_buffer数组即为Key_Queue内部的一个顺序队列(此顺序队即copy到这个顺序队列中,创建队列如下:1024*4,voidvoidMSG_SIZE_TYPE队列中内容,并根据内容来控制LED的不同状态,实际的程序引入了等待voidTask_Queue_Buffer_Fun(void*{RAW_U16RAW_U32timeout_value=500个时钟周期,RAW_U8RAW_U8MSG_SIZE_TYPEraw_memset(msg,0,{if(RAW_BLOCK_TIMEOUT==res{}elseifRAW_SUCCESS {if(0==raw_strncmp((constchar*)msg,"KEY0",4){}elseif(0==raw_strncmp((constchar*)msg,"KEY1",4){}elseif(0==raw_strncmp((constchar*)msg,"KEY2",4){}}}}数据长度,这也和queue_buffer的内部数据,copy等实现机制有关,具体此问题作一个形像的演示,在下两节将说明采用mutex来解决此问题。在本例程序中了lcd_test命令,请首先保证LCD驱动程序正确,LCD设备的时候,会被高优先级任务抢占,这样造成LCD设备使用,因为低优voidFirst_Task(void*{{//优先级高,2sLCD资源LCD_ShowString(20,180,200,16,16,(u8*)"}}oThisisvoidSecond_Task(void*{charstr[]="ThisisSecondTask:";inti=0;{while(++i<{str[sizeof(str2i0x30;}if(i=={i=}}}LCDLCD2就被打断了。抢占,此时它还未使用完LCD。mutex的出现是为了解决优先级反转的问题,由于优先级反转对实时性影响太大,所以mutex的稳定性直接影响了实时性。纵观目前多种实时操作系统mutexRTOSmutex优先级逐步还原的问题,导致了实时性以及其它的一些逻辑错误等等。rawos的mutex模块成功弥补了其它实时系统在这方面的不足。Rawos的mutex同时支持优先级置顶和优先级继承的方式来解决优先级RAW_MUTEXraw_mutex_create(&lcd_mutex,(RAW_U8*)"lcd_mutex", ,级被自动提升为高优先任务的优先级,比如在本例中两个任务的优先级分别10分析采用mutex实验思路:创建两个任务分时使用LCD,在低优先级任务使用共享资源LCDmutex,它的优先级会被提升为高优先级任务的voidFirst_Task(void*{{//1.1优先级高,但要使用临界资源,也要先获得mutexUart_Printf("Task1getmutex,Task1currentPriorityis:LCD_ShowString(20,180,200,16,16,(u8*)" oThisisFirst //3.使用完毕,释放临界资源Uart_Printf("Task1putmutex\r\n");}}voidSecond_Task(void*{charstr[]="ThisisSecondTask:";inti=0;{任务切换,Task1要获得锁但被Task2占有,Task1把Task2的优先级提高,然后执行Task2Uart_Printf("Task2getmutex,Task2currentPriorityi=while(++i {str[sizeof(str2i0x30}Uart_Printf("Task2putmutex!\r\n");}}2raw_sleep进行任务切12的优先为和自已一样(故称优先级继承),然后接着执行任务2LCD设备,直到使用完毕释放锁后,阻塞在在对于mutex的使用,首先是定义并创建它:RAW_MUTEX//任务占有mutex时置顶的优先级为8raw_mutex_create(&lcd_mutex,(RAW_U8*)"lcd_mutex", ,8);#defineRAW_MUTEX_NONE_
priorityprotocol(优先级置顶)。所谓优先级置顶方法需要给每一个mutex静态指定一个优先级,第一个获得mutex的任务会把优先级提高到静态指定的优先级。优先级置顶的方法需要mutex的所有任务优先级都要搞清楚,通常适用于系统中运行的任mutex锁,这个时候假设mutex1的任务有t1,t2,t3,t1的优先级为20,t2的优先25,t330,数字越小表明优先级越高。这个时候mutex1的优先级置顶的优先级是19,即比t1,t2的优先级要高。假设任务t3首先获得mutex1,这个时候任务t3的优先级会提升为19,所以t3会运行完分析采用mutex实验思路:创建两个任务分时使用LCD,在低优先级任务使用共享资源LCDmutexmutex时指voidFirst_Task(voidvoidFirst_Task(void*{{mutex期间,mutex8Uart_Printf("Task1getmutex,Task1currentPriorityLCD_ShowString(20,180,200,16,16,(u8*)"oThisis /*Uart_Printf("Task1putmutex,Task1currentPriority}}voidSecond_Task(void*{charstr[]="ThisisSecondTask:";inti=0;{Uart_Printf("Task2getmutex,Task2currentPriorityi=while(++i<={str[sizeof(str)-2]=i+/*}Uart_Printf("Task2putmutex,Task2currentPriority}}动态内存分配往往是一个必需的过程,标准C库的malloc以及可以嵌入式系统上不是总是有标准CC标准C库中的malloc以 内存管理往往是一个复杂的过程,Raw-os5种内存分配方法,分别是block,byte,page,malloc,slab。以下会讲解这5种基本原理以及适用场合。这5种里面只有block和slab是没有内存碎片的,其余的都会有一定的5block和byte能用于中断内内存分配,强烈推荐使用中断内采用block内存分配,因为byte内存的分配除了在分配情况block内存分配顾名思义是一块块的分配内存给用户,每一块的内存空间都定了不利于不确定大小的内存分配。实战中可以分配多个不同大小的block去满足变长的分配完全是可行的。强烈建议大部分情况用block去解决内存分配如上如图所示分配了4个块,每块大小为2K。用户使用block内存分配2Kbyte内存分配顾名思义是可以分配任何大小的字节的内存给用户,缺点是page内存分配顾名思义是可以分配以page为单位的内存给用户去使用,pagepage2K4K大小。好处是用户大内存分配的话很方便,速度也很快。坏处是可能存在page级别的内存碎片。malloc内存分配是可以分配任意字节的小的,也存在内存碎片。具体和标准C库的内存分配全部吻合。slab内存分配也是基于一块块的分配给用户,不过这一块快的各自大小是rawos支持的内存种类繁多,从小级别的内存分配到大级别的内block内存分配方法对应的是raw_block.c,byte内存分配的方法对应的是raw_byte.c,page内存分配的方法对应的是raw_page.c,malloc的内存分配算法对应的是raw_malloc.c,slab内存分配算法对应的是raw_slab.c。在尊重实时操作系统RTOS的下,RAW-OS引进了额外4种内存heap_1,heap_2,heap_3,heap_4,4种内存分heap_1heap_2bestfitheap_3采用了C库自定义的malloc以及,但是加了可重入机制,对heap_4firstfitheap_1,heap_2heap_3,heap_4的时候,需要分别他们修改他们各自的配置文件来指定堆的大小等,比如heap_1_config.h,heap_2_config.h,heap_3_config.h,heap_4_config.h。blockbyte内存分配适合在中blockbyte内存分配方#define#defineRAW_BLOCK_SIZE1024* unsignedcharMEM_POOL 创建一个块内存池,10K,raw_block_pool_create(&block_pool,(RAW_U8*)"block_pool",1024,raw_block_pool,RAW_BLOCK_SIZE);voidFirst_Task(voidFirst_Task(void*{intret;inti=0;{ret=raw_block_allocate(&block_pool,ifRAW_NO_MEMORYret {Uart_Printf("blockpoolnomemorytobe} {ptr:%p\r\n",i,block_ptr[i]);iif(i>={i=}}}}voidSecond_Task(void*{inti=0;intret;{if(RAW_SUCCESS!=ret){}{block_ptr[i]=NULL; //释放后要置NULL}i}}voidThrid_Task(void*{inti;int{for(i0i20i {ifblock_ptr[iNULL)有效内存,{ret=raw_block_release(&block_pool,ifif(RAW_SUCCESS!={%d,blockptr:}{block_ptr[i]=NULL; //释放后要置NULLUart_Printf("blockreleasesuccess!,blocknumber:%d,blockptr:}}}}}#define#define 1024*voidFirst_Task(voidFirst_Task(void*{intret;inti=0;{ret=raw_byte_allocate(&byte_pool,(RAW_VOID1024*(i+1)ifRAW_NO_MEMORYret {Uart_Printf("bytepoolnomemorytobe} {%p\r\n",i,byte_ptr[i])iif(i>={i=}}}}voidSecond_Task(void*{inti=0;intret;{ret=raw_byte_release(&byte_pool,(RAW_VOIDif(RAW_SUCCESS!={Uart_Printf("bytereleaseerror!,bytenumber:%d,byte}{byte_ptr[i]=NULL; //释放后要置NULLUart_Printf("bytereleasesuccess!,bytenumberd,byteptr:}i}}voidThrid_Task(void*{inti;{for(i=0;i<20;i{if(byte_ptr[i]!=NULL{ret=raw_byte_release(&byte_pool,if(RAW_SUCCESS!={ptr:%p\r\n",i,byte_ptr[i]);}{byte_ptr[i]=NULL; //释放后要置NULLUart_Printf("blockreleasesuccess!,bytenumber:%d,byteptr:}}}}}本节演示基于RTOS的heap_4内存管理使用,首先添加heap_4.c源文其中heap_4.c文件在Raw-os源 下的 下面heap_4_config.h头文件在Raw-os源 下的Heap_4内存管理的API使用也相当简单:10K大小的内存控制块(内存池)2按下,为按键按下的次数,按键0按下,则释放所有内存。voidFirst_Task(void*{unsignedint{count= memory:%d}}voidSecond_Task(void*{inti={mem_ptr=mem_4_malloc(1000*i);if(NULL==mem_ptr){}{iUart_Printf("memorymallocsuccess,}}}voidThrid_Task(void*{{ mem_ptr=}}16.当一个任务需要和多种同步的时候可以使用标志来同步。一组事件标志有32个bit。一个任务可以同步任何一个的发生,这个时候就叫或的机制,也可以同步所有的发生,这个时候叫与的机制。理论上rawos可以无限的创建标志,但是实践上内存制约了这一点。标志的代码在raw_event.c。(and),假如一个任务等待几个标志位的任何一个满足条件,就能运行,这是没有的,如果满足标志了就相当于状态机的状态转换。建,设置,获取。代码如下://定义一 设置////设置 组的BIT2raw_event_set(&Key_Event,0x2,RAW_OR);获取////获取 的BIT3或BIT2,有任一满足返回, 到event_flag中raw_event_get(&Key_Event,0x6,RAW_OR_CLEAR,&event_flag,三个任务阻塞到这个上,当按键按下的时候,相应的任务被唤醒。voidFirst_Task(void*{{ raw_event_get(&Key_Event,0x2,RAW_OR_CLEAR,Uart_Printf("Task1ReceiveEventBIT2,theeventflagValueis:}}voidSecond_Task(void*{{ raw_event_get(&Key_Event,0x1,RAW_OR_CLEAR,Uart_Printf("Task1ReceiveEventBIT1,TheEventFlagValueis:}}voidThrid_Task(void*{{//阻塞等待 raw_event_get(&Key_Event,0x6,RAW_OR_CLEAR,is:0X%X\r\n",event_flag);}}17.::本实验的源码在eventset部分和上节一样,在eventget//获取 raw_event_get(&Key_Event,0x6,RAW_AND_CLEAR,&event_flag,//设置 组的BIT2raw_event_set(&Key_Event,0x2,RAW_OR);Idle_TaskCPU_Taskraw_config.h宏,这样系统中就有一个预定义的优先级为0的任务Task_0,它的源码在raw_task_0.c中。Tick_Task1,如果系统没有中,这样会影响到实时性,所以建议开启Tick_Task。Timer_Task任务中,#defineCPU_TASK_PRIORITY#defineCPU_STACK_SIZE
(CONFIG_RAW_PRIO_MAX-三项表示它的栈是256。这个函数通常放在配置完OS时钟之后:对于统计任务的使用就是开启宏,调用初始化函数两步,然后系统提供给//打印CPU利用率和最大CPU利用 Uart_Printf("CPUUsage:%d CPUMaxUsage:%d 本例程向系统中cpuusage命令,在s中输入此命令,查的FIFO即环形缓冲区,是只能在一端写数据,在另一端读的结构。是一种使放在extension 下的lib子 中,实现文件为fifo.c或fifo_lock.c,两个的区别在于后者在读写FIFO过程中加入了锁机制,这样对多任务环境下操作更安FIFO具体的原理请参见本文档的附录四RAW-OSFIFO机制分析,端中输入一个字符时,触发USART的接收中断,在中断中释放信号量去同步S任务,然后输入的字符存到缓中区中。如果收到的字符是回册符,则如果是回册符,则释放信号量去同步S任务去FIFO中的内容(命令字符ch=_Taskif(ch=={ }elseif(ch {故此处无处理,仅为演示Raw-os内核扩展模块FIFO的使用,}{ } /*/*等待信号量阻塞,直到终端输入回册符后唤醒////printalen=fifo_out_all(&USART1_FIFO,(void*)input_buffer);if(len){input_buffer[len]={ret mand((const}while(ret==}细心的读者会发现,面的例程中,都是任务阻塞在一个内核对像上,比如,在例程4中s任务阻塞一个信号量上,在例程7–9中任务阻塞在一个队rawos支持任务同时阻塞在队列(queue)或者信号量(semaphore)上。rawos实现多对象阻塞的功能主要是通过函数通知的功能来实现的。通过个的函数。怎么样一个函数通知功能的回调函数呢?举例如下raw_semphore_send_notify(&sem1,notify_function)通过此函数调用可以注册一个回调函数notify_function到信号量sem上,当用户使用函数raw_semaphore_put的时候就可以触发此回调函数。通过此函数可以一个回调函数notify_function到queue1上。当用户使用函数raw_queue_end_post时会触发此的回调函数。上图(1)处任务1需要等待queue1或者queue2有消息才能继续运行。queue1queue21(2)和(3)queue1queue21需要去接收,(4)和(5)1rawos对于上面问题的解决方式,不同的操作系上图(1)处任务1阻塞在网关处当sem1的内部计数器值为0时说明queue1和queue20queue1queue2有消息。(2)和(3)queue1queue21(4)和(5)处说明任务1接收了消息后继续运行。sem1的网关,具体的代码演示如下:queue1以及queue2上注册一个通知函数voidvoidnotify_queue(RAW_QUEUE{}可以看到只要queue1和queue2里面一有消息就会触发notify_queue回sem1,1。任务1的代码如下ret=raw_queue_receive(&queue1,RAW_NO_WAIT,if(ret=={/*Accessqueue1}retret=raw_queue_receive(&queue2,RAW_NO_WAIT,if(ret=={/*Accessqueue2}1sem1queue1queue2上有notify_queue这个回调函数,回调函数内会释放一个信号量,进而唤醒任务1。raw_queue_receive时需要采用没有消息立马返回的功能,即超时参数为RAW_NO_WAIT。void{//3. raw_queue_send_notify(&Queue_1,notify_queue_1);raw_queue_send_notify(&Queue_2,notify_queue_2);raw_queue_send_notify(&Queue_3,notify_queue_3);raw_task_create(&Task_MultiPend,(RAW_U8*)"Task_Multi",0,10,0,Task_MultiPend_Stack,TASK_STACK_SIZE,Task_MultiPend_Fun,}{}{}{}voidTask_MultiPend_Fun(void*{RAW_U16res;signedchar*msg;{ res=raw_queue_receive(&Queue_1,RAW_NO_WAIT,if(res=={}{{res=raw_queue_receive(&Queue_2,RAW_NO_WAIT,if(res=={}{}} if(0==raw_strncmp((constchar*)msg,"KEY0",4){}elseif(0==raw_strncmp((constchar*)msg,"KEY1",4){}elseif(0==raw_strncmp((constchar*)msg,"KEY2",4){}}}实验思路:创建一个任务阻塞在多个内核对像上,在本节例程中是阻塞在KEY2KEY1步任务,然后任务再从消息队列中消息或信号量。而控制不同的LED工作。中断下半部workqueueRaw-os提供独特的中断下半部机制,其实现方法有多种,具体原理与源码raw-osworkqueue实现方法。在这里做出实验说明。实验思路:500ms的#definePORT_STACK RAW_VOIDvoidMy_Func(RAW_U32arg,void{Uart_Printf("%d} unsignedcharmsg[]=unsignedintcount=oworld!msg void{/*模拟 到数据*/count++;if(count>999)count=msgmsg[sizeof(msg)-4]=count/100+0X30;msg[sizeof(msg)-3]=count%100/10+0X30;msg[sizeof(msg)-2]=count%10+0X30;}void{//初始化workqueuesystem//创建一个workqueue//}raw_os内核中采用了一套通用的、一般的、可以用到各种不同数据结构的previousnext从具体的“宿主”数LIST,这种数据结构既可以“寄宿”typedeftypedefstruct{structLISTstructLIST}{ list_head->previous=}{return(list->next==}RAW_INLINERAW_INLINEvoidlist_insert(LIST*head,LIST{element->previous=head->previous;element->next=head;head->previous->next=element;head->previous=element;}{element->previous->next=element->next;element->previous->next=element->next;}#define#definelist_entry(node,type,((type*)((RAW_U8*)(node)把上面的代码分开来理解,先说(RAW_U32)(&((type*)0)(type*)00type(RAW_U32)(&((type*)0)->member)RAW_U32型,事实上它就offset大小,再看(type*)((RAW_U8nodememberlist类型的结点,它是嵌入到宿主结构体nodeoffset (RAW_U8*)(node)(RAW_U32)(&((type*)0)->member)已经是宿主结构体的起始地址,再对它进行一下强制类型转换(type*)就得到宿主结构体类型了。RAW-OSS使用一种简单、易用、高效的机制使得应用程序支持命令行护一个单向链表,新加入令依次挂help这个链表头后面,当在应用层面输入命令时,执行s解析的任务会这个命令,并通过 函数从单链表头开始查找这个命令是否已(挂接到命令链表,每个命令会首先分析下一个命令所对应的数据结构类型,rsh.h文件中定义了定义一个typedeftypedefstruct{constRAW_S8*constRAW_S8*constRAW_S8}//上面的数据结构中第一项 typedeftypedefRAW_S32MAND_LINE_CALLBACK)(RAW_S8size_txWriteBufferLen,constRAW_S8mandString pcWriteBuffer:命令执行的输出结:eg:添加一个打印MCUIDstaticstaticconstmand{ no 0staticxCommandLineInputListItemmand_list_pointmand_list_point->pxNext=pxNewListItem;mand_list_point=pxNewListItem;} typedeftypedefstruct{constxCommandLineInput* structxCOMMAND_INPUT_LIST*pxNext;}mandLineDefinition那对于这个函数来说,首先是将欲添加令结构staticxCommandLineInputListItemmand_list_pointstaticxCommandLineInputListItemmand_list_point 上面代码是定义了一个指针,并初始化该指针指向链表的头结点—help命/*/*Thedefinitionofthe"help"command.Thiscommandisalwaysattheofthelistofregisteredcommands.staticconst mand{"help:Listsalltheregistered0/*/*定义一个命令链表,所有的 命令均挂接在这个链表上static mands{0command,definedinthisfile.*/arenootherregisteredcommandsyet.当启动系统时,首先启动s_Task,在s_Task中完成一些硬件初始化工作,然后依次各个命令,然后改变Task的优先级使其最低,并且让这个/*定义一个指针,指向当前正在检索的链表结点*pcWriteBuffer,size_txWriteBufferLen{RAW_S32xReturn=constRAW_S8* RAW_U8s_input_length; ifmandInput==0)}if(pcWriteBuffer==0)}if(xWriteBufferLen==0)}if mand_point==0)for mand_point mand_point!=0; mand_point mand_point->pxNext) mandString if(s_input_length mand_length)mpare_length=}else}
mpare_length if(raw_strncmp((constchar mandInput,(const mpare_length)==0) berOfParameters>=0){ if mandInput) erOfParameters){xReturn=}} }}}}if mand_point&&(xReturn==1))raw_strncpy((char*)pcWriteBuffer,"\rIncorrectcommandparameter(s).Enter\"help\"toviewalistofavailablecommands.\r\n\r\n",xWriteBufferLen); mand_point }elseif mand_point!=0)xReturn rpreter(pcWriteBuffer,xWriteBufferLen, if(xReturn==1) mand_point=}}elseraw_strncpy((char*)pcWriteBuffer,(constchar*)"\rCommandnotrecognised.Enter\"help\"toviewalistofavailablecommands.\r\n\r\n",xWriteBufferLen);xReturn=}return}//得到命令行的长度 staticstaticRAW_U8command_length_get(constRAW_S8{constRAW_S8for(sc=command;(*sc!='\0')&&(*sc!='');++sc)returnsc-command;}//得到参数的个数 staticstaticRAW_S8rsh_get_parameters_numbers(constRAW_S8{RAW_S8cParameters=RAW_S32xLastCharacterWasSpace=while({if(({mandString!=0x00mandString)==''if(xLastCharacterWasSpace!=0{ xLastCharacterWasSpace=0;}}{xLastCharacterWasSpace=}}return}//uxWantedParameter,RAW_S32*pxParameterStringLength{RAW_S32uxParametersFound constRAW_S8*pcReturn=while(uxParametersFound<uxWantedParameter{''){}}while(((==''){mandString)!=0x00)&&((}if( mandString!=0x00{if(uxParametersFound==uxWantedParameter{pcReturn while((( mandString)!=0x00)((mandString)!=''){(*pxParameterStringLength}}}{}}return}staticconstxCommandLineInputListItemstaticstaticmand(RAW_S8*pcWriteBuffer,xWriteBufferLen,constRAW_S8 mandString{RAW_S32(voidifmand_point==0)/*Resetmandpointerbacktothestartofthelist.mand_point }thenextcommandinthelist.raw_strncpy((char*)pcWriteBuffer,(const*mand_point ifmand_point==0)stringstoreturnafterthisoneand1shouldbereturned.*/xReturn=}elsexReturn=}return}附录三、RAW-OSW-OS0usSTM32平台编写的时钟节拍服务函数voidvoid{#if(CONFIG_RAW_TASK_0>}大0中断特性时的处理方法作一个分析。RAW_VOIDRAW_VOID{#if(CONFIG_RAW_TASK_0>0)if(raw_int_nesting)}#if(CONFIG_RAW_USER_HOOK>/*update/*updatesystemtimetocalculatewhethertasktimeout#if(CONFIG_RAW_TICK_TASK> /*updatetasktimesliceif#if(CONFIG_SCHED_FIFO_RR>0) //计算时间片/*informthetimertasktoupdatesoftwaretimer*/#if(CONFIG_RAW_TIMER>0) //开了定时器}系统时钟节拍的执行流程一般是这样的ISRISR时最后调用,那么这两个函数做了RAW_U16RAW_U16{ifif(raw_int_nesting>={return} return}义RAW_VOIDRAW_VOID{ //if(raw_int_nesting==0)}//中断嵌入层数-1if(raw_int_nesting)}if(raw_sched_lock)}ifif(high_ready_obj==raw_task_active)}}unsignedintcpu_sr={cpu_sr=#if#if(CONFIG_RAW_TICK_TASK> 0task_0机制,0tick_tasktick_taskraw_time_tickupdateticklist。txj的这句话让我深刻,Raw-os最大关中断0us特性确实牛X,task_0特性#if#if(CONFIG_RAW_TICK_TASK>staticvoidtick_task_process(void{while(1){retraw_task_semaphore_get(RAW_WAIT_FOREVER);ifif(ret==RAW_SUCCESS)if(raw_os_active==RAW_OS_RUNNING)}}}}void{//创建tick_task任务,用于updateticklistraw_task_create(&tick_task_objRAW_U8*)"tick_task_object"0,TICK_TASK_PRIORITY,0,tick_task_stack,TICK_TASK_STACK_SIZE,(RAW_U8*)"tick_semaphore_obj",0);}#if#if(CONFIG_RAW_TICK_TASK>这样用的,raw_task_semaphore_put(&tick_task_obj),直接把信号量发给了tick_taskRAW-OS中提供了任务信号量这种机制,当时确的知道ISR和任务或任务和任务之间的同步关系时,可以直接把信号量发给这个任务。合txj的讲解看,理解的更好。 FIFOLinuxFIFO有异曲同工之妙,是一种典型空余大小(字节structraw_fifostructraw_fifo这正是该fifo实现的精妙之处。staticstaticRAW_U32fifo_unused(structraw_fifo{return(fifo->mask+1)-(fifo->in-fifo-}RAW_S8fifo_init(structraw_fifo*fifo,void*buffer,RAW_U32RAW_U32fifo_in(structraw_fifo*fifo,constvoid*buf,unsignedintRAW_U32fifo_out(structraw_fifo*fifo,void*buf,RAW_U32len);RAW_U32fifo_out_peek(structraw_fifo*fifo,void*buf,RAW_U32len);RAW_U32fifo_out_all(structraw_fifo*fifo,voidstaticstaticstructraw_fifostaticchar//定义一个变量(uart接收数据缓冲//内存地址sizeRAW_S8fifo_init(structraw_fifo*fifo,void*buffer,RAW_U32{}fifo->in=fifo->out=fifo->data=if(size<2)fifo->mask=return}fifo->mask=size-1; _bytes=size;return}FIFO写(入队功能描述:把buf中len长度数据写入FIFO RAW_U32fifo_in(structraw_fifo*fifo,constvoid*buf,RAW_U32{RAW_U32l;l=if(len>lenlen=fifo_copy_in(fifo,buf,len,fifo-fifo->in _bytes-=return} len,RAW_U32off){RAW_U32RAW_U32size=fifo->mask+off&=fifo-l=fifo_min(len,size-off);raw_memcpy((unsignedchar*)fifo->data+off,src,lensizefifo->in,则下面是回写到队头,lensizeraw_memcpy(fifo->data,(unsignedchar*)src+l,len-}off&=fifo->maskfifo->in&(fifo->size1),在初始化代码保证了fifo->size2102410000000000,fifo->size101111111111,OKfifo->in对fifo->sizefifo->infifo->in本质上为unsignedint,溢出了呢?后面再分析。参数说明:fifo:目标FIFO;buf:读出数据的 地址;len:读出数据长度功能描述:从fifo中读出len长度的数据到buf中返回值:读出数据的长度RAW_U32fifo_out(structraw_fifo*fifo,void*buf,RAW_U32{ leninternal_fifo_out_peek(fifobuflen);fifo->out+=len; //移动读指针 _bytes+=len; return }参数说明:fifo:目标FIFO;buf:读出数据的 地址;len:读出数据长度功能描述:从fifo中off位置读出len长度的数据到buf中返回值:读出数据的长度RAW_U32{RAW_U32l=fifo->in-fifo- iflen len= // kfifo_copy_out(fifo,buf,len,fifo->out);returnlen; //返回 }参数说明:fifo:目标FIFO;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年湖北(高考)语文真题(含答案)
- 广东省阳江市2026年重点学校初一入学数学分班考试试题及答案
- 2026年辽宁省锦州市中小学教师招聘考试题库含答案
- 第四单元 第12讲 两宋的政治、军事与社会治理
- 公路安全员c证模拟考试试题及答案
- 内审模拟面试题及答案
- 换电站电池搬运设备升级及自动化搬运效率提升项目可行性研究报告
- DRG3.0时代医院、科室、医生的应对策略2026
- 二次回路相关反措学习总结
- 甘肃省张掖市2025-2026学年高考冲刺语文模拟试题含解析
- 实施指南(2025)《HB 8567-2019 轻小型无人直升机系统通 用要求》
- 人工智能+乡村振兴中国式现代化道路上的农村智能治理策略报告
- 青桐鸣大联考2025-2026学年高一上学期10月月考物理试卷
- 失独老人课题申报书
- 简单的详细房屋抵押合同模板7篇
- GJB1032A-2020 电子产品环境应力筛选方法
- 血透室水处理维护课件
- 工会经费审计条例课件
- 2025年机关事业单位工勤技能人员职业道德试题及答案
- 镀锌工安全教育培训手册
- 第三届全国技能大赛竞赛(软件测试赛项)选拔赛备考试题(附答案)
评论
0/150
提交评论