基于在STM32下完成FreeRTOS的多任务程序开发,多任务串口以及AHT20封装库,原理图,PCB图以及AHT20(实际用到的是LMT70)及采集一次温度数据的模块实战

基于在STM32下完成FreeRTOS的多任务程序开发,多任务串口以及AHT20封装库,原理图,PCB图以及AHT20(实际用到的是LMT70)及采集一次温度数据的模块实战

序 言

1)FreeRTOS

(一)FreeRTOS简介

--------- FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。

(二)FreeRTOS基本原理

---------任务调度机制是嵌入式实时操作系统的一个重要概念,也是其核心技术。对于可剥夺型内核,优先级高的任务一旦就绪就能剥夺优先级较低任务的CPU使用权,提高了系统的实时响应能力。不同于μC/OS-II,FreeRTOS对系统任务的数量没有限制,既支持优先级调度算法也支持轮换调度算法,因此FreeRTOS采用双向链表而不是采用查任务就绪表的方法来进行任务调度

当任务、队列和信号量创建的时候,FreeRTOS要求分配一定的RAM。虽然采用malloc()和free()函数可以实现申请和释放内存的功能,但这两个函数存在以下缺点:并不是在所有的嵌入式系统中都可用,要占用不定的程序空间,可重入性欠缺以及执行时间具有不可确定性。为此,除了可采用malloc()和free()函数外,FreeRTOS还提供了另外两种内存分配的策略,用户可以根据实际需要选择不同的内存分配策略。

第1种方法是按照需求内存的大小简单地把一大块内存分割为若干小块,每个小块的大小对应于所需求内存的大小。这样做的好处是比较简单,执行时间可严格确定,适用于任务和队列全部创建完毕后再进行内核调度的系统;这样做的缺点是,由于内存不能有效释放,系统运行时应用程序并不能实现删除任务或队列。
第2种方法是,采用链表分配内存,可实现动态的创建、删除任务或队列。系统根据空闲内存块的大小按从小到大的顺序组织空闲内存链表。当应用程序申请一块内存时,系统根据申请内存的大小按顺序搜索空闲内存链表,找到满足申请内存要求的最小空闲内存块。为了提高内存的使用效率,在空闲内存块比申请内存大的情况下,系统会把此空闲内存块一分为二。一块用于满足申请内存的要求,一块作为新的空闲内存块插入到链表中。
方法2的优点,能根据任务需要高效率地使用内存,尤其是当不同的任务需要不同大小的内存的时候。方法2的缺点是,不能把应用程序释放的内存和原有的空闲内存混合为一体,因此,若应用程序频繁申请与释放“随机”大小的内存,就可能造成大量的内存碎片。方法2的另一个缺点是,程序执行时间具有一定的不确定性。
(三)FreeRTOS总结

作为一个轻量级的操作系统,FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能等,可基本满足较小系统的需要。FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU总是让处于就绪态的、优先级最高的任务先运行。FreeRTOS内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。
FreeRTOS的内核可根据用户需要设置为可剥夺型内核或不可剥夺型内核。当FreeRTOS被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这样可提高CPU的运行效率。

2)AHT20

== AHT20简介==

2020年上市,奥松生产;
3mmx3mmx1mm 超小体积;
经过标定的数字信号,标准I2C输出格式;
由一个电容式湿度传感元件和一个标准的片上温度传感元件组成;
采用SMD封装适于回流焊;
响应迅速、抗干扰能力强;
AHT20 的供电范围为 2.0-5.5V, 推荐电压为3.3V。
在这里插入图片描述

二.项目说明

1.)阅读国产温湿度采集芯片AHT20数据手册,在stm32最小系统电路原理中添加 AHT20数据采集原理电路
2).学习FreeRTOS原理,了解FreeRTOS的多任务程序的实现
3).在STM32下完成一个基于FreeRTOS的多任务程序,执行3个周期性task具体任务不限,但建议如下:task1,每间隔500ms闪烁(变化)一次LED;task2,每间隔2000ms,向串口发送一次指令数据“helloworld!";task3,每间隔5000ms,从AHT20采集一次温湿度数据(不考虑硬件情况,仅写出整个多任务框架模拟代码)。

三.创建AHT20封装,以及画原理图

博主前面有绘制原理图的相关教程,如果想看详细过程请关注博主,然后找到前面绘制原理图的博客,需要AHT20封装的朋友们请关注末尾我的微信公众号,回复:AHT20
这里博主只讲主要的过程
首先我们可以百度查找AHT20产品手册
在这里插入图片描述

然后绘制创建工程绘制AHT20 PCB
在这里插入图片描述
AHT20 sch
在这里插入图片描述
导入库
在这里插入图片描述
根据AHT20产品手册绘制原理图
在这里插入图片描述

在这里插入图片描述

四.由STM32最小系统板画PCB图

博主在另外一篇博客中有详细介绍PCB画法,这里就不多讲述链接: PCB设计,Altium Designer软件绘制一个stm32最小系统的电路原理图、PCB图,以及添加个性logo,生成生成BOM表和网络表以及输出为Gerber光绘文件。(二).
布线
在这里插入图片描述

在这里插入图片描述
LOGO展示
在这里插入图片描述

在这里插入图片描述
电气检查
在这里插入图片描述

五.FreeRTOS实战过程

我们的实战过程博主主要讲解的是,第一,我们自己画加AHT20模块原理图,第二我们要如何利用模板来快速上手FreeRTOS

1)实验器材

1.野火mini开发板
2.j—link下载线
3.LMT70(本来是想用LMT20的,但是博主刚好有LMT70)

在这里插入图片描述

2)开始实战

博主这里使用的是野火mini开发板的资料快速上手首先我们可以在官网下载野火mini的开发板资料

注意:这是野火开源的资源,但是只能用于学习

野火所有产品资料下载链接:
http://products.embedfire.com(复制到浏览器打开)
教学视频可直接B站在线观看:https://space.bilibili.com/356820657(复制到浏览器打开)
为更加方便的下载资料,请安装“野火大学堂”客户端,下载资料速度远超百度云,还可以在线看视频
客户端下载地址: http://t.cn/A62lVJAk (复制到浏览器打开)


1.下载完成后我们可以找到SRAM动态创建多任务这个模板
在这里插入图片描述
2.打开工程文件
在这里插入图片描述
在这里插入图片描述
3.进行分析,我们可以发现这个模板创建一个多任务主要四个部分组成,其实比较简单
/* LED1任务句柄 */

static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED1任务句柄 */
static TaskHandle_t LED1_Task_Handle = NULL;
/* LED2任务句柄 */
static TaskHandle_t LED2_Task_Handle = NULL;

函数声明

/*
*************************************************************************
*                             函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */

static void LED1_Task(void* pvParameters);/* LED1_Task任务实现 */
static void LED2_Task(void* pvParameters);/* LED2_Task任务实现 */
static void usb_Task(void* pvParameters);/* LED2_Task任务实现 */
	

/* 创建LED_Task任务 */

  /* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED1_Task, /* 任务入口函数 */
                        (const char*    )"LED1_Task",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )2,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LED1_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
    //printf("创建LED1_Task任务成功!\r\n");
  
	/* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* 任务入口函数 */
                        (const char*    )"LED2_Task",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )3,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LED2_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
		

任务主体构成

**********************************************************************
  * @ 函数名  : LED_Task
  * @ 功能说明: LED_Task任务主体
  * @ 参数    :   
  * @ 返回值  : 无
  ********************************************************************/
static void LED2_Task(void* parameter)
{	
    while (1)
    {
        LED2_ON;
        vTaskDelay(500);   /* 延时500个tick */
        
			
        
        LED2_OFF;     
        vTaskDelay(500);   /* 延时500个tick */		 		
        
    }
		
}

在这里插入图片描述

3)任务实现

其实非常简单,我们可以按照他的模板自己添加,博主这里只需要一个LED,和一个串口模块,以及一个LMT70采集一次温湿度数据的模块,所以博主修改如下:

/* LED1任务句柄 */

 /* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED1任务句柄 */
static TaskHandle_t LED1_Task_Handle = NULL;
/* LED2任务句柄 */
static TaskHandle_t LMT70_Task_Handle = NULL;

static TaskHandle_t Usart_Task_Handle = NULL;

函数声明

*************************************************************************
*                             函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */

static void LED1_Task(void* pvParameters);/* LED1_Task任务实现 */
static void AHT20_Task(void* pvParameters);/* AHT20_Task任务实现 */
static void Usart_Task(void* pvParameters);/* Usart_Task任务实现 */
	

/* 创建Task任务 */,这里注意的是我们的任务优先级可用的是2—15,所以我们选择的时候要注意

 /* 创建LED_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LED1_Task, /* 任务入口函数 */
                        (const char*    )"LED1_Task",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )2,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LED1_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
    //printf("创建LED1_Task任务成功!\r\n");
 
	/* 创建Usart_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )Usart_Task, /* 任务入口函数 */
                        (const char*    )"Usart",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )3,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&Usart_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
  	/* 创建AHT70_Task任务 */
  xReturn = xTaskCreate((TaskFunction_t )LMT70_Task, /* 任务入口函数 */
                        (const char*    )"LMT70_Task",/* 任务名字 */
                        (uint16_t       )512,   /* 任务栈大小 */
                        (void*          )NULL,	/* 任务入口函数参数 */
                        (UBaseType_t    )4,	    /* 任务的优先级 */
                        (TaskHandle_t*  )&LMT70_Task_Handle);/* 任务控制块指针 */
  if(pdPASS == xReturn)
		
    //printf("创建AHT70_Task任务成功!\r\n");

任务主体构成,博主这里直接设置了三个任务,一个是LED灯,一个是串口通信,还有一个是LMT70读取温度

/**********************************************************************
  * @ 函数名  : LED_Task
  * @ 功能说明: LED_Task任务主体
  * @ 参数    :   
  * @ 返回值  : 无
  ********************************************************************/
static void LED1_Task(void* parameter)
{	
    while (1)
    {
        LED1_ON;
        vTaskDelay(500);   /* 延时500个tick */
        
        
        LED1_OFF;     
        vTaskDelay(500);   /* 延时500个tick */		 		
       
    }
}

/**********************************************************************
  * @ 函数名  : Usart_Task
  * @ 功能说明: Usart_Task任务主体
  * @ 参数    :   
  * @ 返回值  : 无
  ********************************************************************/

static void Usart_Task(void* parameter)
{	
    while (1)
    {   vTaskDelay(2000);
        Usart_SendString( DEBUG_USARTx,"5032  helloworld!\n\n");
	      
    }
		
}
/**********************************************************************
  * @ 函数名  : LMT70_Task
  * @ 功能说明: LMT70_Task任务主体
  * @ 参数    :   
  * @ 返回值  : 无
  ********************************************************************/
static void LMT70_Task(void* parameter)
{	
    while (1)
    {
        vTaskDelay(5000);  
			  adcx=Get_Adc_Average(ADC_Channel_1,10);
		    temp=(float)adcx*(3.3/4096)*1000;
		    tem = (-0.0000084515)*temp*temp+(-0.176928)*temp+204.393;
		    printf("\r\nADC电压为:%.2f\n\r",tem);
        	printf("\r\n温度为(摄氏度):%.2f\n\r",tem);	
        
    }
		
}
		
}

4)效果展示

下载说明
我们插入J-link之后要在设备管理器看是否有相应的驱动,然后确保下载线已连接,在keil作如下设置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

依次编译
在这里插入图片描述
运行结果

串口助手
在这里插入图片描述

开发板
在这里插入图片描述

六. 结语

这个实战对于我们了解基于在STM32下完成FreeRTOS的多任务程序开发有着重要的意义,所以博主在这里希望各位也要好好学习,争取掌握这个知识点。博主觉得这次开发其实很简单,希望大家在以后的学习中,善于使用我们的工具还有现成的资料。一定会事半功倍,还有就是希望各位有问题可以联系博主,博主很乐意和各位一起学习。请您关注我个人的微信公众号,微信搜索h生活剪影很期待您的关注,我们一起进步。在这里插入图片描述

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值