在开发实际应用系统时,我们经常需要考虑数据的实时性和多任务,嵌入式实时操作系统的出现为实现这一目的提供了很好的助力。FreeRTOS是近年来比较流行的嵌入式实时操作系统,而且是开源免费的,STM32CubeMX对它也提供了支持。我们可以使用STM32CubeMX很方便的添加上FreeRTOS,只需要在配置界面找到“MiddleWares”并将其下的FreeRTOS选为“Enable”就可添加上FreeRTOS:

配置完成后,更新源码就会在软件中添加上FreeRTOS的相关文件,各文件的功能网上已经有很多介绍,就不啰嗦了,而且也不属于我们需要说明的内容。

添加完了之后,源码中就会添加创建一个缺省任务的代码。因为最少要有一个任务才有意义。查看main()函数,就会出现如下这样一段代码:

/* Create the thread(s) */

/* definition and creation of defaultTask */

osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);

defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

/* USER CODE BEGIN RTOS_THREADS */

/* add threads, ... */

/* USER CODE END RTOS_THREADS */

/* USER CODE BEGIN RTOS_QUEUES */

/* add queues, ... */

/* USER CODE END RTOS_QUEUES */

/* Start scheduler */

osKernelStart();

其实这段代码就实现两个功能:创建任务和情动任务调度。不过ST在FreeRTOS的基础上做了进一步的封装。其中osKernelStart()函数用于启动任务调度,这个函数比较简单只不过是调用了一下FreeRTOS中的任务调度函数vTaskStartScheduler(),其实现原型如下:

osStatus osKernelStart (void)

{

vTaskStartScheduler();

return osOK;

}

而实现任务创建的就是osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);和defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);这两行代码。这两行代码就是创建了一个任务显示名称为defaultTask的StartDefaultTask任务。带是代码看起来有点不容易理解,其实是ST进行了进一步封装的结果。

首先osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128)其实是一个宏,其定义的原型如下:

#define osThreadDef(name, thread, priority, instances, stacksz)  \

const osThreadDef_t os_thread_def_##name = \

{ #name, (thread), (priority), (instances), (stacksz)  }

那么osThreadDef_t又是个什么呢?其实是ST定义的创建任务的参数结构体:

typedef struct os_thread_def  {

char                   *name;        ///< Thread name

os_pthread             pthread;      ///< start address of thread function

osPriority             tpriority;    ///< initial thread priority

uint32_t               instances;    ///< maximum number of instances of that thread function

uint32_t               stacksize;    ///< stack size requirements in bytes; 0 is default stack size

} osThreadDef_t;

所以第一句的含义就很明确了,就是定义了一个osThreadDef_t类型的变量用于存储用于创建任务的参数。第二句很明显是一个函数调用,但参数与我们见到的FreeRTOS中的创建任务的函数有些不同。其实它的第一个参数osThread(defaultTask)也是一宏:

#define osThread(name)  \

&os_thread_def_##name

其实就是调用第一句中定义的osThreadDef_t类型的结构体变量。这样就明确了,第二句实际上就是调用FreeRTOS中的任务创建函数创建任务:

osThreadId osThreadCreate (const osThreadDef_t *thread_def, void *argument)

{

TaskHandle_t handle;

if (xTaskCreate((TaskFunction_t)thread_def->pthread,(const portCHAR *)thread_def->name,

thread_def->stacksize, argument, makeFreeRtosPriority(thread_def->tpriority),

&handle) != pdPASS)  {

return NULL;

}

return handle;

}

所以我们要创建其他的任务,只需照此设计即可。当然任务中的内容根据需要修改,STM32CubeMX添加的缺省任务,参数和实现内容也可以更改。在这里我们不对缺省任务做太多修改,在其任务函数中添加部分我们的内容。

考虑到我们所应用到的功能,我们需要6个任务,利用上缺省任务我们还需要添加5个任务。之所以要添加这么多的任务是因为我们不想让各种功能相互影响。在某一外设出现操作错误时不会影响其他部分的应用,这也是我们使用多任务实时操作系统的原因之一。

缺省任务我们让它来跑逻辑控制。再增加几个任务分别来跑各种功能,由于AD和DA都是通过SPI1通讯来完成的,所以采用同一个任务。

首先定义几个任务操作句柄:

/*定义任务句柄*/

osThreadId defaultTaskHandle;

osThreadId addaTaskHandle;

osThreadId ndirTaskHandle;

osThreadId lcdTaskHandle;

osThreadId ethernetTaskHandle;

osThreadId paraTaskHandle;

在声明对应的任务处理函数:

/*声明任务处理函数*/

void StartDefaultTask(void const * argument);

void ADDATask(void const * argument);

void NDIRTask(void const * argument);

void LCDTask(void const * argument);

void EthernetTask(void const * argument);

void ParameterTask(void const * argument);

编写各任务处理函数,由于各种功能在之前已经实现了所以任务函数比较简单:

/* 缺省任务,用来处理逻辑控制 */

void StartDefaultTask(void const * argument)

{

for(;;)

{

/*逻辑处理*/

LogicOperation();

osDelay(1);

}

}

/* AD/DC数据处理任务函数 */

void ADDATask(void const * argument)

{

for(;;)

{

/*获取AD采集的测量值*/

GetMeasuredValue();

/*设置模拟量输出*/

SetOutputValue();

osDelay(1);

}

}

/* 远红外炭氢检测数据处理任务函数 */

void NDIRTask(void const * argument)

{

for(;;)

{

/*获取CH4测量值*/

GetNDIRData();

osDelay(1);

}

}

/* LCD显示通讯处理任务函数 */

void LCDTask(void const * argument)

{

for(;;)

{

/*显示屏数据通讯*/

LCD_DataExchange();

osDelay(1);

}

}

/* 以太网通讯处理任务函数 */

void EthernetTask(void const * argument)

{

for(;;)

{

/*以太网通讯处理*/

EthernetProcess();

osDelay(1);

}

}

/* 参数存取处理任务函数 */

void ParameterTask(void const * argument)

{

for(;;)

{

/*参数的存储、恢复等处理*/

ParameterProcess();

osDelay(1);

}

}

再在系统中创建任务:

/* Create the thread(s) */

/* definition and creation of defaultTask */

osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);

defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

/* USER CODE BEGIN RTOS_THREADS */

osThreadDef(addaTask, ADDATask, osPriorityNormal, 0, 128);

addaTaskHandle = osThreadCreate(osThread(addaTask), NULL);

osThreadDef(ndirTask, NDIRTask, osPriorityNormal, 0, 128);

ndirTaskHandle = osThreadCreate(osThread(ndirTask), NULL);

osThreadDef(lcdTask, LCDTask, osPriorityNormal, 0, 128);

lcdTaskHandle = osThreadCreate(osThread(lcdTask), NULL);

osThreadDef(ethernetTask, EthernetTask, osPriorityNormal, 0, 128);

ethernetTaskHandle = osThreadCreate(osThread(ethernetTask), NULL);

osThreadDef(paraTask, ParameterTask, osPriorityNormal, 0, 128);

paraTaskHandle = osThreadCreate(osThread(paraTask), NULL);

/* USER CODE END RTOS_THREADS */

至此在系统中添加FreeRTOS的过程完成,编译调试看看结果:

编译无错误,运行正常。通过IO中断看看运行结果与没有操作系统时有没有区别:

在运行一段时间后再看看结果:

系统运行无误,与我们所希望的一样。

STM32F412应用开发笔记之九:移植FreeRTOS到F412ZG平台的更多相关文章

  1. FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放

    前言   ffmpeg播放rtsp网络流和摄像头流.   Demo   使用ffmpeg播放局域网rtsp1080p海康摄像头:延迟0.2s,存在马赛克     使用ffmpeg播放网络rtsp文件流 ...

  2. Java开发笔记(九十一)IO流处理简单的数据压缩

    前面介绍的文件I/O,不管是写入文本还是写入对象,文件中的数据基本是原来的模样,用记事本之类的文本编辑软件都能浏览个大概.这么存储数据,要说方便确实方便,只是不够经济划算,原因有二:其一,写入的数据可 ...

  3. Java开发笔记(九十七)利用Runnable启动线程

    前面介绍了线程的基本用法,按理说足够一般的场合使用了,只是每次开辟新线程,都得单独定义专门的线程类,着实开销不小.注意到新线程内部真正需要开发者重写的仅有run方法,其实就是一段代码块,分线程启动之后 ...

  4. STM32F412应用开发笔记之五:结合W5500实现以太网通讯

    因实际使用需求我们测试一下网络通讯,在NUCLEO-F412ZG测试板上没有以太网部分,我们选择外接一个W5500的实验板.W5500支持SPI接口通讯,DC3.3V供源.而NUCLEO-F412ZG ...

  5. STM32F412应用开发笔记之一:初识NUCLEO-F412ZG

    今天终于收到了期待已久的NUCLEO-F412ZG,感谢电子发烧友论坛! 近几年来基本都是在STM32平台上做一些设计开发工作.STM32F103.STM32F107.STM32F429等都应用过,但 ...

  6. STM32F412应用开发笔记之三:SPI总线通讯与AD采集

    本次我们在NUCLEO-F412ZG试验模拟量输入采集.我们的模拟量输入采用ADI公司的AD7705,是一片16位两路差分输入的AD采集芯片.具有SPI接口,我们将采用SPI接口与AD7705通讯.两 ...

  7. STM32F412应用开发笔记之二:基本GPIO控制

    NUCLEO-F412ZG板子上的元器件并没有完全焊接,除去ST-LINK部分和电源部分后,还有用一个USB主机接口,三个LED灯和两个按钮,不过很多功能引脚都已经引到了插针.查看原理图可发现,由原理 ...

  8. Modbus库开发笔记之九:利用协议栈开发Modbus TCP Server应用

    前面我们已经完成了Modbus协议栈的开发,但这不是我们的目的.我们开发它的目的当然是要使用它来解决我们的实际问题.接下来我们就使用刚开发的Modbus协议栈开发一个Modbus TCP Server ...

  9. STM32F412应用开发笔记之十:多组分气体分析仪设计验证

    本次将NUCLEO-F412ZG应用于我们的多组分气体分析仪的实现试验,从整体上测试实际项目的应用情况. 一.项目概述 多组分气体分析仪是我公司近期研发的三个主要产品之一.采用模块化设计,可增减配置, ...

随机推荐

  1. 线程Thread类

    进程:资源分配与调动的基本单位.如QQ.迅雷等每个独立运行的程序就是一个进程. 每一个进程可以有多个线程,如QQ可以收发信息.下载上传文件等. 多线程同时工作时,由CPU分配处理. public cl ...

  2. 在Linux上安装Elasticsearch5.x

    这里使用elasticsearch做全文检索,不是ELK日志采集. elasticsearch作为全文检索,必须服务端和客服端的版本一致,所以在安装elasticsearch时,要注意版本问题. 前言 ...

  3. scrapy 动态IP、随机UA、验证码

    随机UA https://github.com/hellysmile/fake-useragent DOWNLOADER_MIDDLEWARES增加自定义 from fake_useragent im ...

  4. python爬虫 bs4_4select()教程

    http://www.w3.org/TR/CSS2/selector.html 5 Selectors Contents 5.1 Pattern matching 5.2 Selector synta ...

  5. Python全栈问答小技巧_1

    Python全栈测试题 作者:尹正杰 声明:答案如有偏差,欢迎指正!欢迎加入高级运维工程师之路:598432640 本文答题用的Python版本是:Python 3.5.2,请知晓! 1.执行 Pyt ...

  6. Simple Sort

    题目描述 You are given an unsorted array of integer numbers. Your task is to sort this array and kill po ...

  7. cpu load过高问题排查

    load average的概念 top命令中load average显示的是最近1分钟.5分钟和15分钟的系统平均负载. 系统平均负载被定义为在特定时间间隔内运行队列中(在CPU上运行或者等待运行多少 ...

  8. Bootstrap的响应式后台管理模板推荐

    1.Admin LTE 该模版开源免费.已用到项目中,客户评价说UI很好看... AdminLTE - 是一个完全响应式管理模板.基于Bootstrap3的框架.高度可定制的,易于使用.支持很多的屏幕 ...

  9. SQL Server分页进化

    DataReader.Dataset 数据量太大就用datareader,dataset都读到内存里了,datareader是直接读取数据库. DataReader是一个快速的只进游标 DataRea ...

  10. Postfix邮件服务 - DNS配置

    DNS 域名系统服务器 IP 与 域名之间解析 :提供分层的域名解析 服务:bing 伯克利加州大学 应用最广的域名服务系统: bind 主要分为 主配置文件 和 域数据记录文件 yum 安装: yu ...