新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 一个抢先式“裸奔\"系统的设计

一个抢先式“裸奔\"系统的设计

作者:时间:2018-09-07来源:网络收藏


2 程序主执行函数main()函数


main()函数也非常简单。首先,调用Sys_init()完成单片机硬件的初始化;然后调用I2c_svr(),完成I2C总线通信的初始化,并执行数据传输,本函数稍后将作详细的介绍;接下来是一个while(1)主循环,其中的mainfunc()是执行主要任务的函数,完成的主要功能,并返回一个bool变量,这个变量用于I2C总线数据传输的请求;
这里定义了一个bool型变量bi2csvr。作用:由mainfunc()执行结果来置位,系统根据此标志,启动数据通信,并在数据传输完成后清零这个标志。

3 I2C总线通信服务程序
通信服务程序I2c_svr()函数代码如下:

这个函数看起来也不复杂,但是需要读者用RTOS任务的概念来理解这个函数。
首先,关于寄存器组,这里的I2C服务程序I2c_svr()使用了单独的寄存器组(寄存器组1),由于#pragmarb(1)编译指令并不会让编译器自动生成切换寄存器组的指令,所以I2c_svr()中又通过修改PSW特殊寄存器来切换到工作寄存器组1。当然,要切换寄存器组,还需要确认在切换前,本函数没有使用工作寄存器。
同时,I2c_svr()的初始化部分还执行了特殊功能寄存器压栈保存和切换堆栈指针SP,这些本是实时内核调度器里要完成的任务,在这里的出现相当于建立了新的任务。
接下来的while(1)表明,这里相当于实时系统里的一个任务了。
这个任务很简单,i2write()的功能就是通过I2C总线,发送数据缓冲区里所有的数据,在这里就不做详细介绍了。在发送完成后,清零数据发送请求标志位bi2csvr,然后执行延时等待。

4 定时中断和延时函数
抢先系统的关键部分是定时中断timer1()和延时函数idelay(),代码如下:

首先看tsksw()宏,它的作用是保存堆栈指针并切换堆栈。这等同于RTOS里任务的上下文切换,但这里仅切换一下堆栈指针即可。
接下来看这个定时中断服务函数timer1(),其中systern_tmr()是个修改定时器TH0的函数,这里不作介绍了。随后,约束判断(后面再作详细介绍)再通过tsksw()函数进行任务间的切换。
接下来看延时函数idelay(),它提供I2C总线时序里要求的延时函数。注意:我们通常都是使用若干nop或者类似“for(x=LOOP;x>0;x——);”的延时来完成的,但这里一改这类传统的方式,而是通过“任务切换”将CPU控制权交给另外一个任务main来实现的。需要特别指出,idelay()里的关中断很重要,学习过RTOS的读者应该都记得RTOS里面的“临界段代码”的概念。
最后,介绍上面未详细说明的定时中断服务函数timer1()中任务切换的约束判断。bi2csvr是I2C总线请求标志,如果这个标志为零,则表示不需要I2C总线的通信服务,定时中断里也就不需要做任务切换;此外,bi2cdly也是个控制切换的小技巧,该标志在idelay()中置位,在定时中断服务中判断并清零。也就是在执行idelay()后发生的第一次定时中断里只清除这个标志,而在第二次定时中断中才可能发生任务切换,以此保证idelay()的延时时间一定不少于一个定时器的溢出周期。


关键词: 系统

评论


相关推荐

技术专区

关闭