嵌入式系统多任务软件设计Word下载.docx
《嵌入式系统多任务软件设计Word下载.docx》由会员分享,可在线阅读,更多相关《嵌入式系统多任务软件设计Word下载.docx(16页珍藏版)》请在冰豆网上搜索。
OpenOSFile:
以读取或写入的模式打开指定的文件,并创建FILE结构,为文件读取分配缓冲区,返回当前指向文件结构(FILE)的指针
ReadOSFile:
读取已经打开的文件到指定的缓冲区,如果成功则返回读取的字节数
WriteOSFile:
把缓冲区写入指定的文件,如果成功则返回TRUE;
否则返回FALSE
LineReadOSFile:
读取指定文件的一行,返回读取文件的字节数
CloseOSFile:
关闭打开的文件,释放文件缓冲区
GetNextFileName:
得到文件目录分配表中指定位置的文件名,文件位置自动下移。
如果文件有效则返回TRUE;
ListNextFileName:
列出当前位置开始第一个指定扩展名的文件,如果没有则返回FALSE
2、基于Unicode的汉字字库
基于32位嵌入式处理器的硬件平台,有着较高的运算速度和大容量的内存,为人机交互建立GUI是首选的方式。
针对常用的图形用户界面建立相应的API函数,主要包括基于Unicode的汉字字库,典型的控件和基本绘图函数
Unicode与传统字符编码集相比具有明显的优势:
首先,使用Unicode避免了乱码的产生,使得国际间文本数据交换成为可能。
其次,解决了多语言文本同平面共存的问题。
最后,实现了软件的全球化。
在图形操作系统中,字符通常有两种存储方式。
一种方式存储的是字符的图形点阵,另一种方式是存储汉字的矢量图形。
在嵌入式处理中,因为处理器的性能和嵌入式系统资源不如PC机,而且一般只针对专用系统设计,基本使用的是图形点阵字库。
用于Unicode字库显示的相关API函数主要有:
Int2Unicode
定义:
voidInt2Unicode(intnumber,U16str[]);
功能:
从int型变量到Unicode字符串的转换
参数说明:
number:
被转换的整型数字
str:
转换成的Unicode字符串
Unicode2Int
intUnicode2Int(U16str[])
Unicode字符串到int型的转换,遇到字符串结束符或者非数字字符时返回,返回值是转换的结果-int型数据
被转换的Unicode字符串
strChar2Unicode
voidstrChar2Unicode(U16ch2[],constcharch1[]);
char类型到Unicode的编码转换
ch1:
ch2:
被转换的Char字符串
UstrCpy
voidUstrCpy(U16ch1[],U16ch2[]);
字符串复制
目标字符串
源字符串
3、基本绘图函数
绘图是操作系统图形界面的基础。
在uCOS-II系统环境下,绘图必须通过使用绘图设备上下文(DC)来实现。
绘图设备上下文(DC)中包括了与绘图相关的信息,比如:
画笔的宽度、绘图的原点等等。
这样,在多任务系统中,不同的任务通过不同的绘图设备上下文(DC)绘图才不会互相影响。
绘图设备上下文(DC)的结构定义如下:
intDrawPointx;
intDrawPointy;
//绘图所使用的坐标点
intPenWidth;
//画笔宽度
U32PenMode;
//画笔模式
COLORREFPenColor;
//画笔的颜色
intDrawOrgx;
//绘图的坐标原点位置
intDrawOrgy;
intWndOrgx;
//绘图的窗口坐标位置
intWndOrgy;
intDrawRangex;
//绘图的区域范围
intDrawRangey;
structRECTDrawRect;
//绘图的有效范围
U8bUpdataBuffer;
//是否更新后台缓冲区及显示
U32Fontcolor;
//字符颜色
}DC,*PDC
与绘图设备上下文(DC)有关的函数有:
initOSDC()用来初始化系统的DC,为DC动
态内存开辟空间;
CreateDC()和DestoryDC(PDCpdc)分别用来创建和删除DC,前者返回所
创建的DC指针,后者则释放DC的内存空间。
和绘图有关的函数有TextOut(),LineTo(),FillRect(),Circle(),ShowBmp()等常见的图形函数。
下面实现了一个屏幕绘图程序。
首先,在屏幕上绘制一个圆角矩形和一个整圆。
然后,再在屏幕上无闪烁地绘制一个移动的正弦波,如图10-1所示。
读者将学习使用嵌入式系统的绘图API函数。
理解绘图设备上下文(DC)在多任务操作系统中的作用。
会使用绘图设备上下文(DC)在屏幕上绘制一个圆角矩形和一个圆。
理解绘制防止闪烁的基本原理,可以实现无闪烁的动画。
下面结合代码介绍其实现过程。
图10-1绘制图形
在μC/OS-II操作系统中,液晶显示屏的刷新是通过Lcd_Fresh_Task任务完成的,该任务是在系统附加任务初始化函数OSAddTask_Int()中定义的,该函数开辟了LCD刷新任务、触摸屏任务和键盘任务等。
绘图首先是在绘图缓冲区中完成的,然后系统自动(也可以通过设置绘图设备上下文参数,不让系统自动刷新)向Lcd_Fresh_Task发送更新信息。
其流程图如图10-2所示。
图10-2绘图流程
因为绘图是在后台进行的,绘制完成后,再更新到液晶屏上。
所以绘图是不用担心反复地擦除屏幕会引起屏幕的闪烁。
这样,可以很方便地实现动画无闪烁的显示。
绘制完一次图形后,必须要使用OSTimeDly()函数给出一定时间的延时(推荐用200),同时使Main_Task任务主动让出对CPU的控制权。
使Lcd_Fresh_Task任务可以完成刷新。
其源代码如下:
/*****************Main_Test_Task的定义*****************/
voidMain_Task(void*Id)
intoldx,oldy;
/*保存原来坐标系位置*/
PDCpdc;
/*定义绘图设备上下文结构*/
intx,y;
/*坐标*/
doubleoffset=0;
/*x坐标偏移量*/
ClearScreen();
/*清屏*/
pdc=CreateDC();
/*创建绘图设备上下文*/
SetDrawOrg(pdc,LCDWIDTH/2,LCDHEIGHT/2,&
oldx,&
oldy);
/*设置绘图原点为屏幕中心*/
Circle(pdc,0,0,50);
/*画圆*/
MoveTo(pdc,-50,-50);
/*移动*/
LineTo(pdc,50,-50);
/*画线*/
ArcTo(pdc,80,-20,TRUE,30);
/*画弧*/
LineTo(pdc,80,20);
ArcTo(pdc,50,50,TRUE,30);
LineTo(pdc,-50,50);
ArcTo(pdc,-80,20,TRUE,30);
LineTo(pdc,-80,-20);
ArcTo(pdc,-50,-50,TRUE,30);
OSTimeDly(3000);
/*将任务挂起3秒*/
SetDrawOrg(pdc,0,LCDHEIGHT/2,&
oldx,&
oldy);
/*设置绘图原点为屏幕左边中部*/
for(;
;
)/*消息循环*/
{
MoveTo(pdc,0,0);
for(x=0;
x<
LCDWIDTH;
x++)
{
y=(int)(50*sin(((double)x)/20.0+offset));
/*画正弦波*/
LineTo(pdc,x,y);
}
offset+=1;
if(offset>
=2*3.14)
offset=0;
OSTimeDly(1000);
ClearScreen();
}
DestoryDC(pdc);
/*删除绘图设备上下文*/
本程序中应注意如下几点:
⑴绘图必须通过使用绘图设备上下文(DC)来实现。
绘图设备上下文(DC)中包括了与绘图相关的信息,例如,画笔的宽度、绘图的原点等。
⑵绘制整圆可以用Circle函数,绘制直线用Line函数,绘制圆弧用ArcTo函数。
调试的过程中可以在每个绘图函数之后调用OSTimeDly函数,使系统更新显示,输出到液晶屏上。
⑶为方便绘图,可使用SetDrawOrg函数设置绘图的原点。
⑷因为本次实验不用系统的字符显示,所以,可以去掉Main()函数中的LoadFont()函数,以节省系统启动的时间。
4、列表框控件
控件是可视化编程的基础,每个控件是一个相对独立的组件,有其自有的显示方式,动
态内存管理模式以及与系统通信的方法。
对于应用程序开发人员来说,并不需要掌握控件内
部到底是怎么样工作,只需要使用控件提供的API函数,设置控件的属性,即可改变控件的
显示结果。
开发平台的uCOS-II操作系统提供了列表框、文本框、图片框、按钮和窗口等几
种简单的控件及其API函数。
在使用系统控件之前需要通过initOSCtrl()函数初始化系统的控件,为动态创建控件分配空间。
与系统控件有关的API函数有:
SetWndCtrlFocus()函数设置窗口中指定ID的控件为焦点控件,返回原来焦点控件的ID;
GetWndCtrlFocus()函数获取当前焦点控件的ID。
ReDrawOSCtrl()函数重画所有的系统可见控件,当由于某原因清屏后必须重画控件。
GetCtrlfromID()函数从指定ID的控件获取该控件的指针。
SetCtrlMessageCallBk()函数设置指定控件的消息回调函数,程序中收到发给该控件的消
息后可以调用其消息回调函数。
OSOnSysMessage()函数是系统的消息处理函数,程序中收到消息后可以用该函数将其传
送给控件。
下面是列表框控件的结构定义:
U32CtrlType;
//控件的类型
U32CtrlID;
//列表框控件的ID
structRECTListCtrlRect;
//列表框的位置和大小
structRECTClientRect;
//列表框列表区域
U32FontSize;
//列表框字体大小
U32style;
//列表框的风格
U8bVisible;
//是否可见
PWndparentWnd;
//控件的父窗口指针
U8(*CtrlMsgCallBk)(void*);
//列表框控件的消息回调函数
U16**pListText;
//列表框所容纳的文本指针
intListMaxNum;
//列表框所容纳的最大文本的行数
intListNum;
//列表框所容纳的文本的行数
intListShowNum;
//列表框所能显示的文本行数
intCurrentHead;
//列表的表头号
intCurrentSel;
//当前选中的列表项号
structRECTListCtrlRollRect;
//列表框滚动条方框
structRECTRollBlockRect;
//列表框滚动条滑块方框
}ListCtrl,*PListCtrl
在程序中可以使用CreateListCtrl()函数来创建列表框控件,该函数返回指向列表框的指针,并用SetWndCtrlFocus()函数将焦点转移到该控件上。
注意在系统中每个控件具有唯一的ID,用它来标识控件。
然后就可以使用AddStringListCtrl()函数向该列表框中添加表项了。
5、文本框控件
文本框控件也是系统的一个基本控件,其结构定义如下:
//控件的ID
structRECTTextCtrlRect;
//文本框的位置和大小
//客户区域
//文本框的字符大小
//文本框的风格
//文本框控件的消息回调函数
U8bIsEdit;
//文本框是否处于编辑状态
char*KeyTable;
//文本框的字符映射表
U16text[40];
//文本框中的字符块
}TextCtrl,*PTextCtrl
对文本框控件的使用和列表框相似,这里可以使用CreateTextCtrl()函数来创建文本框控件,同样必须指定文本框的唯一ID。
用SetTextCtrlText()函数即可将Unicode文本添加到文本框中,而GetTextCtrlText()函数用来获取文本框中字符串的指针。
用AppendChar2TextCtrl()函数和TextCtrlDeleteChar()函数分别在文本框中追加一个字符或删除最后一个字符。
也可以用SetTextCtrlEdit()函数设置文本框为编辑状态,使文本框可以响应键盘消息,通过键盘输入文字。
6、消息循环
通常在多任务操作系统中,任务之间的通讯是通过发送消息来实现的。
消息队列是
uCOS-II操作系统的一种通信机制,它可以使一个任务或者中断服务程序向另一个任务发送
以指针方式定义的变量。
uCOS-II操作系统提供了若干对消息队列进行操作的函数,例如
OSQCreate(),OSQPend(),OSQPost()等,都定义在OS_Q.C中。
但是,在将uCOS-II移植到
本ARM嵌入式开发平台时,对消息队列相关函数又作了提高,使得程序中对消息队列的使
用变得更加简单易行。
程序中可以用OSCreateMessage()函数为某个控件创建消息,用
SendMessage()函数将该消息发送到消息队列中,用WaitMessage()函数等待消息,用
DeleteMessage()函数删除消息。
消息的数据结构定义如下:
typedefstruct{
POS_CtrlpOSCtrl;
//消息所发到的窗口(控件),为NULL时指桌面
U32Message;
//消息类型
U32WParam;
//消息参数
U32LParam;
}OSMSG,*POSMSG;
下面是平台的基本消息类型定义:
#defineOSM_KEY1//键盘消息
#defineOSM_TOUCH_SCREEN2//触摸屏消息
#defineOSM_SERIAL100//串口收到数据的消息
#defineOSM_LISTCTRL_SELCHANGE1001//列表框的选择被改变的消息
#defineOSM_LISTCTRL_SELDBCLICK1002//列表框的选择双击消息
#defineOSM_BUTTON_CLICK1003//单击按钮消息
下面是各基本消息类型的参数说明:
Message
WParam
LParam
OSM_KEY
键盘扫描码
OSM_TOUCH_SCREEN
低16位=触摸点x坐标值
高16位=触摸点y坐标值
触摸动作
OSM_LISTCTRL_SELCHANGE
CtrlID
CurrentSel
OSM_LISTCTRL_SELDBCLICK
OSM_BUTTON_CLICK
对于键盘消息来说其类型pMsg->
Message=OSM_KEY,参数pMsg->
WParam则是按键
的键码(pMsg是指向该消息结构体的指针)。
键盘消息是由键盘扫描任务(void
Key_Scan_Task(void*Id))创建并发送到系统的消息队列,键盘扫描任务用函数
KeyBoard_Read()从IIC的数据收发移位寄存器中获得键盘扫描码,这个扫描码是由
ATMEGA8当有键盘按下时发送到IIC的数据收发移位寄存器的。
主任务由消息队列中得到
消息。
staticvoidKey_Scan_Task(void*Id)
U32key;
INT8Uerr;
POSMSGpmsg;
printk("
beginkeytask\n"
);
for(;
){
OS_FLAGSflag;
flag=OSFlagPend(Input_Flag,UCOS2_KBINPUT,OS_FLAG_WAIT_SET_ANY,0,
&
OSFlagPost(Input_Flag,flag,OS_FLAG_CLR,&
key=KeyBoard_Read(0,FALSE);
if(key==-1)
continue;
pmsg=OSCreateMessage(NULL,OSM_KEY,key,0);
if(pmsg)
SendMessage(pmsg);
应用程序在Main_Task任务中等待消息,并对该消息进行判断和处理,如果是键盘消息
则提取出键码,变换为对应字符,然后将其显示到液晶屏上。
在图形模式下,液晶屏的文字
输出函数是TextOut(),实际是通过在图形方式下绘图完成文字显示的。
此函数输出的字符数组必须是基于双字节Unicode编码的。
在程序中可以使用Int2Unicode()和strChar2Unicode()两个函数分别将整形数或ASCII字符转换为Unicode字符串。
7、综合应用举例
采用多任务编程方法,每个任务监视一路AD转换,每一路AD的转换结果在液晶屏上
用一个条形图的长短来表示,直观地显示每路模拟输入电压的大小。
可以通过文本框给每路
AD设置警戒值,某路输入超出警戒线之后条形图中超出的部分会以闪动的方式显示。
设计主要思路如下:
1.打开main.c文件,编辑Main_Task任务中的代码。
用init_ADdevice()函数初始化处理器的AD转换硬件,启动消息循环。
2.编写OnKey()函数,响应键盘消息。
流程图如图10-3所示。
1)这里设置了两个文本框,用来输入通道编号和该通道的警戒值,在键盘消息响
应函数里针对两个文本框分别作出处理,只处理回车键和取消键,其他键由控件本身处
理。
程序里用变量EditNumber指示当前要编辑的文本框控件;
用变量input指示该文本框控件是否处于输入编辑状态。
以此决定回车键应该执行的功能。
2)当文本框控件不是编辑状态时,回车将使其进入编辑状态,在程序里用
SetWndCtrlFocus()函数将焦点转移到该控件并用SetTextCtrlEdit()函数设置为编辑状态;
当文本框正处于编辑状态时,回车将使其退出编辑状态,并将要编辑的文本框切换到另一个文本框控件,取消键的处理和这种情况类似。
3)如果当前要编辑的文本框是警戒值输入框,在编辑状态中回车确定后,所输入的通道编号以及警戒值就会保存在数组WarnningData中,代码如下:
WarnningData[Unicode2Int(pChannelTextCtrl->
text)]=Unicode2Int(pValueTextCtrl->
text);
图10-3流程图
3.编写绘图显示任务Display_Task,绘制文本框和条形图等,并实现文本框编辑过程中
和超过警戒值后的动画显示。
流程图如图10-4所示。
1)程序中用TextOut()函数显示文本框的提示信息,用数组edit记录两个文本框是否处于编辑状态,用变量IsEdit指示提示信息是否显示。
实际上,IsEdit这个变量在显示任务循环一次就改变一次状态,当IsEdit==1时将提示信息擦掉,否则保持显示不变。
这就是闪烁显示的原理,表示AD转换结果的条形图超出警戒值的部分的闪烁也是这样实现的,随着任务的循环隔次的改变状态。
2)和变量IsEdit的作用类似,warnning[x]是条形图闪烁的指示变量。
当某路AD转换的结果result_ADx大于对应通道的警戒值WarnningData[x]时,根据warnning[x]的值决定条形图的长度是和result_ADx对应还是和WarnningData[x]对应,这样看起来条形图的长度是变化的,效果就是超过警戒线的那部分在闪烁。
3)这里条形图实际上是一个实心矩形,用FillRect()函数填充。
4.编写4路AD采集任务ADx_Task。
图10-4文本框编辑显示流程图