首页
关于
Search
1
开发环境搭建(FTP、VSCode、交叉编译器、SSH、NFS、TFTP)
33 阅读
2
linux内核编译报错(gcc: not found + fatal error curses.h)
26 阅读
3
安装WMware Tools选项显示灰色解决方法及WMware Tools安装笔记
17 阅读
4
ubuntu24.2下解压.tar.bz2报错(bzip2: 无法exec:没有那个文件或目录)
14 阅读
5
linux内核编译报错(usr/bin/ld: scripts/dtc/dtc-parser.tab.o:(.bss+0x50): multiple definition of 'yylloc';)
14 阅读
学习笔记
linux学习笔记
文件系统
FreeRTOS
资源分享
小作品
登录
/
注册
Search
Warren
有钱人终成眷属,没钱人亲眼目睹
累计撰写
37
篇文章
累计收到
1
条评论
首页
栏目
学习笔记
linux学习笔记
文件系统
FreeRTOS
资源分享
小作品
页面
关于
搜索到
4
篇与
的结果
2025-02-24
第四章 FreeRTOS中断配置和临界段
4.1 Cortex-M中断4.1.1 中断简介 Cortex-M 内核的 MCU 提供了一个用于中断管理的嵌套向量中断控制器(NVIC). Cortex-M3内核支持256个中断,其中包括240个外部中断+16个内核中断 其中16个内核中断包括一个不可屏蔽中断(NMI)、一个Systick定时器中断(滴答定时器)和多个系统异常中断4.1.2 中断管理简介 Cortex-M 处理器有多个用于管理中断和异常的可编程寄存器。这些寄存器大多数都在NVIC 和系统控制块(SCB)typedef struct { __IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */ uint32_t RESERVED0[24]; __IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */ uint32_t RSERVED1[24]; __IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */ uint32_t RESERVED2[24]; __IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */ uint32_t RESERVED3[24]; __IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register */ uint32_t RESERVED4[56]; __IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) */ uint32_t RESERVED5[644]; __O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */ } NVIC_Type; ISER:向该寄存器的对应bit写入1,则会使能对应的中断(256位)ICER:向该寄存器的对应bit写入1,则会除能对应的中断(256位)ISPR:向该寄存器的对应bit写入1,则会挂起对应的中断(256位)ICPR:向该寄存器的对应bit写入1,则会解挂对应的中断(256位)IABR:只读属性,若对应bit为1,则表示该中断正在执行(256位)IP:中断优先级寄存器,只可以配置外部中断(240位)STIR:软件中断触发中断寄存器,向该寄存器写入标号,则标号对应的中断会被悬起。typedef struct { __I uint32_t CPUID; /*!< Offset: 0x00 CPU ID Base Register */ __IO uint32_t ICSR; /*!< Offset: 0x04 Interrupt Control State Register */ __IO uint32_t VTOR; /*!< Offset: 0x08 Vector Table Offset Register */ __IO uint32_t AIRCR; /*!< Offset: 0x0C Application Interrupt / Reset Control Register */ __IO uint32_t SCR; /*!< Offset: 0x10 System Control Register */ __IO uint32_t CCR; /*!< Offset: 0x14 Configuration Control Register */ __IO uint8_t SHP[12]; /*!< Offset: 0x18 System Handlers Priority Registers (4-7, 8-11, 12-15) */ __IO uint32_t SHCSR; /*!< Offset: 0x24 System Handler Control and State Register */ __IO uint32_t CFSR; /*!< Offset: 0x28 Configurable Fault Status Register */ __IO uint32_t HFSR; /*!< Offset: 0x2C Hard Fault Status Register */ __IO uint32_t DFSR; /*!< Offset: 0x30 Debug Fault Status Register */ __IO uint32_t MMFAR; /*!< Offset: 0x34 Mem Manage Address Register */ __IO uint32_t BFAR; /*!< Offset: 0x38 Bus Fault Address Register */ __IO uint32_t AFSR; /*!< Offset: 0x3C Auxiliary Fault Status Register */ __I uint32_t PFR[2]; /*!< Offset: 0x40 Processor Feature Register */ __I uint32_t DFR; /*!< Offset: 0x48 Debug Feature Register */ __I uint32_t ADR; /*!< Offset: 0x4C Auxiliary Feature Register */ __I uint32_t MMFR[4]; /*!< Offset: 0x50 Memory Model Feature Register */ __I uint32_t ISAR[5]; /*!< Offset: 0x60 ISA Feature Register */ } SCB_Type; 该寄存器暂未学习清除,不记录笔记;待后续补充!!! 内嵌向量中断控制器(NVIC)和系统控制块(SCB)在地址分配上都属于系统控制空间(SCS)内;SCS的基地址为0xE000E000。NVIC的偏移为0x100;SCB的偏移为0xD00.4.1.3 优先级分区定义 STM32中的每个中断都有一个优先级编号。优先级编号越小的中断优先执行。高优先级的中断可以抢占低优先级的中断。并且Cortex-M 处理器的有些中断是具有固定的优先级的,比如复位、 NMI、HardFault,这些中断的优先级都是负数,优先级也是最高的。 Cortex-M 处理器有三个固定优先级和 256 个可编程的优先级(并不是指有256个优先级可编程的中断),最多有 128 个抢占等级。256个可编程的优先级指IP寄存器的位宽为8Bit;2^8=256128个抢占等级是2^7=128,因为相应优先级(亚优先级)至少1Bit上面这些对于STM32而言就是扯淡。因为STM32只有4个bit来表示优先级。所以对于STM32而言就没有那么多了。不管怎么裁剪。有效位永远是高位对齐。在NVIC中有一个应用程序中断及复位控制寄存器(AIRCR),AIRCR 寄存器里面有个位段名为“优先级组。如下图可以看到它的位宽为3bit。可以设置0-7共8个分组。不同的分组对应的优先级和亚优先级分组如下可以看到抢占优先级最大7bit,最少0bit但是在STM32中,我们只有高4bit来配置中断的优先级。所以我们只选中分组3-分组7。共5组来配置中断优先级。则对STM32的优先级分组就只有5个。STM32中分组0-------PRIGROUP中的分组7STM32中分组1-------PRIGROUP中的分组6STM32中分组2-------PRIGROUP中的分组5STM32中分组3-------PRIGROUP中的分组4STM32中分组4-------PRIGROUP中的分组3 【注意】 FreeRTOS得到中断配置没有处理亚优先级这种情况。所以我们只能给STM32配置分区4。4.1.4 优先级设置 4个相临的寄存器可以拼成一个32位的寄存器,因此地址0xE000_ED20~0xE000_ED23 这四个寄存器就可以拼接成一个地址为0xE000_ED20的32位寄存器。 这一点很重要! 因为 FreeRTOS 在设置 PendSV 和 SysTick 的中断优先级的时候都是直接操作的地址 0xE000_ED204.1.5 用于中断屏蔽的特殊寄存器PRIMASK、FAULTMASK 和 BASEPRI 这三个寄存器用于控制中断的屏蔽。三个有一些不同如下:PRIMASK: 置1后 禁止除 NMI 和 HardFalut 外的所有异常和中断。FAULTMASK: 置1后,禁止除 NMI外的所有异常和中断。BASEPRI:填入设定的值,只屏蔽优先级低于该值的中断。向 BASEPRI 写 0 的话就会停止屏蔽中断。4.2 FreeRTOS中断配置宏configPRIO_BITS该宏用来设置MCU使用几位优先级。在STM32中使用4BIT。所以该宏为4configLIBRARY_LOWEST_INTERRUPT_PRIORITY此宏用来设置最低优先级。前面配置了STM32使用4bit来表示优先级;则最低优先级为2^4-1;即此宏为15configKERNEL_INTERRUPT_PRIORITY此宏用来设置内核中断优先级;内核的中断优先级就是系统滴答定时器的优先级和PendSV中断的优先级。configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY此宏用来设置 FreeRTOS 系统可管理的最大优先级;也就是高于该值的优先级(优先级数小于该值)不归 FreeRTOS 管理configMAX_SYSCALL_INTERRUPT_PRIORITY低于此优先级的中断可以安全的调用 FreeRTOS 的 API 函数,高于此优先级的中断 FreeRTOS 是不能禁止的,中断服务函数也不能调用 FreeRTOS 的 API 函数。目的:确保 FreeRTOS 内核的关键部分不会被更高优先级的中断打断,这些中断可能会调用 FreeRTOS API 函数,从而导致竞态条件或数据损坏4.3 FreeRTOS开关中断FreeRTOS 开关中断函数为 portENABLE_INTERRUPTS ()和 portDISABLE_INTERRUPTS()它通过往BASEPRI写入0来实现打开中断;通过往BASEPRI中写入configMAX_SYSCALL_INTERRUPT_PRIORITY来实现屏蔽configMAX_SYSCALL_INTERRUPT_PRIORITY优先级以下的中断4.4 临界段代码临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段!FreeRTOS 与 临 界 段 代 码 保 护 有 关 的 函 数 有 4 个 : taskENTER_CRITICAL() 、taskEXIT_CRITICAL() 、 taskENTER_CRITICAL_FROM_ISR() 和taskEXIT_CRITICAL_FROM_ISR()分别为:任务级临界段代码保护 和 中断级临界段代码保护任务级临界段代码保护是通过一个全局变量uxCriticalNesting来实现中断管理。uxCriticalNesting==1时候关闭中断;uxCriticalNesting==0时候开启中断;即保证了在有多个临界段代码的时候不会因为某一个临界段代码的退出而打乱其他临界段的保护,只有所有的临界段代码都退出以后才会使能中断。中断级临界段代码保护这个就比较粗暴了。直接向BASEPRI寄存器中写入configMAX_SYSCALL_INTERRUPT_PRIORITY来实现关闭中断。进入时候读出BASEPRI的值并保存该值,同时向BASEPRI寄存器写入configMAX_SYSCALL_INTERRUPT_PRIORITY退出时候向BASEPRI寄存器写入进入时刻读出来的值。4.5 FreeRTOS中断测试实验实验目的:用来验证FreeRTOS的APIportENABLE_INTERRUPTS ()和 portDISABLE_INTERRUPTS()以及宏configMAX_SYSCALL_INTERRUPT_PRIORITY。实验方法:创建两个任务task1;在task1中在运行5秒后关闭中断。在运行10秒后打开中断。并且开启两个定时器中断。在中断服务函数中打印"timer1 is runing" 和 "timer2 is runing"。configMAX_SYSCALL_INTERRUPT_PRIORITY配置为5;定时器1中断优先级为4;定时器2中断优先级为5;实验设想:前5秒,有定时器1和定时器2的输出。5-10秒只有定时器1的输出;10秒以后定时器12都有输出。实验代码如下#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "timer.h" #include "FreeRTOS.h" #include "task.h" //任务优先级 #define START_TASK_PRIO 1 //任务堆栈大小 #define START_STK_SIZE 256 //任务句柄 TaskHandle_t StartTask_Handler; //任务函数 void start_task(void *pvParameters); //任务优先级 #define INTERRUPT_TASK_PRIO 2 //任务堆栈大小 #define INTERRUPT_STK_SIZE 256 //任务句柄 TaskHandle_t INTERRUPTTask_Handler; //任务函数 void interrupt_task(void *p_arg); int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4 delay_init(); //延时函数初始化 uart_init(115200); //初始化串口 LED_Init(); //初始化LED TIM3_Int_Init(10000-1,7200-1); //初始化定时器3,定时器周期1S TIM5_Int_Init(10000-1,7200-1); //初始化定时器5,定时器周期1S //创建开始任务 xTaskCreate((TaskFunction_t )start_task, //任务函数 (const char* )"start_task", //任务名称 (uint16_t )START_STK_SIZE, //任务堆栈大小 (void* )NULL, //传递给任务函数的参数 (UBaseType_t )START_TASK_PRIO, //任务优先级 (TaskHandle_t* )&StartTask_Handler); //任务句柄 vTaskStartScheduler(); //开启任务调度 } void start_task(void *pvParameters) { taskENTER_CRITICAL(); //进入临界区 //创建中断测试任务 xTaskCreate((TaskFunction_t )interrupt_task, //任务函数 (const char* )"interrupt_task", //任务名称 (uint16_t )INTERRUPT_STK_SIZE, //任务堆栈大小 (void* )NULL, //传递给任务函数的参数 (UBaseType_t )INTERRUPT_TASK_PRIO, //任务优先级 (TaskHandle_t* )&INTERRUPTTask_Handler); //任务句柄 vTaskDelete(StartTask_Handler); //删除开始任务 taskEXIT_CRITICAL(); //退出临界区 } void interrupt_task(void *pvParameters) { static u32 total_num=0; while(1) { total_num+=1; if(total_num==5) { printf("关闭中断.............\r\n"); portDISABLE_INTERRUPTS(); //关闭中断 delay_xms(5000); //延时5s printf("打开中断.............\r\n"); //打开中断 portENABLE_INTERRUPTS(); } LED0=~LED0; vTaskDelay(1000); } } #include "timer.h" #include "usart.h" void TIM3_Int_Init(u16 arr, u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler = psc; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM3, ENABLE); } void TIM5_Int_Init(u16 arr, u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler = psc; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); TIM_Cmd(TIM5, ENABLE); } void TIM3_IRQHandler(void) { if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //????ж? { printf("TIM3???.......\r\n"); } TIM_ClearITPendingBit(TIM3, TIM_IT_Update); } void TIM5_IRQHandler(void) { if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET) //????ж? { printf("Timer 5 ???\r\n"); } TIM_ClearITPendingBit(TIM5, TIM_IT_Update); }
2025年02月24日
8 阅读
0 评论
0 点赞
2025-02-21
第三章 FreeRTOS系统配置
本章节教材本人读完没有搞清楚。决定先学习第四章。从实践触发,学完后再回头补充学习第三章。2025-02-21 21:57:34 星期五
2025年02月21日
4 阅读
0 评论
0 点赞
2025-02-20
第二章 FreeRTOS移植
2.1 准备工作首先准备一个简单的基础工作;选用基础例程中的跑马灯来作为基础工程 FreeRTOS的源码使用V9.0.0版本2.2 FreeRTOS移植2.2.1向工程中添加相应的文件 在基础工程中新建一个FreeRTOS的文件夹。将FreeRTOSv9.0.0\FreeRTOS\Source下的所有文件复制到该文件夹下面。完成后如下图所示: 再打开portable文件夹。只保留keil、MemMang、RVDS三个文件夹。将其他的内容均删除掉。完成后portable文件夹如下图所示 接下来打开工程,新建两个分组。分别为FreeRTOS_CORE和FreeRTOS_PORTABLE。向FreeRTOS_CORE分组中添加FreeRTOS里面的所有文件。向FreeRTOS_PORTABLE分组中添加portable/MemMang/heap_4.c和portable/RVDS/ARM_CM3/port.c 然后在工程中添加FreeRTOS源码的头文件路径 到目前为止,我们还缺少一个FreeRTOSConfig.h的文件。这个文件有3中解决办法,1、自己创建,2、在FreeRTOS的官方移植工程中拷贝,3、从正点原子教程的Demo中拷贝。我选择第三种。 到此工程可以正常编译。工程所需要的文件均已添加。2.2.2 修改SYSTEM文件在sys.h文件中将将宏 SYSTEM_SUPPORT_OS 改为 1usart.c文件中添加FreeRTOS.h头文件。另在删除掉串口1的中断函数中的OSIntEnter()和 OSIntExit()delay.c文件直接重写。delay.h中增加对void delay_xms(u32 nms);的声明#include "delay.h" #include "sys.h" ////////////////////////////////////////////////////////////////////////////////// //如果需要使用OS,则包括下面的头文件即可. #if SYSTEM_SUPPORT_OS #include "FreeRTOS.h" //FreeRTOS使用 #include "task.h" #endif static u8 fac_us=0; //us延时倍乘数 static u16 fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数 extern void xPortSysTickHandler(void); //systick中断服务函数,使用ucos时用到 void SysTick_Handler(void) { if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行 { xPortSysTickHandler(); } } //初始化延迟函数 //SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8 //这里为了兼容FreeRTOS,所以将SYSTICK的时钟频率改为AHB的频率! //SYSCLK:系统时钟频率 void delay_init() { u32 reload; SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);//选择外部时钟 HCLK fac_us=SystemCoreClock/1000000; //不论是否使用OS,fac_us都需要使用 reload=SystemCoreClock/1000000; //每秒钟的计数次数 单位为M reload*=1000000/configTICK_RATE_HZ; //根据configTICK_RATE_HZ设定溢出时间 //reload为24位寄存器,最大值:16777216,在72M下,约合0.233s左右 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 } //延时nus //nus:要延时的us数. //nus:0~204522252(最大值即2^32/fac_us@fac_us=168) 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(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行 { if(nms>=fac_ms) //延时的时间大于OS的最少时间周期 { vTaskDelay(nms/fac_ms); //FreeRTOS延时 } nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时 } delay_us((u32)(nms*1000)); //普通方式延时 } //延时nms,不会引起任务调度 //nms:要延时的ms数 void delay_xms(u32 nms) { u32 i; for(i=0;i<nms;i++) delay_us(1000); }最后可以看到三个报错信息,提示SysTick_Handler()、 SVC_Handler()和 PendSV_Handler()在项目中存在多出定义。 SysTick_Handler()滴答定时器中断在delay.c中实现。需要屏蔽掉stm32f10x_it.c中的实现。这个中断函数主要是为FreeRTOS系统提供系统节拍 SVC_Handler()是一种特殊得到软件中断,SVC中断是由软件指令触发的,通常用于系统调用。他的中断函数由FreeRTOS系统接管。在port.c中已实现。需要在stm32f10x_it.c中屏蔽掉重复的实现函数。SVC中断是操作系统与用户程序之间交互的桥梁。通过SVC中断,用户程序可以请求操作系统执行各种服务,如文件操作、进程管理、内存分配等。 PendSV_Handler(),主要职责是在任务切换时保存当前任务的上下文,并恢复下一个要运行的任务的上下文。具体来说,PendSV_Handler()可能会执行以下操作:1.保存当前任务的上下文;2.更新任务状态;3.恢复下一个任务的上下文;4.返回。他的中断函数由FreeRTOS系统接管。在port.c中已实现。需要在stm32f10x_it.c中屏蔽掉重复的实现函数。2.3 移植验证实验2.3.1 实验程序设计在实验工程中启动4个任务。分别为start_task()、 led0_task ()、 led1_task ();start_task():用来创建其他三个任务led0_task ():控制 LED0 的闪烁,提示系统正在运行led1_task ():控制 LED1 的闪烁。#include "sys.h" #include "delay.h" #include "usart.h" #include "led.h" #include "FreeRTOS.h" #include "task.h" #define START_TASK_PRIO 1 //任务优先级 #define START_STK_SIZE 128 //任务堆栈大小 TaskHandle_t StartTask_Handler; //任务句柄 void start_task(void *pvParameters); //任务函数声明 #define LED0_TASK_PRIO 2 //任务优先级 #define LED0_STK_SIZE 50 //任务堆栈大小 TaskHandle_t LED0Task_Handler; //任务句柄 void led0_task(void *pvParameters); //任务函数声明 #define LED1_TASK_PRIO 3 //任务优先级 #define LED1_STK_SIZE 50 //任务堆栈大小 TaskHandle_t LED1Task_Handler; //任务句柄 void led1_task(void *pvParameters); //任务函数声明 int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4 delay_init(); //延时函数初始化 uart_init(115200); //初始化串口 LED_Init(); //LED外设初始化 //创建开始任务 xTaskCreate( (TaskFunction_t)start_task, //任务函数 (const char*)"start_task", //任务名称 (uint16_t)START_STK_SIZE, //任务堆栈大小 (void*)NULL, //传递给任务函数的参数 (UBaseType_t)START_TASK_PRIO, //任务优先级 (TaskHandle_t)&StartTask_Handler //任务句柄 ); vTaskStartScheduler(); //开启任务调度 } //开始任务 任务函数 void start_task(void *pvParameters) { taskENTER_CRITICAL(); //进入临界区 //创建LED0任务 xTaskCreate( (TaskFunction_t)led0_task, //任务函数 (const char*)"led0_task", //任务名称 (uint16_t)LED0_STK_SIZE, //任务堆栈大小 (void*)NULL, //传递给任务函数的参数 (UBaseType_t)LED0_TASK_PRIO, //任务优先级 (TaskHandle_t)&LED0Task_Handler //任务句柄 ); //创建LED1任务 xTaskCreate( (TaskFunction_t)led1_task, //任务函数 (const char*)"led1_task", //任务名称 (uint16_t)LED1_STK_SIZE, //任务堆栈大小 (void*)NULL, //传递给任务函数的参数 (UBaseType_t)LED1_TASK_PRIO, //任务优先级 (TaskHandle_t)&LED1Task_Handler //任务句柄 ); vTaskDelete(StartTask_Handler); //删除开始任务 taskEXIT_CRITICAL(); //退出临界区 } //LED0任务函数 void led0_task(void *pvParameters) { while(1){ LED0 = ~LED0; vTaskDelay(500); } } //LED1任务函数 void led1_task(void *pvParameters) { while(1){ LED1 = 0; vTaskDelay(200); LED1 = 1; vTaskDelay(800); } }2.3.2 实验程序运行结果分析LED0 和 LED1 开始闪烁。LED0 均匀闪烁,LED1 亮的时间短,灭的时间长。
2025年02月20日
3 阅读
0 评论
1 点赞
2025-02-19
第一章 FreeRTOS简介
1.1初识FreeRTOS1.1.1 什么是FreeRTOS? FreeRTOS的名字由两部分构成,Free+RTOS。Free就是免费的意思,RTOS的全称是RealTimeOperatingSystem,中文名就是实时操作系统。RTOS 不是指某一个确定的系统, 而是指一类系统。 比如 UCOS, FreeRTOS, RTX, RT-Thread 等这些都是 RTOS 类操作系统。 一般操作系统允许多个任务同时允许,但实际上一个处理器在同一时刻只能运行一个任务。所谓的多个任务同时运行是操作系统在各个任务之间进行切换,且该操作非常的快,就给人一种同一时刻有多个任务同时运行的错觉。在操作系统中决定某一个时刻运行哪个任务是由 任务调度器 来决定的。 操作系统的分类方式可以由任务调度器的工作方式决定。比如Unix操作给每个任务分配了同样的运行时间,时间到了就轮到下一个任务。RTOS类的操作系统的任务调度器被设计为可预测的。原因是实时环境中要求操作系统必须对某一个事件做出实时的响应。 FreeRTOS 这种传统的 RTOS 类操作系统是由用户给每个任务分配一个任务优先级, 任务调度器就可以根据此优先级来决定下一刻应该运行哪个任务。1.1.2 为什么选择 FreeRTOS?免费其他半导体厂商的SDK使用FreeRTOS简单文档齐全在各种微处理器上都有使用设备占有量较高1.1.3 FreeRTOS 特点FreeRTOS 的内核支持抢占式, 合作式和时间片调度SafeRTOS 衍生自 FreeRTOS, SafeRTOS 在代码完整性上相比 FreeRTOS 更胜一筹提供了一个用于低功耗的 Tickless 模式系统的组件在创建时可以选择动态或者静态的 RAM, 比如任务、消息队列、信号量、软件定时器等等已经在超过 30 种架构的芯片上进行了移植FreeRTOS-MPU 支持 Corex-M 系列中的 MPU 单元, 如 STM32F103FreeRTOS 系统简单、小巧、易用, 通常情况下内核占用 4k-9k 字节的空间高可移植性,代码主要 C 语言编写支持实时任务和协程(co-routines 也有称为合作式、 协同程序, 本教程均成为协程)任务与任务、 任务与中断之间可以使用任务通知、消息队列、二值信号量、数值型信号量、 递归互斥信号量和互斥信号量进行通信和同步创新的事件组(或者事件标志)具有优先级继承特性的互斥信号量高效的软件定时器强大的跟踪执行功能堆栈溢出检测功能任务数量不限任务优先级不限1.2 磨刀不误砍柴工1.2.1 资料查找 其实找资料没有这么复杂,官网是最好的地方, FreeRTOS的官网是 www.freertos.org1.2.2 FreeRTOS 官方文档FreeRTOS 有一个在线文档,可以直接在官网浏览文档链接1.2.3 Cortex-M 架构资料 学习FreeRTOS 任务切换的时候需要我们了解 Cortex-M 内核架构相关的知识,否则的话根本看不懂任务切换的过程。参考《ARM Cortex-M3 与 Cortex-M4 权威指南(第三版)》,oseph Yiu 著,吴常玉、曹孟娟、王丽红译,清华大学出版社1.3 FreeRTOS 源码初探1.3.1 FreeRTOS 源码下载 在官网的主页点击下载按钮即可下载最新版本的FreeRTOS源码 下载完成后可以进行解压,在FreeRTOS-LTS\FreeRTOS\FreeRTOS-Kernel下查看FreeRTOS的源码。 当前是2025-02-19 21:59:57 星期三。目前最新的源码版本为v202406.01-LTS。本人的学习资料为正点原子的STM32F1 FreeRTOS开发手册_V1.1。教材中使用的版本为FreeRTOSv9.0.0。所以后续的笔记还是使用9.0.0的源码。1.3.2 FreeRTOS 文件预览1.3.2.1 FreeRTOS 文件夹打开 FreeRTOS 文件夹,里面有三个文件夹, Demo、 License 和 Source。Demo 文件夹里面就是 FreeRTOS 的相关例程License文件夹里面就是相关的许可信息Source文件夹就是 FreeRTOS 的本尊了include 文件夹是一些头文件,下面的这些.C 文件就是 FreeRTOS 的源码文件了;重点来看一下 portable这个文件夹。portable 文件夹里面的东西就是 FreeRTOS系统和具体的硬件之间的连接桥梁! 不同的编译环境从上图中可以看出FreeRTOS 针对不同的编译环境和 MCU 都有不同的“桥梁”。MemMang 这个文件夹是跟内存管理相关的。这个在移植时候是必须的。再看Keil文件夹。里面提示查看RDVS文件夹。打开RVDS文件夹我们可以看到对于不同的MCU有着不同的分类。我们要往STM32F1的MCU上移植。它属于CM3架构。打开后我们可以看到一个port.c和portmacro.h文件。我们在移植的时候是必须的。1.3.2.2 FreeRTOS-Plus 文件夹打开FreeRTOS-Plus文件夹我们可以看到也是有三个文件夹,与FreeRTOS文件夹一样。我们再打开Source文件夹。可以看出, FreeRTOS-Plus 中的源码其实并不是 FreeRTOS 系统的源码, 而是在 FreeRTOS系统上另外增加的一些功能代码, 比如 CLI、 FAT、 Trace 等等。 就系统本身而言, 和 FreeRTOS里面的一模一样的
2025年02月19日
2 阅读
0 评论
0 点赞