本帖最后由 QianFan 于 2015-6-30 18:02 编辑
之前简单的学习了下ucos,仅仅是会用,并没有深究。毕竟平时用的不是很多。最近闲来无事,好好的阅读了一下ucos的源码,看了下任务调度的内部细节,感觉挺有意思。许多问题在QQ社区群请教了橙子大哥,感谢橙子大哥的不吝赐教。
但是不满足于ucos的代码,太复杂,函数太长。虽然功能强大,但是像我这样的懒人,不想敲那么多次键盘。于是开始自己DIY一个任务调度器。目前只是简单的实现了任务调度。在今后还要添加其余的功能。但是毕竟一个人的能力太弱,自己DIY的仅供娱乐和学习,不能满足于商业化的使用。
在DIY的时候使用了303Nucleo,这个板子有80K的内存,所以给堆提供了10K的内存,这些足够malloc消遣了。所以有关任务的栈使用了malloc来进行分配。在测试的时候创建了两个任务(空闲任务除外),用来控制两个led灯。一个间隔1s闪烁,另一个间隔2s闪烁。视频效果可以点击这里查看:https://v.youku.com/v_show/id_XMTI3MjQ2NTQyNA==.html?firsttime=0&from=y1.4-2 请自觉忽略视频的声音,因为在录制的时候有人在讨论电源的问题。测试用的工程可以在附件中下载。
- #include "QSys.h"
- #include "stm32f30x.h"
- #include "stm32f30x_rcc.h"
- #include "stm32f30x_gpio.h"
- GPIO_InitTypeDef ioIt =
- {
- GPIO_Pin_5 | GPIO_Pin_6,
- GPIO_Mode_OUT,GPIO_Speed_50MHz,
- GPIO_OType_PP,GPIO_PuPd_NOPULL,
- };
- void PA5On(void);
- void PA6On(void);
- #define pidPA5 5
- #define pidPA6 6
-
- int main(void)
- {
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
- GPIO_Init(GPIOA,&ioIt);
- SysTick_Config(64000000 / 20 ); //50ms
-
- taskCreate(pidPA5,PA5On,"PA5");
- taskCreate(pidPA6,PA6On,"PA6");
-
- QSysStart();
- }
- void PA5On(void)
- {
- while(1)
- {
- GPIO_SetBits(GPIOA,GPIO_Pin_5);
- delay(pidPA5,20);
- GPIO_ResetBits(GPIOA,GPIO_Pin_5);
- delay(pidPA5,20);
- }
- }
- void PA6On(void)
- {
- while(1)
- {
- GPIO_SetBits(GPIOA,GPIO_Pin_6);
- delay(pidPA6,40);
- GPIO_ResetBits(GPIOA,GPIO_Pin_6);
- delay(pidPA6,40);
- }
- }
复制代码
Update:0.0.2
- 改进taskCreate,不再使用malloc和free进行自动内存分配。
- 删除void delay(unsigned int pid,unsigned int ticks);
- 新增函数void suspend(void),用于挂起任务本身。
- 新增函数void resume(unsigned int pid),用于恢复已经被挂起的任务或者被sleep阻塞的任务。
Example:
将Nucleo的按键设置成为下降沿触发中断的方式。建立一个任务,每隔2s闪烁一次led,闪烁完1次之后将自身挂起,当按键按下的时候,在按键中断中 恢复任务。视频地址:https://v.youku.com/v_show/id_XMTI3MzUwMjQ4OA==.html
在视频中可以看到,第一次按键的时候,亮的时间特别短。这个是按键有抖动导致的,另一方面,sleep这个函数做的也不行。即使任务被sleep阻塞了,resume也能够恢复它。这个也算是bug吧。在之后会继续改进的。
- #include "QSys.h"
- #include "stm32f30x.h"
- #include "stm32f30x_rcc.h"
- #include "stm32f30x_gpio.h"
- #include "stm32f30x_exti.h"
- #include "stm32f30x_syscfg.h"
- EXTI_InitTypeDef EXTI_InitStructure;
- GPIO_InitTypeDef ioIt =
- {
- GPIO_Pin_5 | GPIO_Pin_6,
- GPIO_Mode_OUT,GPIO_Speed_50MHz,
- GPIO_OType_PP,GPIO_PuPd_NOPULL,
- };
- void PA5On(void);
- void PA6On(void);
- #define pidPA5 HIGHEST_PID
- #define pidPA6 LOWEST_PID
- unsigned int spPA5[128];
- unsigned int spPA6[128];
- struct task taskPA5,taskPA6;
-
- int main(void)
- {
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
-
- GPIO_Init(GPIOA,&ioIt);
- ioIt.GPIO_Pin = GPIO_Pin_13;
- ioIt.GPIO_Mode = GPIO_Mode_IN;
- GPIO_Init(GPIOC,&ioIt);
-
- /* Connect EXTI13 Line to PC13 pin */
- SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOC, EXTI_PinSource13);
-
- /* Configure EXTI13 line */
- EXTI_InitStructure.EXTI_Line = EXTI_Line13;
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
- EXTI_InitStructure.EXTI_LineCmd = ENABLE;
- EXTI_Init(&EXTI_InitStructure);
-
- NVIC_EnableIRQ(EXTI15_10_IRQn);
- SysTick_Config(64000000 / 20 ); //50ms
-
- taskCreate(&taskPA5,pidPA5,PA5On,spPA5,128,"PA5");
- taskCreate(&taskPA6,pidPA6,PA6On,spPA6,128,"PA6");
-
- QSysStart();
- }
- void PA5On(void)
- {
- while(1)
- {
- for(int i=0;i<2;i++)
- {
- GPIO_SetBits(GPIOA,GPIO_Pin_5);
- sleep(20);
- GPIO_ResetBits(GPIOA,GPIO_Pin_5);
- sleep(20);
- }
- }
- }
- void PA6On(void)
- {
- suspend();
- while(1)
- {
- GPIO_SetBits(GPIOA,GPIO_Pin_6);
- sleep(40);
- GPIO_ResetBits(GPIOA,GPIO_Pin_6);
- sleep(40);
-
- suspend();//suspend itself,watting next exti interrupe
- }
- }
- void EXTI15_10_IRQHandler(void)
- {
- resume(pidPA6);
- EXTI_ClearITPendingBit(EXTI_Line13);
- }
复制代码
Bug Report:
||
||
\\//
\/
|
我又来了哈...
example1:
void sleep(int delayTicks)中
在if((taskList[pid]==NULL)||(pid==IDLE_PID)||(delayTicks==0))
return ;
之前taskSwOn();之后产生调度
并不能确保taskList[pid]不是NULL(taskList[curpid]本不应该NULL.)
(调度后来了个changePid).
example2:
updateNextTask执行中产生调度,
每一个taskList[pid]都有被其它任务修改的可能,应该有风险.
请教个问题,比如当前OS的节拍数是100,有一个任务Task1,调用了自身的sleep,sleep的时间是1000个节拍。也就是到1100个节拍的时候这个任务应该被唤醒。
假设到了第200个OS节拍的时候,另一个任务Task2更改了Task1的优先级,将他的优先级提高了。你说这个时候是应该让Task1立即执行呢,还是到1100个节拍的时候才能再次执行?
我觉得Task1既然sleep(1000)了,那就应该有sleep(1000)的样子,在1100节拍之前就不应该是就绪状态吧...