- 积分
- 3537
- 下载分
- 分
- 威望
- 点
- 原创币
- 点
- 下载
- 次
- 上传
- 次
- 注册时间
- 2014-11-13
- 精华
|
马上注册,获取阅读精华内容及下载权限
您需要 登录 才可以下载或查看,没有帐号?注册
x
又是一周过去了,这周使用F412跑个RTOS,性能绝对杠杠的,不过这次改成了标准库,整个软件工程的结构也进行了调整。1MB的flash可以做很多事情。只不过有一点遗憾,就是这个flash的SECTOR太大,用来模拟eeprom有点浪费,也浪费内存。从最开始玩了一下uCOS,对实时操作系统也有一个简单的入门,不过当时虽然听说有FreeRTOS这么一个轻便的实时内核,但是由于编程能力有限,再加上思维上的错误,导致刚接触就退缩了。后来出于好奇,再次开始捣鼓这个实时内核,不过这次有点不同,主要是思维上的转变,开始不再深入内核源码,而是直接使接口函数,把它当个工具来用,后来熟悉了,遇到问题了再稍微深入源码看一下。前期还是要多看一些资料。
FreeRTOS的移植要比uCOS简单,重点就在FreeRTOSConfig.h这个文件中进行配置,对内核进行裁剪。
既然有了内核,那么就应该好好利用内核提供的接口函数。内核固然很好,但是过分依赖于内核,会导我们的代码过分依赖于内核,降低了可移植性。所以需要尽量做一些封装,先对信号量做一些封装,这也是学了一下lwip协议栈。
先定义一下信号量类型。
- typedef struct{
- int count;//初始值为0,表示当前已被占用信号量的个数。
- void *sem;//信号量。
- }os_sem_t;
[color=rgb(51, 102, 153) !important]复制代码
下面是信号量的两个操作函数。
- int os_sem_get(os_sem_t*sem,int count);//获取信号量,count是创建信号量时的信号量总数,这个必须确定,这个地方做的不太好。
- int os_sem_del(os_sem_t*sem);//用完之后需要释放信号量
[color=rgb(51, 102, 153) !important]复制代码
接下来是这两个函数的具体实现,os_sem_get在获取信号量时,如果不存在,则会创建,这也是其参数count的作用。os_sem_del在释放信号量时,如果信号量已全部释放,则会自动释放信号量暂用的内存空间。
- int os_sem_get(os_sem_t*sem,int count)
- {
- BaseType_t xResult;
- if(sem->sem==NULL)
- {
- sem->count=0;
- sem->sem = pvPortMalloc(sizeof(SemaphoreHandle_t));//首次使用,需要创建
- if(sem->sem==NULL)
- return -1;
- sem->sem = xSemaphoreCreateCounting(count, count);
- }
- if(sem->sem==NULL)
- return -2;
- xResult = xSemaphoreTake(sem->sem, portMAX_DELAY);
- if(xResult!=pdTRUE)
- return -3;
- sem->count++;
- return 0;
- }
- <blockquote>int os_sem_del(os_sem_t*sem)
[color=rgb(51, 102, 153) !important]复制代码
接下来就使用这两个函数把printf函数封装成线程安全的print函数。关键就是调用printf之前先获取信号量,获取成功后再执行printf,执行完后要释放信号量,不然下次就无法再次执行printf。这里再插一句,由于printf这里是重映射到串口,所以,应该建立一个二值信号量,保证串口的发送函数顺序不会出错。所以这里再次对这个信号量进行封装,如下,注意应该首先建立一个com_tx_sem信号量。
- #define com_get_sem() os_sem_get(&com_tx_sem, 1)
- #define com_del_sem() os_sem_del(&com_tx_sem)
[color=rgb(51, 102, 153) !important]复制代码
下面对printf进行封装。printf是一个参数个数可变的函数,暂时也就是仿照网上的方法,使用,printf内部的具体实现没有深入了解。封装之后就可以使用了。
- int os_print(const char *fmt, ...)
- {
- int res = -1;
- com_get_sem();
- va_list args; //定义va_list类型变量,用来存储单个参数
- va_start(args, fmt); //使用args指向可变参数的第一个参数
- res = printf(fmt, args); //直接传给printf
- va_end(args); //结束可变参数的获取
- com_del_sem();
- return res;
- }
[color=rgb(51, 102, 153) !important]复制代码
虽然互斥信号量可以解决优先级反转的问题,但是这需要暂时提升低优先级任务的优先级,在学习FreeRTOS的时候了解到,可以使用守护任务,对于共享资源,使用一个任务进行操作,其他任务通过这个任务间接的使用共享资源,这样就不会有优先级反转的问题了,这样的结构确实挺好。
这里就是使用一个任务来打印字符,另外建立两个任务,向这个任务发送数据,通过这个任务把数据打印到串口终端上。任务之前的数据传送是通过os_printstr函数向队列中发送数据。再专门建立一个任务来处理队列中的数据。先贴个效果图。
接下来看一下处理数据的具体实现,又是贴代码,见谅了。
- int os_printstr(const char *str)
- {
- portBASE_TYPE xStatus;
- int ret=-1;
- if(pxPrintQueue==NULL)
- {
- pxPrintQueue = xQueueCreate(5, sizeof(int));
- }
- xStatus=xQueueSendToBack(pxPrintQueue, &str, portMAX_DELAY);
- if(xStatus!=pdPASS)
- {
- ret = os_print("Could not send to printstr queue.\r\n");
- }
- return ret;
- }
- void vTaskPrint(void *pvParameter)
- {
- portBASE_TYPE xStatus;
- char *str = NULL;
- os_print("print task startup!\r\n");
- while(1)
- {
- if(pxPrintQueue!=NULL)
- {
- xStatus = xQueueReceive(pxPrintQueue, &str, portMAX_DELAY);
- if(xStatus==pdPASS)
- os_print(str);
- else
- os_print("Could not receive from printstr queue.\r\n");
- }
- vTaskDelay(10);
- }
- }
[color=rgb(51, 102, 153) !important]复制代码
接下来是向队列中发送数据的任务。这个就很简单了,使用xTaskCreate建立两个任务,仅仅传入参数不一样。
- void vTaskPrintDemo(void *pvParameter)
- {
- while(1)
- {
- os_printstr((const char *)pvParameter);
- vTaskDelay(1000);
- }
- }
[color=rgb(51, 102, 153) !important]复制代码
|
|