整个专栏主要是博主结合自身对FreeRTOS的实战学习以及源码分析,基于STM32F767 Nucleo-144平台,在CubeIDE下进行开发,结合官方的HAL库,将硬件环节的问题减少到最小,将精力主要放在RTOS的学习上.

相关文章

【FreeRTOS实战汇总】小白博主的RTOS学习实战快速进阶之路(持续更新)

1 FreeRTOS

FreeRTOS是免费的嵌入式实时系统,可以访问官网,至少目前是免费,并且社区相当活跃,但是以后会不会被割韭菜就不清楚了,所以感觉还是支持国产比较好,大家可以参考一下RT-Thread

1.1 获取源码

我们可以登陆到官网下载源码的压缩包,如下图所示;



FreeRTOS还将源码托管到github上,登陆官网可以看到下图的两个仓库;

  • FreeRTOS-Kernel:这个仓库是RTOS最核心的东西,很纯净,包括调度算法,信号量,内存管理等等,它同时作为一个子模块存在于FreeRTOS仓库中;
  • FreeRTOS:这个仓库是比较全的源码,除了核心的部分,还包括对各个芯片平台的支持以及各个主流IDE的demo,因此如果要移植的话,主要还是下载这个源码;

但是本文暂不会介绍如何移植RTOS,在远古时期,因为第三方的支持力度不够,因此有一些平台只能自己移植,现在第三方的支持相当于给力,直接拿来用即可.

1.2 源码结构

自动生成的代码中找到FreeRTOS的源码如下;







对于相应的文件夹和源码文件做一下介绍;

  • CMSIS_RTOS_V2:这是API的版本,对应的还有CMSIS_RTOS_V1;
  • portable:这里主要是移植的时候需要修改的一些文件,针对不同的MCU以及不同的编译器,需要对这块进行修改;
    • portmacro.h:定义编译器相关的数据类型和中断处理的宏定义;
    • port.c:实现任务的堆栈初始化systick任务上下文切换
  • MemMang:内存管理的文件,目前主要用heap_1.c,heap_2.c,heap_3.c,heap_4.c,heap_5.c
  • list.c:双向链表的实现,主要供给内核调度器使用;
  • queue.c: 队列的实现,主要支持中断环境和信号量控制;
  • croutine.c :任务使用同一个堆栈,这样使得减小RAM的使用,但是在使用上会受到相当大的限制;
  • task.c:每个任务都有各自的独立堆栈,支持完全的抢占式调度

2 CubeMX 整合 RTOS

  1. 在配置工程的时候或者打开后缀名为.ioccubemx配置文件;
  2. 点击菜单栏Pinout&Configuration
  3. 点击Middleware选择FREERTOS

具体如下图所示;

最终生成的文件结构如下图所示;



这时候已经将FreeRTOS集成到工程中了,*****,简直不能再方便了;

3 新建RTOS任务

直接生成的工程中,系统已经创建好了一个任务StartDefaultTask;

整体的main.c代码如下;

#include "main.h"
#include "cmsis_os.h" /* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 128 * 4
}; void SystemClock_Config(void);
static void MX_GPIO_Init(void);
void StartDefaultTask(void *argument); int main(void)
{
HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); osKernelInitialize(); defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
while (1)
{ }
} void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{ /* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE(); }
void StartDefaultTask(void *argument)
{
for(;;)
{
osDelay(1);
}
} void Error_Handler(void)
{ } #ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{ }
#endif /* USE_FULL_ASSERT */

这里可以看到整体的流程为两部分HAL层和OS层;

HAL

  • 硬件初始化 HAL_Init
  • 时钟配置 SystemClock_Config
  • BSP初始化 MX_GPIO_Init

OS

  • 内核初始化 osKernelInitialize
  • 创建任务/线程 osThreadNew
  • 任务调度 osKernelStart

整体流程图如下所示;

Created with Raphaël 2.2.0开始HAL_InitSystemClock_ConfigBSP_InitosKernelInitializeosThreadNewosKernelStart结束

从OS的设计上来讲,`Thread`拥有自己的`id`,并且可以分配`timer` 并且拥有一个类似线程的任务函数或者称为任务回调函数(可能不太严谨,下面统一称之为任务回调函数),因此这里定义一个FreeRTOS任务需要三点;

  1. osThreadId_t defaultTaskHandle;定义一个变量,后面创建任务会分配一个id作为该任务的唯一标识符/身份证;
  2. osThreadAttr_t defaultTask_attributes;作为定义一个任务时的参数,包括任务的优先级,所需要分配的栈空间大小.以及任务的名字等等;具体结构体osThreadAttr_t如下所示;
typedef struct {
const char *name; ///< name of the thread
uint32_t attr_bits; ///< attribute bits
void *cb_mem; ///< memory for control block
uint32_t cb_size; ///< size of provided memory for control block
void *stack_mem; ///< memory for stack
uint32_t stack_size; ///< size of stack
osPriority_t priority; ///< initial thread priority (default: osPriorityNormal)
TZ_ModuleId_t tz_module; ///< TrustZone module identifier
uint32_t reserved; ///< reserved (must be 0)
} osThreadAttr_t;
  1. 创建任务回调函数,这里有一个生命周期的问题,通常在任务中放一个死循环,以便于任务保持存活,可以被一直调度;
void StartDefaultTask(void *argument)
{
for(;;)
{
osDelay(1);
}
}

最后,调用osThreadNew创建任务;该函数声明如下所示;

osThreadId_t osThreadNew (	osThreadFunc_t func,
void *argument,
const osThreadAttr_t *attr);

4 总结

通过cube自动生成了一个FREERTOS工程,简单分析了一下如何创建一个任务,后续需要在实践中深入到源码中学习FreeRTOS

【FreeRTOS学习01】CubeIDE快速整合FreeRTOS创建第一个任务的更多相关文章

  1. spring boot学习01【搭建环境、创建第一个spring boot项目】

    1.给eclipse安装spring boot插件 Eclipse中安装Spring工具套件(STS): Help -> Eclipse Marketplace... 在Search标签或者Po ...

  2. 2月4号学习的一个SSM整合项目,第一课

    本文引自:https://github.com/Sunybyjava/seckill  原作者:sunybyjava@gmail.com seckill 一个整合SSM框架的高并发和商品秒杀项目,学习 ...

  3. 【FreeRTOS学习05】深度解剖FreeRTOSConfig.h实现对系统的自定义剪裁

    ROM/RAM太小,因此要对系统进行剪裁: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 相关文章 1 系统的剪裁 2 FreeRTOSConfi ...

  4. 【FreeRTOS学习02】源码结构/数据类型/命名规则总结

    个人不是很喜欢FreeRTOS的编程风格,但是没办法,白嫖人家的东西,只能忍了,这里先简单总结一下: 相关文章 [FreeRTOS实战汇总]小白博主的RTOS学习实战快速进阶之路(持续更新) 文章目录 ...

  5. (45)FreeRTOS学习之二

    一:架构概述 FreeRTOS是一个相对较小的应用程序.最小化的FreeRTOS内核仅包括3个(.c)文件和少数头文件,总共不到9000行代码,还包括了注释和空行.一个典型的编译后(二进制)代码映像小 ...

  6. FreeRTOS学习及移植笔记之一:开始FreeRTOS之旅

    1.必要的准备工作 工欲善其事,必先利其器,在开始学习和移植之前,相应的准备工作必不可少.所以在开始我们写要准备如下: 测试环境:我准备在STM32F103平台上移植和测试FreeRTOS系统 准备F ...

  7. 【零基础学习FreeRTOS嵌入式系统】之一:FreeRTOS环境搭建

    [零基础学习FreeRTOS嵌入式系统]之一:FreeRTOS环境搭建 一:FreeRTOS系统下载 在官网上https://www.freertos.org/,找到下载入口. 或直接进入下载地址ht ...

  8. 020 - FreeRTOS学习路线总结

    零.为什么写? 在H7-tools预售群里,有位朋友提出如何学习FreeRTOS这类的问题,便由此总结下自己的学习路线.最近又打算接触RTT,和FreeRTOS做个对比. 文章分两步来讲,学习路线和学 ...

  9. SpringBoot学习(六)—— springboot快速整合RabbitMQ

    目录 Rabbit MQ消息队列 简介 Rabbit MQ工作模式 交换机模式 引入RabbitMQ队列 代码实战 Rabbit MQ消息队列 @ 简介 优点 erlang开发,并发能力强. 社区活跃 ...

随机推荐

  1. 5个有趣的Python小知识,结果令人意外

    1 字符串驻留 如果上面例子返回True,但是下面例子为什么是False: 这与Cpython 编译优化相关,行为称为字符串驻留,但驻留的字符串中只包含字母,数字或下划线. 2 相同值的不可变对象 这 ...

  2. L6循环神经网络

    循环神经网络 本节介绍循环神经网络,下图展示了如何基于循环神经网络实现语言模型.我们的目的是基于当前的输入与过去的输入序列,预测序列的下一个字符.循环神经网络引入一个隐藏变量HHH,用HtH_{t}H ...

  3. 我用Python一键保存了半佛老师所有的骚气表情包

    本文首发于公众号「Python知识圈」,如需转载,请在公众号联系作者授权. 2019年发现两个有意思而且内容比较硬核的公众号.都是同一个人运营的,我们都叫他半佛老师,现实中的职业是风控,公众号内容涉及 ...

  4. Xor Path 牛客,HPU--C--LCA

    题解: 题目要求求出u和v两点在最短路径上的异或和.怎么确定最短路径呢?,就是U到LCA(u,v)的路径加上V到LCA(u,v).根据异或的性质,如k^a^a=k,即异或一个值两边等于原数值. 所以维 ...

  5. PHP函数:fwrite

    fwrite()  - 写入文件(可安全用于二进制文件) 说明: fwrite ( resource $handle , string $string [, int $length ] ) : int ...

  6. tensorflow1.0 矩阵相乘

    import tensorflow as tf matrix1 = tf.constant([[3,3]]) matrix2 = tf.constant([[2],[2]]) product = tf ...

  7. php的一个有意思的命令:-S

    php -S localhost:8188 /web 会启动一个监控IP:PORT 的http服务,算是简易的web服务器吧.基本上,实现了PHP+MySQL就可以建立一个简易测试网站的环境.

  8. serialize和json_encode 区别

    (1)serialize主要用于php的序列化,存储到文件或者数据库中,json_encode 也是序列化,但是 主要用于与其他语言比如js进行交互使用,对于传输来说,json有许多优点. (2)在显 ...

  9. css中的宽和高

    width width表示宽 height height表示高 max-width.min-width max-width表示最大宽度 min-width表示最小宽度 max-height.min-h ...

  10. strpos的坑

    $a = 'abcd'; $c = 'a'; echo strpos($a,$c)!==false ? '原来是兄弟' : '非我族类,砍ta';