大家好,又见面了,我是你们的朋友全栈君。
1.什么是操作系统? 操作系统是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。介于APP和硬件之间。
2. 为什么要用操作系统? 1)相比裸机,可以实现更加复杂的功能。 2)屏蔽硬件。使得上层应用APP的移植性更好。
实时操作系统:以任务优先级作为调度原则 分时操作系统:以时间片作为调度原则
UCOSII是实时操作系统,所以它是以任务优先级作为调度原则。
裸机:有且只能有一个主函数,并且在主函数必须要有死循环(while(1)),把要实现的功能在主函数里实现。
上了UCOSII操作系统后:有且只能有一个主函数,在主函数中可以不需要死循环(while(1)),在工程中有多个任务,每个任务都必须有个死循环,把要实现的功能写进各个任务中。
任务结构:任务控制块、任务函数地址、任务栈、任务优先级、任务状态
任务控制块:当成功创建了一个任务之后,系统就会自动分配一段内存空间,这段内存空间就是所谓任务控制块,存放这该任务的相关信息,包括任务函数地址、任务栈、任务优先级、任务状态。
任务函数:可以看成是一个功能函数,把要该任务实现的功能写进该函数中,系统通过该任务函数名(地址)访问该任务函数。 任务栈:当任务与任务之间发生切换时,保存当前任务环境(寄存器配置,变量等)和恢复任务环境。 任务优先级:每个任务都有唯一的优先级,是系统调度和任务切换的依据。 任务状态:休眠/停止、等待/挂起、就绪、运行、中断
系统调度:当发生系统调度的时候,系统就会查询当前所有处于就绪状态中的任务的优先级,把CPU的使用权给到优先级最高的那个任务(就绪)。 处理就绪状态中任务的优先级问题。 任务切换:CPU从一个任务切换到另一个任务。
什么时候发生系统调度? 满足两个条件中的一个即可发生。
发生系统调度一定会产生任务切换吗? 发生系统调度不一定会产生任务切换
举例: 任务A优先级为10–挂起 任务B优先级为13–运行 任务C优先级为18–就绪 任务D优先级为20–就绪 当前任务B正在运行,突然Tick到了,就会发生一次系统调度,当前任务B从运行态转为就绪态,然后目前一定有任务B,任务C和任务D处于就绪态,并且任务B优先级最高,那么CPU的使用权仍然会给到任务B。 所以,这种情况虽然发生了系统调度,但是并没有产生任务切换。
A—>B—>A
上了操作系统后,中断的写法跟以前裸机基本没有变化。 同样需要设置中断分组,中断优先级,使用中断等(配置NVIC)–没有变化 中断服务函数名也没有没变化 编写中断服务函数的内容需要增加两个UCOSII的API函数。—变化
在中断服务函数里的第一个行,必须加入“OSIntEnter()”,表示当前操作系统进入了中断服务函数 在中断服务函数里的最后一行,必须加入“OSIntExit()”,表示当前操作系统要退出中断服务函数
裸机:当发生了中断事件,会在当前运行的地方设定一个断点,执行完中断服务函数后,CPU会回到断点中继续执行。
上了UCOSII系统后:当发生了中断事件,同样会在当前运行的地方设定一个断点,执行完中断服务函数后,不一定会回到断点处。因为出中断前会执行“OSIntExit()”,执行这个API函数会产生一次系统调度,一旦发生了任务切换,CPU就不会回到断点处。
任务状态:休眠/停止、等待/挂起、就绪、运行、中断
当前用到的是UCOSII版本。 UCOSII源码链接:www.micrium.com/downloadcenter/
选择对应的处理器
核心文件:
1)新建一个空白文件夹 2)在上面创建的文件夹里再新建名为“CMSIS”、“USER”和“TASK”两个文件夹 3)在“USER”里再新建名为“inc”和“src”两个文件夹 4)在“TASK”里再新建名为“inc”和“src”两个文件夹 5)把芯片相关支持文件复制到“CMSIS” 6)把“UCOSII”整个文件夹复制到与“CMSIS”同目录下 7)打开KEIL软件创建新工程 8)创建虚拟工程树(在原来基础上增加“UCOSII_CONFIG”、“UCOSII_CORE”、“UCOSII_PORT”) 9)配置工程属性 10)设定头文件路径(在原来基础上增加“./TASK/inc”、“./UCOSII/CONFIG”、“./UCOSII/CORE”、 “./UCOSII/PORT”) 11)新建文件并添加到工程中
//函数功能:系统滴答中断
//参数说明:待延时的毫秒
//返回值:无
//注意事项:
//时间:2019.6
void Systick_Interrupt(u32 nms)
{
SysTick->CTRL &=~(0x01<<2);// 选择时钟源(21M)
SysTick->LOAD =21*nms*1000;// 设置重载值(LOAD)
SysTick->VAL=0;// 写VAL(清除VAL,重装载,清标志)
//使能中断(设置NVIC优先级,模块级中断使能)
//设置优先级分组
NVIC_SetPriority(SysTick_IRQn,NVIC_EncodePriority (7-2, 2,2));
//NVIC中断使能---系统滴答中断NVIC是必须响应,不需要再使能
//NVIC_EnableIRQ(SysTick_IRQn);
SysTick->CTRL |=0x01<<1;
SysTick->CTRL |=0x01<<0;// 开启(使能)定时器
}
void SysTick_Handler(void)
{
OSIntEnter();//告诉操作系统当前进入了中断服务函数
OSTimeTick();
OSIntExit();//告诉操作系统已经处理完了中断服务函数
}
nt main(void)
{
//各种模块的初始化
LED_Init( );//LED初始化
Key_Init( );
Uart1_Init(84,115200);
Systick_Interrupt(1000/OS_TICKS_PER_SEC);//TICK=5ms
OSInit();//初始化 UCOS-II 内核
//至少要创建一个任务
GPIO_ResetBits(GPIOF, GPIO_Pin_6);
OSStart();//开启操作系统
//一旦开启了操作系统,下面的代码就不会再执行了
GPIO_SetBits(GPIOF, GPIO_Pin_6);
GPIO_ResetBits(GPIOF, GPIO_Pin_9);
while(1)
{
}
}
调用 OSTaskCreate 创建一个任务,ucos会给这个任务分配一个任务控制块,任务控制块中记录了任务的任务函数地址,任务栈地址,任务的优先级,任务的状态。 如果成功创建一个任务,这个任务就处于了就绪状态。 不能在中断中创建任务,每个任务的优先级唯一,如果先后创建的两个任务的优先级一样,后一个任务创建会失败。任务的优先级不能低于最低优先级。 函数原型: INT8U OSTaskCreate ( void (* task) (void *pd), void *pdata, OS_STK *ptos, INT8U prio )
参数说明: 1)task:函数指针,是“指向一个返回值类型为void,有一个形参为 void* 指针的函数的”指针。—–其实是就指向任务函数。 2)pdata:void* 指针,任务函数被调用需要传递实参,所传入参数就是这个参数,如果任务函数不需要使用这个参数,可以传递 0、NULL 或 (void*)0 。 3)ptos:任务栈(用户定义一个数组)顶部分,对于栈是递减方式,就是传递数组的最后一个元素地址,如果是递增,就是第0个元素地址。(ARM的CPU一般默认是递减的栈,所以看到的都是传入 最后一个 元素地址; 51单片的栈是递增的,所以51上使用ucOS传入的是第0个元素地址)。(一般不会在51上运行) OS_STK 类型:实际上 unsigned int (对于32位平台),平台不同,长度不同,所以使用时候一般是使用 OS_STK 定义数组。 ptos空间最小不能小于17*4,如果任务函数局部变量比较多,还要更大;如果任务函数用到了浮点运算,一定要把栈设置成8字节对齐,否则出栈异常! 4)prio:任务的优先级。 ucOS2 范围是0~63,实际上是由 os_cfg.h 中宏 OS_LOWEST_PRIO 配置最大值(只能改小,不能改大)。 其中可用的优先级最低2个是内建任务使用,用户不能使用 最低优先级(等于 OS_LOWEST_PRIO):空闲任务 — 当所有用户任务都不运行的时候,CPU在执行空闲任务,通俗说:所有人都不要它时候,给空闲任务收留它。 次低优先级(等于 OS_LOWEST_PRIO -1):统计任务 — 统计CPU利用率。(该任务是可选择的,可裁剪的)。 ucOS 任务优先级不能相同,每个任务优先级都是惟一的。 (经验:建议最高前几个等级不要用,任务间优先级不要连续,考虑程序拓展性)
返回值说明: 1)成功:0,一般不直接使用数字,而使用ucOS提供宏判断执行结果。 OS_ERR_NONE //创建任务成功。
Returns : OS_ERR_NONE if the function was successful.
OS_ERR_PRIO_EXIST if the task priority already exist
* (each task MUST have a unique priority).
* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed
* (i.e. >= OS_LOWEST_PRIO)
* OS_ERR_TASK_CREATE_ISR if you tried to create a task from an ISR.
具体代码请看示例
任务一个任务都必须有主动放弃CPU的动作,否则,比它优先级低的任务用于都得不到CPU。
任务函数: void Start_Task(void *pdata);
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/136141.html原文链接:https://javaforall.cn