电子电路设计实验报告_第1页
电子电路设计实验报告_第2页
电子电路设计实验报告_第3页
电子电路设计实验报告_第4页
电子电路设计实验报告_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、电子线路专题实验一、实验要求:1. 认真阅读学习系统线路及相关资料2. 将键盘阵列定义为0. 1. 2- E. F,编程实现将键盘输入内容显示在LCD显示器上。3. 编程实现将日历、时钟显示在LED显示屏上(注意仔细阅读PCF8563资料),日历、时钟轮回显示。4. 利用D/A转换通道(下行通道)实现锯齿波发生器;输出(15V)固定电压转换成(420mA)电流。5. 利用A/D转换通道(上行通道)实现数据采集,将采集信号显示在LED屏上。程序要求分别具有平均值滤波、中值滤波和滑动滤波功能。6. 将按键阵列定义成与16个语音段对应,编写程序,实现按键播放不同的语音段。二、实验设计思路:本次实验用

2、c语言实现,主要包括LCD,LED,AD,DA,日历芯片,测温传感芯片。受到嵌入式系统实验的启发,将LCD,LED,I2C总线协议,键盘扫描模块接口写成一个文件库(放在library文件夹下),尽量做到调用时与底层硬件无关。通过调用库文件中的函数,实现代码的重用性。键盘,LCD的代码由于与嵌入式实验具有相通之处,因此可将高层的函数(与底层硬件无关的函数)方便地移植过来。三、实验设计:1.矩阵键盘扫描模块4×4的矩阵键盘,通过扫描可得到按下键的行列值,将行列值转换为相应的对应数字0F。函数GetKey()实现获得按键的键值。对于键盘模块对于对按键的键值识别主要是通过两次扫描而取得。对于

3、第一次扫描,给四行键全部赋予1,然后读回键盘值,对于第二次扫描,逐行为键盘送1,每次送1后再读回键盘值,若非零,说明此行有键按下,最终确定键值。通过调用GetKey函数构造GetChar()函数,实现获取键盘字符(0F)的功能。通过调用GetChar()函数构造GetDec()函数,实现获取键盘输入整数的功能,整数范围在099999。有按C键回退一格,按E清空当前未完输入,按F键结束输入的功能。程序代码:/键盘初始化,将标志位置1;void Key_Init(void) bKeyUp_Flag=1;/标志(全局变量)位置1/键盘扫描函数,得到键的行列位置;unsigned char GetSc

4、anKey(void)unsigned char key, i, temp;unsigned char xdata * ptr;key=0xff;for (i=1; i<0x10; i<<=1)/i的低4位为行数位,行依次检测循环4次ptr=0x8fff; * ptr =i;temp = * ptr; /取键盘IO口的值temp &= 0x0f; /屏蔽高四位if (temp!=0x00) /是否有有效键值 key = i<<4; /取行数位的值并将其放入返回值高4位key|=temp; /列数位的值放入返回值低4位break;return key; /返

5、回行位(高四)和列位(低四)/取键值,长按无效unsigned char GetKey(void)unsigned char key, temp;if (!bKeyUp_Flag)/判断标志,是0执行/*按键程序执行一次后会将bKeyUp_Flag标志位清零,执行此段程序,长按键无效返回无效值,直至按键无效返回无效按键值,置"1"标志位。按键输入恢复有效。屏蔽这部分则长按键有效*/key=GetScanKey();if (key=0xff)/没有按键,置标志位bKeyUp_Flag=1;else/保持按键return 0xff;/因为0xff大于15,故为无效键值,实现长按

6、键无效key=GetScanKey();if (key=0xff)/没有按键return key;else/有按键有效temp=key;/取键值Delay_ms(20);/延时20ms 消抖key=GetScanKey();/键盘扫描if(key!=temp)/判断两次键值是否相同,排除干扰信号影响确认有效信号key=0xff;return key;else/取键值 /*这部分主要作用是软件抗干扰*/temp=Key_Value_Tablekey>>4;/见说明 /*行值有效位(键盘的4个行SEL返回的值含有的有效位"1")有且只有一位键值才有效否则返回无效键值

7、*/if (temp=0xff) key=0xff;return key; temp=Key_Value_Tablekey&0x0f; /*列值有效位(键盘的4个列RL返回的值含有的有效位"1")有且只有一位键值才有效否则返回无效键值*/if (temp=0xff) key=0xff;return key; key=Key_Value_Tablekey>>4*4+Key_Value_Tablekey&0x0f;/行对应的中间值的四倍与列对应的中间值之和即为按键编号015 /*行列组合后的值大于15无效*/if (key>15) key=0x

8、ff;return key; bKeyUp_Flag=0;return key; /获得键盘输入字符int GetChar(void)unsigned char key=0xff;while(key=0xff)key=GetKey();/* wait input fix*/return (int)key_arrengekey);/* change to ASCII code and return*/获得键盘输入整数long GetDec(void)long out_dec = 0;/* result(decimal number) 数值范围099999*/unsigned char i,j;/

9、* variable for character count*/int temp = 0;int key;for(i = 0;i<6 ; )key =GetChar();/* 获取键值09 */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);/* 显示当前

10、输入的数据 */continue;if('E'= key) /* 当前输入清零 */out_dec = 0;back_cursol(i); /* 清显示区 */for(j=0;j<i;j+)LCD_putchar(' ');back_cursol(i);/* 清显示区 */continue;if('F' = key) /* ENTER键,数值确认 */return out_dec;if('C' = key)/* 撤销最近一个输入数字*/out_dec = out_dec / 10;back_cursol(1);LCD_put

11、char(' ');back_cursol(1);continue;2. LED模块通过送字形码和字位码可以点亮对应的一个8段LED。8个LED的同时显示通过循环扫描显示实现,即每次在一个LED上显示设定的数字,延时显示一段时间(延时越长,亮度越好),然后切换显示下一个,依次轮换。程序代码:unsigned char Led_table16=0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71;void Delay_us1(int t)while(t->=0);/函数

12、功能描述:给显示数组赋初始值;void Led_Init(unsigned char *show)unsigned char i;for (i=0;i<8;i+) /在此处给显示数组赋值 *show= 0x00;show+;/函数功能描述:在LED上显示;void display(unsigned char *show)unsigned char i=1,j;unsigned char xdata *ptr;for (j=0; j<8; j+)/八个数码管全部显示 ptr=0x8fff;/段选地址 *ptr=i;ptr=0x9fff;/位选地址/在此给*ptr赋值送字形码*ptr=

13、Led_tableshowj;Delay_us1(30); *ptr=0x00;i<<=1;/下一位/数字转led字形码unsigned char asc2led(unsigned char a)return *(Led_table+a);3. LCD显示模块设计思路:LCD的显示通过给LCD写命令和数据实现。写数据与写指令时各控制引脚的电平不同,对应了不同的地址。先构造写数据和写命令函数(与硬件相关操作),已经检测LCD是否忙的函数(当处于忙状态时不能写数据,否则硬件会工作不正常),在此接口的基础上构造库(与硬件无关操作,通过调用写数据和写命令函数实现),实现各种不同的功能,包括

14、初始化设定工作方式,显示字符,显示字符串,显示数字(099999),清屏,设定光标的位置等。这里的显示字符,显示整数和键盘检测模块的读入字符,读入整数对应起来,可以合作使用。使用时先调用初始化函数初始化LCD,设定工作方式,然后可以调用不同的函数实现不同的显示。程序代码:/*=define variable =*/unsigned char cursol_x;/* cursor position (horizontal) */unsigned char cursol_y;/* cursor positon (vertical) */unsigned char xdata *ptr;/指向XDA

15、TA的指针(访问片外地址)unsigned char code ASC2_Value_Table16=0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46;/=向1602指令寄存器写指令=void WriteW(unsigned char a) ptr=0xAFF0; /RS=0,R/W=0*ptr=a;/=向1602指令寄存器写指数据=void WriteD(unsigned char key_asc2)CheckBF();ptr=0xAF02; *ptr=key_asc2;/=检查忙标

16、志位BF=void CheckBF(void)unsigned int i;while(1) ptr=0xAFF1;/RS=0,R/W=1 i=*ptr;i&= 0x80;if(i=0)break;/=LCD初始化=void LCD_Init(void)CheckBF();WriteW(0x38);CheckBF();WriteW(0x01);/Clear display 清显示CheckBF();WriteW(0x06);/Entry mode set:I/D=1,S=0 I:Increase,D:Decline,S:ShiftCheckBF();WriteW(0x0F);/Disl

17、pay on/off control D=1,C=1,B=1D:Display,C:Cursor,B:BlinkCheckBF();WriteW(0x80);/Dislpay on/off control D=0,C=0,B=0D:Display,C:Cursor,B:Blink/=设定光标所在位置=voidLCD_setcursol(unsigned char x, unsigned char y)cursol_x = x;/* cursor position (horizontal) */cursol_y = y;/* cursor positon (vertical) */CheckBF

18、();/* wait LCD process */WriteW(0x80| y*0x40 + x);/*address of the second line 0x40-0x4f */=后移光标=voidmove_cursol(void)if(+cursol_x > 0x0f)/* move cursor to right, if get to end of the line */cursol_x = 0;/* move to begin of the line */if(+cursol_y >= 2)/* return, if over the second line */curs

19、ol_y = 0;/* return to begin of the line */LCD_setcursol(cursol_x, cursol_y);/* set cursor */=前移光标=voidback_cursol(int i)cursol_x -= i;LCD_setcursol(cursol_x, cursol_y);/* set cursor */=清屏=void LCD_clear(void)CheckBF();/* wait LCD process */WriteW(0x01);/* clear display */=写字符=voidLCD_putchar(int c)i

20、f(c = 'n')|(c = 'r')/* line feed code*/cursol_x = 0;cursol_y = 1;LCD_setcursol(cursol_x, cursol_y);/* set cursor*/CheckBF();/* wait LCD process*/WriteD(c);/* write Data-Register*/CheckBF();/* wait LCD process*/move_cursol();/* move cursor position*/=写字符串=voidLCD_puts(const unsigned c

21、har *s)for(; '0' != *s; s+)/* loop before null code */LCD_putchar(*s);/* display character on LCD */=写整数=voidLCD_putdec(long dec) /* 可打印的数据小于99999 */long num ;/* number to be displayed*/int i;/* loop counter*/unsigned char str_buf5;/* buffer for data display*/num = dec;/* save number to be d

22、isplayed */for(i = 0 ;num != 0; i+)/* confirm digit*/str_bufi = num % 10;/* get every digit number and save in buffer*/num= num / 10;if(i = 0)/* if number is 0*/LCD_putchar('0');/* display '0' in LCD*/else/* if number is not 0*/for(-i; i >= 0; i-)/* loop times of digits*/LCD_putch

23、ar(str_bufi + '0');/* after transfered into ASCII code*/* display in LCD*/ /十六进制码转换为ascii码unsigned char Key_ASC2(unsigned char key)unsigned char key_asc2;key_asc2=ASC2_Value_Tablekey;return key_asc2;4.I2C总线协议I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。I2C总线在传送数据过程中共有三种类型信号,它们分别是:开始信号、结束信号和应答信号。 

24、; 开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。  结束信号:SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。  应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。协议代码:sbit SCL=P10;sbit SDA=P11;/*/*功能:启动I2C总线/*void i2c_start() SDA=1;SCL=1;_n

25、op_();_nop_();SDA=0;_nop_();_nop_();SCL=0;/*/*功能:停止I2C总线/*void i2c_stop()SDA=0;SCL=0;_nop_();_nop_();SCL=1; _nop_();_nop_();SDA=1;/*/*功能:应答I2C总线/*bit i2c_rec_ack()bit ack_flag;SDA=1;_nop_();_nop_();SCL=1;_nop_();_nop_();if(SDA=0)ack_flag=1;elseack_flag=0;SCL=0;returnack_flag; void i2c_send_ack(void)

26、SDA=0;_nop_();_nop_();SCL=1;_nop_();_nop_();SCL=0;_nop_();_nop_();SDA=1;/*/*功能:无应答I2C总线/*void i2c_send_noack()SDA=1;_nop_();_nop_();SCL=1; _nop_();_nop_();SCL=0;/*/*功能:往I2C总线发送数据/*void i2c_send_byte(unsigned char data_byte)unsigned char i;for(i=0;i<8;i+)SDA=(bit)(data_byte&0x80);_nop_();_nop_

27、();SCL=1;_nop_();_nop_();SCL=0;data_byte<<=1;/*/*功能:从I2C总线接受数据/*unsigned char i2c_rec_byte()unsigned char i, temp;temp=0;for(i=0;i<8;i+)temp<<=1;SCL=1;_nop_();_nop_();if(SDA=1)temp|=0x01;SCL=0; return(temp);/*/*功能:往I2C总线上器件指定地址写字节的数据/*bit i2c_write_byte(unsigned char sla,unsigned char

28、 data_addr,unsigned char data_byte)i2c_start();/发送I2C START信号i2c_send_byte(sla);/发送器件从地址if(i2c_rec_ack()=0)/检测应答信号return 0;i2c_send_byte(data_addr);/发送数据地址if(i2c_rec_ack()=0)/检测应答信号return 0;i2c_send_byte(data_byte);if(i2c_rec_ack()=0)return 0;i2c_stop();/发送I2C STOP信号return 1; /*/*功能:往I2C总线上器件指定地址开始写

29、指定长度的数据/*bit i2c_write_nbyte(unsigned char sla,unsigned char data_addr,unsigned char *ptr,unsigned char len)i2c_start();/发送I2C START信号i2c_send_byte(sla);/发送器件从地址if(i2c_rec_ack()=0)/检测应答信号return 0;i2c_send_byte(data_addr);/发送数据地址if(i2c_rec_ack()=0)/检测应答信号return 0;for(;len>0;len-)/连续发送LEN长度的字节数据i2c

30、_send_byte(*ptr+);if(i2c_rec_ack()=0)return 0;i2c_stop();/发送I2C STOP信号return 1; /*/*功能:从I2C总线上器件指定地址接收一个字节的数据/*unsigned char i2c_read_byte(unsigned char sla,unsigned char data_addr)unsigned int temp;i2c_start();/发送I2C START信号i2c_send_byte(sla);/发送从器件写命令if(i2c_rec_ack()=0)/检测应答信号return 0;i2c_send_byt

31、e(data_addr);/发送数据地址if(i2c_rec_ack()=0)/检测应答信号return 0;i2c_start();/重新发送I2C START信号i2c_send_byte(sla|0x01);/发送器件从器读命令if(i2c_rec_ack()=0)/检测应答信号return 0;temp=i2c_rec_byte();i2c_send_noack();/接收最后一个字节后发送NOACK信号i2c_stop();/发送I2C STOP信号return temp;/*/*功能:从I2C总线上器件指定地址接收一个字节的数据/*bit i2c_read_nbyte(unsign

32、ed char sla,unsigned char data_addr,unsigned char *ptr,unsigned char len)i2c_start();/发送I2C START信号i2c_send_byte(sla);/发送从器件写命令if(i2c_rec_ack()=0)/检测应答信号return 0;i2c_send_byte(data_addr);/发送数据地址if(i2c_rec_ack()=0)/检测应答信号return 0;i2c_start();/重新发送I2C START信号i2c_send_byte(sla|0x01);/发送器件从器读命令if(i2c_re

33、c_ack()=0)/检测应答信号return 0;for(;len>1;len-)/连续接收LEN-1长度的字节数据*ptr+=i2c_rec_byte();i2c_send_ack();/发送ACK信号*ptr=i2c_rec_byte();/接收最后一个字节i2c_send_noack();/发送NOACK信号i2c_stop();/发送I2C STOP信号return 1;5. AD模块(SPI总线)利用TLC1549实现,TLC1549可以将输入的模拟量转换成数字量,并且是10位数字量,然后也是利用SPI总线一位一位的发送,因此需要传两字节的数据,高地址中的低两位有效,低地址中

34、的八位都有效,传送过程结合时序图进行编程。模块使用的函数是模块驱动程序参考中的函数sbit SCLK=P12;sbit DIO=P13;sbit ADCS=P14;sbit DACS=P15;void Before_Once_AD(void);/预采集uint adc_1549(void) ;/读取AD输出的10bit数据6. DA模块(SPI总线)利用TLC5615实现的,TLC5615也是利用SPI总线一位一位的传送,并且要求传送的数据是12位,因此需要传两字节的数据,分别放在HIGHD和LOWD中,12位数据是HIGHD中的八位和LOWD中的高四位,但是12为数据中的低两位又是无效的,所

35、以只有10位有效数字。模块使用的函数是模块驱动程序参考中的函数 /函数功能描述:驱动TLC5615开始DA转换/dat为被转换的数字量void tlc5615(uint dat) ;7.日历芯片PCF8563 是低功耗的CMOS 实时时钟日历芯片,它提供一个可编程时钟输出,一个中断输出和掉电检测器,所有的地址和数据通过I2 C 总线接口串行传递。每次读写数据后,内嵌的字地址寄存器会自动产生增量。按I2C 总线协议规约PCF8563 有唯一的器件地址0A2H。因此,可以由CPU把初始化的日历时钟通过总线接口串行传递写入PCF8563,由PCF8563以此为起点自动计时,再通过I2C总线串行接口从

36、PCF8563读出内部的日历/时钟。这部分主要是在I2C总线协议的基础上进行通信,向芯片指定地址写入控制字,写入时间数据或读出时间数据。由于芯片中的实际数据都是以BCD码形式存储,因此通信时需要进行十六进制数和BCD码的互相转换。具体设计函数包括向芯片写入时间,从芯片读出时间,码制转换。程序代码:/8bit 十六进制转bcd码unsigned char NUM2BCD(unsigned char x)return (x)/10)<<4)|(x%10);/8bit bcd码转十六进制unsigned char BCD2NUM(unsigned char x) return (x)&g

37、t;>4)*10+(x)&0x0f);/*-函数说明:写入时间:秒,分,时,日,星期,月,年,BCD码-*/void wt_time(unsigned char *t)i2c_write_byte(0xA2,0x00,0x00);/开始计时i2c_write_nbyte(0xA2,0x02,t,7);/写入时间/*-读时间-*/void rd_time(unsigned char *time)int i;unsigned char addr=0x02;unsigned char temp;for(i=0;i<7;i+)temp=i2c_read_byte(0xA2,addr

38、); if(i=0|i=1) /去掉无效位 /秒,分temp&=0x7f; if(i=2|i=3) /时,日temp&=0x3f; if(i=4) /星期temp&=0x07; if(i=5) /月temp&=0x1f;timei=temp; /Delay_ms(50); Delay_us(100); addr=addr+1; /页读须软件累加地址8语音芯片这部分直接使用了模块驱动程序参考中的函数,ISD_WR_APC2(uchar voiceValue)函数可以调节音量,0xa8对应最大音量,0xaf对应最小音量。play_open(unsigned int

39、AddST,unsigned int AddEN)函数可以根据播放的首尾地址播放不同的音乐。9.库文件定义和使用一个模块的文件包括头文件(*.h)和源文件(*.c)。在头文件中进行函数的声明,在对应源文件中将头文件首先包含进来,然后对函数进行具体定义实现。使用时用到了某个模块,先将头文件include进来,然后在工程中添加对应的C文件。千万不要忽略了头文件中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。还是把头文件的内容都放在#ifndef和#endif中吧

40、。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:#ifndef <标识>#define <标识>.#endif四、实验过程:1.键盘和LCD的测试功能描述:初始状态:LCD上第一行显示"0:get char",第二行显示"1:get decimal"。按0进入获取字符并显示的状态,按字符F退出返回初始状态,按1进入获取整数并显示状态(整数范围:099999),当键入99999时退出返回初始状态。主要代码:#lcdtest.c#void main(void)unsigned char key,flag;lon

41、g dec;LCD_Init();/lcd初始化Key_Init();LCD_clear();while(1)LCD_setcursol(0,0);LCD_puts("0:get char");LCD_setcursol(0,1);LCD_puts("1:get decimal");flag=GetChar();if(flag='0'|flag='1')break;LCD_clear();LCD_setcursol(0,0);while(1)if(flag='0')key=GetChar();LCD_put

42、char(key);if(key='F')break;/当按F时跳出if(flag='1')LCD_setcursol(0,0);dec=GetDec();LCD_clear();LCD_putdec(dec);if(dec=99999)break;/当输入整数为99999时跳出2.LCD和LED显示日历功能描述:初始状态LCD显示欢迎界面,提示按F键进入,按F后进入提示菜单,按0选择程序中默认的日期设定,按1选择手动设定日期,依次按照提示键入日期。日期设定后在LCD上显示全部日期信息,LED上显示时分秒。主要代码:#calendar.c#unsigned ch

43、ar show8=0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00;/led显示数值表unsigned char time7=0x01;/秒,分,时,日,星期,月,年(BCD码)/*-函数说明:软件设定时间:秒,分,时,日,星期,月,年,BCD码-*/void set_time(unsigned char *time)LCD_clear();LCD_setcursol(0,0);LCD_puts("Set year(099):");LCD_setcursol(0,1);time6=NUM2BCD(unsigned char)(GetDec();

44、LCD_clear();LCD_setcursol(0,0);LCD_puts("Set month(112):");LCD_setcursol(0,1);time5=NUM2BCD(unsigned char)(GetDec();LCD_clear();LCD_setcursol(0,0);LCD_puts("Set day:");LCD_setcursol(0,1);time3=NUM2BCD(unsigned char)(GetDec();LCD_clear();LCD_setcursol(0,0);LCD_puts("Set weekday(06):");LCD_setcursol(0,1);time4=NUM2BCD(unsigned char)(GetDec();LCD_clear();LCD_setcursol(0,0);LCD_puts("Set hour(023):");LCD_setcursol(0,1);time2=NUM2BCD(unsigned char)(GetDec();LCD_clear();LCD_setcursol(0,0);LCD_puts(&

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论