《嵌入式微系统》买来很长时间了,也很用心的看,觉得里面的软件很巧妙和精致,一看就是很用心的一本良心之作。
但没有在系统层面看懂, 总结的原因有2个: 1 没有实际的应用。 前后台是设计方法已经满足一般的设计要求,没有更上一层楼的动力。
2 以前一直用PIC的芯片, 对STM32的芯片不熟悉,一改动一出错就不知所措。
PIC芯片的厂家在青岛有好多技术支持也是最主要的原因。
现在没有什么事情了,准备重新开始,在一个小领域从0开始。
罗胖子说过很多没有节操的话,也说过很多有用 的。 他说: 一个人要不断的从傻瓜开始,在一个方向努力,从开始傻瓜到不傻瓜 的时间 称其为:傻瓜时间。
傻瓜的周期越短,说明人进步的越快。
/*******************************************************************************
* 操作系统 的节拍
*******************************************************************************/
操作系统了解的不多,只知道比常用的程序多了节拍和抢断的概念。
在常用的前后台设计中也有节拍的概念, 譬如常用到的数码管显示用4~5MS的节拍来轮扫。 按键扫描用20MS 的速度来扫描。
例:
main
{
if (abs(LedT -Time0Value)>= Con_5ms )
{
LedT = Time0Value; //重新计时
SubLedDisplay(&ledBuf); //5ms时间到,运行LED显示程序
}
if (abs(KeyT - Time0Value) > Con_20ms)
{
KeyT = Time0Value; // 重新赋值
SubKey ();
}
.......
}
一般情况下,SubLedDisplay(),SubKey () 这些函数 运行时间是可以估值出来的,
但是在大系统中,如果某个单一的函数运行时间过长,会造成其他函数的响应迟钝。
msOS 的节拍 是10ms, 我一个初学者的理解:
是一个高优先极的任务在运行到10ms时,系统强制切换到另一个任务。吃饭也不能一人光吃,也得转转桌子。
/*******************************************************************************
* 操作系统 的切换和抢占
*******************************************************************************/
操作系统任务的切换,和正常的中断处理 几乎是一个流程。
中断处理要打断主程序,转去中断处理程序时,当然首先要保存当前的运行指针 PC, 还要保存当前主程序运行所需要的变量寄存器,R0.R1....之类的,
还有状态寄存器等一堆,估计得有10多个吧。 运行完中断处理程序,再把这10多个数据从堆栈里取出来,继续运行主程序。
操作系统的切换也是要把这套流程完整的做一遍,所不同的是,任务切换用的栈不同。 中断是用MSP主栈,任务使用PSP任务栈。
可见STM32的架构 就是为操作系统设计的。 平常我们单任务系统只用到MSP,浪费了PSP。
2019 0918
/*******************************************************************************
* msOS 双任务内核的理解 (我写的没有规律,理解到那,写到那,写下来是为了加深理解和记忆)
*******************************************************************************/
int main(void)
{
InitData();
System.Init();
System.OS.CreateLogicTask(LogicTask); // 创建业务逻辑任务
System.OS.CreateMenuTask(MenuTask); // 创建第二个任务
System.OS.Start();
EnableIrq(); // 关中断
}
msOS 在主程序里一共有2个任务, LogicTask和MenuTask .一个高优先级的任务和低优先级的任务。
在学习msOS的过程中,源码与系统学习无关的东西实在太多, 我很长时间为里面的逻辑关系和菜单项目的各种关系头痛。
初学者第一要务是能照着葫芦花瓢的先用起来,然后那不懂再深入学习会好些,总比一开始就看一个实际项目,就此难住好些。
我的目标就是把MSOS 先简化成一个KEY 任务和一个LED灯的任务。KEY 高优先级,LED灯 低优先级。
2019 0918 22:25
我理解的msOS任务 就是两个while(1). ....两个死循环。
人为认定这两个死循环 一个是高任务,一个是低任务。
当运行在低任务循环中时,有两种情况可以检测事件的发生,外设中断和定时中断。
定时中断以0.1MS的周期中断,在系统中称为节拍。 void SysTick_Handler(void)
在节拍中处理的程序 Routine
无论外设中断和节拍Routine ,都可以发出消息。PostMessageQueue
消息是只对高任务的,有Message ,则切换到高任务循环。
/*******************************************************************************
* 描述 : 发送一个消息到消息队列中,处于等待的任务会自动运行
*******************************************************************************/
static bool PostMessageQueue(uint message)
{
EnterCritical();
// 菜单界面任务下,且无消息,用任务成员Message传递,不用消息队列
if (CurrentTaskPointer == &MenuTask && LogicTask.Message == 0)
{
LogicTask.Delay = 0;
LogicTask.Message = message;
ExitCritical();
Schedule(&LogicTask); //切换到业务逻辑业务
return (true);
}
if (MessageQueue.Entries >= QueueBufferSum) // 消息队列满 ,退出
{
ExitCritical();
return (false);
}
//在高任务下,有消息,则保存到消息队列中。
MessageQueue.Entries++;
*MessageQueue.In++ = message;
if (MessageQueue.In > MessageQueue.End)
MessageQueue.In = MessageQueue.Start;
ExitCritical();
return (true);
}
高任务的退出 : 有消息,进行处理,处理完毕 ,退出,退回到低任务循环。
高任务循环的时候,节拍程序还是要定时运行的。
关于内核切换和消息 之类的内容都在 OS.C, 我认为是整个系统的核心和精华。
2019 0922
大体明白了OSMS 的框架。 低优先级任务,高优先级任务,10MS的节拍运行例行扫描的程序,类似中断。
其中内核的切换,看了看,模模糊糊明白了点,其实里面的细节不清楚,其实也没有必要弄的太明白吧,毕竟对我来说是用系统,不是写系统。
在低任务中 加了一个LED 灯,闪动频率1HZ.
/*******************************************************************************
* 函数名 : MenuTask
* 描述 : MenuTask任务,必须为最低优先级任务
* 返回参数 : 无
********************************************************************************
*版本 作者 日期 说明
*V0.1 Wangsw 2013/12/16 修改版本
*******************************************************************************/
void MenuTask (void)
{
static uint MenuSystick;
InitMenu();
InitLed(); //testt
MenuSystick = App.Data.Systick1000 + 500; //Systick1000 在系统中是1MS ,+500 间隔就是500MS
while(true)
{
if (App.Data.Systick1000 >= MenuSystick) //500MS
{
MenuSystick = App.Data.Systick1000 + 500;
GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)((1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0)))); //取反
}
}
}
再增加一个按键, 在节拍中扫描,按下则进入高任务。
/*******************************************************************************
* 描述 : 系统节拍中断入口,非常重要,每秒10000次,即0.1mS一次
* : 系统节拍通过switch细分为每秒1000次,每秒100次的例行节拍
* : 同层直接调用,高层采用注册调用
*******************************************************************************/
void SysTick_Handler(void)
{
byte div;
static byte Counter = 0;
if(++Counter == 100) Counter = 0;
div = Counter / 10;
switch(Counter % 10)
{
case 0: Systick1000RegisterPointerBlock[0](); break;
case 1: Systick1000RegisterPointerBlock[1](); break;
case 2: Systick1000RegisterPointerBlock[2](); break;
case 3: Systick1000RegisterPointerBlock[3](); break;
case 4: Systick100RegisterPointerBlock[div]();break;
case 5: AppDataPointer->Systick1000++; break; //软件定时器 ,1MS加1;
case 6: Systick1000RegisterPointerBlock[3](); break;
case 7: Systick1000RegisterPointerBlock[3](); break;
case 8: KeySystick1000Routine(); break; //按键扫描
case 9: Systick1000RegisterPointerBlock[0](); break;
}
}
#define GetKey GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) //读取按键0
//---------------------------------------------------------------------------------------------------------------
void KeySystick1000Routine(void)
{
if (GetKey ==0)
{
PostMessage(MessageKey, 1);
}
}
//--------------------------------------------------------------------------------------------------------------------
在高任务中 ,增加按键后的事件处理程序。
void LogicTask(void)
{
int i;
uint message;
uint data;
InitLogic();
System.OS.DelayMs(2000);
//逻辑业务任务获取消息,分配处理
while(true)
{
message = System.OS.PendMessageQueue(); //获取消息
data = message & 0x00FFFFFF;
switch(message >> 24)
{
case MessageKey: //按键消息
GPIO_WriteBit(GPIOB, GPIO_Pin_0, (BitAction)((1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0))));
break;
case MessageTimer:
// Function(data + RomBase);
break;
default:
break;
}
}
}
//--------------测试,运行正常。 下一步整合自己的程序,一点一点的加进去。
如果需要源代码,请留E-MAIL ,我会发到您邮箱。
同时建议去雨滴科技 去下最新版本的OSMS , 对照着看。 我的是简化的。
http://bbs.raindi.net/forum.php
凤舞天 2019-1-7 21:53