微机接口课程设计试验报告――超市收银系统计算机0211班唐京川012002014319一.课程设计目的,要求及条件:掌握接口硬件开发平台的使用方法,利用现有的实验平台和PC机,组成一个微机模拟应用系统;掌握基本接口电路的综合应用掌握接口电路的驱动程序和界面软件的设计与编制,学会调试与测试接口软件的一般方法;结合实际应用,设计一微机应用系统,要求该系统综合应用并行接口、串行接口,时间接口、中断接口、模拟接口,等等,实现微机系统对模拟信号的采集、转换、并行输入,输出,远距离传送,以及远程控制、检测并显示.二.设计内容根据以上任务,需进行如下工作:◆数据采集系统接口设计(包括电路和程序设计与实现)◆微机并行通信接口设计(包括电路和程序设计与实现)◆微机时间远程监督并显示(包括电路和程序设计与实现)◆双机串行通信设计(包括电路和程序设计与实现)◆远程控制﹑检测﹑显示接口及界面的设计与实现.题目35 设计完成超市收银系统一个主控机对应多个下位机,主控机存储商品资料,并输出相关信息,下位机从执行部件读入商品号,到主控机查询资料,并显示资料.商品查询成功有声音提示,收银统计时有音乐背景.输入商品号,在主机上查询商品价格并发回给终端,由主机计价,终端机可以打印数据,交易结束,有主机向终端发送总价.三.设计要求◆自行设计可以根据自己的设计,适当增加元、器件,自己设计电路,配合实验台使用,实现预定功能。
编程语言可采用汇编语言或C/C++。
自选。
编程环境采用MF集成开发环境。
MF在系统机上已经安装好。
◆8255接口端口地址分配:PA口为300H,PB口为301H,PC口为302H,命令口为303H。
◆8251接口端口地址分配:命令/状态口为309H,数据(出/入)口为308H。
◆8253/8254定时接口端口地址分配:T0=304H,T1=305H,T2=306H,命令口=307H。
◆开关,音乐发生器四.设计步骤主要分成上位机和下位机。
上位机主要是一个数据库的作用,用来接收下位机传过来的商品号,返回商品信息。
下位机输入数据,并显示信息,播放音乐。
首先完成串口的设计,让两台机子能进行简单的通信,然后设计上位机和下位机的主要程序,再在下位机上添加8255的控制,最后再连接音乐发生器。
五.设计思想首先用8255作为主控,口c下连接一个开关,下位机判断8255的0x302口的输入,如果按下,程序才能继续执行。
然后是8251的串口传输。
先判断是否键盘有案件,如果是esc,则推出,如果是其他,则传送,没有键盘输入时,为接收状态。
字符sletter接收键盘输入,检查8253的TXRDY状态,如果准备好,从8251输出。
上位机接收到商品号,判断后,执行不同的函数。
在上位机中,存储商品信息的是一个结构体数组,上位机将每个结构数组中的信息以单个字符的形式传送到下位机。
如果下位机输入的是“y”,说明这次交易结束,上位机判断后,调用totle函数,返回总价。
在传送总价是,先要吧总价int型转换成字符数组,然后从8251传送,下位机接到数组后,直接显示。
同时,上位机返回一个z字符,下位机接收到这个字符后,开始播放音乐。
我在这次的试验中的主要任务是设计上位机和下位机的主要程序,上位机的流程图:下位机的流程图八.源程序下位机的程序如下:#include <conio.h> //kbhit();#include <stdio.h> //printf();#include <dos.h> //delay();#include <stdlib.h> //exit(0);#define data51 0x308 //8251A数据口#define ctrl51 0x309 //8251A命令/状态口#define ctrl55 0x303 //8255命令口#define timer2 0x306 //8253的2号计数器端口#define timctl 0x307 //8253命令口#define factor 16 //波特率因子16unsigned long int clk = 1193182;//8251输入时钟频率(十六进制表示)int tc_table[8]={110, // 0=110bps150, // 1=150b/s300, // 2=300b/s600, // 3=600b/s1200, // 4=1200b/s2400, // 5=2400b/s4800, // 6=4800b/s9600 // 1=9600b/s};const unsigned long CLK = 1193180; // 声明时钟频率const unsigned char INTR = 0X1C; // 声明中断号short int *pFreq; // 声明音频指针short int *pTimeDelay; // 声明延时指针short int nFreq[] = {//声明歌曲“两个老虎”的音乐频率262,294,330,262,262,294,330,262,330,349,392,330,349,392,392,440,392,349,330,262,392,440,392,349,330,262,294,196,262,294,196,262,};short int nTimeDelay[] = {//声明歌曲“两个老虎”的音乐延时8,8,8,8,8,8,8,8,8,8,16,8,8,16,4,4,4,4,8,8,4,4,4,4,8,8,8,8,16,8,8,16};void Playing(void){ outportb( 0x303, 0x80); // 初始化8255outportb( 0x303, 0x0c); // 置pc6=0 禁止8253通道2的gate引脚 outportb( 0x303, 0x00); // 置pc0=0 禁止7408outportb( 0x307, 0xb6); // 初始化8253pFreq = nFreq; // 取歌曲的第一个音频pTimeDelay = nTimeDelay; // 取歌曲的第一个时延while (*pFreq&&!kbhit()){outportb( 0x306, (unsigned char)(CLK / *pFreq % 256));// 先送低字节outportb( 0x306, (unsigned char)(CLK / *pFreq / 256));// 再送高字节// 以上置8253通道2 的计数初值outportb( 0x303, 0x01);outportb( 0x303, 0x0d); // 开扬声器delay(*pTimeDelay*30); //等待延时到outportb( 0x303, 0x0c);outportb( 0x303, 0x00); // 关闭扬声器pFreq++; // 获取下一个音频pTimeDelay++; // 获取下一个延时} // 歌曲结束或按了任意键outportb( 0x303, 0x0c);outportb( 0x303, 0x00); // 再次关闭扬声器}void int51(); //初始化8251avoid set_bps(int bps); //8253-5记数初值计算与装入void main(){int getvalue=3;int temp=-1;int sletter,rletter,status,s;int c55;temp = getvalue - '0';int51();printf("\n input commodity number\n");outportb(0x303,0x8a);for(;;){if(kbhit()) getch();c55=inportb(0x302);if(!(c55&0x20)) {for(;;)//判断是否Esc键{if (kbhit()){//若无键按下,则转接收 //这里是输出if((sletter=getche())==0x1b)//是ESC?是,则退出,并返回DOS {outport(ctrl55,0x0c);//关闭8253return;}else{status=inportb(ctrl51);//获取8253 TXRDY 状态if((status&0x01)!=0)//已准备好,则将键入的字符发送出去{outportb(data51,sletter);printf("\t");}}}else{ //接收status=inportb(ctrl51);//已准备好,即有数据传送过来,则接收1个字符if((status&0x02)!=0){rletter=inportb(data51);if(rletter=='z') Playing();else printf("%c",rletter);}}}}}}void int51(){outportb(ctrl51,0x00);delay(100);outportb(ctrl51,0x40);//8251复位delay(100);outportb(ctrl51,0x4e);//8251A方式命令delay(100);outportb(ctrl51,0x27);//8251A工作命令}void set_bps(int bps){int i,sendhigh,sendlow;i=clk/bps;i=i/factor;//计算计数初值sendhigh = (i>>8)&0x00ff;sendlow = i & 0x00ff;outportb(timctl,0xb6);outportb(timer2,sendlow);//装计数初值低字节outportb(timer2,sendhigh);//装计数初值高字节}上位机的源程序如下:#include <conio.h> //kbhit();#include <stdio.h> //printf();#include <dos.h> //delay();#define data51 0x308 //8251A数据口#define ctrl51 0x309 //8251A命令/状态口#define ctrl55 0x303 //8255命令口#define timer2 0x306 //8253的2号计数器端口#define timctl 0x307 //8253命令口#define factor 16 //波特率因子16unsigned long int clk = 1193182;//8251输入时钟频率(十六进制表示)int tc_table[8]={110, // 0=110bps150, // 1=150b/s300, // 2=300b/s600, // 3=600b/s1200, // 4=1200b/s2400, // 5=2400b/s4800, // 6=4800b/s9600 // 1=9600b/s};char trans[3];struct goods{ int num;char name[20];char price;}a1[3]={{1,"book",8},{2,"pen",9},{3,"food",5} };void numbertostring(int num, char* p){int dec=num/10;p[0]=dec+48;p[1]=(num-dec*10)+48;p[2]='\0';}int stringtonum(char *p){int all;all=(p[0]-48)*10+(p[1]-48);return all;}void int51(); //初始化8251avoid set_bps(int bps); //8253-5记数初值计算与装入int sletter,status,sum=0;void out1(){ //接收到‘1’时char *p;int i,digit;char price1;p=a1[0].name;price1=a1[0].price;for (i=0;i<10;i++){sletter=*(p+i);status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51);//已准备好,则将键入的字符发送出去{outportb(data51,sletter);}}status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51); outportb(data51,'\t');status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51); outportb(data51,price1+48);status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51); outportb(data51,'\n');digit=price1;sum=sum+digit;}void out2(){char *p;int i,digit;char price1;p=a1[1].name;price1=a1[1].price;for (i=0;i<10;i++){sletter=*(p+i);status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51);{outportb(data51,sletter);}}status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51); outportb(data51,'\t');status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51); outportb(data51,price1+48);status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51); outportb(data51,'\n');digit=price1;sum=sum+digit;}void out3(){char *p;int i,digit;char price1;p=a1[2].name;price1=a1[2].price;for (i=0;i<10;i++){sletter=*(p+i);status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51);{outportb(data51,sletter);}}status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51); outportb(data51,'\t');status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51); outportb(data51,price1+48);status=inportb(ctrl51);while((status&0x01)==0) status=inportb(ctrl51); outportb(data51,'\n');digit=price1;sum=sum+digit;}void totle() //接收到‘y’时,统计总价{numbertostring(sum, trans);status=inportb(ctrl51);while((status&0x01)==0)status=inportb(ctrl51);outportb(data51,trans[0]);status=inportb(ctrl51);while((status&0x01)==0)status=inportb(ctrl51);outportb(data51,trans[1]);status=inportb(ctrl51);while((status&0x01)==0)status=inportb(ctrl51);outportb(data51,'\n');sum=0;}void main(){int getvalue=3;int temp=-1;int rletter;for(;;){clrscr();break;}temp = getvalue - '0';set_bps(tc_table[temp]);int51();printf("\n waitting input \n");outportb(0x303,0x80);//置PC6=1,打开8253-5的GATE2,开始输出方波outportb(0x303,0x0d);for(;;)//判断是否Esc键{if (kbhit()){//有键按下if((sletter=getche())==0x1b)//是ESC?是,则退出,并返回DOS {outport(ctrl55,0x0c);//关闭8253return;}else{status=inportb(ctrl51);//获取8253 TXRDY 状态if((status&0x01)!=0)//已准备好,则将键入的字符发送出去{outportb(data51,sletter);}}}else{ //接收status=inportb(ctrl51);//已准备好,即有数据传送过来,则接收1个字符if((status&0x02)!=0){rletter=inportb(data51);printf("%c",rletter);switch(rletter){case '1': out1();printf("\n");break;case '2': out2();printf("\n");break;case '3': out3();printf("\n");break;case 'y': totle();printf("\n"); break;}}}}}void int51(){outportb(ctrl51,0x00);delay(100);outportb(ctrl51,0x40);//8251复位delay(100);outportb(ctrl51,0x4e);//8251A方式命令delay(100);outportb(ctrl51,0x27);//8251A工作命令}void set_bps(int bps){int i,sendhigh,sendlow;i=clk/bps;i=i/factor;//计算计数初值sendhigh = (i>>8)&0x00ff;sendlow = i & 0x00ff;outportb(timctl,0xb6);outportb(timer2,sendlow);//装计数初值低字节outportb(timer2,sendhigh);//装计数初值高字节}下位机的截图为:在试验过程中,我们本来是想用dip开关来输入商品号的,但是,在开关的连接过程中,发现开关有很大的问题,就是:在全为低电平的时候,开关是正常的,但是,如果把其中一个拨为高,就会出现与它对称的那个也变为高,比如,把8号拨为高电平时,1号也变成了高,这使得在输入商品信息的时候就没有办法正确的控制。