青岛 网站优化,中国联通 腾讯,长沙市网站设计公司,无锡高端网站建设咨询(一)移植前的准备1.HAL库基本工程模板新建一个工程模块#xff0c;其中包含LED驱动和串口驱动程序即可#xff0c;用于验证UCOS-III系统能够正常工作。2.UCOS-III源码准备去Micrium官网下载最新的UCOSIII源码#xff0c;下载地址#xff1a;Micrium官网下载地址#xff0c…(一)移植前的准备1.HAL库基本工程模板新建一个工程模块其中包含LED驱动和串口驱动程序即可用于验证UCOS-III系统能够正常工作。2.UCOS-III源码准备去Micrium官网下载最新的UCOSIII源码下载地址Micrium官网下载地址没有注册过的用户需要注册一下我自己注册的过程都是泪。由于我选择的是正点原子F7的开发板所以在官网上选择合适源码时就选择F7的。具体版本选择下图中19年2月6号的版本下载完成之后发现发现源码文件夹中东西很多大部分都是和网络移植相关的目前我们只移植最新版本的UCOSIII所以这些文件夹都不需要去看。进入源码目录下的uCOS-III文件夹发现里面只有针对IAR的编译器的文件难道MDK就凉凉了吗凡是先不要慌虽然编译器不同但是实现的功能就是相同的并不会影响到移植后操作系统的运行。UCOSIII的移植(一)源码文件的摘选1.在准备好的工程文件夹下新建一个UCOS-III目录用于存放和UCOSIII相关的所有代码。在UCOS-III目录下新建如下目录用于UCOS源码的分类。(1)将源码目录Micrium_STM32F746G-DISCO_Crypto\Micrium\Software\uC-CPU下的文件全部拷贝到我们创建的uC-CPU目录下为了减少文件夹的个数我把ARM-Cortex-M\ARMv7-M目录下和ARM-Cortex-M\ARMv7-M\ARM目录下的文件都移到了自己创建的uC-CPU目录下了。这里我要说明下一下IAR和ARM目录下的文件除了汇编文件有些不同以外头文件内容都是相同的这边选择ARM目录下的汇编文件还是IAR目录下的汇编文件都行因为我们都是要修改成MDK支持的形式的。(2)将源码目录Micrium_STM32F746G-DISCO_Crypto\Micrium\Software\uC-LIB文件夹下的文件全部拷贝到自己创建的uC-LIB目录下这边我直接把Micrium\Software\uC-LIB\Ports\ARM-Cortex-M4\RealView目录下的文件和其他文件放在了一个文件夹下具体如下图所示由于我们使用的是MDK编译所以这边选择的是RealView目录下的汇编文件具体什么原因的话网上有很多解释我就不复制他们的解释了。(3)将Micrium_STM32F746G-DISCO_Crypto\Micrium\Software\uCOS-III目录下的文件全部拷贝到自己创建uCOS-III目录下。点开Ports的目录发现最后只有一个IAR文件下这边我们先不用关注只需将文件都拷贝过来具体内容如下图所示(4)将源码例程目录Micrium_STM32F746G-DISCO_Crypto\ST\STM32F746G_Disco\Crypto下的部分文件和OS3下的部分文件拷贝到自己创建的UCOS-CONFIG文件夹下。具体文件如下图所示在源码例程文件中发现很多都是网络相关的移植代码所以没有拷贝过来。但是有一个clk_cfg.h很明显不是和网络相关的为什么不移植过来呢从名字上看就是和时钟相关的难道说不需要时钟配置吗时钟当然是需要配置的但是裸机工程中时钟已经配置OK了这边和时钟相关的文件也就不需要了后面操作系统的时钟需要自己通过HAL库配置这边就不详细说明了。(5)将Micrium_STM32F746G-DISCO_Crypto\ST\BSP\STM32F746G_Disco目录下的bsp_cpu.c文件拷贝到自己创建的UCOS-BSP目录下并且新建一个bsp_cpu.h头文件(用于包含操作系统的头文件)。其他文件都不需要拷贝大多是和芯片外设相关的初始化。(二)文件添加(1)打开MDK工程将拷贝的文件添加至工程当中具体内容如下图所示以及头文件路径添加如下图所示:上述文件都添加完成之后点击编译提示下图错误出现unknown opcode什么的错误而且出现在os_cpu_a.asm文件中那就打开这个汇编文件看一下是什么问题发现PUBLIC关键字都没有标蓝那肯定是由于这个关键字不是MDK的关键字所以讲PUBLIC修改为MDK所用的关键字EXPORT具体EXPORT这个关键字怎么来的我是查看了其他版本的UCOS在STM32的移植看到用的是这个关键字就直接抄过来了。还有错误与FPU相关如下图所示#ifdef __ARMVFP__EXPORT OS_CPU_FP_Reg_PushEXPORT OS_CPU_FP_Reg_Pop#endif查看了正点原子的移植手册发现上面说到Cortex-M7内核中有个Lazy Stacking的功能如果使用FPU功能的话就需要关闭这个功能需要修改startup_stm32f767xx.s汇编文件在里面关闭这个功能。具体代码如下所示:IF {FPU} ! SoftVFP; Enable Floating Point Support at reset for FPULDR.W R0, 0xE000ED88 ; Load address of CPACR registerLDR R1, [R0] ; Read value at CPACRORR R1, R1, #(0xF 20) ; Set bits 20-23 to enable CP10 and CP11 coprocessors; Write back the modified CPACR valueSTR R1, [R0] ; Wait for store to completeDSB; Disable automatic FP register content; Disable lazy context switchLDR.W R0, 0xE000EF34 ; Load address to FPCCR registerLDR R1, [R0]AND R1, R1, #(0x3FFFFFFF) ; Clear the LSPEN and ASPEN bitsSTR R1, [R0]ISB ; Reset pipeline now the FPU is enabledENDIF在startup_stm32f767xx.s中就如下图所示修改完这些接下去就解决… error: A1163E: Unknown opcode ARMVFP , expecting opcode or Macro 这个错误。将原先的判断语句修改为如下语句IF {FPU} ! SoftVFPEXPORT OS_CPU_FP_Reg_PushEXPORT OS_CPU_FP_Reg_PopENDIFIF {FPU} ! SoftVFPOS_CPU_FP_Reg_PushMRS R1, PSP ; PSP is process stack pointerCBZ R1, OS_CPU_FP_nosave ; Skip FP register save the first timeVSTMDB R0!, {S16-S31}LDR R1, OSTCBCurPtrLDR R2, [R1]STR R0, [R2]OS_CPU_FP_nosaveBX LRENDIFIF {FPU} ! SoftVFPOS_CPU_FP_Reg_PopVLDMIA R0!, {S16-S31}LDR R1, OSTCBHighRdyPtrLDR R2, [R1]STR R0, [R2]BX LRENDIF修改完成之后再次编译依旧存在 error: A1163E: Unknown opcode RSEG , expecting opcode or Macro 的错误这主要是由于编译器关键字的问题所以这里直接借鉴其他其他版本在MDK上的移植。具体修改代码如下PRESERVE8THUMBAREA CODE, CODE, READONLY再次编译发现这个汇编文件中还有一个警告 warning: A1581W: Added 2 bytes of padding at address 0x112这是提示地址没对齐那就在末尾添加一个对齐指令具体代码如下OS_CPU_PendSVHandlerCPSID I ; Cortex-M7 errata notice. See Note #5MOV32 R2, OS_KA_BASEPRI_Boundary ; Set BASEPRI priority level required for exception preemptionLDR R1, [R2]MSR BASEPRI, R1DSBISBCPSIE IMRS R0, PSP ; PSP is process stack pointerSTMFD R0!, {R4-R11, R14} ; Save remaining regs r4-11, R14 on process stackMOV32 R5, OSTCBCurPtr ; OSTCBCurPtr-StkPtr SP;LDR R1, [R5]STR R0, [R1] ; R0 is SP of process being switched out; At this point, entire context of process has been savedMOV R4, LR ; Save LR exc_return valueBL OSTaskSwHook ; Call OSTaskSwHook() for FPU Push PopMOV32 R0, OSPrioCur ; OSPrioCur OSPrioHighRdy;MOV32 R1, OSPrioHighRdyLDRB R2, [R1]STRB R2, [R0]MOV32 R1, OSTCBHighRdyPtr ; OSTCBCurPtr OSTCBHighRdyPtr;LDR R2, [R1]STR R2, [R5]ORR LR, R4, #0x04 ; Ensure exception return uses process stackLDR R0, [R2] ; R0 is new process SP; SP OSTCBHighRdyPtr-StkPtr;LDMFD R0!, {R4-R11, R14} ; Restore r4-11, R14 from new process stackMSR PSP, R0 ; Load PSP with new process SPMOV32 R2, #0 ; Restore BASEPRI priority level to 0MSR BASEPRI, R2BX LR ; Exception return will restore remaining contextALIGNEND再次编译os_cpu_a.asm文件内没有错误还有两个小错误将os_cpu_c.c中os.h的头文件路径修改意见将bsp_cpu.c中的bsp_clk.h头文件注释掉再次编译。报错信息如下图发现报错信息都在bsp_cpu.c当中而且都是和时钟频率相关的打开源码例程中的bsp_clk.c文件查看BSP_ClkFreqGet()函数发现里面调用的函数不就是HAL库提供的吗那我们直接将bsp_cpu.c中的时钟获取函数修改为HAL库提供的函数不就OK了吗。修改后的代码如下所示#if (CPU_CFG_TS_TMR_EN DEF_ENABLED)void CPU_TS_TmrInit (void){CPU_INT32U fclk_freq;CPU_INT32U reg_val;/* ---- DWT WRITE ACCESS UNLOCK (CORTEX-M7 ONLY!!) ---- */reg_val CPU_BSP_REG_DWT_LSR; /* Read lock status register. */if ((reg_val CPU_BSP_BIT_DWT_LSR_SLI) ! 0) { /* Check if Software lock control mechanism exits */if ((reg_val CPU_BSP_BIT_DWT_LSR_SLK) ! 0) { /* Check if DWT access needs to be unlocked */CPU_BSP_REG_DWT_LAR CPU_BSP_DWT_LAR_KEY; /* Unlock DWT write access. */}}fclk_freq HAL_RCC_GetHCLKFreq();CPU_BSP_REG_DEMCR | DEF_BIT_24; /* Set DEM_CR_TRCENA */CPU_BSP_REG_DWT_CR | DEF_BIT_00; /* Set DWT_CR_CYCCNTENA */CPU_TS_TmrFreqSet((CPU_TS_TMR_FREQ)fclk_freq);}#endif#if (CPU_CFG_TS_32_EN DEF_ENABLED)CPU_INT64U CPU_TS32_to_uSec (CPU_TS32 ts_cnts){CPU_INT64U ts_us;CPU_INT64U fclk_freq;fclk_freq HAL_RCC_GetHCLKFreq();ts_us ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);return (ts_us);}#endif#if (CPU_CFG_TS_64_EN DEF_ENABLED)CPU_INT64U CPU_TS64_to_uSec (CPU_TS64 ts_cnts){CPU_INT64U ts_us;CPU_INT64U fclk_freq;fclk_freq HAL_RCC_GetHCLKFreq();ts_us ts_cnts / (fclk_freq / DEF_TIME_NBR_uS_PER_SEC);return (ts_us);}#endif修改完之后再次编译发现了很多重复定义的错误都适合__dbg_ucos-iii.c文件相关那就直接移除掉这个文件再编译看看结果如何。编译之后发现只有一个未定义的错误打开os_cpu.h头文件发现了下面这行代码#define OS_TASK_SW_SYNC() __ISB()明明定义了却还是提示未定义的错误那我搜索了一下__ISB()函数在cmsis_armcc.h中明确定义了难道没添加头文件引起的吗那就添加头文件再编译一下报错信息更多了那很明显不是这个问题了。看到cmsis_armcc.h中有这一行代码#define __ISB() do {\__schedule_barrier();\__isb(0xF);\__schedule_barrier();\} while (0U)那就直接修改成#define OS_TASK_SW_SYNC() __isb(0xF)这样编译倒是没问题了。但是系统运行起来有没有问题就不知道先这么做吧这个头文件中还有一行代码也需要修改#ifdef__ARMVFP__#define OS_CPU_ARM_FP_EN 1u#else#define OS_CPU_ARM_FP_EN 0u#endif修改为#ifdef __TARGET_FPU_SOFTVFP#define OS_CPU_ARM_FP_EN 1u#else#define OS_CPU_ARM_FP_EN 0u#endif编译后无错误。现在这系统能够正常运行起来了吗讲实话我也不太清楚那就测试一下吧。(三)测试系统拷贝如下代码至main.c中。#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bsp_cpu.h//任务优先级#define START_TASK_PRIO2//任务堆栈大小#define START_STK_SIZE 512//任务控制块OS_TCB StartTaskTCB;//任务堆栈CPU_STK START_TASK_STK[START_STK_SIZE];//任务函数void start_task(void *p_arg);//任务优先级#define LED0_TASK_PRIO3//任务堆栈大小#define LED0_STK_SIZE 128//任务控制块OS_TCB Led0TaskTCB;//任务堆栈CPU_STK LED0_TASK_STK[LED0_STK_SIZE];void led0_task(void *p_arg);//任务优先级#define LED1_TASK_PRIO4//任务堆栈大小#define LED1_STK_SIZE 128//任务控制块OS_TCB Led1TaskTCB;//任务堆栈CPU_STK LED1_TASK_STK[LED1_STK_SIZE];//任务函数void led1_task(void *p_arg);//任务优先级#define FLOAT_TASK_PRIO5//任务堆栈大小#define FLOAT_STK_SIZE256//任务控制块OS_TCBFloatTaskTCB;//任务堆栈CPU_STKFLOAT_TASK_STK[FLOAT_STK_SIZE];//任务函数void float_task(void *p_arg);/****************************************************************************************************************************************** Function Name: main* Input: None* Output: None* Returns: None* Description: 主函数* Note: None*****************************************************************************************************************************************/int main(void){OS_ERR err;CPU_SR_ALLOC();HW_Init();MT_Init();OSInit(err); //初始化UCOSIIICPU_CRITICAL_ENTER(); //进入临界区//创建开始任务OSTaskCreate((OS_TCB * )StartTaskTCB,//任务控制块(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_OPT_TASK_SAVE_FP, //任务选项,为了保险起见所有任务都保存浮点寄存器的值(OS_ERR * )err);//存放该函数错误时的返回值CPU_CRITICAL_EXIT();//退出临界区OSStart(err); //开启UCOSIIIwhile(1){}}//开始任务函数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#ifOS_CFG_SCHED_ROUND_ROBIN_EN//当使用时间片轮转的时候//使能时间片轮转调度功能,设置默认的时间片长度sOSSchedRoundRobinCfg(DEF_ENABLED,10,err);#endifCPU_CRITICAL_ENTER();//进入临界区//创建LED0任务OSTaskCreate((OS_TCB * )Led0TaskTCB,(CPU_CHAR* )led0 task,(OS_TASK_PTR )led0_task,(void* )0,(OS_PRIO )LED0_TASK_PRIO,(CPU_STK * )LED0_TASK_STK[0],(CPU_STK_SIZE)LED0_STK_SIZE/10,(CPU_STK_SIZE)LED0_STK_SIZE,(OS_MSG_QTY )0,(OS_TICK )0,(void * )0,(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR|OS_OPT_TASK_SAVE_FP,(OS_ERR * )err);//创建LED1任务OSTaskCreate((OS_TCB * )Led1TaskTCB,(CPU_CHAR* )led1 task,(OS_TASK_PTR )led1_task,(void* )0,(OS_PRIO )LED1_TASK_PRIO,(CPU_STK * )LED1_TASK_STK[0],(CPU_STK_SIZE)LED1_STK_SIZE/10,(CPU_STK_SIZE)LED1_STK_SIZE,(OS_MSG_QTY )0,(OS_TICK )0,(void * )0,(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR|OS_OPT_TASK_SAVE_FP,(OS_ERR * )err);//创建浮点测试任务OSTaskCreate((OS_TCB * )FloatTaskTCB,(CPU_CHAR* )float test task,(OS_TASK_PTR )float_task,(void* )0,(OS_PRIO )FLOAT_TASK_PRIO,(CPU_STK * )FLOAT_TASK_STK[0],(CPU_STK_SIZE)FLOAT_STK_SIZE/10,(CPU_STK_SIZE)FLOAT_STK_SIZE,(OS_MSG_QTY )0,(OS_TICK )0,(void * )0,(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR|OS_OPT_TASK_SAVE_FP,(OS_ERR * )err);CPU_CRITICAL_EXIT();//进入临界区OSTaskSuspend((OS_TCB*)StartTaskTCB,err);//挂起开始任务}//led0任务函数void led0_task(void *p_arg){OS_ERR err;p_arg p_arg;while(1){HW_Led0_On(); //LED0打开OSTimeDlyHMSM(0,0,0,200,OS_OPT_TIME_HMSM_STRICT,err); //延时200msHW_Led0_Off(); //LED0关闭OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_HMSM_STRICT,err); //延时500ms}}//led1任务函数void led1_task(void *p_arg){OS_ERR err;p_arg p_arg;while(1){HW_Led1_On();HW_Delay_ms(500);//延时500msHW_Led1_Off();HW_Delay_ms(500);OSTimeDlyHMSM(0,0,0,100,OS_OPT_TIME_HMSM_STRICT,err);}}//浮点测试任务void float_task(void *p_arg){OS_ERR err;CPU_SR_ALLOC();static double double_num0.00;while(1){double_num0.01f;CPU_CRITICAL_ENTER();//进入临界区printf(double_num的值为: %.4f\r\n,double_num);CPU_CRITICAL_EXIT();//退出临界区OSTimeDlyHMSM(0,0,0,20,OS_OPT_TIME_HMSM_STRICT,err);}}编译后烧写进开发板查看现象LED灯没亮那系统肯定没有运行起来通过Debug看看哪里出问题了结果发现程序停在了如下地方那说明是PendSV中断处理出了问题看看整个工程中哪里需要调整。os_cpu_a.asm汇编文件中定义了OS_CPU_PendSVHandler函数这是Micrium官方移植例程中修改了PendSV中断函数的名称所以这边需要修改回来然后再编译报该函数的重定义错误。这边屏蔽掉stm32f7xx_it.c中的PendSV_Handler函数定义再次编译没有报错那就再下载验证一下。结果还是失败了那就再Debug一下看看是哪里的问题发现程序运行之后开始任务调度之后就挂在空闲任务上。找来找去没发现什么问题本来都准备放弃了后来看到操作系统的时间都是通过滴答定时器中断产生的然后仔细看了一下代码虽然使用了滴答定时器但是没有使用中断那赶紧加上试试顺便将stm32f7xx_it.h中定义的滴答定时器中断函数屏蔽掉。编译之后没报错那就在测试一下。终于LED灯如愿的闪烁起来 串口也正常工作起来了说明操作系统真正运行起来了。下面附上移植后的工程。链接https://pan.baidu.com/s/1AGw1SWNMI_BpX7NLsxvQdg提取码bzne复制这段内容后打开百度网盘手机App操作更方便哦