一、前言
我在移植FreeRTOS操作系统的时候,hal库的维护需要一个定时器,如果需要 us级的定时器,那么又需要一个定时器,一共就需要三个定时器,这样很浪费单片机的资源,原子哥的方法很实用,一个Systick就解决了!上节,已经移植了成功了一个简单的模板,那么今天来优化一下,那么我们重新移植一下,同样使用原子哥的串口例程。
二、注意点
上节,我把hal库的维护时间中断改成了TIme1,这节就不动这一块
三、修改delay.c
这里修改的比较多,我直接贴出代码
#include "delay.h"
#include "sys.h"
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h"
#include "task.h"
#endif
static u32 fac_us=0;
#if SYSTEM_SUPPORT_OS
static u16 fac_ms=0;
#endif
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_OS
u32 reload;
#endif
fac_us=SYSCLK;
#if SYSTEM_SUPPORT_OS
reload=SYSCLK;
reload*=1000000/configTICK_RATE_HZ;
fac_ms=1000/configTICK_RATE_HZ;
#endif
}
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD;
ticks=nus*fac_us;
told=SysTick->VAL;
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow;
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break;
}
};
}
void delay_ms(u32 nms)
{
#if SYSTEM_SUPPORT_OS
if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)
{
if(nms>=fac_ms)
{
vTaskDelay(nms/fac_ms);
}
nms%=fac_ms;
}
#endif
delay_us((u32)(nms*1000));
}
void delay_xms(u32 nms)
{
u32 i;
for(i=0;i<nms;i++) delay_us(1000);
}
四、Freertos移植
1、Freertos 下载
获取源码可以直接到FreeRTOS的官网获取,官网:https://www.freertos.org/ 。
下载会有点慢 我已经准备好了
链接:https://pan.baidu.com/s/12ao3oX2q53fDGA8HkCygjw?pwd=5djt 提取码:5djt –来自百度网盘超级会员V4的分享
2、 FreeRTOS目录结构
我们解压出来后,就得到了FreeRTOS的源码了,里面包含了所需要的全部源码资料。这里对FreeRTOSv10.4.0版本的源码目录结构简单介绍一下。解压出来后,目录结构如下图
├─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文件夹
4、复制核心文件
移动FreeRTOS工程下面的Source文件先移动到裸机下面的FreeRTOS文件夹下面
5、FreeRTOS\portable 文件夹修剪
只留下这三个文件夹(其他的是其他编译器的 我们只需要keil的)
6、工程添加文件
把刚刚移植的文件添加到工程里面 选择heap4.c的内存管理方式和我们单片机的m4内核
7、添加头文件编译
把头文件添加进入工程里面编译
8、解决没有FreeRTOSConfig.h
编译以后,看到没有FreeRTOSConfig.h
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3Yz5LBl-1659261483067)(https://myx-typora-img.oss-cn-hangzhou.aliyuncs.com/typora-img/image-20220727165035237.png)]
这个文件,FreeRTOS 例程里面的预定义很少,不全,这里我贴出原子哥写的
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#include "sys.h"
#include "usart.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__)
#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#define configUSE_TICKLESS_IDLE 0
#define configUSE_QUEUE_SETS 1
#define configCPU_CLOCK_HZ (SystemCoreClock)
#define configTICK_RATE_HZ (1000)
#define configMAX_PRIORITIES (32)
#define configMINIMAL_STACK_SIZE ((unsigned short)130)
#define configMAX_TASK_NAME_LEN (16)
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_TASK_NOTIFICATIONS 1
#define configUSE_MUTEXES 1
#define configQUEUE_REGISTRY_SIZE 8
#define configCHECK_FOR_STACK_OVERFLOW 0
#define configUSE_RECURSIVE_MUTEXES 1
#define configUSE_MALLOC_FAILED_HOOK 0
#define configUSE_APPLICATION_TASK_TAG 0
#define configUSE_COUNTING_SEMAPHORES 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configTOTAL_HEAP_SIZE ((size_t)(20*1024))
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configGENERATE_RUN_TIME_STATS 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configUSE_CO_ROUTINES 0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1)
#define configTIMER_QUEUE_LENGTH 5
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2)
#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
#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) )
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
void xPortSysTickHandler(void);
#endif
不同的上一节的是 这里我把#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();
}
9、编译有错误(1)
…\FreeRTOS\queue.c(2762): error: #268: declaration may not appear after executable statement in block
? QueueRegistryItem_t * pxEntryToWrite = NULL;
10、解决办法(1)
在Keil的魔术棒中C/C++选项卡下选择C99mode,该模式下能通过以下省略参数的语句,
11、还有错误(2)
…\FreeRTOS\portable\RVDS\ARM_CM4F\port.c(482): error: A1586E: Bad operand types (UnDefOT, Constant) for operator (
12、解决错误(2)
定位问题
往上找
最终问题找到
最后发现 6<<(8-4U)
4U unsigned int 4
解决方法 U去掉
13、测试下延时函数
1、编译没问题,先测试一下延时函数有没有问题
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();
Stm32_Clock_Init(336,8,2,7);
delay_init(168);
uart_init(115200);
LED_Init();
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;
delay_ms(10);
}
}
}
看到没问题
测试delay_ms
int main(void)
{
u8 len;
u16 times=0;
HAL_Init();
Stm32_Clock_Init(336,8,2,7);
delay_init(168);
uart_init(115200);
LED_Init();
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;
delay_ms(10);
}
}
}
都没问题!!!
工程下载
https://download.csdn.net/download/mayuxin1314/86268752
后面我都是基于这个模板做的修改
|