电脑打铃器设计.docx

上传人:b****7 文档编号:10166213 上传时间:2023-02-09 格式:DOCX 页数:23 大小:80.31KB
下载 相关 举报
电脑打铃器设计.docx_第1页
第1页 / 共23页
电脑打铃器设计.docx_第2页
第2页 / 共23页
电脑打铃器设计.docx_第3页
第3页 / 共23页
电脑打铃器设计.docx_第4页
第4页 / 共23页
电脑打铃器设计.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

电脑打铃器设计.docx

《电脑打铃器设计.docx》由会员分享,可在线阅读,更多相关《电脑打铃器设计.docx(23页珍藏版)》请在冰豆网上搜索。

电脑打铃器设计.docx

电脑打铃器设计

目录

一.设计要求1

二.系统框图1

三.硬件电路设计1

1.输出控制电路1

2.键盘显示部分1

四.任务设计1

五.任务优先级的设计1

六.任务的数据结构设计1

1.与操作系统有关的数据结构设计1

2.与操作系统无关的数据结构设计1

七.多个任务之间的互斥与协调1

1.行为同步1

2.资源互斥1

八.多个任务之间的信息传递1

1.全局变量1

2.消息邮箱1

九.程序设计1

1.人机界面设计1

2.主函数1

3.键盘任务1

4.显示任务1

5.输出控制任务1

6.RTC中断1

十.附录1

附录1键盘任务代码1

附录2显示任务1

附录3输出控制任务代码1

附录4RTC中断代码清单1

 

电脑打铃器设计

一.设计要求

●具有实时时钟功能,能显示时分秒,年月日星期(采用8位数码管显示)

●具有键盘输入功能

●可以设置若干个闹钟,以及闹钟的禁止与使能

●可设置每个闹钟发生时的输出动作(一共四路输出,可独立设置每路输出的时间和电平状态

二.系统框图

图1系统框图

如图1,LPC2000系列ARM具有RTC功能,RTC掉电后仍可使用电池继续运行,从而保证了系统掉电后时钟的准确性。

ZLG7290是一款键盘和LED驱动芯片,最多支持64个按键和8个共阴极数码管。

三.硬件电路设计

电脑自动打铃器的硬件电路包括键盘显示部分和输出控制电路,键盘显示部分用于完成人机交互,输出控制电路用于控制电子打铃器的触发。

1.输出控制电路

图2输出控制电路

如图2,为输出控制电路,在应用中可能需要继电器等用于对打铃器的控制

2.键盘显示部分

键盘和数码管显示按照ZLG7290的相关数据手册设计,详细可以查看技术手册,基本构成为4*4矩阵键盘和两个4位数码管组成。

四.任务设计

按照嵌入式系统任务划分的原则来看,电脑自动打铃器具有键盘输入功能,用于设置时钟和闹钟,因此需要一个键盘任务;同时需要有显示功能,用来显示时钟和闹钟,因此需要一个显示任务;还需要一个输出控制任务,用于控制闹钟时间到达后的各路的输出;另外,具有实时时钟功能,需要一个RTC中断。

ZLG7290是键盘任务和显示任务的共享资源,需要信号量保护。

RTC实时时钟中断,负责实时时钟计时,1s产生一次中断,检测闹钟。

输出控制任务由RTC中断触发。

显示任务通过刷新机制来显示信息,每隔100ms刷新一次。

他们之间的通信采用相应的消息邮箱,信号量等来实现,具体将在后面讨论。

五.任务优先级的设计

在电脑自动打铃器的设计中,安排有键盘任务,显示任务,输出控制任务和RTC中断。

在这些任务中,键盘任务和显示任务是人机交互接口任务,实时性要求很低,输出控制任务相对于实时性要求较高,综合考虑,我们选择优先级:

输出控制任务优先级为6;

键盘任务优先级为12;

显示任务优先级为13。

六.任务的数据结构设计

对于一个任务,除了它的代码(任务函数)外,还有相关的信息。

为保存这些信息,必须为任务设计对应的若干数据结构。

任务需要配备的数据结构分为两类:

一类是与操作系统有关的数据结构;另外一类是与操作系统无关的数据结构。

1.与操作系统有关的数据结构设计

在电脑自动打铃器应用中,我们设计了3个任务(键盘任务、显示任务和输出控制任务),与操作系统有关的数据结构定义如下:

#defineTASKKEY_ID12//定义键盘任务的ID

#defineTASKKEY_PRIOTASKKEY_ID//定义键盘任务的优先级

#defineTASKKEY_STACK_SIZE512//定义键盘任务堆栈的大小

#defineTASKDISP_ID13//定义显示任务的ID

#defineTASKDISP_PRIOTASKDISP_ID//定义显示任务的优先级

#defineTASKDISP_STACK_SIZE512//定义显示任务堆栈的大小

#defineTASKCTRL_ID6//定义控制任务的ID

#defineTASKCTRL_PRIOTASKCTRL_ID//定义控制任务的优先级

#defineTASKCTRL_STACK_SIZE512//定义控制任务堆栈的大小

OS_STKTaskKeyStk[TASKKEY_STACK_SIZE];//定义键盘任务的堆栈

OS_STKTaskDispStk[TASKDISP_STACK_SIZE];//定义显示任务的堆栈

OS_STKTaskCtrlStk[TASKCTRL_STACK_SIZE];//定义控制任务的堆栈

voidTaskKey(void*pdata);//键盘任务声明

voidTaskDisp(void*pdata);//显示任务声明

voidTaskCtrl(void*pdata);//控制任务声明

2.与操作系统无关的数据结构设计

电脑自动打铃器具有时钟和闹钟功能,那么我们首先就要构造这两个数据结构,定义如下:

定义时钟和闹钟全局变量

#defineMAX_ALARM4//最大闹钟个数

TIMEGtimeCurrentTime;//时钟全局变量

ALARMGalarmRingTime[MAX_ALARM];//闹钟全局变量

时钟结构定义

structtime{

unsignedcharucHour;//时

unsignedcharucMin;//分

unsignedcharucSec;//秒

unsignedcharucWeek;//星期

unsignedshortusYear;//年

unsignedcharucMon;//月

unsignedcharucDay;//日

};

typedefstructtimeTIME;

typedefTIME*PTIME;

闹钟结构定义

structalarm{

unsignedcharucHour;//时

unsignedcharucMin;//分

unsignedcharucSec;//秒

unsignedcharucEnable;//闹钟使能控制

struct{

unsignedshortusLevel;//输出电平控制

unsignedshortusTime;//输出时间控制

}c[4];//4路输出控制

};

typedefstructalarmALARM;

typedefALARM*PALARM;

七.多个任务之间的互斥与协调

1.行为同步

为了说明问题,我们在这里将键盘任务拆分成为两个任务,一个是键盘扫描任务,另一个是键盘处理任务。

当键盘扫描到键值的时候,键盘处理任务就应该及时的处理该键值,二者之间是一种同步接力的关系,用于行为同步的手段有计数器信号量,事件标志组,消息邮箱,消息队列,由于要求处理键值,同步的痛死需要伴随着通信,可以采用消息邮箱。

基本代码如下:

voidTaskKeyScan(void*pdata)//键盘扫描任务

{

uint32keytmp;

//初始化代码

if(扫描到按键)

{

OSMboxPost(Mbox,(void*)keytmp);//向消息邮箱发送按键消息

}

//其他相关代码

}

voidTaskKeyDeal(void*pdata)//按键处理函数

{

uint32keytmp;

//初始化代码

keytmp==(uint32)OSMboxPend(Mbox,0,&err);//从消息邮箱中获取键值信息

处理按键

//其他相关代码

}

2.资源互斥

在电脑自动打铃器的设计中,ZLG7290是通过I2C总线与LPC2000连接的,I2C总线是键盘任务和显示任务的共享资源,必须遵循资源互斥的原则进行访问,二者之间使用信号量进行资源互斥。

操作ZLG7290采用到了I2C软件包,该软件包是uc/os-II系列中间件之一,所以提供的接口函数在多任务环境下是安全的。

在本次设计中需要为ZLG7290封装两个函数

(1)获取键值,i2cRead()这个函数的功能是指定总线接口,指定器件从机地址,指定子地址,读取指定字节数量的数据到接受数据缓冲区。

代码如下:

uint16ZLG7290GetKey(void)

{

uinttemp[2];

i2cRead(0,//I2C

0x70,//机器从机地址

temp,//接受数据缓冲区

1,//器件子地址

1,//器件子地址类型为单字节型

2);//读取数据长度

while(i2cGetFlag(0)==I2C_BUSY);//等待总线操作完毕

return(uint16)(temp[0]+(temp[1]*256));

}

(2)显示数据,i2cWrite()函数的功能是指定总线接口,指定从机地址,指定子地址,写入指定字节数量的写入数据缓冲区中的数据。

代码如下:

uint16ZLG7290ShowChar(void)

{

uintbuf[2];

buf[0]=(uint8)(0x60|(index&0x0f));

buf[1]=data;

i2cWrite(0,//I2C

0x70,//机器从机地址

buf,//接受数据缓冲区

0x07,//器件子地址

1,//器件子地址类型为单字节型

2);//读取数据长度

while(i2cGetFlag(0)==I2C_BUSY);//等待总线操作完毕

}

八.多个任务之间的信息传递

1.全局变量

在任务的数据结构设计中,我们设计了时钟和闹钟两个数据结构,并定义了时钟和闹钟两个全局变量。

键盘任务,显示任务和RTC中断通过它们传递信息。

RTC中断每隔1s中断一次,更新当前时钟信息,并检测闹钟。

如果闹钟时间到,就向输出控制任务发送控制信息。

显示任务每隔100ms刷新一次,更具当前显示模式进行时钟或者闹钟的显示。

键盘任务负责时钟和闹钟的设置。

这两个全局变量就是这三个任务的共享资源,必须保证访问互斥。

全局变量虽然可以实现数据的传输,但是不能够实现行为的同步:

新的数据产生之后并不能够自定的通知相关使用者,使用者也不知道当前数据是何时产生的,因此,全局变量只能用于没有行为同步要求的任务之间,即每次产生的新数据不要求立即使用,甚至可以不被使用。

其中RTC中断代码如下:

voidRTC_Exception(void)

{

//相关代码

GtimeCurrentTime.ucHour=(uint8)HOUR;

GtimeCurrentTime.ucMin=(uint8)MIN;

GtimeCurrentTime.ucSec=(uint)SEC;

//相关代码

}

显示任务:

voidTaskDisp(void*pdata)

{

while

(1){

OSTimeDly(20);//延时100ms

OS_ENTER_CRITICAL();//关中断

dispbuf[0]=GtimeCurrentTime.ucHour;//更新显示缓冲区

dispbuf[1]=GtimeCurrentTime.ucMin;

dispbuf[2]=GtimeCurrentTime.ucSec;

……

OS_EXIT_CRITICAL();//开中断

//显示时间

}

}

2.消息邮箱

RTC中断检测闹钟,闹钟到就向输出控制任务发送控制信息,在本设计实例中使用消息邮箱。

具体实现是在RTC代码中加入发送消息邮箱函数,在输出控制任务中加入从消息邮箱中接受信息函数。

九.程序设计

1.人机界面设计

对于一个具有人机界面的应用系统来说,首先应该考虑的是人机界面如何设计。

8位数码管显示力度有限,只能通过按键分屏显示,显示界面定义如下:

(1)时钟模式:

12时59分59秒星期一

(2)日历模式:

2007年12月12日

(3)闹钟模式:

A表示闹钟,0表示第一个闹钟,闹钟时间08:

30:

00

(4)闹钟模式:

闹钟使能控制(E使能,d禁能),从左至右,第一个是总开关,接着是星期6~0(分别对应星期日~星期一)的开关。

(5)闹钟模式:

C表示通道,0表示第一个通道(每个闹钟有4个通道),H/L表示输出高低电平控制,接着是输出时间控制,最大为9999秒。

根据上述分析,电脑自动打铃器具有时钟和闹钟模式,时钟和闹钟模式都分别有不同的显示内容,闹钟模式还有若干不同的闹钟,为了修改时钟和闹钟的设置,还需要一个光标闪烁来提示用户进行修改,为此定义了如下全局变量:

unsignedintGuiMode=0;//模式(时钟和闹钟模式)

unsignedintGuiCursor=8;//光标(闪烁位置提示)

unsignedintGuiIndex=0;//索引(不同的闹钟)

unsignedintGuiItem=0;//条目(时钟或闹钟的不同内容)

按键的处理比较灵活,可自行设计,这里定义如下表1:

表格1按键设计

按键上的标识

按键功能定义

按键上的标示

按键功能定义

“S1”~”S9”键

数字’1’-‘’9’键

“S13”

上移动键

“S10”

数字”0”键

“S14”

下移动键

“S11”

左移动键

“S15”

状态切换键

“S12”

右移动键

“S16”

确定键

2.主函数

在主函数中,进行了操作系统的初始化,创建了一个键盘任务,最后,启动多任务操作系统,其中键盘任务TaskKey()的优先级为12,负责初始化目标板和创建一些其他任务。

其主要代码如下:

intmain(void)

{

OSInit();//初始化操作系统

OSTaskCreateExt(TaskKey,

(void*)0,

&TaskKeyStk[TASKKEY_STACK_SIZE-1],

TASKKEY_PRIO,

TASKKEY_ID,

&TaskKeyStk[0],

TASKKEY_STACK_SIZE,

(void*)0,

OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR//创建键盘任务);

OSStart();//启动多任务操作系统

return(0);

}

3.键盘任务

键盘任务首先进行目标板的初始化,主要完成系统时钟中断的设置;然后初始化I2C0总线接口并设置中断;然后创建消息邮箱GmboxRingCtrl,用于闹钟触发输出控制任务;接着初始化RTC并设置中断;最后创建了显示任务和输出控制任务,就进入了周期性循环,通过读取ZLG7290获取键值,进行按键处理,其基本的流程图如图3所示:

图3键盘任务流程图

键盘任务代码由于相对较长,见附录1。

4.显示任务

显示任务是个周期性的任务,负责显示界面的刷新,显示任务的具流程图见下图*:

图4显示任务流程图

显示任务周期性的输出全局变量的信息,100ms是个经验值,可以根据适当情况调节,显示任务主要根据当前状态,光标位置,索引,条目进行相应的显示。

其具体任务代码见附录2.

5.输出控制任务

输出控制任务接受RTC中断发送的控制信息,控制4路输出的电平和时间,其主要流程图如图*所示:

图5输出控制任务流程图

输出控制任务首先初始化输出控制端口,默认为高电平,然后进入任务循环,从消息邮箱中等待一条信息。

由于消息邮箱没有消息。

输出控制任务一直处于挂起状态,直到RTC中断检测到发送了闹钟事件,然后根据消息的内容设置各路的输出电平,接着就进入了输出时间控制循环。

在此循环中不断查询消息邮箱是否有新的消息,如果有怎退出循环,从而处理新的消息,否则知道所有4路输出时间到为止。

其具体代码见附录3.

6.RTC中断

RTC中断更新实时时钟,遍历所有闹钟,向输出控制任务发送闹钟控制信息。

流程图*如下所示:

图6RTC中断流程图

RTC中断具体代码见附录4.

一十.附录

附录1键盘任务代码

voidTaskKey(void*pdata)

{

unsignedcharucKey;

unsignedcharucKey0;

unsignedcharucFlag=0;//修改状态标志

pdata=pdata;//防止编译器报错

TargetInit();//目标板初始化

OSTimeDly(OS_TICKS_PER_SEC/10);

PINSEL0=(PINSEL0&0xffffff0f)|0x50;//设置I2C引脚功能

i2cInit(0,"Speed=30000",NULL);//设置I2C

SetVICIRQFunction(9,2,(int)i2c0IRQ);

GmboxRingCtrl=OSMboxCreate((void*)0);//创建消息邮箱

rtcInit();//RTC初始化

SetVICIRQFunction(13,3,(int)RTC_Exception);

OSTaskCreateExt(

TaskDisp,

(void*)0,

&TaskDispStk[TASKDISP_STACK_SIZE-1],

TASKDISP_PRIO,

TASKDISP_ID,

&TaskDispStk[0],

TASKDISP_STACK_SIZE,

(void*)0,

OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR

);//创建显示任务

OSTaskCreateExt(

TaskCtrl,

(void*)0,

&TaskCtrlStk[TASKCTRL_STACK_SIZE-1],

TASKCTRL_PRIO,

TASKCTRL_ID,

&TaskCtrlStk[0],

TASKCTRL_STACK_SIZE,

(void*)0,

OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR

);

while

(1){

OSTimeDly(4);

ucKey=(uint8)ZLG7290GetKey();//获取按键

if((ucKey==0)||(ucKey>16))

{continue;}

//按键处理代码省略

while

(1){//等待按键释放

OSTimeDly(4);

ucKey=(uint8)ZLG7290GetKey();

if((ucKey==0)||(ucKey>16)){

break;

}

}

}

}

voidrtcInit(void)//RTC初始化

{

if(ALYEAR!

=2007){//初始化一次

CCR=0x00;//禁止时间计数器

PREINT=Fpclk/32768-1;//设置基准时钟分频器

PREFRAC=Fpclk%32768;

AMR=0xFF;//禁止报警中断

CIIR=0x01;//使能秒增量中断

ILR=0x03;//清除RTC中断标志

ALYEAR=2007;//初始化标志

YEAR=2007;//初始化时间寄存器

MONTH=11;

DOM=6;

DOW=0;

HOUR=12;

MIN=0;

SEC=0;

CCR=0x11;//启动RTC,32.768独立晶振

}

}

附录2显示任务

voidTaskDisp(void*pdata)

{

uint8i;

pdata=pdata;//防止编译器警告

while

(1){

OSTimeDly(20);

OS_ENTER_CRTICAL();

ToDispBug();

OS_EXIT_CRTICAL();

switch(GuiMode){

case0:

for(i=0;i<8;i++)//时钟模式

{

ZLG7290SHowCHar(i,(uint8)((i==BuiCursor)?

0x40:

0x00)

|GucTimeDispBuf[GuiItem[i]]);

OSTimeDly(20);

}

break;

case1:

//闹钟模式

for(i=0;i<8;i++)

{

ZLG7290SHowCHar(i,(uint8)((i==GuiCursor)?

0x40:

0x00)

|GucAlarmDispBuf[GuiIndex][GuiItem][i]);

OSTimeDly

(1);

}

break;

default:

break;

}

}

}

附录3输出控制任务代码

voidTaskCtrl(void*pdata)

{

INT8UucErr;

unsignedcharusLevel[4];

unsignedcharusTime[4];

unsignedshort*pusMsg;

OS_MBOX_DATAmboxdataMsg;

inti;

pdata=pdata;

IO0DIR|=(LED0|LED1|LED2|LED3);

IO0SET=(LED0|LED1|LED2|LED3);

while

(1){

pusMsg=(unsignedshort*)OSMboxPend(GmboxRingCtrl,0,&ucErr);

for(i=0;i<4;i++)

{

usLevel

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1