有哪些公司的网站设计的好,企业服务网站制作,页面设计层次架构包括什么,辽阳专业建设网站今日学习嵌入式实时操作系统RTOS#xff1a;UC/OS-III实时操作系统
本文只是个人学习笔记备忘用#xff0c;附图、描述等 部分都是对网上资料的整合......
文章主要研究如何将UC/OS-III 移植到 STM32 F407VET6上#xff0c;提供测试工程下载 #xff08;2024.5.21 文章未… 今日学习嵌入式实时操作系统RTOSUC/OS-III实时操作系统
本文只是个人学习笔记备忘用附图、描述等 部分都是对网上资料的整合......
文章主要研究如何将UC/OS-III 移植到 STM32 F407VET6上提供测试工程下载 2024.5.21 文章未写完测试有问题以后再说 2024.5.22 系统移植失败测试有问题以后再说 附言网络上的资料真是参差不齐整整浪费我一天时间...... 目录 UCOS基础知识 任务的五种状态: 任务五种状态转换图 UCOS-III的三大列表 UCOS-III系统配置文件说明 UC/OS-III移植(STM32F4): 添加 UC/OS-III 源码部分 修改system_stm32f4xx.s启动文件代码 修改/确定 系统时钟(SysTick)内核 修改CONFIG/app_cfg.h: 修改CONFIG/includes.h 尝试编写简单的 UC/OS-III 任务例程 先引用头文件 定义任务栈大小/优先级 定义任务控制块TCB: 定义任务栈 定义任务主体函数: 创建任务TASK1-2-3 CPU_SR_ALLOC(); OS_CRITICAL_ENTER(); OS_CRITICAL_EXIT(); 启动UCOS III 系统函数 主函数调用情况展示 测试效果展示 整体测试工程下载 网上学习资料网址贴出 UCOS基础知识
任务的五种状态: 任务五种状态转换图 1、被创建的任务初始状态均为就绪态 2、被删除的任务会转为休眠态 3、仅就绪态和中断态可转变成运行态 4、其他状态的任务想运行必须先转变成就绪 UCOS-III的三大列表 UCOS-川主要有三大类列表用来跟踪任务状态 就绪列表 准备运行的任务将放在就绪列表OSRdyList[x],其中x代表任务优先级数值Tick列表 正在等待延时超时或挂起的对象超时的任务将放在OSTickList挂起列表 当任务等待信号量、事件时任务将放置在挂起列表PendList UCOS-III系统配置文件说明
以下就是我们接下来需要移植的 部分文件他们的作用大致各自如下 UC/OS-III移植(STM32F4): 本次尝试移植UC/OS-III 于立创梁山派天空星开发板上芯片型号是STM32F407VET6 其中UC/OS-III 的源码可以在整体工程下载中的压缩包内找到 注意这里的源码是被我阉割过的削除了官方文件中不必要的文件与目录 其次就是网络上那些所谓提供UC/OS源码或者教程的如果没有移植成功的工程供下载的案例基本都是垃圾浪费时间不是缺少文件就是解释不详细缺步漏步 本人也是在艰难的学习中掉进太多移植源码方面的坑里了......... 添加 UC/OS-III 源码部分 在工程中新建几个分组 uC-OS3/CPU uC-OS3/LIB uC-OS3/PORT uC-OS3/SOURCE uC-OS3/CONFIG 点击uC-OS3/CPU–Add Files UC-OSIII/CPU添加以下文件如果只查找到一个请将文件类型(I)选为 ALL files(.) 点击uC-OS3/CPU–Add Files UCOSIII\bsp添加以下文件如果只查找到一个请将文件类型(I)选为 ALL files(.) 点击uC-OS3/LIB–Add Files UCOSIII\uC-LIB添加以下所有文件如果只查找到一个请将文件类型(I)选为 ALL files(.) 点击uC-OS3/PORT–Add Files UCOSIII\uCOS-III\Ports添加以下所有文件如果只查找到一个请将文件类型(I)选为 ALL files(.) 点击uC-OS3/SOURCE–Add Files UCOSIII\uCOS-III\Source添加以下所有文件如果只查找到一个请将文件类型(I)选为 ALL files(.) uC-OS3/CONFIG添加文件 UCOSIII\config添加以下所有文件如果只查找到一个请将文件类型(I)选为 ALL files(.) 最后别忘记在魔棒中添加各个文件路径 补补充添加一条bsp的路径之前忘记添加了导致报错...... 添加结束编译看看有无报错缺漏 这里也是完美无报错的典范了哈哈哈...... 修改system_stm32f4xx.s启动文件代码 打开工程自带的 system_stm32f4xx.s启动文件(这是启动文件不是UC/OS源码) 我们需要对其进行一些修改 1 第80行框出代码修改 DCD OS_CPU_PendSVHandler ; PendSV HandlerDCD OS_CPU_SysTickHandler ; SysTick Handler 第220行框出代码修改 OS_CPU_PendSVHandler\PROCEXPORT OS_CPU_PendSVHandler [WEAK]B .ENDP
OS_CPU_SysTickHandler\PROCEXPORT OS_CPU_SysTickHandler [WEAK]B .ENDP 最后编译检查无问题 修改/确定 系统时钟(SysTick)内核 这里我还特意出去学习了一下系统内核时钟的初始化等知识并附文 STM32F407VET6 学习笔记3内核定时器SystemTickSysTick初始化中断-CSDN博客 /*** This function will initial stm32 board.*/
void board_init(void)
{/* NVIC Configuration */
#define NVIC_VTOR_MASK 0x3FFFFF80
#ifdef VECT_TAB_RAM/* Set the Vector Table base location at 0x10000000 */SCB-VTOR (0x10000000 NVIC_VTOR_MASK);
#else /* VECT_TAB_FLASH *//* Set the Vector Table base location at 0x08000000 */SCB-VTOR (0x08000000 NVIC_VTOR_MASK);
#endifSysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); //Systick 时钟源频率168M// 计算SysTick重装载值SystemCoreClock为168MHz希望SysTick中断频率为1ms(1000 Hz)//SysTick_LOAD (SystemCoreClock / TickRate) - 1uint32_t reload SystemCoreClock / 1000 - 1; // 1ms中断频率 SysTick-LOAD reload; // 清除SysTick当前值并启动SysTick同时使能中断SysTick-VAL 0; // 清空当前值 SysTick-CTRL SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* 设置NVIC优先级分组 */ // 4位抢占优先级和0位子优先级 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); /* 设置SysTick中断的优先级 */ // 设置SysTick的抢占优先级为3最低没有子优先级因为分组4没有子优先级位 NVIC_SetPriority(SysTick_IRQn, 3); // 注意优先级值根据分组设置可能有所不同 }
// 声明SysTick中断处理函数
void SysTick_Handler(void)
{OSIntEnter(); //进入中断OSTimeTick(); //调用ucos的时钟服务程序 OSIntExit(); //触发任务切换软中断
}修改CONFIG/app_cfg.h: #define APP_CFG_SERIAL_EN DEF_ENABLED ------ #define APP_CFG_SERIAL_EN DEF_DISABLED 改后如下 #define APP_TRACE BSP_Ser_Printf -------- #define APP_TRACE (void) 修改CONFIG/includes.h 尝试编写简单的 UC/OS-III 任务例程
先引用头文件
/*****************UC/OS头文件***************/
#include os.h
#include os_cpu_bsp.h
#include app_cfg.h
#include cpu_core.h
#include os_app_hooks.h
#include cpu.h
/* USER CODE END Includes */ 定义任务栈大小/优先级 //任务栈大小定义
#define START_STK_SIZE 128
#define TASK1_STK_SIZE 128
#define TASK2_STK_SIZE 128
#define TASK3_STK_SIZE 128//任务优先级定义
#define APP_TASK_START_PRIO 4
#define APP_TASK_1_PRIO 5
#define APP_TASK_2_PRIO 6
#define APP_TASK_3_PRIO 7 定义任务控制块TCB: //创建任务控制块
static OS_TCB Start_Task_TCB;
static OS_TCB Task1_TCB;
static OS_TCB Task2_TCB;
static OS_TCB Task3_TCB; 定义任务栈 //任务堆栈
CPU_STK START_TASK_STK[START_STK_SIZE];
CPU_STK TASK1_TASK_STK[TASK1_STK_SIZE];
CPU_STK TASK2_TASK_STK[TASK2_STK_SIZE];
CPU_STK TASK3_TASK_STK[TASK3_STK_SIZE]; 定义任务主体函数: 这个放置在主函数下面吧就 任务里面一定要有阻塞延时如果这个任务的优先级最高且没有阻塞延时那么操作系统就只会执行这一个任务其他的任务就得不到执行。 注意这里的 OSTimeDly ( 2000, OS_OPT_TIME_DLY, err ); 对应的延时 不仅与 内传的参数 有关 还与 内核定时器SystemTick 有关 创建任务TASK1-2-3 各个TASK的任务如下描述 //TASK_1 报告自己执行次数(2s),并在执行8次后删除 TASK_2 //TASK_2 串口报告自己执行的次数 (4s) //这里的 TASK_3 会每隔 17S 恢复TASK_2 (全新的开始) /* 创建一个全新的任务实例而不是简单地“恢复”一个已经被删除的任务。 这意味着新的任务实例将拥有自己独立的堆栈stack和其他资源而原来的任务实例如果已经被删除的资源将被释放 */ //TASK_1 报告自己执行次数(2s),并在执行8次后删除 TASK_2
void TASK_1(void)
{OS_ERR err; // 定义一个“错误” 变量用来存放一些错误的类型int TASK1_num0; //记录任务TASK_1执行次数//在某些嵌入式系统中进入和退出关键区域可能需要禁用中断以防止在关键代码执行过程中被中断打断。 CPU_SR_ALLOC(); //为保存和恢复CPU的状态寄存器Status Register或中断状态做准备工作。OS_CRITICAL_ENTER();/* 此处添加不希望被打断的硬件初始化代码等......*/OS_CRITICAL_EXIT();while(1){TASK1_num; //任务TASK_1执行次数加1if(TASK1_num%80){OSTaskDel((OS_TCB*)Task2_TCB,err); //任务1每执行8次后(即16s时) 删除掉任务2printf(TASK_1 has Deleted the TASK_2 !\r\n);//打印报告 任务1 删除了 任务2}UsartPrintf(USART1,TASK_1 has Carred out %d times! \r\n,TASK1_num); //打印测试字符串(并报告TASK_1执行次数)OSTimeDly ( 2000, OS_OPT_TIME_DLY, err ); //使当前任务延迟指定的时间(2s): (让当前任务放弃CPU一段时间,CPU让给其余任务)}
}//TASK_2 串口报告自己执行的次数 (4s)
void TASK_2(void)
{OS_ERR err; // 定义一个“错误” 变量用来存放一些错误的类型int TASK2_num0; //记录任务TASK_2执行次数while(1){UsartPrintf(USART1,TASK_2 has Carred out %d times! \r\n,TASK2_num); //打印测试字符串(并报告TASK_2执行次数)OSTimeDly ( 4000, OS_OPT_TIME_DLY, err );//使当前任务延迟指定的时间(4S): (让当前任务放弃CPU一段时间,CPU让给其余任务) }
}//这里的 TASK_3 会每隔 17S 恢复TASK_2 (全新的开始)
/*创建一个全新的任务实例而不是简单地“恢复”一个已经被删除的任务。这意味着新的任务实例将拥有自己独立的堆栈stack和其他资源而原来的任务实例如果已经被删除的资源将被释放
*/
void TASK_3(void)
{OS_ERR err; // 定义一个“错误” 变量用来存放一些错误的类型int TASK3_num0; //记录任务TASK_3执行次数CPU_SR_ALLOC();OS_CRITICAL_ENTER(); //进入临界区 //重新创建TASK2任务OSTaskCreate((OS_TCB * )Task2_TCB, (CPU_CHAR * )TASK_2, (OS_TASK_PTR )TASK_2, (void * )0, (OS_PRIO )TASK2_PRIO, (CPU_STK * )TASK2_TASK_STK[0], (CPU_STK_SIZE)TASK2_STK_SIZE/10, (CPU_STK_SIZE)TASK2_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )err); OS_CRITICAL_EXIT(); //退出临界区 while(1){UsartPrintf(USART1,TASK_3 has Resume the TASK_2 %d times! \r\n,TASK3_num); //打印测试字符串(并报告TASK_3执行次数) OSTimeDly ( 17000, OS_OPT_TIME_DLY, err );//使当前任务延迟指定的时间(17S): (让当前任务放弃CPU一段时间,CPU让给其余任务) }
}//开始任务任务函数
void start_task(void *p_arg)
{OS_ERR err;CPU_SR_ALLOC();p_arg p_arg;CPU_Init();
#if OS_CFG_STAT_TASK_EN 0uOSStatTaskCPUUsageInit(err); //统计任务
#endif#ifdef CPU_CFG_INT_DIS_MEAS_EN //如果使能了测量中断关闭时间CPU_IntDisMeasMaxCurReset();
#endif#if OS_CFG_SCHED_ROUND_ROBIN_EN //当使用时间片轮转的时候//使能时间片轮转调度功能,时间片长度为1个系统时钟节拍既1*55msOSSchedRoundRobinCfg(DEF_ENABLED,1,err);
#endif OS_CRITICAL_ENTER(); //进入临界区//创建TASK1任务OSTaskCreate((OS_TCB * )Task1_TCB, //任务控制块(CPU_CHAR * )TASK_1, //任务名字 (OS_TASK_PTR )TASK_1, //任务函数(void * )0, //传递给任务函数的参数 (OS_PRIO )TASK1_PRIO, (CPU_STK * )TASK1_TASK_STK[0], (CPU_STK_SIZE)TASK1_STK_SIZE/10, (CPU_STK_SIZE)TASK1_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,(OS_ERR * )err); //创建TASK2任务OSTaskCreate((OS_TCB * )Task2_TCB, (CPU_CHAR * )TASK_2, (OS_TASK_PTR )TASK_2, (void * )0, (OS_PRIO )TASK2_PRIO, (CPU_STK * )TASK2_TASK_STK[0], (CPU_STK_SIZE)TASK2_STK_SIZE/10, (CPU_STK_SIZE)TASK2_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )err); //创建TASK3任务OSTaskCreate((OS_TCB * )Task3_TCB, (CPU_CHAR * )TASK_3, (OS_TASK_PTR )TASK_3, (void * )0, (OS_PRIO )TASK3_PRIO, (CPU_STK * )TASK3_TASK_STK[0], (CPU_STK_SIZE)TASK3_STK_SIZE/10, (CPU_STK_SIZE)TASK3_STK_SIZE, (OS_MSG_QTY )0, (OS_TICK )0, (void * )0, (OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR * )err); OS_CRITICAL_EXIT(); //退出临界区OSTaskDel((OS_TCB*)0,err); //删除start_task任务自身
} CPU_SR_ALLOC();
OS_CRITICAL_ENTER();
OS_CRITICAL_EXIT(); //在某些嵌入式系统中进入和退出关键区域可能需要禁用中断以防止在关键代码执行过程中被中断打断。 CPU_SR_ALLOC(); //为保存和恢复CPU的状态寄存器Status Register或中断状态做准备工作。/*OS_CRITICAL_ENTER();这个函数通常用于进入一个关键区域。在进入关键区域之前它可能会禁用中断如果之前通过CPU_SR_ALLOC();已经做了相关准备或者通过其他机制如锁来确保没有其他线程或中断可以访问当前线程正在使用的共享资源。通过禁用中断或获得锁OS_CRITICAL_ENTER();确保了代码的关键部分在执行时不会被其他任务或中断打断从而保证了数据的一致性和操作的原子性。*/OS_CRITICAL_ENTER();/*OS_CRITICAL_EXIT();这个函数用于退出之前由OS_CRITICAL_ENTER();进入的关键区域。在退出关键区域时它可能会重新启用之前被禁用的中断或者释放之前获得的锁。这样做允许其他任务或中断再次访问之前被保护的共享资源*/OS_CRITICAL_EXIT(); 启动UCOS III 系统函数
//启动UCOS III 系统
void UCOS_III_init(void)
{OS_ERR err;CPU_SR_ALLOC();OSInit(err); //初始化UCOSIIIOS_CRITICAL_ENTER(); //进入临界区 //创建开始任务OSTaskCreate((OS_TCB * )Start_Task_TCB, //任务控制块(CPU_CHAR * )start_task, //任务名字(OS_TASK_PTR )start_task, //任务函数(void * )0, //传递给任务函数的参数(OS_PRIO )START_TASK_PRIO, //任务优先级(CPU_STK * )START_TASK_STK[0], //任务堆栈基地址(CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位(CPU_STK_SIZE)START_STK_SIZE, //任务堆栈大小(OS_MSG_QTY )0, //任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息(OS_TICK )0, //当使能时间片轮转时的时间片长度为0时为默认长度(void * )0, //用户补充的存储区(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项(OS_ERR * )err); //存放该函数错误时的返回值OS_CRITICAL_EXIT(); //退出临界区 OSStart(err); //开启UCOSIII
}主函数调用情况展示 网上学习资料网址贴出 第3讲 UCOS基础知识_哔哩哔哩_bilibili uCosII移植STM32F407教程_stm32f407 ucos-CSDN博客 基于stm32cubemx移植uC/OS-III操作系统_cubemx ucos-CSDN博客