无线餐厅点菜机 - 图文

更新时间:2024-05-07 10:49:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

一、基本任务与要求

基本任务:设计一个无线点餐系统,客人通过手持终端点餐,点餐点餐完成后将结果通过无线数传模块分别传输给在厨房和总台的上位机,其中厨房上位机以先后顺序显示客人所在桌号和菜名,总台上位机要求显示桌号、菜名、单价等信息,并可以计算消费总额,打印消费小票,保存消费记录等

要求:(1)手持终端能显示菜名、单价等信息;人机界面要求操作简单、直观;

(2)手持端使用电池供电,所以必须尽可能降低其功耗; (3)当没有客人时自动进入低功耗状态,有客人到来时自动唤醒; (4)数据传输要求误码率小于0.1%,传输距离大于300米;

(5)毕业设计论文按照学院统一格式要求,内容提要用中、外文资料统一、准确。

1、

随着经济和科技的高速发展,人们的生活质量越来越高,电子产品也越来越深入的融入人们的日常生活中,在餐饮行业也不例外,于是无线电子点餐系统应运而生。

在传统的餐饮行业,点餐时都是由服务员拿来菜单,客人根据菜单点菜,服务员再将客人所点的菜送到厨房和总台。这种方式办事效率低、容易出错、而且浪费大量的人力资源、客人需要等待较长的时间等等弊端。

而无线电子点餐系统则完全克服了这些问题,它完全颠覆了传统的点餐方式,采用手持PDA+无线收发器+总台控制器+显示器的方式使点餐系统形成一个有机的整体。为饭店提供了一个无纸化、人性化、低功耗、高效、节省人力资源的点餐解决方案。

本系统由手持终端、接收机和上位机界面三部分组成。手持终端由电池供电,为了降低功耗,MCU用TI公司的超低功耗单片机MSP430F1611,通过热释电传感器检测是否有人,无人则关闭所有外围模块,单片机进入最低功耗模式。LCD菜单和独立键盘构成人机交互界面,客人可以通过此界面来点菜,并通过无线数传模块传输到接收部分。接收部分考虑到设计成本和功能需求,采用了MICROCHIP的PIC16F877作为控制器。当接收部分接收到数据后,将其按照串行通信协议送给与之相连的上位机。上位机由Labview实现,当上位机收到数据后,把数据转化为相应的菜名、单价等信息显示出来。上位机可以对价格进行计算、统计、打印凭条等操作。

选题背景与意义。

1. 理论分析与方案论证

根据题目要求,系统可分为以下几个模块,如图3-1-1,3-1-2 所示:

供电部分 液晶显示 热释电

USB模块 PC机 供电部分

图3-1-2(上位机连接部分)

MCU 地址编码 数据编码 数据解码 无线收发模块 地址解码 控制键 图3-1-1(终端部分)

MCU 地址编码 数据编码 数据解码 无线收发模块 地址解码 对各模块的实现,分别有以下一些不同的设计方案:

(1)收发模块

收发模块的功能及原理框图如图3-3:

图3-3

发射电路 调制电路 高频振荡电路 高频功率放大电路接收电路 高频放大解调电路 因题目对频带宽度没有限制,为了提高抗干扰能力。

方案一:使用ZigBee技术组成无线局域网络,传输数据速度快,抗干扰能力强 ,但实现难度大,开发成本高,功耗相对较高,使用效率低。

方案二:采用分离器件,分别制作收发电路,价格便宜,但是由于题目要求传输距离要远,而且要求系统比较稳定,会使电路比较复杂。

方案三:使用专用的(DT1000)无线数传模块,使用集成芯片能比较容易的实现要求,而且价格便宜,能实现高稳定度的远距离传输。

综上所述,我们采用方案三进行设计。

(2)控制部分

方案一:采用FPGA实现。FPGA资源丰富,速度快,可靠性好,但针对本次设计而言显得太浪费,使得其使用效率低,而且价格较高。

方案二:采用MSP430F1611单片机为控制系统的核心。其低功耗,高性能,48KFLASH和10K RAM均能满足菜单的实现,对信号进行处理,显示及硬件与软件都比较容易实现,且满足本题的要求。性价比较高,资源丰富,利于提高系统稳定度。

比较以上两个方案,方案一与方案二均可以实现本题的要求,并且精度都可

以满足要求,但方案一用与本系统不能充分利用器件的性能且其器件昂贵;方案二能够发挥各个器件的优势且性能价格比较高,还能进行功能扩展。因此我们采用方案二进行设计。

(3)显示部分

方案一:采用TFT薄膜晶体管有源矩阵液晶显示器,18位以上真彩色(256K),可以实现分辨率为VGA、SVGA、XGA、SXGA、UXGA,但由于MSP430F1611不带液晶控制器,需外加液晶控制器,实现难度大,硬件工艺复杂,成本也较高。

方案二:采用TN小规模点阵像素,不需外加控制器,硬件也易于实现。与终端控制器能很好的协调工作,能达到本设计要求。

综上所述,我们采用方案二进行设计。

(4)传感器部分

方案一:使用HS0038和红外二极管组成障碍反射感测装置,其成本低、灵敏度较高、实现容易,但反射角小、盲区大不易全范围监测,且距离较大时误差增大。

方案二:使用热释电传感器,监测盲区小、灵敏度高、选择人体热释电范围,可避免误开起,完全符合本系统要求。

综上所述,我们选择方案二。

2.系统硬件设计

4.1 系统总体设计

根据题目要求,我们作出的系统总体设计为:

采用TI公司的MSP430F1611作为手持控制核心,以OCMJ8X15触摸屏实现终端人机交互,315M无线电传输作为无线组网环境,利用热释电识别模块开启或关断条件以降低功耗。上位机人机交互界面由LabVIEW实现,采用PIC16F877编解码完成PC机与无线网络的串行通信。

4.2 单元电路功能及原理分析

1. 终端:

1. 控制器:

终端控制器为TI公司的16位,具有精简指令集、超低功耗的混合型单片机。64只管脚(图4-2-1),

图4-2-1

低频震荡器使用32.768KHz晶体,高频震荡器使用8MHz晶体复位电路使用

了阻容延时滤波、稳压二极管限幅。本系统用到的MSP430F1611的供电电压是

3.3V,输入电压最大也不超过3.3V而用到的外围模块供电均为5.0V输出电压也到达5.0V,如表4-2-1,两者属于不同电源电压的逻辑器件相互接口时会出现以下三个问题:

(1)如果本系统的MSP430F1611的引脚直接与5.0V的管脚相连,5.0V电压会向MSP430F1611的3.3V电源充电。持续的电流会损坏MSP430F1611或其他器件。

(2)两个电源间电流的互串问题。在等待或掉电方式时MSP430F1611的3.3V电源降落到0V,大电流通到地,这使总线上的高电压被下拉到地,这种情况会引起信号丢失和原件损坏。

(3)输入转换门限的问题。每个器件都会有自己的驱动门限,MSP430F1611引脚上的输出电压必须达到外围器件的驱动电压门限,如果单纯考虑MSP430F1611引脚最大电压限制而把接口电压钳制在一个很小的值上,系统也是不能运行的。 其解决方案为:

采用输入输出分开处理的办法,5.0V到3.3V的耦合使用串接3.3KΩ电阻输出端接3.3V稳压管将与MSP430F1611连接的接口电压钳制在3.3V(如图4-2-2),

3.3V到5.0V的耦合使用HC373实现将

MSP430F1611输出的3.3V提升到可以驱动外 图4-2-3 图4-2-3 围模块的5.0V电压(图4-2-3)。

表4-2-1 逻辑输入电压(V) 逻辑输出电压(V) 模块或芯片 最小 标准 最大 最小 标准 最大 液晶 4.5 5.0 5.5 4.5 5.0 5.5 无线模块 4.0 5.0 5.5 4.5 5.0 5.4 热释电 -- -- -- 4.0 5.0 6.0 MSP430F1611 2 3.3 3.3

2.液晶:

终端人机交互使用了OCMJ5X15液晶,对比度调节使用了10KΩ可调电阻,利用S8050对背光进行可编程管理,原理图连接见(图4-2-4)

图4-2-4

3.热释电:

为了更优化的管理终端电源,我们使用了热释电对外界信息进行采集,其核心为BIS0001和热释电传感器组成,原理图祥见(图4-2-5)

图2-4-5

3. 无线收发:

根据本设计速度的要求,我们选用了315M的无线传输模块BT1000,巧妙的使用串行通信协议,以减小软件实现难度,其传输速度可达6000BPS、射频输出功率为10MW、接受灵敏度-106DBM、误码率<0.001、传输距离最大300M。

原理图见(图4-2-6)

图4-2-6

2 上位机连接模块(以下称连接模块):

由于本设计的无线模块借用了串行通信协议,而连接模块控制核心使用的MICROCHIP公司的PIC16F877单片机只有一组UART,因此我们使用了模拟串行通信的方案,使用PIC16F877的B2和B3作模拟串口的RX和TX(输入和输出)PL-2303为核心的UART转USB,与PC机通信,以便于数据传输和为连接模块供电,原理图见(图4-2-7)

图4-2-7

3 上位机:

上位机人机界面采用LabVIEW实现,(实现方法请参阅上位机软件实现)

4 电源: 1

终端电源:终端电源使用电池供电,经7805和CX1117电压变换滤波得到5.0V

和3.3V两组电压,分别为外围模块和

7805 MSP430F1611供电,具体电路与各元件连接方式如图(图4-2-8)

图4-2-8

2

连接模块电源:根据连接模块功耗要求小于500MA的要求,我们选择使

用USB电源供电。

5. 系统软件设计

本系统的MCU使用了TI 公司的超低功耗单片机MSP430F1611,在软件设计中,充分利用了该MCU的低功耗特点。主程序中仅完成了系统的初始化和开始的显示部分,然后就进入最低功耗模式(LPM4)。其他功能模块都在中断服务子程序中完成。当产生中断时,MCU被唤醒并执行相应的中断服务子程序,从中断子程序返回后,系统又进入到LPM4模式,整个程序的设计使系统在绝大多数时间都处于最低功耗状态。

整个程序用全部用C 语言编写,使用模块化的设计方法,把各个模块相关的程序放在一个文件中,便于分块调试和管理,缩短了调试周期,增加了程序的可移植性和可剪裁性。

整个程序结构如下:

Menu.c Menu.c为主函数,它包含了header.h、

uart.c、lcd.c、list.c、key.c这些功能模块文件。在

Header.h Uart.c Lcd.c List.c Key.c menu.c文件中主要完成MCU和各模块的初始化,并打开中断并进入低功耗模式:

WDTCTL = WDTPW + WDTHOLD; _DINT(); //关中断 Init_CLK(); //时钟初始化 Init_lcd(); //LCD初始化 Init_interrupt(); //中断初始化

程序结构图 _BIS_SR(LPM4_bits+GIE);

//打开全局中断

//进入最低功耗模式

在header.h文件中,对数据类型进行了重定义,不仅简化了程序的书写,而且

提高了程序在不同编译环境下的可移植性: typedef unsigned char uchar ; //定义无符号字符型为uchar

typedef unsigned int uint ; //定义无符号整型为uint

全局变量和延时函数也在这里做了定义。而且,考虑到一条记录包含有编号、菜名、单价三个成员,于是使用结构体进行了定义:

struct menu //定义一个结构体类型 struct menu { uchar Num[2]; //给每个菜定义一个唯一标识符 uchar Name[14]; //菜名 uchar Price[8]; //单价

};

Uart.c程序中,对系统时钟、UART1进行了初始化,由于UART波特率对时序的严格要求,必须对系统时钟进行正确的初始化,否则计算的波特率将与实际不符而导致数据无法正确传输:

BCSCTL1 = 0X04; BCSCTL2 = 0X00; BCSCTL2 += SELM1; BCSCTL2 += SELS;

//将寄存器的内容清零 //XT2震荡器开启 //LFTX1工作在低频模式 //ACLK的分频因子为1 //将寄存器的内容清零 //MCLK的时钟源为TX2CLK,分频因子为1 //SMCLK的时钟源为TX2CLK,分频因子为1

MSP430的波特率发生器使用一个分频计数器和一个调整器,分频因子N 由送到分频计数器的时钟(BRCLK)频率和所需要的波特率来决定:

N=BRCLK/(UBR+(M7+M6+M5+M4+M3+M2+M1+M0))/8

根据以上公式及所需要的波特率(9600)可以得到分频计数器和调整器的值:

U1TCTL = SSEL1; //波特率发生器选择SMCLK

UBR0_1 = 0X43; //波特率为9600 UBR1_1 = 0X03; UMCTL_1 = 0X03; //调整寄存器

通过以上公式得到的波特率可以使误差降到最低,经过计算,本程序中波特率的误差为4.17% 。

Lcd.c程序中包含了所有与LCD显示有关的函数,包括清屏、上下左右移动、反色显示、显示ASCII码、汉字、点阵图形等函数。其中清屏、移动,反色等函数简单且比较常用,所以使用宏定义的方式来实现,不仅简化了书写,而且增加了程序的可读性:

#define CLEAR send_data1(0xF4 ) #define MOVE_UP send_data1(0xF5) #define MOVE_DOWN send_data1(0xF6) #define MOVE_LEFT send_data1(0xF7) #define MOVE_RIGHT send_data1(0xF8) #define OVERTURN send_data1(0xFA) #define DISP_CURSOR(l) send_data1(0xFB);send_data1(l) #define CH_SPEED(v) send_data1(0xFC);send_data1(v) ASCII

码、汉字显示程序可以实现在指定位置显示,当一行写满时可以自动换行:

void disp_ascii(uint addr_x, uint addr_y, uchar *eng) { uint i; uint lenght; lenght=strlen(eng); for(i=0;i

}

send_data1(eng[i]); }

List.c文件中定义了一个结构体数组,存放着要显示的相关记录。 Key.c文件中存放着按键中断服务子程序,是实现人机界面的关键部分。每个函数对应着一个按键的处理程序,按键中断服务子程序通过调用各程序来完成各自的功能。具体功能的实现见附录1。

5.1 主程序流程图及其功能 在主程序中,首先关闭了看门狗和总中断,避免了在初始化过程中看门狗或其他中断导致单片机复位,使初始化无法完成。初始化过程分模块进行,增加了程序的可读性,而已便于分块调试,缩短了调试周期。

考虑到LCD和UART对时序的要求,在

时钟初始化部分对系统的默认时钟进行了调整,开启了XT2震荡器,调整了分频因子,使整个系统能协调工作。

在对各个模块初始化完成之后,就打开中断并进入最低功耗模式。此时全部活动部件停止工作,只有RAM、端

1. 主程序流程图

口和寄

存器的内容保持,此时功耗达到最低。当有外

部中断发生时,CPU被唤醒并执行相应操作,完成后再次进入低功耗模式。整个系统除了响应中断之外,其他时间都处于最低功耗模式,满足了低功耗的要求。

5.2 中断服务子程序

在本设计中,中断服务子程序是整个系统的核心,几乎所有外围模块的功能都在中断服务子程序中实现。当执行完中断服务子程序后,系统又进入低功耗模式。 5.2.1 热释电红外中断服务子程序流程图及功能

热释电红外传感器主要用来实现智能化,当热释电红外传感器检测到有人靠近时,便产生中断唤醒MCU,使其进入工作状态,并显示出欢界面、当前时间,同时启动定时器并打开定时器中断。延迟一段时间后,自动进入点菜界面。

图2. 红外中断服务子程序流程图

5.2.1 定时器中断服务子程序流程图及功能

当红外中断使MCU进入工作状态时,定时器定时为15s 并开始工作。在每次按键产生中断时,定时器都会重新开始计时。如果在15s 内没有任何操作,则定时器产生中断。在中断服务子程序中,首先关闭液晶背光,使系统降低功耗,然后做系统进入低功耗前的准备工作:使能红外中断,关闭定时器中断,然后进入低功耗模式。

图3. 定时器中断服务子程序流程图

5.2. 2按键中断服务子程序流程图及功能

图4. 按键中断服务子程序流程图

在进入按键中断服务子程序后,都必须首先重启定时器,因为系统在15s内无

方向键(KEY_UP、KEY_DOWN)中断程序流程图

任何操作,定时器便会产生中断,使MCU进入低功耗模式并关闭所有外围模块。 5.2.3.1

图5. KEY_UP键程序流程图

在本设计中,使用向上(KEY_UP)、向下(KEY_DOWN)两个方向键来改变

光标所指向的当前记录,并用反白显示出来,当按KEY_UP、KEY_DOWN键时,

反白显示条上下移动来指示光标的当前位置,实现方法如下(以KEY_UP键为例):

cls_chn(2,line,13); //清除当前记录 disp_record(line,record[number].Num,record[number].Name,record[number].Price); //再次显示当前记录 line-=1; OVERTURN; //写入反色指令

number-=1; disp_record(line,record[number].Num,record[number].Name,record[number].Price); //反色显示上一条记录 OVERTURN; //再次写入反色指令,取消反色 当光标已经指向第一条记录时,如果按KEY_UP键,则会在相应位置显示错误标志(Err)并不停闪烁。同样,当光标已经到达了最后一条记录,如果按KEY_DOWN键,也会显示出(Err)标志。除此之外,他们还具有自动翻页功能,当光标指向了当前页的首/尾记录。 5.2.3.2

选择(SELECT) 、取消(CANCEL)键中断程序流程图

当进入SELECT键中断服务子程序后,首先在已选中的列表中查找是否有该编号的记录,如果该记录已经存在,则将已选标志位置1 (select_flag=1),在后面的程序中,先判断 select_flag 是否为 1,如果为 1 则直接从中断返回;否则将该记录的编号存入已选中列表中,选中计数器自加一(r_counter+=1)并显示在LCD的左上角:

if(r_counter>9) { disp_char(0,8,r_counter/10+48);

disp_char(1,8,r_counter+48); } Else disp_char(0,8,r_counter+48); 图6. 选择键程序流程图

图7. KEY_UP键程序流程图

CANCEL键的中断服务子程序与SELECT键基本相同,首先也必须判断光标当前所指记录是否已经选中,不同的是当该记录不存在时直接从中断返回,存在时则删除选中列表中的记录,清除选中标志,选中计数器减 1,并显示出来。

5.2.3.3

发送(SEND)键中断程序流程图

当按下SEND键时,就进入发送中断服务子程序,在此段程序中,首先读出已选中列表中的编号,在根据编号去查找与之对应的菜名,并显示出来。并询问是否发送,如果发送则再次按SEND键即可将数据发送出去,发送由发送中断服务子程序来完成,每16个BIT数据构成一个数据桢,数据在发送过程中,数据在发送时遵循串口通讯协议。

图8. 发送中断程序流程图

5.2 程序清单 见附1。 4,系统组装与调试

6.1 整机结构和工艺及pcb制作

整机分为手持终端、PC连接器和PC机三个部分,由于本系统使用无线

电高频发射,在制作PCB时,要对相关规则进行设置,具体设置要求如下: 1 导线布设尽可能短,导线拐弯处应成45度或圆角式 3 导线的公共接地应尽可能宽,在20~40mil

4 相邻导线间距必须能满足电器安全要求,间距应尽量宽

5 PCB的公共地线应尽量布置在边缘部分,在PCB上应尽量保留铜箔做地线,这样可以减小分布电容的作用

6 焊盘的焊孔尺寸必须从元件引脚直径和公差尺寸搪炀层厚度,孔径公差,金属化孔电镀等方面考虑,焊盘的钻孔一般不小于30mil

综合以上制作原则我们对电路板设计具体是:手持终端部分由于元件和布线比较多,把线宽设定为20mil,地线35mil,线与线间距10mil,线与焊盘距离10mil。连接部分元件较少,线宽为30mil,地线40mil,平行导线间距15mil ,线与焊盘距离15mil,具体布局如图6-1-1

参考文献

[1] Texas Iinstruments 公司.MSP430x1xx Family User’s Guide.

[2] 魏小龙 .MSP430系列单片机接口技术及系统设计实例 . 北京:北京航空航

天大学出版社,2002.

[3] 秦龙. MSP430单片机C语言应用程序设计实例精讲.北京:电子工业出版

社,2006.

[4] 胡大可 . MSP430系列单片机C语言程序设计与开发 . 北京:北京航空航天大

学出版社, 2002. [5] 胡大可.MSP430系列超低功耗16位单片机原理与应用.北京:北京航空航

天大学出版社,2004.

[6] 魏小龙 . 南航MSP430课程试用书.PDF.www.mcu-china.com [7] IAR Embedded Workbench User’s Guide.

[8] MSP430开发环境—AQ430使用说明.PDF . www.lierda.com

[9] 彭良清.基于节点编号的通用树状菜单设计方法与实现.www.lierda.com [10] 3v与5v混合系统中逻辑器接口耦合问题. www.microcontrol.cn [11] 金鹏公司. B系列中文液晶显示模块使用说书.PDF www.gptlcm.cn [12] 印制电路板排版设计 科学技术文献出版社

[13] 李学海.PIC单片机原理.北京:北京航空航天大学出版社

send_data1(*chn-0xA0);chn++; send_data1(*chn-0xA0);chn++; } }

/******************显示单个字符8x8****************/ void disp_char(uint addr_x,uint addr_y,uchar code) { send_data1(0xF1); send_data1(addr_x); send_data1(addr_y); send_data1(code); }

/*********************************************** ***************显示8x8ASCII码子程序***************/ void disp_ascii(uint addr_x, uint addr_y, uchar *eng) { uint i;

uint lenght;

lenght=strlen(eng); for(i=0;i

/***********************************************

***************显示8x16ASCII码子程序***************/ void disp_ASCII(uint addr_x, uint addr_y, uchar *eng) { uint i;

uint lenght;

lenght=strlen(eng); for(i=0;i

/*********************************************** *函数名称:disp_img() * *功能描述:使一个汉字字符串在指定位置显示出来 * *参数说明:addr_x-----要显示的首个字符所在的行 * * addr_y-----要显示的首个字符所在的列 * * wide-------显示图形的宽度(像素) *

* hight------显示图形的宽度(像素) * * img--------要显示的位图点阵的数组名 * *补 充:坐标原点为液晶右上角,行列均以0开始 * * : 行以8个像素计算,列以1个像素计算 * ***********************************************/

void disp_img(uchar addr_x,uchar addr_y,uchar wide,uchar hight, uchar *img) { uchar i,j; for(j=0;j

/*********************************************** *函数名称:disp_record() * *功能描述:在指定位置以一定格式显示一条记录 * *参数说明: * * addr_y-----要显示的首个字符所在的行 * * num-------记录的ID号 * * name------记录名称 * * price--------价格 * ***********************************************/

void disp_record(uchar addr_y,uchar *num,uchar *name,uchar *price) {

disp_ASCII(4,addr_y,num); disp_chn(5,addr_y,name);

disp_char(22,6+addr_y*16,127); disp_ASCII(23,addr_y,price); }

List.c 程序清单

uchar menu0_0[]={\编号\

uchar menu0_1[]={\菜 名%uchar menu0_2[]={\单 价%uchar error[]={\

uchar cm[]={\您所点的菜如下:\

uchar sel[]={/*--选中时显示的标志\V\ 宽度x高度=24x16 --*/ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x00,0x00,0x38,0x00, 0x00,0x70,0x1C,0x00,0xE0,0x0E,0x01,0xC0,0x07,0x03,0x80,0x03,0x87,0x00,0x01,0xCE, 0x00,0x00,0xFC,0x00,0x00,0x78,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };

struct menu record[60]={

{\鸡皮鲟龙\ {\蟹黄鲜菇\ {\玉簪出鸡\ {\夜合虾仁\ {\酥姜皮蛋\ {\京都肾球\ {\酥炸鲫鱼\ {\凤眼腰\ {\一品官燕\ {\凤尾大裙翅\ {\象拔虞琴\ {\金钱豹狸\ {\虎扣龙藏\ {\仙鹤烩熊掌\ {\银针炒翅\ {\鼎湖上素\ {\月中丹桂\ {\鹿羧水鸭\ {\清汤雪耳\ {\清蒸海鲜\ {\广肚乳鸽\ {\乌龙肘子\ {\灯烧羊腿\ {\母子鲜虾饺\ {\鸡肉拉皮卷\ {\云腿馅儿府\ {\蟹肉海棠果\ {\蒸熊掌\ {\烧花鸭\ {\酱鸡\

{\什锦苏盘\ {\卤子鹅\ {\炝虾仁儿\ {\焖白鳝\ {\豆鼓鲇鱼\ {\烀皮甲鱼\ {\锅烧鲤鱼\ {\软炸里脊\ {\炒白虾\ {\炝青蛤\ {\芙蓉燕菜\ {\炒肝尖儿\ {\油爆肚仁儿\ {\炒金丝\ {\烩银丝\ {\糖熘荸荠\

{\蜜丝山药\ {\拔丝鲜桃\ {\烩鸭丝\ {\清蒸鸡\ {\黄焖鸡\

{\清蒸玉兰片\ {\炒虾仁儿\ {\锅烧海参\ {\锅烧白菜\ {\清蒸翅子\ {\炸飞禽\

{\烩鸡肠肚儿\ {\盐水肘花儿\ }; uchar img1[]={/*-- “图片:欢迎光临” 宽度x高度=208x96 已省略--*/}; uart.c 程序清单 //定义串口操作变量

char nRX0_Flag; // 串口 0 的接收标志 char UART0_RX_BUF[16]; // 串口 0 的接收缓冲区 char nRX0_Len_temp; // 串口 0 接收长度计数 char nRX0_Len; // 串口 0 接收字符串长度

char UART0_TX_BUF[16]; // 串口 0 的发送缓冲区 int nTX0_Len_temp; // 串口 0 发送长度计数 int nTX0_Len; // 串口 0 发送字符串长度 char nTX0_Flag; // 串口 0 的发送标志 void Init_UART0(void) {

U1CTL = CHAR; //00010000控制寄存器 U1TCTL = 0X00; //发送控制寄存器 U1TCTL = SSEL1; //波特率发生器选择SMCLK UBR0_1 = 0X43; //波特率为9600 UBR1_1 = 0X03;

UMCTL_1 = 0X03; //调整寄存器

ME2 |= UTXE1 + URXE1; //使能UART0的TXD和RXD IE2 |= URXIE1; //使能UART0的RX中断 IE2 |= UTXIE1; //使能UART0的TX中断 P3SEL |= BIT6; //设置P3.4为UART1的TXD P3SEL |= BIT7; //设置P3.5为UART1的RXD P3DIR |= BIT6; //P3.4为输出管脚 return; }

void Init_CLK(void) {

unsigned int i;

BCSCTL1 = 0X04; //将寄存器的内容清零

//XT2震荡器开启 //LFTX1工作在低频模式 //ACLK的分频因子为1 do { IFG1 &= ~OFIFG; // 清除OSCFault标志 for (i = 0x20; i > 0; i--);

}while(IFG1 & OFIFG == OFIFG); // 如果OSCFault =1 BCSCTL2 = 0X00; //将寄存器的内容清零

BCSCTL2 += SELM1; //MCLK的时钟源为TX2CLK,分频因子为1 BCSCTL2 += SELS; //SMCLK的时钟源为TX2CLK,分频因子为1 }

// 处理来自串口 1 的接收中断 #if __VER__ < 200

interrupt [UART1RX_VECTOR] void UART1_RX_ISR(void) #else

#pragma vector=UART1RX_VECTOR __interrupt void UART1_RX_ISR(void) #endif {

UART0_RX_BUF[nRX0_Len_temp] = RXBUF1; //接收来自的数据 nRX0_Len_temp += 1;

if(UART0_RX_BUF[nRX0_Len_temp - 1] == '!') {

nRX0_Len = nRX0_Len_temp; nRX0_Flag = 1;

nRX0_Len_temp = 0; } }

// 处理来自串口 1 的发送中断 #if __VER__ < 200

interrupt [UART1TX_VECTOR] void UART1_TX_ISR(void) #else

#pragma vector=UART1TX_VECTOR __interrupt void UART1_TX_ISR(void) #endif {

if(nTX0_Len != 0) {

TXBUF1 = UART0_TX_BUF[nTX0_Len_temp]; nTX0_Len_temp += 1; if(nTX0_Len_temp >= nTX0_Len) {

nTX0_Len_temp = 0; nTX0_Len = 0; } } }

void uart_sendstring(char UART_sendstring[],char send_len) {

char i;

nTX0_Len=send_len; nTX0_Len_temp=0;

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

UART0_TX_BUF[i] = UART_sendstring[i]; IFG2 |=UTXIFG1; }

Key.c 程序清单 void key_up(void) {

if(number==0) //当前记录是首记录 {

uint i; for(i=0;i<3;i++) { disp_ascii(0,0,error); delayms(20); cls_ascii(0,0,3); //清除错误标志 delayms(10); } disp_ascii(0,0,error); } else { if(number%7==0) //当前记录是当前页的首记录 { line=1; loop_control=0; cls_chn(0,1,105);

for(line=1,number-=7;loop_control<7;loop_control++,number++,line++) //翻页 disp_record(line,record[number].Num,record[number].Name,record[number].Price);

line=7; number-=1; OVERTURN; //反色显示最下面一条记录 disp_record(line,record[number].Num,record[number].Name,record[number].Price);

OVERTURN; } else //其他情况 { cls_chn(2,line,13); disp_record(line,record[number].Num,record[number].Name,record[number].Price);

line-=1; OVERTURN;

number-=1; disp_record(line,record[number].Num,record[number].Name,record[number].Price);

OVERTURN; } } }

void key_down(void) { number+=1; if(number%7==0) //当前记录是当前页的最后一条记录 {

line=1;

loop_control=0; cls_chn(0,1,105); for(line=1;loop_control<7;loop_control++,number++,line++) /翻页 disp_record(line,record[number].Num,record[number].Name,record[number].Price);

line=1; number-=7;

OVERTURN; //反色显示最上面一条记录 disp_record(line,record[number].Num,record[number].Name,record[number].Price);

OVERTURN; }

else //其他情况 {

cls_ascii(0,0,3); //清除错误标志 cls_chn(2,line,13); //清除上一条记录 disp_record(line,record[number-1].Num,record[number-1].Name,record[number-1].Price);

line+=1;

OVERTURN; disp_record(line,record[number].Num,record[number].Name,record[number].Price);

OVERTURN; } }

void key_sel(void) { uint i; uchar flag=1;

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

if(number+1==BUFFER[i]) flag=0; if(flag==1) {

BUFFER[BUFFER_j]=number+1;

BUFFER_j++;

disp_img(0,line*16,24,16,sel); r_counter+=1;

cls_ascii(0,1,3); //清除计数器显示 if(r_counter>9) { disp_char(0,8,r_counter/10+48); disp_char(1,8,r_counter+48); } else disp_char(0,8,r_counter+48); } }

void key_cancel(void) {

for(BUFFER_i=0;BUFFER_i<32;BUFFER_i++) {

if(number+1==BUFFER[BUFFER_i]) { BUFFER[BUFFER_i]=0; cls_chn(0,line,2); r_counter-=1; cls_ascii(0,1,3); if(r_counter>9) { disp_char(0,8,r_counter/10+48); disp_char(1,8,r_counter+48); } else disp_char(0,8,r_counter+48); } }

void key_send(void) { uint m; uint n=0; uint line=1; uint counter=0; CLEAR; delayms(1); disp_chn(4,0,cm); for(m=0;m<32;m++) { if(BUFFER[m]==0); else { if(counter%2==1) line+=1; { if(n%2==0) disp_chn(1,line,record[BUFFER[m]-1].Name);

}

}

else disp_chn(8,line-1,record[BUFFER[m]-1].Name); counter+=1; }

n+=1;

附录二 电路图

附录三 效果图

附图一 登陆界面效果图

附图二 收银台菜单显示界面

附图三 厨房菜单显示界面

本文来源:https://www.bwwdw.com/article/zsxg.html

Top