电子线路专题实验Ⅱ一、实验要求:1.认真阅读学习系统线路及相关资料2.将键盘阵列定义为0.1.2------E.F,编程实现将键盘输入内容显示在LCD显示器上。3.编程实现将日历、时钟显示在LED显示屏上(注意仔细阅读PCF8563资料),日历、时钟轮回显示。4.利用D/A转换通道(下行通道)实现锯齿波发生器;输出(1~5V)固定电压转换成(4~20mA)电流。5.利用A/D转换通道(上行通道)实现数据采集,将采集信号显示在LED屏上。程序要求分别具有平均值滤波、中值滤波和滑动滤波功能。6.将按键阵列定义成与16个语音段对应,编写程序,实现按键播放不同的语音段。二、实验设计思路:本次实验用c语言实现,主要包括LCD,LED,AD,DA,日历芯片,测温传感芯片。受到嵌入式系统实验的启发,将LCD,LED,I2C总线协议,键盘扫描模块接口写成一个文件库(放在library文件夹下),尽量做到调用时与底层硬件无关。通过调用库文件中的函数,实现代码的重用性。键盘,LCD的代码由于与嵌入式实验具有相通之处,因此可将高层的函数(与底层硬件无关的函数)方便地移植过来。三、实验设计:1.矩阵键盘扫描模块4×4的矩阵键盘,通过扫描可得到按下键的行列值,将行列值转换为相应的对应数字0~F。函数GetKey()实现获得按键的键值。对于键盘模块对于对按键的键值识别主要是通过两次扫描而取得。对于第一次扫描,给四行键全部赋予1,然后读回键盘值,对于第二次扫描,逐行为键盘送1,每次送1后再读回键盘值,若非零,说明此行有键按下,最终确定键值。通过调用GetKey函数构造GetChar()函数,实现获取键盘字符(’0’~’F’)的功能。通过调用GetChar()函数构造GetDec()函数,实现获取键盘输入整数的功能,整数范围在0~99999。有按’C’键回退一格,按’E’清空当前未完输入,按’F’键结束输入的功能。程序代码://键盘初始化,将标志位置1;voidKey_Init(void){bKeyUp_Flag=1;//标志(全局变量)位置1}//键盘扫描函数,得到键的行列位置;unsignedcharGetScanKey(void){unsignedcharkey,i,temp;unsignedcharxdata*ptr;key=0xff;for(i=1;i0x10;i=1)//i的低4位为行数位,行依次检测循环4次{ptr=0x8fff;*ptr=i;temp=*ptr;//取键盘IO口的值temp&=0x0f;//屏蔽高四位if(temp!=0x00)//是否有有效键值{key=i4;//取行数位的值并将其放入返回值高4位key|=temp;//列数位的值放入返回值低4位break;}}returnkey;//返回行位(高四)和列位(低四)}//取键值,长按无效unsignedcharGetKey(void){unsignedcharkey,temp;if(!bKeyUp_Flag)//判断标志,是0执行/***按键程序执行一次后会将bKeyUp_Flag标志位清零,执行此段程序,长按键无效返回无效值,直至按键无效返回无效按键值,置1标志位。按键输入恢复有效。屏蔽这部分则长按键有效***/{key=GetScanKey();if(key==0xff)//没有按键,置标志位bKeyUp_Flag=1;else//保持按键return0xff;//因为0xff大于15,故为无效键值,实现长按键无效}key=GetScanKey();if(key==0xff)//没有按键returnkey;else//有按键有效temp=key;//取键值Delay_ms(20);//延时20ms消抖key=GetScanKey();//键盘扫描if(key!=temp)//判断两次键值是否相同,排除干扰信号影响确认有效信号{key=0xff;returnkey;}else//取键值{/*这部分主要作用是软件抗干扰*/temp=Key_Value_Table[key4];//见说明/*行值有效位(键盘的4个行SEL返回的值含有的有效位1)有且只有一位键值才有效否则返回无效键值*/if(temp==0xff){key=0xff;returnkey;}temp=Key_Value_Table[key&0x0f];/*列值有效位(键盘的4个列RL返回的值含有的有效位1)有且只有一位键值才有效否则返回无效键值*/if(temp==0xff){key=0xff;returnkey;}key=Key_Value_Table[key4]*4+Key_Value_Table[key&0x0f];//行对应的中间值的四倍与列对应的中间值之和即为按键编号0~15/*行列组合后的值大于15无效*/if(key15){key=0xff;returnkey;}bKeyUp_Flag=0;returnkey;}}//获得键盘输入字符intGetChar(void){unsignedcharkey=0xff;while(key==0xff)key=GetKey();/*waitinputfix*/return((int)key_arrenge[key]);/*changetoASCIIcodeandreturn*/}//获得键盘输入整数longGetDec(void){longout_dec=0;/*result(decimalnumber)数值范围0~99999*/unsignedchari,j;/*variableforcharactercount*/inttemp=0;intkey;for(i=0;i6;){key=GetChar();/*获取键值’0’-’9’*/if((key='9')&&(key='0')){temp=key-'0';/*获取数值0-9*/out_dec=out_dec*10+(long)temp;if(out_dec==0){continue;/*首位数据输入为0时,显示不变*/}i++;LCD__putchar(key);/*显示当前输入的数据*/continue;}if('E'==key)/*当前输入清零*/{out_dec=0;back_cursol(i);/*清显示区*/for(j=0;ji;j++)LCD__putchar('');back_cursol(i);/*清显示区*/continue;}if('F'==key)/*ENTER键,数值确认*/{returnout_dec;}if('C'==key)/*撤销最近一个输入数字*/{out_dec=out_dec/10;back_cursol(1);LCD__putchar('');back_cursol(1);continue;}}}2.LED模块通过送字形码和字位码可以点亮对应的一个8段LED。8个LED的同时显示通过循环扫描显示实现,即每次在一个LED上显示设定的数字,延时显示一段时间(延时越长,亮度越好),然后切换显示下一个,依次轮换。程序代码:unsignedcharLed_table[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};voidDelay_us1(intt){while(t--=0);}//函数功能描述:给显示数组赋初始值;voidLed_Init(unsignedchar*show){unsignedchari;for(i=0;i8;i++){//在此处给显示数组赋值*show=0x00;show++;}}//函数功能描述:在LED上显示;voiddisplay(unsignedchar*show){unsignedchari=1,j;unsignedcharxdata*ptr;for(j=0;j8;j++)//八个数码管全部显示{ptr=0x8fff;//段选地址*ptr=i;ptr=0x9fff;//位选地址//在此给*ptr赋值送字形码*ptr=Led_table[show[j]];Delay_us1(30);*ptr=0x00;i=1;//下一位}}//数字转led字形码unsignedcharasc2led(unsignedchara){return*(Led_table+a);}3.LCD显示模块设计思路:LCD的显示通过给LCD写命令和数据实现。写数据与写指令时各控制引脚的电平不同,对应了不同的地址。先构造写数据和写命令函数(与硬件相关操作),已经检测LCD是否忙的函数(当处于忙状态时不能写数据,否则硬件会工作不正常),在此接口的基础上构造库(与硬件无关操作,通过调用写数据和写命令函数实现),实现各种不同的功能,包括初始化设定工作方式,显示字符,显示字符串,显示数字(0~99999),清屏,设定光标的位置等。这里的显示字符,显示整数和键盘检测模块的读入字符,读入整数对应起来,可以合作使用。使用时先调用初始化函数初始化LCD,设定工作方式,然后可以调用不同的函数实现不同的显示。程序代码:/*=====definevariable=====*/unsignedcharcursol_x;/*cursorposition(horizontal)*/unsignedcharcursol_y;/*cursorpositon(vertical)*/unsignedcharxdata*ptr;//指向XDATA的指针(访问片外地址)unsignedcharcodeASC2_Value_Table[16]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46};//===========向1602指令寄存器写指令=============voidWriteW(unsignedchara){ptr=0xAFF0;//RS=0,R/W=0*ptr=a;}//==============向1602指令寄存器写指数据============voidWriteD(unsignedcharkey_asc2){CheckBF();ptr=0xAF02;*ptr=key_asc2;}//===========检查忙标志位BF=============voidCheckBF(void){unsignedinti;while(1){ptr=0xAFF1;//RS=0,R/W=1i=*ptr;i&=0x80;if(i==0)break;}}//==========LCD初始化==========voidLCD_Init(void){CheckBF();WriteW(0x38);CheckBF();WriteW(0x01);//Cleardisplay清显示CheckBF();WriteW(0x06);//Entrymodeset:I/D=1,S=0[I:Increase,D:Decline,S:Shift]CheckBF();WriteW(0x0F);//Dislpayon/offcontrolD=1,C=1,B=1[D:Display,C:Cursor,B:Blink]CheckBF();WriteW(0x80);//Dislpayon/offcontrolD=0,C=0,B=0[D:Display,C:Cursor,B:Blink]}//======设定光标所在位置==========voidLCD__setcursol(unsignedcharx,unsignedchary){cursol_x=x;/*cursorposition(horizontal)*/cursol_y=y;/*cursorpositon(vertical)*/CheckBF();/*waitLCDprocess*/WriteW(0x80|y*0x40