完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
;/*********************** (C) COPYRIGHT 2010 Libraworks *************************
;* File Name : os_cpu_a.asm ;* Author : Librae ;* Version : V1.0 ;* Date : 06/10/2010 ;* Description : μCOS-II asm port for STM32 ;*******************************************************************************/ EXTERN CPU_ExceptStkBase EXTERN p_TCB_Cur EXTERN p_TCBHighRdy ;IMPORT OSPrioCur ;IMPORT OSPrioHighRdy ;IMPORT OSTCBCur ;IMPORT OSTCBHighRdy EXPORT OSStartHighRdy EXPORT OSCtxSw EXPORT OSIntCtxSw EXPORT OS_CPU_SR_Save ; Functions declared in this file EXPORT OS_CPU_SR_Restore EXPORT PendSV_Handler NVIC_INT_CTRL EQU 0xE000ED04 ; 中断控制寄存器 NVIC_SYSPRI14 EQU 0xE000ED22 ; 系统优先级寄存器(2) NVIC_PENDSV_PRI EQU 0xFF ; PendSV中断和系统节拍中断 ; (都为最低,0xff). NVIC_PENDSVSET EQU 0x10000000 ; 触发软件中断的值. PRESERVE8 AREA |.text|, CODE, READONLY THUMB ;******************************************************************************************************** ; CRITICAL SECTION METHOD 3 FUNCTIONS ; ; Description: Disable/Enable interrupts by preserving the state of interrupts. Generally speaking you ; would store the state of the interrupt disable flag in the local variable 'cpu_sr' and then ; disable interrupts. 'cpu_sr' is allocated in all of uC/OS-II's functions that need to ; disable interrupts. You would restore the interrupt disable state by copying back 'cpu_sr' ; into the CPU's status register. ; ; Prototypes : OS_CPU_SR OS_CPU_SR_Save(void); ; void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr); ; ; ; Note(s) : 1) These functions are used in general like this: ; ; void Task (void *p_arg) ; { ; #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */ ; OS_CPU_SR cpu_sr; ; #endif ; ; : ; : ; OS_ENTER_CRITICAL(); /* cpu_sr = OS_CPU_SaveSR(); */ ; : ; : ; OS_EXIT_CRITICAL(); /* OS_CPU_RestoreSR(cpu_sr); */ ; : ; : ; } ;******************************************************************************************************** ;CPSID I ;PRIMASK=1, ;关中断 ;CPSIE I ;PRIMASK=0, ;开中断 ;CPSID F ;FAULTMASK=1, ;关异常 ;CPSIE F ;FAULTMASK=0 ;开异常 OS_CPU_SR_Save MRS R0, PRIMASK ;读取 常规异常屏蔽寄存器(PRIMASK) 到R0,R0为返回值 CPSID I ;PRIMASK=1,关中断(NMI和硬件FAULT可以响应) BX LR ;返回 OS_CPU_SR_Restore MSR PRIMASK, R0 ;读取R0到PRIMASK中,R0为参数 BX LR ;返回 ;/************************************************************************************** ;* 函数名称: OSStartHighRdy ;* ;* 功能描述: 使用调度器运行第一个任务 ;* ;* 参 数: None ;* ;* 返 回 值: None ;**************************************************************************************/ OSStartHighRdy LDR R4, =NVIC_SYSPRI14 ; set the PendSV exception priority LDR R5, =NVIC_PENDSV_PRI STR R5, [R4] MOV R4, #0 ; set the PSP to 0 for initial context switch call MSR PSP, R4 LDR R4, =CPU_ExceptStkBase ; 中断嵌套时有用 主堆栈 LDR R5, [R4] MSR MSP, R5 ;读取主堆栈指针到MSP,就是设置MSP,初始化的意思 ;切换到最高优先级的任务 LDR R4, =NVIC_INT_CTRL ;rigger the PendSV exception (causes context switch) LDR R5, =NVIC_PENDSVSET STR R5, [R4] CPSIE I ;enable interrupts at processor level 中断可以运行了 ,然后就进入pendsv中断要了 OSStartHang B OSStartHang ;should never get here ;/************************************************************************************** ;* 函数名称: OSCtxSw ;* ;* 功能描述: 任务级上下文切换 ;* ;* 参 数: None ;* ;* 返 回 值: None ;***************************************************************************************/ OSCtxSw PUSH {R4, R5} LDR R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch) LDR R5, =NVIC_PENDSVSET STR R5, [R4] ;触发了pendsv异常,切换的事情在pendsv异常里面处理 POP {R4, R5} BX LR ;/************************************************************************************** ;* 函数名称: OSIntCtxSw ;* ;* 功能描述: 中断级任务切换 ;* ;* 参 数: None ;* ;* 返 回 值: None ;***************************************************************************************/ OSIntCtxSw PUSH {R4, R5} LDR R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch) LDR R5, =NVIC_PENDSVSET STR R5, [R4] POP {R4, R5} ;同上一个函数一样,不过,是从中断里面切出来的,应该是这样,,, BX LR NOP ;/************************************************************************************** ;* 函数名称: OSPendSV ;* ;* 功能描述: OSPendSV is used to cause a context switch. ;* ;* 参 数: None ;* ;* 返 回 值: None ;***************************************************************************************/ ;真正的上下文切换是在这里面是下面的汇编函数实现的。 ; PendSV_Handler CPSID I ; Prevent interruption during context switch 硬中断没关,意思是除了严重的问题,还是可以有中断来处理的 MRS R0, PSP ; PSP is process stack pointer 如果在用PSP堆栈,则可以忽略保存寄存器,参考CM3权威中的双堆栈-白菜注 CBZ R0, PendSV_Handler_Nosave ; Skip register save the first time ;CBZ : 比较,如果结果为 0 就转移到 PendSV_Handler_Nosave函数 (只能跳到后面的指令——译注) SUBS R0, R0, #0x20 ; Save remaining regs r4-11 on process stack ;先减去八个寄存器的共32个字节,然后把8个寄存器的值装进去。 STM R0, {R4-R11} LDR R1, =p_TCB_Cur ; OSTCBCur->OSTCBStkPtr = SP; LDR R1, [R1] STR R0, [R1] ; R0 is SP of process being switched out ; At this point, entire context of process has been saved ;注意,,,这里并没有跳转指令,这是一个函数啊,接着往下运行,只是第一次运行这个函数时,直 ;接跳到了PendSV_Handler_Nosave,后面就不会跳了,而是一直往下运行 PendSV_Handler_Nosave LDR R0, =p_TCB_Cur ; OSPrioCur = OSPrioHighRdy; LDR R1, =p_TCBHighRdy LDR R2, [R1] ;R2里面是最高优先级任务控制块的地址 STR R2, [R0] ;R2里面是最高优先级任务控制块的地址给到R0,就是说,R0里面装的就是最高优先级任务的地址 LDR R0, [R2] ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr; ;上面这一步就是说取出最高优先级任务地址里面装的值,由于任务控 ;制块是一个结构体,里面第一个地址装的值就是该任务的堆栈指 ;针,所以说堆栈指针要放在最前面,就是取地址的地址,R0里面放的就是最高优先级任务的堆栈指针 LDM R0, {R4-R11} ; Restore r4-11 from new process stack ;LDM 是多个数据的加载指令 ,有几个寄存器不用指定它加载,因为处理器自己完成这个事情,不用你管 ;上面这条指令就是加载新的任务上下文所做的事情, ;注意,这里并没有先保存上一个任务的上下文,原因是,这是第一次运行,并没有上一个任务,而 ;且PendSV_Handler_Nosave只是PendSV_Handler函数的一部分,别以为是两个函数,,, ADDS R0, R0, #0x20 ;上面的0x20等于32,就是加载的8个寄存器的值 MSR PSP, R0 ; Load PSP with new process SP ORR LR, LR, #0x04 ; Ensure exception return uses process stack CPSIE I BX LR ; Exception return will restore remaining context end #include "timer.h" #include "led.h" #include "OS_Need.h" //通用定时器3中断初始化 //这里时钟选择为APB1的2倍,而APB1为36M //arr:自动重装值。 //psc:时钟预分频数 //这里使用的是定时器3! void TIM3_Int_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能 //定时器TIM3初始化 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断 //中断优先级NVIC设置 NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器 TIM_Cmd(TIM3, ENABLE); //使能TIMx } //定时器3中断服务程序 void TIM3_IRQHandler(void) //TIM3中断 { char i=0; if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志 for(i=0;i if(TCB_Task.Dly > 0) { TCB_Task.Dly--; if(TCB_Task.Dly == 0) { OSSetPrioRly(i); } } } } } |
|
|
|
#include "sys.h"
#include "delay.h" #include "usart.h" #include "led.h" #include "timer.h" uint32_t OSRdyTbl;//此系统有32个优先级,同时只能有32个任务,每个任务和优先级对应 uint32_t OSPrioHighRdy; uint32_t OSPrioCur; struct os_tcb{ //任务控制块结构体 uint32_t *StkPtr; uint32_t Dly; uint32_t Prio;//没有用到 }; typedef struct os_tcb TCB; TCB *p_TCB_Cur; TCB *p_TCBHighRdy; #define OS_EXCEPT_STK_SIZE (1024*10) #define TASK_1_STK_SIZE 1024 #define TASK_2_STK_SIZE 1024 #define OS_IdleTask_STK_SIZE 1024 uint32_t TASK_1_STK[TASK_1_STK_SIZE]; uint32_t TASK_2_STK[TASK_2_STK_SIZE]; uint32_t OS_IdleTask_Stk[OS_IdleTask_STK_SIZE]; TCB TCB_Task1,TCB_Task2; #define TCB_Task_NUM 32 TCB TCB_Task[TCB_Task_NUM];//最对创建TCB_Task_NUM个任务 uint32_t TCB_Task_NUM_Counts=0;//记录现在有几个任务 uint32_t cpu_sr; #define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();} #define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);} uint32_t OS_CPU_SR_Save(void); void OS_CPU_SR_Restore(uint32_t cpu_sr); void OSCtxSw(void); void OSIntCtxSw(void); void OSStartHighRdy(void); void OSPendSV(void); void OSTimeDly(uint32_t ticks); void OSSched(void); void OS_TASK_Init(void); void task_1(void); void task_2(void); void OS_IdleTask(void); void OSSetPrioRly(uint16_t prio) { OSRdyTbl |= 0x01< void OSDelPrioRly(uint16_t prio) { OSRdyTbl &= ~(0x01< void OSGetHighRdy(void) {//此函数在优先级表OSRdyTbl中选出最高的优先级 uint32_t OSNextTaskPrio; for(OSNextTaskPrio = 0;(OSNextTaskPrio<32) && !(OSRdyTbl&(0x01< OSPrioHighRdy = OSNextTaskPrio; } //以下是任务控制块 //以下是堆栈 uint32_t CPU_ExceptStk[OS_EXCEPT_STK_SIZE]; uint32_t *CPU_ExceptStkBase; //建立一个任务 void Task_Create (void (*task)(void ), uint32_t *p_stk ,uint16_t prio) { uint32_t *stk; stk = p_stk; /* Load stack pointer */ /* Registers stacked as if auto-saved on exception */ *(stk) = (uint32_t)0x01000000L; /* xPSR */ *(--stk) = (uint32_t)task; /* Entry Point */ *(--stk) = (uint32_t)0xFFFFFFFEL; /* R14 (LR) (init value will cause fault if ever used)*/ *(--stk) = (uint32_t)0x12121212L; /* R12 */ *(--stk) = (uint32_t)0x03030303L; /* R3 */ *(--stk) = (uint32_t)0x02020202L; /* R2 */ *(--stk) = (uint32_t)0x01010101L; /* R1 */ *(--stk) = (uint32_t)0x01010101L; /* R0 : argument */ /* Remaining registers saved on process stack */ *(--stk) = (uint32_t)0x11111111L; /* R11 */ *(--stk) = (uint32_t)0x10101010L; /* R10 */ *(--stk) = (uint32_t)0x09090909L; /* R9 */ *(--stk) = (uint32_t)0x08080808L; /* R8 */ *(--stk) = (uint32_t)0x07070707L; /* R7 */ *(--stk) = (uint32_t)0x06060606L; /* R6 */ *(--stk) = (uint32_t)0x05050505L; /* R5 */ *(--stk) = (uint32_t)0x04040404L; /* R4 */ TCB_Task[prio].StkPtr = (stk); OSSetPrioRly(prio); //TCB_Task[TCB_Task_NUM_Counts].Prio = prio; //TCB_Task_NUM_Counts++;//任务数量计数器加1 , TCB_Task_NUM_Counts 必须不能大于TCB_Task_NUM } int main(void) { delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 LED_Init(); //初始化与LED连接的硬件接口 uart_init(9600); TIM3_Int_Init(49,7199);//10Khz的计数频率,计数到50为5ms printf("this is the begin of the task ...ntask is running ...n"); CPU_ExceptStkBase = CPU_ExceptStk + OS_EXCEPT_STK_SIZE - 1; OS_ENTER_CRITICAL(); Task_Create( task_1 , &TASK_1_STK[TASK_1_STK_SIZE-1] ,7); Task_Create( task_2 , &TASK_2_STK[TASK_2_STK_SIZE-1] ,6); OS_EXIT_CRITICAL(); //p_TCBHighRdy = &TCB_Task1; //OSStartHighRdy(); OS_TASK_Init(); while(1); } /* void Task_Switch(void) { if(p_TCB_Cur == &TCB_Task1) p_TCBHighRdy = &TCB_Task2; else p_TCBHighRdy = &TCB_Task1; OSCtxSw(); }*/ void OSTimeDly(uint32_t ticks) { if(ticks > 0) { OS_ENTER_CRITICAL(); OSDelPrioRly(OSPrioCur); TCB_Task[OSPrioCur].Dly = ticks; OS_EXIT_CRITICAL(); OSSched(); } } void OS_TASK_Init(void) { OS_ENTER_CRITICAL(); Task_Create(OS_IdleTask , &OS_IdleTask_Stk[OS_IdleTask_STK_SIZE-1],TCB_Task_NUM-1);//将空闲任务设置为最低优先级 OS_EXIT_CRITICAL(); OSGetHighRdy(); OSPrioCur = OSPrioHighRdy; p_TCBHighRdy = &TCB_Task[OSPrioHighRdy]; OSStartHighRdy(); } void OSSched(void) { OSGetHighRdy(); if(OSPrioHighRdy != OSPrioCur) { p_TCBHighRdy = &TCB_Task[OSPrioHighRdy]; OSPrioCur = OSPrioHighRdy; OSCtxSw(); } } void task_1(void){ while(1) { printf("task 1n"); //Task_Switch(); OSTimeDly(20); } } void task_2(void){ while(1) { printf("task 2n"); //Task_Switch(); OSTimeDly(20); } } void OS_IdleTask(void) { while(1){ OSSched(); } } |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1645 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1564 浏览 1 评论
992 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
691 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1610 浏览 2 评论
1871浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
656浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
526浏览 3评论
542浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
515浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-26 23:04 , Processed in 0.427334 second(s), Total 45, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号