3、FreeRTOS移植模板优化测试 System作为hal库维护时钟,us延时

一、前言

我在移植FreeRTOS操作系统的时候,hal库的维护需要一个定时器,如果需要 us级的定时器,那么又需要一个定时器,一共就需要三个定时器,这样很浪费单片机的资源,原子哥的方法很实用,一个Systick就解决了!上节,已经移植了成功了一个简单的模板,那么今天来优化一下,那么我们重新移植一下,同样使用原子哥的串口例程。

二、注意点

上节,我把hal库的维护时间中断改成了TIme1,这节就不动这一块

image-20220731165026998

三、修改delay.c

这里修改的比较多,我直接贴出代码

#include "delay.h"
#include "sys.h"
// 	 
//如果使用OS,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h"					//FreeRTOS使用	 
#include "task.h"
#endif
//  
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F429开发板
//使用SysTick的普通计数模式对延迟进行管理(FreeRTOS专用)
//包括delay_us,delay_ms
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2016/9/13
//版本:V1.1
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved
//********************************************************************************
//修改说明
// 

static u32 fac_us=0;							//us延时倍乘数

#if SYSTEM_SUPPORT_OS		
    static u16 fac_ms=0;				        //ms延时倍乘数,在os下,代表每个节拍的ms数
#endif


			   
//初始化延迟函数
//当使用ucos的时候,此函数会初始化ucos的时钟节拍
//SYSTICK的时钟固定为AHB时钟
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{
    
    
#if SYSTEM_SUPPORT_OS	
	u32 reload;
#endif
    //HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLK
	fac_us=SYSCLK;						    //不论是否使用OS,fac_us都需要使用
#if SYSTEM_SUPPORT_OS	
	reload=SYSCLK;					        //每秒钟的计数次数 单位为K	   
	reload*=1000000/configTICK_RATE_HZ;		//根据configTICK_RATE_HZ设定溢出时间
											//reload为24位寄存器,最大值:16777216,在180M下,约合0.745s左右	
	fac_ms=1000/configTICK_RATE_HZ;			//代表OS可以延时的最少单位		
//    SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
//	SysTick->LOAD=reload; 					//每1/configTICK_RATE_HZ断一次	
//	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#endif
}								    

//延时nus
//nus:要延时的us数.	
//nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)	    								   
void delay_us(u32 nus)
{
    
    		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;				//LOAD的值	    	 
	ticks=nus*fac_us; 						//需要的节拍数 
	told=SysTick->VAL;        				//刚进入时的计数器值
	while(1)
	{
    
    
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{
    
    	    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}  
	};									    
}  
	
//延时nms,会引起任务调度
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u32 nms)
{
    
    	
#if SYSTEM_SUPPORT_OS	
	if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
	{
    
    		
		if(nms>=fac_ms)						//延时的时间大于OS的最少时间周期 
		{
    
     
   			vTaskDelay(nms/fac_ms);	 		//FreeRTOS延时
		}
		nms%=fac_ms;						//OS已经无法提供这么小的延时了,采用普通方式延时    
	}
#endif
	delay_us((u32)(nms*1000));				//普通方式延时
}

//延时nms,不会引起任务调度
//nms:要延时的ms数
void delay_xms(u32 nms)
{
    
    
	u32 i;
	for(i=0;i<nms;i++) delay_us(1000);
}
			 

四、Freertos移植

1、Freertos 下载

获取源码可以直接到FreeRTOS的官网获取,官网:https://www.freertos.org/ 。

image-20220727155946682

下载会有点慢 我已经准备好了

链接:https://pan.baidu.com/s/12ao3oX2q53fDGA8HkCygjw?pwd=5djt
提取码:5djt
–来自百度网盘超级会员V4的分享

image-20220727160054781

2、 FreeRTOS目录结构

我们解压出来后,就得到了FreeRTOS的源码了,里面包含了所需要的全部源码资料。这里对FreeRTOSv10.4.0版本的源码目录结构简单介绍一下。解压出来后,目录结构如下图

image-20220727160754509

├─FreeRTOS
│  ├─Demo               // 集成开发环境完整的Demo模板
│  ├─License            // 许可证相关
│  └─Source             // FreeRTOS的源码,非常重要,移植就是使用该目录里面的源码了
│      ├─include        // 源码的头文件
│      └─portable       // 不同硬件平台相关的代码
│            ├─MemMang  // FreeRTOS内存管理方案,我们选择其中一个文件即可
│            │     heap_1.c
│            │     heap_2.c
│            │     heap_3.c
│            │     heap_4.c
│            │     heap_5.c
│   		 ├─RVDS		// ARM架构相关的代码,我们在里面选择其中的CM3架构目录即可 
│            └─其他     // 其他架构、开发平台相关的代码
│      croutine.c       // 协线程(协程)文件,和任务类似,在系统资源比较缺乏下使用
│      event_groups.c   // 事件标志组
│      list.c           // 列表结构描述,在内核整体控制上都使用了列表格式数据处理,一切数据结构的基础
│      queue.c          // 队列,任务和任务之间的通讯处理
│      tasks.c          // 所有任务相关函数
│      timers.c         // 软件定时器,以任务形式存在
│      stream_buffer.c  // 流缓冲区文件,该文件是v10.0.0新增的,v9.0.0没有
|─FreeRTOS-Plus         // FreeRTOS生态相关的文件,基本用不到
|-tools					// 使用python和js编写的一些脚本和工具 都用不到
......					// 剩下的都是一些文档 我们也用不了

3、在裸机工程里面新建一个FreeRTOS文件夹

image-20220727162810745

4、复制核心文件

移动FreeRTOS工程下面的Source文件先移动到裸机下面的FreeRTOS文件夹下面

image-20220727163025487

5、FreeRTOS\portable 文件夹修剪

只留下这三个文件夹(其他的是其他编译器的 我们只需要keil的)

image-20220727163249357

6、工程添加文件

把刚刚移植的文件添加到工程里面 选择heap4.c的内存管理方式和我们单片机的m4内核

image-20220731174256047

7、添加头文件编译

把头文件添加进入工程里面编译

image-20220727164314745

image-20220727165004093

8、解决没有FreeRTOSConfig.h

编译以后,看到没有FreeRTOSConfig.h

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3Yz5LBl-1659261483067)(https://myx-typora-img.oss-cn-hangzhou.aliyuncs.com/typora-img/image-20220727165035237.png)]

这个文件,FreeRTOS 例程里面的预定义很少,不全,这里我贴出原子哥写的

/*
    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
    All rights reserved

    VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.

    This file is part of the FreeRTOS distribution.

    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.

    ***************************************************************************
    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
    >>!   distribute a combined work that includes FreeRTOS without being   !<<
    >>!   obliged to provide the source code for proprietary components     !<<
    >>!   outside of the FreeRTOS kernel.                                   !<<
    ***************************************************************************

    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  Full license text is available on the following
    link: http://www.freertos.org/a00114.html

    ***************************************************************************
     *                                                                       *
     *    FreeRTOS provides completely free yet professionally developed,    *
     *    robust, strictly quality controlled, supported, and cross          *
     *    platform software that is more than just the market leader, it     *
     *    is the industry's de facto standard.                               *
     *                                                                       *
     *    Help yourself get started quickly while simultaneously helping     *
     *    to support the FreeRTOS project by purchasing a FreeRTOS           *
     *    tutorial book, reference manual, or both:                          *
     *    http://www.FreeRTOS.org/Documentation                              *
     *                                                                       *
    ***************************************************************************

    http://www.FreeRTOS.org/FAQHelp.html - Having a problem?  Start by reading
    the FAQ page "My application does not run, what could be wrong?".  Have you
    defined configASSERT()?

    http://www.FreeRTOS.org/support - In return for receiving this top quality
    embedded software for free we request you assist our global community by
    participating in the support forum.

    http://www.FreeRTOS.org/training - Investing in training allows your team to
    be as productive as possible as early as possible.  Now you can receive
    FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
    Ltd, and the world's leading authority on the world's leading RTOS.

    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
    compatible FAT file system, and our tiny thread aware UDP/IP stack.

    http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
    Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.

    http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
    Integrity Systems ltd. to sell under the OpenRTOS brand.  Low cost OpenRTOS
    licenses offer ticketed support, indemnification and commercial middleware.

    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
    engineered and independently SIL3 certified version for use in safety and
    mission critical applications that require provable dependability.

    1 tab == 4 spaces!
*/


#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

#include "sys.h"
#include "usart.h"
//针对不同的编译器调用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include <stdint.h>
    extern uint32_t SystemCoreClock;
#endif

//断言
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

/***************************************************************************************************************/
/*                                        FreeRTOS基础配置配置选项                                              */
/***************************************************************************************************************/
#define configUSE_PREEMPTION					1                       //1使用抢占式内核,0使用协程
#define configUSE_TIME_SLICING					1						//1使能时间片调度(默认式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION	1                       //1启用特殊方法来选择下一个要运行的任务
                                                                        //一般是硬件计算前导零指令,如果所使用的
                                                                        //MCU没有这些硬件指令的话此宏应该设置为0!
#define configUSE_TICKLESS_IDLE					0                       //1启用低功耗tickless模式
#define configUSE_QUEUE_SETS					1                       //为1时启用队列
#define configCPU_CLOCK_HZ						(SystemCoreClock)       //CPU频率
#define configTICK_RATE_HZ						(1000)                  //时钟节拍频率,这里设置为1000,周期就是1ms
#define configMAX_PRIORITIES					(32)                    //可使用的最大优先级
#define configMINIMAL_STACK_SIZE				((unsigned short)130)   //空闲任务使用的堆栈大小
#define configMAX_TASK_NAME_LEN					(16)                    //任务名字字符串长度

#define configUSE_16_BIT_TICKS					0                       //系统节拍计数器变量数据类型,
                                                                        //1表示为16位无符号整形,0表示为32位无符号整形
#define configIDLE_SHOULD_YIELD					1                       //为1时空闲任务放弃CPU使用权给其他同优先级的用户任务
#define configUSE_TASK_NOTIFICATIONS            1                       //为1时开启任务通知功能,默认开启
#define configUSE_MUTEXES						1                       //为1时使用互斥信号量
#define configQUEUE_REGISTRY_SIZE				8                       //不为0时表示启用队列记录,具体的值是可以
                                                                        //记录的队列和信号量最大数目。
#define configCHECK_FOR_STACK_OVERFLOW			0                       //大于0时启用堆栈溢出检测功能,如果使用此功能
                                                                        //用户必须提供一个栈溢出钩子函数,如果使用的话
                                                                        //此值可以为1或者2,因为有两种栈溢出检测方法。
#define configUSE_RECURSIVE_MUTEXES				1                       //为1时使用递归互斥信号量
#define configUSE_MALLOC_FAILED_HOOK			0                       //1使用内存申请失败钩子函数
#define configUSE_APPLICATION_TASK_TAG			0                       
#define configUSE_COUNTING_SEMAPHORES			1                       //为1时使用计数信号量

/***************************************************************************************************************/
/*                                FreeRTOS与内存申请有关配置选项                                                */
/***************************************************************************************************************/
#define configSUPPORT_DYNAMIC_ALLOCATION        1                       //支持动态内存申请
#define configTOTAL_HEAP_SIZE					((size_t)(20*1024))     //系统所有总的堆大小

/***************************************************************************************************************/
/*                                FreeRTOS与钩子函数有关的配置选项                                              */
/***************************************************************************************************************/
#define configUSE_IDLE_HOOK						0                       //1,使用空闲钩子;0,不使用
#define configUSE_TICK_HOOK						0                       //1,使用时间片钩子;0,不使用

/***************************************************************************************************************/
/*                                FreeRTOS与运行时间和任务状态收集有关的配置选项                                 */
/***************************************************************************************************************/
#define configGENERATE_RUN_TIME_STATS	        0                       //为1时启用运行时间统计功能
#define configUSE_TRACE_FACILITY				1                       //为1启用可视化跟踪调试
#define configUSE_STATS_FORMATTING_FUNCTIONS	1                       //与宏configUSE_TRACE_FACILITY同时为1时会编译下面3个函数
                                                                        //prvWriteNameToBuffer(),vTaskList(),
                                                                        //vTaskGetRunTimeStats()
                                                                        
/***************************************************************************************************************/
/*                                FreeRTOS与协程有关的配置选项                                                  */
/***************************************************************************************************************/
#define configUSE_CO_ROUTINES 			        0                       //为1时启用协程,启用协程以后必须添加文件croutine.c
#define configMAX_CO_ROUTINE_PRIORITIES         ( 2 )                   //协程的有效优先级数目

/***************************************************************************************************************/
/*                                FreeRTOS与软件定时器有关的配置选项                                            */
/***************************************************************************************************************/
#define configUSE_TIMERS				        1                               //为1时启用软件定时器
#define configTIMER_TASK_PRIORITY		        (configMAX_PRIORITIES-1)        //软件定时器优先级
#define configTIMER_QUEUE_LENGTH		        5                               //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH	        (configMINIMAL_STACK_SIZE*2)    //软件定时器任务堆栈大小

/***************************************************************************************************************/
/*                                FreeRTOS可选函数配置选项                                                      */
/***************************************************************************************************************/
#define INCLUDE_xTaskGetSchedulerState          1                       
#define INCLUDE_vTaskPrioritySet		        1
#define INCLUDE_uxTaskPriorityGet		        1
#define INCLUDE_vTaskDelete				        1
#define INCLUDE_vTaskCleanUpResources	        1
#define INCLUDE_vTaskSuspend			        1
#define INCLUDE_vTaskDelayUntil			        1
#define INCLUDE_vTaskDelay				        1
#define INCLUDE_eTaskGetState			        1
#define INCLUDE_xTimerPendFunctionCall	        1

/***************************************************************************************************************/
/*                                FreeRTOS与中断有关的配置选项                                                  */
/***************************************************************************************************************/
#ifdef __NVIC_PRIO_BITS
	#define configPRIO_BITS       		__NVIC_PRIO_BITS
#else
	#define configPRIO_BITS       		4                  
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY			15                      //中断最低优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY	5                       //系统可管理的最高中断优先级
#define configKERNEL_INTERRUPT_PRIORITY 		( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 	( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )

/***************************************************************************************************************/
/*                                FreeRTOS与中断服务函数有关的配置选项                                          */
/***************************************************************************************************************/
#define xPortPendSVHandler 	PendSV_Handler
#define vPortSVCHandler 	SVC_Handler
void xPortSysTickHandler(void);
//#define xPortSysTickHandler		SysTick_Handler
#endif /* FREERTOS_CONFIG_H */


不同的上一节的是 这里我把#define xPortSysTickHandler SysTick_Handler注释了

声明了void xPortSysTickHandler(void);

8、修改stm32f4xx_it.c

xPortPendSVHandler()

vPortSVCHandler()

xPortSysTickHandler()

这三个中断需要给FreeRTOS 使用和hal库冲突了,我们屏蔽hal库的xPortPendSVHandler(),vPortSVCHandler()个中断函数,修改一下xPortSysTickHandler()中断函数

void SysTick_Handler(void)
{
    
    
	#if SYSTEM_SUPPORT_OS
	  if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
    {
    
    
        xPortSysTickHandler();	
    }
#endif

  HAL_IncTick();
}

image-20220731173033352

9、编译有错误(1)

…\FreeRTOS\queue.c(2762): error: #268: declaration may not appear after executable statement in block

​ QueueRegistryItem_t * pxEntryToWrite = NULL;

image-20220727170848061

10、解决办法(1)

在Keil的魔术棒中C/C++选项卡下选择C99mode,该模式下能通过以下省略参数的语句,

image-20220727170915115

11、还有错误(2)

…\FreeRTOS\portable\RVDS\ARM_CM4F\port.c(482): error: A1586E: Bad operand types (UnDefOT, Constant) for operator (

image-20220727171054700

12、解决错误(2)

定位问题

image-20220727171147636

往上找

image-20220727171225372

最终问题找到

image-20220727171302107

最后发现 6<<(8-4U)

4U unsigned int 4

解决方法 U去掉

13、测试下延时函数

1、编译没问题,先测试一下延时函数有没有问题

image-20220727171349642

2、测试延时函数

先测试一下Hal_Delay()和delay_ms (因为delay_ms用的是delay_us函数,测试了delay_ms是否正常,就能知道delay_us是否正常了),再进行下一步,后面会把串口的相关代码统一整理。现在先测试

测试HAL_Delay

int main(void)
{
    
    
	u8 len;	
	u16 times=0;
	
    HAL_Init();                    	//初始化HAL库    
    Stm32_Clock_Init(336,8,2,7);  	//设置时钟,168Mhz
	delay_init(168);               	//初始化延时函数
	uart_init(115200);              //初始化USART
	LED_Init();						//初始化LED	
    KEY_Init();                     //初始化按键
	
    while(1)
    {
    
    
				printf("Hello is ok\r\n");
			HAL_Delay(1000);
  			  if(USART_RX_STA&0x8000)
		{
    
    					   
			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			printf("\r\n您发送的消息为:\r\n");
			HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,1000);	//发送接收到的数据
			while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET);		//等待发送结束
			printf("\r\n\r\n");//插入换行
			USART_RX_STA=0;
		}else
		{
    
    
			times++;
			if(times%5000==0)
			{
    
    
				printf("\r\nALIENTEK 探索者STM32F407开发板 串口实验\r\n");
				printf("正点原子@ALIENTEK\r\n\r\n\r\n");
			}
			if(times%200==0)printf("请输入数据,以回车键结束\r\n");  
			if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
			delay_ms(10);   
		} 
    }
}

看到没问题

image-20220731170402984

测试delay_ms

int main(void)
{
    
    
	u8 len;	
	u16 times=0;
	
    HAL_Init();                    	//初始化HAL库    
    Stm32_Clock_Init(336,8,2,7);  	//设置时钟,168Mhz
	delay_init(168);               	//初始化延时函数
	uart_init(115200);              //初始化USART
	LED_Init();						//初始化LED	
    KEY_Init();                     //初始化按键
	
    while(1)
    {
    
    
				printf("Hello is ok\r\n");
			delay_ms(1000);
     		  if(USART_RX_STA&0x8000)
		{
    
    					   
			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			printf("\r\n您发送的消息为:\r\n");
			HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,1000);	//发送接收到的数据
			while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET);		//等待发送结束
			printf("\r\n\r\n");//插入换行
			USART_RX_STA=0;
		}else
		{
    
    
			times++;
			if(times%5000==0)
			{
    
    
				printf("\r\nALIENTEK 探索者STM32F407开发板 串口实验\r\n");
				printf("正点原子@ALIENTEK\r\n\r\n\r\n");
			}
			if(times%200==0)printf("请输入数据,以回车键结束\r\n");  
			if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
			delay_ms(10);   
		} 
    }
}

image-20220731172149715

都没问题!!!

工程下载

https://download.csdn.net/download/mayuxin1314/86268752

后面我都是基于这个模板做的修改

猜你喜欢

转载自blog.csdn.net/mayuxin1314/article/details/126088521