专业实验嵌入式系统实验指导书版Word下载.docx
《专业实验嵌入式系统实验指导书版Word下载.docx》由会员分享,可在线阅读,更多相关《专业实验嵌入式系统实验指导书版Word下载.docx(30页珍藏版)》请在冰豆网上搜索。
程序暂停后在窗口中将显示出程序暂停的位置。
(5)通过Execute|Step菜单(或者工具栏中的相应按钮)可以单步运行程序。
也可以使用StepIn、StepOut菜单命令进入或者跳出函数的调用。
RunToCursor命令运行到光标位置。
(6)程序停止后可以通过ProcessorViews|Sources菜单查看源文件,并可在适当位置按F9设置端点。
(7)使用在ProcessorView菜单下的Registers、Variables和Memory命令可以查看工作寄存器或者内存变量。
可以逐一地尝试,以方便对程序进行调试。
2.LCD的驱动方法
市面上出售的LCD有两种驱动类型:
一种是带有驱动电路的LCD显示模块,这种LCD可以方便地和各种低档单片机进行接口,如8051系列单片机,但是由于硬件驱动电路的存在,体积比较大。
这种模式常常使用总线方式来驱动。
另一种是LCD显示屏,没有驱动电路,需要和驱动电路配合使用。
特点是体积小,但却需要另外的驱动芯片。
也可以使用带有LCD驱动能力的高档MCU驱动,如ARM系列的S3C44BOX。
S3C44B0X中具有内置的LCD控制器,它具有将显示缓存(在系统存储器中)中的LCD图象数据传输到外部LCD驱动电路的逻辑功能。
S3C44B0X中内置的LCD控制器可支持灰度LCD和彩色LCD。
在灰度LCD上,使用基于时间的抖动算法(time-basedditheringalgorithm)和FRC(FrameRateControl)方法,可以支持单色、4级灰度和16级灰度模式的灰度LCD。
在彩色LCD上,可以支持256级彩色。
对于不同尺寸的LCD,具有不同数量的垂直和水平象素、数据接口的数据宽度、接口时间及刷新率,而LCD控制器可以进行编程控制相应的寄存器值,以适应不同的LCD显示板。
和ARM自带LCD驱动器有关的寄存器可参见S3C44B0X的数据手册。
3.延时函数和嵌入式系统的主函数写法
voidDelay(inttime)函数可以实现延时功能,(注意函数名中的字母D是大写),其中参数time是设定的延时值,单位为0.1ms。
例如延时1s,可以调用:
Delay(10000);
即可实现。
该延时函数的精度比较高,是采用S3C44B0X芯片内部的定时器来实现定时功能的。
嵌入式系统的主函数一般是一个永不结束或返回的函数。
在程序结构上,写成一个大循环。
永远循环的两种写法:
while
(1)
{
循环内容;
}
或
for(;
;
)
循环内容
LCD显示配合延时功能,可以实现各种动画功能。
例如一个实现两幅图不停的切换的程序框架如下:
main()
开发板及必要的初始化;
while
(1)
LCD_Cls();
//清屏
画第一幅图;
LCD_Refresh();
//刷新屏幕,只有调用该函数液晶屏才会真正显示所画内容;
Delay(20000);
//延时2s
LCD_Cls();
画第二幅图;
}
如果画面重画的速度比较快(例如每秒切换24张),人眼就不会看到重画过程,从而形成动画。
清屏函数例子:
voidLCD_Cls()
intx,y;
for(x=0;
x<
320;
x++)
for(y=0;
y<
240;
y++)
LCDBuffer[y][x]=0x0;
六、实验步骤
1.将“Exp1LCD驱动控制实验”整个文件夹复制到自己所建的目录下,将其改为英文名(ADS对中文目录的支持不好),然后双击exp1.mcp文件,便可以打开工程。
2.查看LCD的驱动文件,包括
(1)有关常量和宏(lcd320.h,lcd320.c)
#defineLCDWIDTH320
#defineLCDHEIGHT240
U32*pLCDBuffer16=(U32*)0xc000000;
//一级缓存指针
U32LCDBuffer[LCDHEIGHT][LCDWIDTH];
//二级缓存
将其定义为32位是为了和RGB颜色兼容。
(2)查看LCD初始化函数(lcd320.c):
设置各功能寄存器,清空显示缓存区。
(3)查看LCD刷新函数(lcd320.c)。
此函数主要是将二级缓存LCDBuffer的数据由32位彩色图形信息转换成8位256色的图形信息,然后放到pLCDBuffer16指向的一级缓存。
转换公式:
pixcolor=(pbuf[0]&
0xe0)|((pbuf[1]>
>
3)&
0x1c)|(pbuf[2]>
6)。
其中,pbuf[0]、pbuf[1]、pbuf[2]是一个象素的32位彩色数据的前24位,分别代表R、G、B。
(4)查看主函数(main.c)
在LCD上显示256色图形的关键是填充二级显示缓冲,将显示象素的24位颜色信息写入LCDBuffer。
将RGB三种基本颜色按一定比例混合即可构成更复杂的颜色,每个象素的三种基本颜色分别占一个字节,可以方便的在程序里改写各基本颜色的数值,从而改变该象素的混合颜色。
例如向位于(x,y)坐标的像素填充红色,对应代码为:
LCDBuffer[x][y]=0xe0;
屏幕的左上角为坐标原点,x轴向右依次增加到320,y轴向下依次增加到240.
3.将示例程序下载到开发板上,调试并查看程序运行结果。
4.在消化吸收示例程序的main.c文件的基础上,按照老师的现场要求,修改或重写main.c文件中的main函数,编写自己的ARM程序,实现LCD显示和ARM动态程序设计。
5.编译、下载和调试自编程序。
七、思考题
1)ARM程序在线调试时主要进行哪些设置?
2)写出ARM程序设计中main函数常用的程序框架。
实验二嵌入式操作系统程序设计
1.了解µ
C/OS-Ⅱ内核的主要结构。
2.掌握µ
C/OS-Ⅱ程序设计的基本方法。
3.学习使用嵌入式系统绘图的API函数。
理解绘图设备上下文(DC)在多任务操作系统中的作用。
会使用绘图设备上下文(DC)在屏幕上绘制一个圆角矩形和一个圆。
了解绘制动画防止闪烁的基本原理,可以实现无闪烁的动画。
4.学习使用系统的消息循环。
掌握如何通过系统的消息循环来响应键盘任务的消息,同时学会使用图形模式下的液晶屏文字显示函数。
二、实验内容(4学时)
1.学习µ
C/OS-Ⅱ的编程方法。
2.编写几个简单任务,在超级终端上观察任务的切换。
3.通过使用嵌入式系统的绘图API函数,首先,在屏幕上绘制一个圆角矩形和一个整圆。
然后,再在屏幕上无闪烁的绘制一个移动的正弦波。
4.通过使用消息队列接收键盘任务发出的按键消息,并把对应按键的字符显示在液晶屏和PC机的终端上。
1.掌握在ADS1.2集成开发环境中编写和调试程序的基本过程。
2.了解ARM7处理器的结构。
3.了解µ
C/OS-Ⅱ系统结构。
PC机操作系Win2000、ADS1.2集成开发环境、仿真器驱动程序、超级终端通讯程序。
(一)µ
C/OS-Ⅱ程序编写基础
为了使µ
C/OS-Ⅱ可以正常运行,硬件初始化和配置文件也是必须的。
STARTUP目录下的文件还包括中断处理,时钟,串口通信等基本功能函数。
在文件main.c中给出了使用程序的基本框架,包括初始化和多任务的创建,启动等。
在µ
C/OS-Ⅱ中创建一个任务的步骤如下:
1)在程序开头定义任务堆栈,任务函数声明和任务优先级:
OS_STKTaskName_Stack[STACKSIZE]={0,};
//任务堆栈
voidTaskName(void*Id);
//任务函数
#defineTaskName_PrioN//任务优先级
2)在main()函数中调用OSStart()函数之前用下列语句创建任务:
OSTaskCreate(TaskName,(void*)0,(OS_STK*)&
TaskName_Stack[STACKSIZE-1],
TaskName_Prio);
OSTaskCreate()函数的原型是:
INT8UOSTaskCreate(void(*task)(void*pd),void*p_arg,OS_STK*ptos,
INT8Uprio);
需要将任务函数TaskName,任务堆栈TaskName_Stack,任务优先级TaskName_Prio三个参数传给OSTaskCreate()函数。
根据任务函数的内容决定堆栈大小,宏STACKSIZE定义为4KB,可以在此基数上乘倍。
任务优先级越高,TaskName_Prio值越小;
µ
C/OS-Ⅱ可以管理64个任务,由OSInit()创建的空闲任务的优先级最低为63;
C/OS-Ⅱ保留4个最高和4个最低优先级,用户任务可以使用其余56个优先级值。
3)编写任务函数内容:
voidTaskName(void*Id)
//添入任务初始化语句
;
{//添入任务循环内容
OSTimeDly(SusPendTime);
//挂起一定时间,以使其他任务可以占用CPU
C/OS-Ⅱ至少要有一个任务,这里首先创建一个系统任务SYS_Task,其中由语句
OSRunning=TRUE;
//使能µ
C/OS-Ⅱ运行
uHALr_InstallSystemTimer();
启动系统时钟和多任务切换。
为了验证µ
C/OS-Ⅱ多任务切换的进行,再编写两个简单的任务,分别在超级终端上输出runtask1和runtask2。
可以参考main.c的结构创建多个不同功能的任务,观察个任务的切换。
(二)完善的µ
C/OS-Ⅱ开发框架
需要说明的是,µ
C/OS-Ⅱ作为一个实时操作系统只提供了多任务调度等基本功能,这在实际使用中显然是不够的。
除了移植好的操作系统内核部分,还必须有文件系统,全部硬件的驱动程序,图形API,控件函数,综合提高的消息函数以及几个系统必须的基本任务,象键盘,触摸屏,LCD刷新等。
有了这些,µ
C/OS-Ⅱ才能实现复杂的功能。
特殊需求的地方还需要像USB通信协议,TCP/IP协议等更复杂的软件模块。
实验系统提供的µ
C/OS-Ⅱ库文件中包含了上述大部分功能,基于库的开发变的非常简单,在基本的程序框架下使用实验系统提供的丰富API函数即可。
实际开发中,用户的工程中无需包括µ
C/OS-Ⅱ的源代码,只需要包括库文件即可。
当然,用户也可以了解库中部分代码的源文件,可以根据自己的需求就行重新编译,也可以对自己的一系列源文件生成一个专门的库,方便自己后续工作。
C/OS-Ⅱ的开发中,使用程序和操作系统是绑在一起编译的,所生成的system.bin文件是唯一的可执行文件,其中包括了所需要的µ
C/OS-Ⅱ代码和被用到的驱动程序等函数代码,以及使用程序的代码。
system.bin文件是存放在平台的16MFLASH中的,在系统启动时由BIOS依靠文件系统从FLASH中读入到SDRAM中,然后把控制转移到该代码上,完成所谓的引导。
而BIOS是存储在另外的ROM中的。
本实验提供了基于库的µ
C/OS-Ⅱ开发框架,可以打开工程进行了解。
图3-3是ADS环境下看到的该框架的文件组成,还可以展开各目录查看更多的文件信息。
图3-3ADS下框架文件构成
可以看出,STARTUP下的都是最基本的硬件初始化和配置文件;
Ucos_lib.a是ADS环境下的库;
SRC是用户编写的工程文件;
C/OS-Ⅱ下都是系统用到的头文件,其中ADD下是添加的基本系统任务和消息函数的相关头文件。
INC下主要是硬件驱动程序的头文件。
Init下的几个文件是ADS环境下配置存储器及堆栈的,和µ
C/OS-Ⅱ无直接关系。
打开Main.c文件,可以看到一个使用工程的基本框架,在这个实验中,所谓的使用很简单,就是在LCD上显示“Helloworld!
”,大部分代码都是框架。
用户可以在这些代码的基础上进行使用开发,创建新任务,编写必要的函数。
当然,如果针对特定的项目有相对独立并集中的一些函数则最好新建源文件和头文件,以方便管理,这些用户新建的源文件可以放到SRC目录下,在编译环境下用AddFiles命令加入对应位置。
下面是Main()函数中的内容:
intmain(void)
ARMTargetInit();
//开发板初始化
OSInit();
//操作系统初始化
uHALr_ResetMMU();
//复位MMU
LCD_Init();
//初始化LCD模块
LCD_printf("
LCDinitializationisOK\n"
);
//向液晶屏输出数据
initOSGUI();
//初始化图形界面
LoadFont();
//调Unicode字库
LoadConfigSys();
//使用config.sys文件配置系统设置
Createtaskonµ
C/OS-Ⅱ...\n"
OSTaskCreate(Main_Task,(void*)0,(OS_STK*)&
Main_Stack[STACKSIZE*8-1],
Main_Task_Prio);
//创建系统任务
OSAddTask_Init();
//创建系统附加任务
Startingµ
Enteringgraphmode...\n"
LCD_ChangeMode(DspGraMode);
//变LCD显示模式为图形模式
InitRtc();
//初始化系统时钟
Nand_Rw_Sem=OSSemCreate
(1);
//创建Nand-Flash读写控制权旗语,初值为1满足互斥
条件
OSStart();
//操作系统任务调度开始
//不会执行到这里
return0;
main()函数中调用了必要的初始化函数,创建了系统任务和用户任务,然后启动系统任务调度。
建议用户不要改动该函数中的初始化过程,但可以按本实验第一部分所述的任务创建方法来创建更多的任务,注意每个任务必须具有不同的优先级。
(三)绘图的API函数
请查阅附录API函数,在Display.h中定义了和绘图显示有关的数据类型和函数原型。
C/OS-Ⅱ系统环境下,绘图必须通过使用绘图设备上下文(DC)来实现。
绘图设备上下文(DC)中包括了和绘图相关的信息,比如:
画笔的宽度、绘图的原点等等。
这样,在多任务系统中,不同的任务通过不同的绘图设备上下文(DC)绘图才不会互相影响。
绘图设备上下文(DC)的结构定义如下:
typedefstruct{
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()等常见的图形函数,用户可以查看附录API函数显示部分,尝试使用这些函数。
C/OS-Ⅱ操作系统中,液晶显示屏的刷新是通过Lcd_Fresh_Task任务完成的,该任务是在系统附加任务初始化函数OSAddTask_Init()中定义的,该函数开辟了LCD刷新任务,触摸屏任务,键盘任务等。
绘图首先是在绘图缓冲区中完成的,然后系统自动(也可以通过设置绘图设备上下文参数,不让系统自动刷新)向Lcd_Fresh_Task发送更新消息。
其流程图如图4-1所示:
图4-1绘图流程
因为绘图是在后台进行的,绘制完成之后,再更新到液晶屏上,所以,在绘图的时候不用担心反覆的擦除屏幕会引起屏幕的闪烁,这样,可以很方便的实现动画无闪烁的显示。
绘制完一次图形以后,必须要使用OSTimeDly()给出一定时间的延时(推荐用200),同时使Main_Task任务主动让出对CPU的控制权,使Lcd_Fresh_Task任务可以完成刷新。
(四)图形系统的消息循环
通常在多任务操作系统中,任务之间的通讯是通过发送消息来实现的。
消息队列是µ
C/OS-Ⅱ操作系统的一种通信机制,它可以使一个任务或者中断服务程序向另一个任务发送以指针方式定义的变量。
C/OS-Ⅱ操作系统提供了若干对消息队列进行操作的函数,例如OSQCreate(),OSQPend(),OSQPost()等,都定义在OS_Q.C中。
但是,在将µ
C/OS-Ⅱ移植到本ARM嵌入式开发平台时,对消息队列相关函数又作了提高,使得程序中对消息队列的使用变得更加简单易行。
请参考附录API函数系统消息部分,开发平台的消息队列相关函数定义在OSMessage.h中。
程序中可以用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是指向该消息结构体的指针)。
键盘中断服务程序只向键盘邮箱(邮箱是µ
C/OS-Ⅱ的另一种通信机制)中发送一个消息,通知键盘扫描任务发生按键事件:
voidISR_Key()
OSMboxPost(Key_MailBox,(void*)1);
当键盘扫描任务等到该邮箱的消息后就会从键盘扫描芯片读取扫描码,继而将该扫描码对应的键码用键盘消息发送到消息队列:
voidKey_Scan_Task(void*Id)//键盘扫描任务
U32key;
INT8Uerr;
POSMSGpmsg;
Uart_Printf("
beginkeytask\n"
for(;
){
OSMboxPend(Key_MailBox,0,&
err);
key=ZLG7289_ReadKey();
if(key>
=64)
continue;
pmsg=