加载中
加载中
表情图片
评为精选
鼓励
加载中...
分享
加载中...
文件下载
加载中...
修改排序
加载中...
自己动手写STM32多任务调度器
张静茹2015/06/04软件综合 IP:山东
首先介绍几个寄存器,这几个寄存器只能在汇编或内联汇编时才能访问,C语言是访问不到的
R0-R12,都可作为临时变量存储,跟C语言的变量差不多,不过汇编中的存储变量是用寄存器,而且不用声明,全局可见,不分全局和局部,而且是32位的
比如想计算1+1,结果放在r0中
mov r0,0x01
add r0,0x01
寄存器.png
图片来自互联网,互联网来自<<Cortex-M3权威指南>>


R13(MSP/PSP)堆栈寄存器,汇编指令PUSH,POP会影响R13的值,
PUSH {R0} //R0的值将被压入栈内 R13-4
POP{R1}    //将SP所指向的内存赋值给R1 SP+4
栈.png


R14 :是连接寄存器(LR),用于在调用子程序时存储返回地址,应该是不能用mov mrs msr访问的,只能用pop push保存
R15 是程序计数器(PC),每条指令前都对应一个地址,把这个地址赋值给R15,程序就立即跳过去执行地址对应的程序
xRPS特殊功能寄存器组 详细内容请参考<<Cortex-M3权威指南>>

之前用过UCOS,可是他每个死循环任务下面必须有一个延时函数,才可以把调度权限交还给系统,自然这个延时函数上面也不可以有死循环,
不然将永远卡在死循环上,别的任务也就不能再被调用了


Other
int main(void) {           GPIO_InitTypeDef  GPIO_InitStructure;                          Stm32_Clock_Init(9); //系统时钟设置     delay_init(72);      //延时初始化     uart_init(72,9600);  //串口初始化为9600     LED_Init();          //初始化与LED连接的硬件接口       SysTick_Configuration();     OSInit();     OSTaskCreate( TaskStart,    //task pointer                     (void *)0,  //parameter                     (OS_STK *)&TASK_START_STK[START_STK_SIZE-1],    //task stack top pointer                     START_TASK_Prio );  //task priority                              OSStart();     return 0;       } //开始任务 void TaskStart(void * pdata) {     pdata = pdata;     OS_ENTER_CRITICAL();       OSTaskCreate(TaskLed, (void * )0, (OS_STK *)&TASK_LED_STK[LED_STK_SIZE-1], LED_TASK_Prio);     OSTaskCreate(TaskLed1, (void * )0, (OS_STK *)&TASK_LED1_STK[LED1_STK_SIZE-1], LED1_TASK_Prio);     OSTaskSuspend(START_TASK_Prio); //suspend but not delete     OS_EXIT_CRITICAL(); } //任务1 //控制DS0的亮灭. void TaskLed(void *pdata) {     while(1)     {         LED0 = !LED0;         OSTimeDlyHMSM(0,0,1,100);       } } //任务2 //控制DS1的亮灭. void TaskLed1(void *pdata) {     while(1)     {         LED1 = !LED1;         OSTimeDlyHMSM(0,0,1,300);       } }








正文开始:
我写的这个调度系统是用stm32 定时器中断调度任务的,任务中不需要ucos那种延时函数,定时器每隔一段时间中断当前任务,保存现场,恢复第二个任务的现场,这时PC寄存器被改为第二个任务上次中断前执行的位置然后退出中断,,从任务二上次中断前的位置继续执行
调度原理:
参考<<Cortex-M3权威指南>>中 第九章 中断的具体行为
当 C M 3开始响应一个中断时内核会自动 把 8个寄存器(R0-R3,R12,LR,PC,xPSR)的值压入栈,最关键的是PC,他直接决定了中断退出以后开始执行的位置,R0-R3,R12则保存了一些中间变量,保证了恢复现场以后程序正确执行


程序流程:                                                                       标志:↓↓↓
进入main() ----> 初始化GPIO,时钟,定时器,开中断 ---->进入任务0 ---->定时器中断时间到 ---->开始进入中断 ---->系统自动8个寄存器(R0-R3,R12,LR,PC,xPSR)的值压入栈 ---->进入中断函数TIM3_IRQHandler(此时SP堆栈指针正指向R0,R0+4后,指向R1)
Other
TIM3_IRQHandler PROC         PUSH     {r4,lr}         MRS      r4,MSP         MOV      r0,r4         ADD      r0,r0,#8         MOV      r4,r0         LDR      r0,|L0.640|         STR      r4,[r0,#0]         BL       IRQHandler         POP      {r4,pc}         ENDP
  ----->生成汇编文件后可以看到,进入TIM3_IRQHandler函数先把R4和LR压栈(这是编译器自动做的),MSP堆栈指针 - 8   ----->MRS      r4,MSP 保存栈指针   ----->指针+8(对前面R4和LR的补偿)对准 8个被自动压栈的寄存器的R0   ----->保存指针到全局变量Address_BASE   ----->bl    IRQHandler  调用任务调度程序   ----->清除中断待处理位   ----->根据之前保存的栈地址,加载8个寄存器保存当前任务现场   ----->   调用任务二的地址----->  task->Start_Next(); 更新任务标志----->   退出中断 并 恢复被修改了返回地址的8个寄存器 ----->  执行任务1----->   定时器中断时间到 ---->进入中断  -----> 保存任务1现场----->   恢复任务0  ----->退出中断  ----->goto 标志;


Other
#include "../h/main.h"                  extern Task *task; int main(void) {                      task = new Task(); //创建任务管理对象 这是一个C++类对象                          Init();//初始化 时钟 串口 GPIO     Timerx_Init(20,7199);//初始化TIM3,开中断,每2ms进一次中断     TIM3->CNT = 0x01;//意义不明 不要也行     __asm  //內联汇编     {         bl Task0 //跳转到任务1     } //  while (true); //  delete task; } int temp = 0; void Task0(void) //任务1 {     while (true)     {         LED0 = !LED0;     } }                  void Task1(void) //任务2 {     while (true)     {         LED1 = !LED1;     } }

Other
class Task //任务管理类 { public:Task(void) //构造函数,初始化时会自动调用     {         Reg_Buff[0][6]=((unsigned int)&Task0) ; //初始化任务0的指针         Reg_Buff[1][6]=((unsigned int)&Task1) ; //初始化任务1的指针         Reg_Buff[0][6]=Reg_Buff[1][7]=0x61000000 ; //初始化xRSP                          Current = 0;         Next = 1;     }     public: static const unsigned char Count = Task_Count;     public: unsigned char Current; //当前任务     public: unsigned char Next ;    //下一个任务     public: volatile unsigned int Reg_Buff[Task_Count][8];     public: void    Start_Next() //更新至下一个任务     {         (Current + 1 < Count) ? Current++ : Current = 0;         (Next + 1 < Count) ? Next++ : Next = 0;                  //      if (Next != 0 && (Next - Current) != 1) //      { //          while (true) //          {                  //          } //      }     }                  };
Other
Task *task ; unsigned int Address_BASE = 0;                  void IRQHandler(void) {                          if(TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源     {         TIM_ClearITPendingBit(TIM3, TIM_IT_Update);  //清除TIMx的中断待处理位:TIM 中断源         __asm         {             ldr r5, [Address_BASE]               str r5, [&task->Reg_Buff[task->Current][0]]//R0                              ldr r5, [Address_BASE , 0x4]             str r5, [&task->Reg_Buff[task->Current][1]]//R1                              ldr r5, [Address_BASE , 0x8]             str r5, [&task->Reg_Buff[task->Current][2]]//R2                              ldr r5, [Address_BASE , 0xc]             str r5, [&task->Reg_Buff[task->Current][3]]//R3                              ldr r5, [Address_BASE , 0x10]             str r5, [&task->Reg_Buff[task->Current][4]]//R12                  //          ldr r5, [Address_BASE , 0x14] //          str r5, [&task->Reg_Buff[task->Current][5]]//R13 LR                              ldr r5, [Address_BASE , 0x18]                              str r5, [&task->Reg_Buff[task->Current][6]]//R14 PC                              ldr r5, [Address_BASE , 0x1c]             str r5, [&task->Reg_Buff[task->Current][7]]//R15 xRSP                                          /*↑↑↑保存当然运行中的任务现场↑↑↑*/                              ldr r5, [&task->Reg_Buff[task->Next][0]]//R0             str r5, [Address_BASE]                              ldr r5, [&task->Reg_Buff[task->Next][1]]//R1             str r5, [Address_BASE, 0x4]                              ldr r5, [&task->Reg_Buff[task->Next][2]]//R2             str r5, [Address_BASE, 0x8]                              ldr r5, [&task->Reg_Buff[task->Next][3]]//R3             str r5, [Address_BASE, 0xc]                              ldr r5, [&task->Reg_Buff[task->Next][4]]//R12             str r5, [Address_BASE, 0x10]                  //          ldr r5, [&task->Reg_Buff[task->Next][5]]//R13 LR //          str r5, [Address_BASE, 0x14]                              ldr r5, [&task->Reg_Buff[task->Next][6]]//R14 PC             //orr r5, 0x01             str r5, [Address_BASE, 0x18]                              ldr r5, [&task->Reg_Buff[task->Next][7]]//R15 xRSP             str r5, [Address_BASE, 0x1c]             /*↑↑↑恢复上一个任务的现场↑↑↑*/         }         task->Start_Next(); //下一个任务     } } extern "C" {     void TIM3_IRQHandler(void)   //TIM3中断  中断中不能有太多东西,否则进中断时压栈太多 MSP不容易计算     {         __ASM         {             mrs r4, msp             add r4, 0x08             str r4, [&Address_BASE]             bl    IRQHandler         }     }                  }

[修改于 10年0个月前 - 2015/06/05 14:26:47]

来自:计算机科学 / 软件综合
62
 
1
新版本公告
~~空空如也
Rcall95
10年0个月前 IP:广东
771764
矣,沙发是我dee
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
10年0个月前 IP:山东
771765
本文关于调度程序基本属于原创,多个高手帮我人肉DEBUG,谢谢啦

本文有任何错误或程序有BUG请指正
attachment icon stm32多任务调度器.rar 6.35MB RAR 235次下载
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
refinder
10年0个月前 IP:德国
771784
妹子是个搞科研的料
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
10年0个月前 IP:四川
771788
C++中public一个就够了,想全部public的话也可以直接把class改成struct。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
10年0个月前 IP:山东
771795
引用 acmilan:
C++中public一个就够了,想全部public的话也可以直接把class改成struct。
C#写习惯了
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
神之觉醒
10年0个月前 IP:广西
771852
非常好的文章, 单CPU的多任务调度和实现讲解得很详细.
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
smith
10年0个月前 IP:广东
771858
妹子代码写得不错,话说现在老板让我写都不一定写得出。。。。。特别是这种涉及到汇编的代码
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
prtemking
10年0个月前 IP:江苏
771859
搞技术的好料子,现在在忙什么具体的项目?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
Master_In_Nursery
10年0个月前 IP:加拿大
771861
堆得一手好代码
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
rudolf
10年0个月前 IP:山东
771863
写代码的时候要统筹这么多东西,大脑的内存需求一定挺高。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
10年0个月前 修改于 10年0个月前 IP:四川
771899
模拟中断返回法
在dos中也可以实现,在win32下由于不能直接挂接中断,timer调用堆栈又过长,所以不大可行
win32下可以用这种方法实现异函数返回,但是要把编译器优化关掉,不然函数搞成内联或不使用ebp就爽了
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn
10年0个月前 IP:浙江
771908
引用 acmilan:
模拟中断返回法
在dos中也可以实现,在win32下由于不能直接挂接中断,timer调用堆栈又过长,所以不大可行
win32下可以用这种方法实现异函数返回,但是要把编译器优化关掉,不然函数搞成内联或不使用ebp就爽了
Win32下中断是可以接管的。IDT hook或者hook KiTrapXX
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
10年0个月前 IP:四川
771911
引用 phpskycn:
Win32下中断是可以接管的。IDT hook或者hook KiTrapXX
怎么做?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn
10年0个月前 IP:浙江
771912
引用 acmilan:
怎么做?
R0下直接改IDT或者KiTrapXX头部。
自己的逻辑中注意同步问题即可
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
10年0个月前 IP:四川
771913
引用 phpskycn:
R0下直接改IDT或者KiTrapXX头部。
自己的逻辑中注意同步问题即可
还是R3下没法做→_→
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
phpskycn
10年0个月前 IP:浙江
771917
引用 acmilan:
还是R3下没法做→_→
……R3下当然不可能了
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
mould
10年0个月前 IP:浙江
771918
作为美术科班出身,看见汇编就蛋疼。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
10年0个月前 IP:山东
771927
引用 acmilan:
模拟中断返回法
在dos中也可以实现,在win32下由于不能直接挂接中断,timer调用堆栈又过长,所以不大可行
win32下可以用这种方法实现异函数返回,但是要把编译器优化关掉,不然函数搞成内联或不使用ebp就爽了
我以为我的办法是歪门邪道呢,原来还有名字呀,还有什么嵌入式OS是这种办法吗,UCOS那样的调度觉得不好玩
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
smith
10年0个月前 IP:广东
771970
很巧,今天工作解了一个问题发现也是和CPU调度算法有关的。囧[s::L]

今天遇到一个3D游戏只能跑30多fps,我和同事这边使用软件分析了,发现性能的瓶颈不在GPU、居然是在CPU!这还是头一次见到这种现象。
这个3D游戏在运行的时候被android系统的SurfaceFlinger服务抢占,运行的时候帧率就会降低,而且不但如此,还会因为SMP策略的改变
切换到其他CPU去运行,这样搞来搞去,导致这个游戏运行的帧率低下。

后面我和同事调整了一下cpu热插拔的命令,让这个游戏固定在一个CPU上去跑,帧率一下子就上升到50fps去了。。。

CPU调度和SMP还是有很多学问在里面的。。。。。。 sfx.jpg
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
kimstoon5677
10年0个月前 IP:浙江
772025
看见汇编就傻眼了唉。。。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
0x3A2B
10年0个月前 IP:陕西
772040
我还是要好好学
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
春燕
10年0个月前 IP:安徽
772061
真厉害啊,隔行如隔山啊,每行都研究很深。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
yanli12321
10年0个月前 IP:新加坡
772580
大赞。。。。。。。表示准备用一个暑假拿下嵌入式linux呵呵SOC FPGA了,敬请期待~~~
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
10年0个月前 IP:北京
772585
引用 yanli12321:
大赞。。。。。。。表示准备用一个暑假拿下嵌入式linux呵呵SOC FPGA了,敬请期待~~~
期待大作
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
hackerboygn
10年0个月前 IP:湖北
772661
ucos是基于抢占式的调度算法,我认为作为实时系统这是优势
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
10年0个月前 IP:北京
772668
引用 hackerboygn:
ucos是基于抢占式的调度算法,我认为作为实时系统这是优势
我倒是没看过ucos的源码,觉得实时性应该差不多吧,都没啥实时性,想要有实时性都可以依靠中断
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
chenhello
10年0个月前 IP:湖南
772689
楼主辛苦了。头像很可爱。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
超级玛丽
9年11个月前 IP:广西
773025
钻研精神不错!不过你这个就没有任务优先级可言了,每个任务从头到尾来一遍再从头到尾往复,如果任务中有时序要求严格的代码就必须关中断调度,ucos的方式就好一些,其实ucos也可以不用delay直接死循环的,高优先级的可以抢占的优先级的任务
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
9年11个月前 IP:北京
773049
引用 超级玛丽:
钻研精神不错!不过你这个就没有任务优先级可言了,每个任务从头到尾来一遍再从头到尾往复,如果任务中有时序要求严格的代码就必须关中断调度,ucos的方式就好一些,其实ucos也可以不用delay直接死循环的,高优先级的可以抢占的优先级的任务
中断给予每个中断相同的CPU时间,如果需要优先级 也可以设置,或者分配不同的权重
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
amo
9年11个月前 IP:广东
773696
如果打算用于具体产品上,建议研究一下protothread,实际就是几个宏定义,任何C语言编译器都直接支持……没有任何一行汇编代码,一个“线程”最低只需额外2字节RAM,完全没有RTOS的各种临界区、同步问题[s::lol]
而且可以直接用在各种RTOS、windows、linux上

著名TCP/IP协议栈uIP就是用这个protothread搭建的,第一次看到的人都会惊叹:原来C语言还能这样玩……
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金星凌日
9年11个月前 IP:陕西
773709
引用 amo:
如果打算用于具体产品上,建议研究一下protothread,实际就是几个宏定义,任何C语言编译器都直接支持……没有任何一行汇编代码,一个“线程”最低只需额外2字节RAM,完全没有RTOS的各种临界区、同步问题
而且可以直接用在各种RTOS、...
就是那个用setjmp/longjmp写出来的库?
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
amo
9年11个月前 IP:江西
773712
引用 金星凌日:
就是那个用setjmp/longjmp写出来的库?
不是什么库,是把switch-case的头尾巧妙的用宏封装一下,你搜索一下关键词,看看代码就知道了
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
9年11个月前 IP:四川
773738
引用 amo:
不是什么库,是把switch-case的头尾巧妙的用宏封装一下,你搜索一下关键词,看看代码就知道了
这个库好像比较适合51单片机。。。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
9年11个月前 IP:北京
773760
引用 amo:
不是什么库,是把switch-case的头尾巧妙的用宏封装一下,你搜索一下关键词,看看代码就知道了
说是不可重入的函数 不支持局部变量
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金星凌日
9年11个月前 IP:陕西
773795
引用 amo:
不是什么库,是把switch-case的头尾巧妙的用宏封装一下,你搜索一下关键词,看看代码就知道了
是这个啊。不过这个用到了静态变量,因而不可重入。我记得还有个改进版,直接在宏里写malloc,可以重入,支持局部变量,只不过写法不太正常。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
amo
9年11个月前 IP:江西
773815
引用 金星凌日:
是这个啊。不过这个用到了静态变量,因而不可重入。我记得还有个改进版,直接在宏里写malloc,可以重入,支持局部变量,只不过写法不太正常。
支持的,因为这个是“协程”,每个任务都是独占CPU的,只有它主动释放CPU,别的任务才可能得到执行。
既然CPU是自己管理的,那么什么时候使用自动变量什么时候使用静态变量,当然也是可以根据自己意愿来控制的。
1-可以使用自动变量的情况:
……
//输出100个脉冲。这里实时性要求高,所以独占CPU直到执行完成——所以这里i可以是自动变量
for(i=0;i<100;i++)
{
    _output = 1;
_delay_us(5);
_output = 0;
_delay_us(5);
}
PT_YIELD(pt);//主动暂时让出CPU,让别的任务执行。下次进入本任务后会自动在这里开始执行

……

2-使用静态变量的情况:
……
//输出100个脉冲。这里实时性和精度要求不高,所以每输出一个脉冲就暂时让出CPU——所以这里i必须是静态变量
for(i=0;i<100;i++)
{
    _output = 1;
_delay_us(5);
_output = 0;
_delay_us(5);
PT_YIELD(pt);//主动暂时让出CPU,让别的任务执行。下次进入本任务后会自动在这里开始执行
}
……

但凡写程序,总会受各种各样的限制,如工业C语言编程规范MISRA,为了减少出错的可能性,就把大量C语言的语法、用法都阉割了,如内存分配、指针、三目运算符等等

最近几年,凡是老产品需要维护,不管原来是裸奔还是带RTOS的复杂人机界面,我都用protothread来重构,工作量非常小,以前代码潜在的隐患在良好的程序结构下也很容易被发现。新的代码也用protothread。暂时还没发现哪些功能用它没法实现的。
加载全文
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
amo
9年11个月前 IP:江西
773816
引用 金星凌日:
是这个啊。不过这个用到了静态变量,因而不可重入。我记得还有个改进版,直接在宏里写malloc,可以重入,支持局部变量,只不过写法不太正常。
C还是不要随便用malloc,建议抽时间读读uip和lwip这两个TCP/IP协议栈,这两个都是亚当的大作,亚当是一个大牛级别的程序员,值得学习……
他的做法就是先设计合理的数据结构,自己管理数据
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金星凌日
9年11个月前 IP:陕西
773819
引用 amo:
支持的,因为这个是“协程”,每个任务都是独占CPU的,只有它主动释放CPU,别的任务才可能得到执行。
既然CPU是自己管理的,那么什么时候使用自动变量什么时候使用静态变量,当然也是可以根据自己意愿来控制的。
1-可以使用自动变量的情况:
…...
我知道这是非抢占式的。但这样的函数显然不能递归。而且,如果我没记错的话,这个协程在出现以下情况时会出错:函数A循环调用函数B和C,B和C都调用了D,而D中使用了这种协程。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
9年11个月前 IP:北京
773824
引用 金星凌日:
我知道这是非抢占式的。但这样的函数显然不能递归。而且,如果我没记错的话,这个协程在出现以下情况时会出错:函数A循环调用函数B和C,B和C都调用了D,而D中使用了这种协程。
麻烦再请评价一下我写的调度器,我只测试过大概是可行的,写了复杂点的程序都是没问题,你觉得有什么缺陷或者会有什么缺陷
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
9年11个月前 IP:北京
773825
引用 amo:
C还是不要随便用malloc,建议抽时间读读uip和lwip这两个TCP/IP协议栈,这两个都是亚当的大作,亚当是一个大牛级别的程序员,值得学习……
他的做法就是先设计合理的数据结构,自己管理数据
麻烦再请评价一下我写的调度器,我只测试过大概是可行的,写了复杂点的程序都是没问题,你觉得有什么缺陷或者会有什么缺陷
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
9年11个月前 修改于 9年11个月前 IP:四川
773828
引用 张静茹:
麻烦再请评价一下我写的调度器,我只测试过大概是可行的,写了复杂点的程序都是没问题,你觉得有什么缺陷或者会有什么缺陷
没见你在Task变量里边保存R4-R11的数值[s:30]
而且并没有保存所有的栈帧,因此如果局部变量不对等的话就爽了[s:20]
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
9年11个月前 IP:北京
773829
引用 acmilan:
没见你在Task变量里边保存R4-R11的数值
而且并没有保存所有的栈帧,因此如果局部变量不对等的话就爽了
确实没存,因为stm32 进入中断之后 自动压栈的寄存器里不包括R4-R11
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
9年11个月前 IP:四川
773832
引用 张静茹:
确实没存,因为stm32 进入中断之后 自动压栈的寄存器里不包括R4-R11
c语言程序可能不会使用这几个寄存器,但是汇编语言不一定。另外最好在主函数里设定一个栈帧保存标志点,在这个标志点以下的栈帧都进行保存,这样即使有局部变量不对等也不会出错。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
张静茹作者
9年11个月前 IP:北京
773833
引用 acmilan:
c语言程序可能不会使用这几个寄存器,但是汇编语言不一定。另外最好在主函数里设定一个栈帧保存标志点,在这个标志点以下的栈帧都进行保存,这样即使有局部变量不对等也不会出错。
可能是,我用内联汇编 操作寄存器,等调试的时候 看的汇编代码操作的就成别的寄存器了,具体什么规律忘记了,

栈没考虑过,可能真的会覆盖
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
9年11个月前 IP:四川
773835
引用 张静茹:
可能是,我用内联汇编 操作寄存器,等调试的时候 看的汇编代码操作的就成别的寄存器了,具体什么规律忘记了,

栈没考虑过,可能真的会覆盖
如果不想保存栈帧,也可以为各个任务分配各自独立的栈(就像电脑操作系统那样)。主任务是当前栈,副任务可能是一个空栈。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
9年11个月前 IP:四川
773836
这样直接切换栈的话反而更方便一些。。。
等东光僧.png
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
9年11个月前 修改于 9年11个月前 IP:四川
773851
不保存栈或切换栈的话,任务A和任务B的局部变量就是共享的了,A改变了局部变量的值也会影响B,如果错位的话至少有一个任务访问的局部变量不是正确地址。。。还有如果A任务调用了其它函数,切到B任务时栈指针就悬空了,B再调用一个函数,切换回A后栈指针也悬空了,会导致A调用的函数不能正常返回,最后导致各种错乱。。。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
amo
9年11个月前 IP:江西
773875
引用 金星凌日:
我知道这是非抢占式的。但这样的函数显然不能递归。而且,如果我没记错的话,这个协程在出现以下情况时会出错:函数A循环调用函数B和C,B和C都调用了D,而D中使用了这种协程。
你这是数据结构没设计好……产生这种问题的场景如多个线程都需要共用一个串口、socket、文件等唯一性的资源,商业软件都会通过队列来解决这种冲突(而不是每个地方都要层层调用直达最底层)。
你如果用单线程的思路去做,肯定会碰到很多问题,然后发现最好还是重构一下……
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
amo
9年11个月前 IP:江西
773879
引用 张静茹:
麻烦再请评价一下我写的调度器,我只测试过大概是可行的,写了复杂点的程序都是没问题,你觉得有什么缺陷或者会有什么缺陷
用了ARM之后就再也没碰过汇编了,所以这个就没法多说了[s::lol]
你不如把它跟流行的RTOS(uCOS,FreeRTOS等)做一个列表对比一下……一个实用的调度器/RTOS,可以拿具体指标来衡量的:Flash和RAM用量、CPU占用率、切换速度、信号量、邮箱……
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
金星凌日
9年11个月前 IP:陕西
773884
引用 amo:
你这是数据结构没设计好……产生这种问题的场景如多个线程都需要共用一个串口、socket、文件等唯一性的资源,商业软件都会通过队列来解决这种冲突(而不是每个地方都要层层调用直达最底层)。
你如果用单线程的思路去做,肯定会碰到很多问题,然后发现...
我说的就是单线程的情况,与多线程根本没有关系。
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
张静茹
进士 学者 机友 笔友
文章
139
回复
1869
学术分
1
2010/12/30注册,1个月12天前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:未同步
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

笔记
{{note.content}}
{{n.user.username}}
{{fromNow(n.toc)}} {{n.status === noteStatus.disabled ? "已屏蔽" : ""}} {{n.status === noteStatus.unknown ? "正在审核" : ""}} {{n.status === noteStatus.deleted ? '已删除' : ''}}
  • 编辑
  • 删除
  • {{n.status === 'disabled' ? "解除屏蔽" : "屏蔽" }}
我也是有底线的