电子电路设计实验报告

时间:2024.4.7

电子线路专题实验Ⅱ

一、实验要求:

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;

void Key_Init(void)

{

bKeyUp_Flag=1;//标志(全局变量)位置1

}

//键盘扫描函数,得到键的行列位置;

unsigned char GetScanKey(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; //返回行位(高四)和列位(低四) }

//取键值,长按无效

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,故为无效键值,实现长按键无效 }

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_Table[key>>4]; //见说明

/*行值有效位(键盘的4个行SEL返回的值含有的有效位"1")有且只有一位键值才有效否则返回无效键值*/

if (temp==0xff)

{

key=0xff;

return key;

}

temp=Key_Value_Table[key&0x0f];

/*列值有效位(键盘的4个列RL返回的值含有的有效位"1")有且只有一位键值才有效否则返回无效键值*/

if (temp==0xff)

{

key=0xff;

return key;

}

key=Key_Value_Table[key>>4]*4+Key_Value_Table[key&0x0f];//行对应的中间值的四倍与列对应的中间值之和即为按键编号0~15

/*行列组合后的值大于15无效*/

if (key>15)

{

key=0xff;

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_arrenge[key]);

/* change to ASCII code and return */

}

//获得键盘输入整数

long GetDec(void)

{

long out_dec = 0; /* result(decimal number) 数值范围0~99999 */

unsigned char i,j; /* variable for character count */ int temp = 0;

int key;

for(i = 0;i<6 ; )

{

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;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__putchar(' ');

back_cursol(1);

continue;

}

}

}

2. LED模块

通过送字形码和字位码可以点亮对应的一个8段LED。8个LED的同时显示通过循环扫描显示实现,即每次在一个LED上显示设定的数字,延时显示一段时间(延时越长,亮度越好),然后切换显示下一个,依次轮换。

程序代码:

unsigned char Led_table[16]={0x3f,0x06,0x5b,0x4f,0x66,

0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71

};

void Delay_us1(int t)

{

while(t-->=0);

}

//函数功能描述:给显示数组赋初始值;

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=Led_table[show[j]];

Delay_us1(30);

*ptr=0x00;

i<<=1;//下一位

}

}

//数字转led字形码

unsigned char asc2led(unsigned char a)

{

return *(Led_table+a);

}

3. LCD显示模块

设计思路:

LCD的显示通过给LCD写命令和数据实现。写数据与写指令时各控制引脚的电平不同,对应了不同的地址。先构造写数据和写命令函数(与硬件相关操作),已经检测LCD是否忙的函数(当处于忙状态时不能写数据,否则硬件会工作不正常),在此接口的基础上构造库(与硬件无关操作,通过调用写数据和写命令函数实现),实现各种不同的功能,包括初始化设定工作方式,显示字符,显示字符串,显示数字(0~99999),清屏,设定光标的位置等。这里的显示字符,显示整数和键盘检测模块的读入字符,读入整数对应起来,可以合作使用。

使用时先调用初始化函数初始化LCD,设定工作方式,然后可以调用不同的函数实现不同的显示。

程序代码:

/*===== define variable =====*/

unsigned char cursol_x; /* cursor position (horizontal) */ unsigned char cursol_y; /* cursor positon (vertical) */

unsigned char xdata *ptr;//指向XDATA的指针(访问片外地址)

unsigned char code ASC2_Value_Table[16]=

{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;

}

//===========检查忙标志位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:Shift] CheckBF();

WriteW(0x0F);//Dislpay on/off control D=1,C=1,B=1[D:Display,C:Cursor,B:Blink] CheckBF();

WriteW(0x80);//Dislpay on/off control D=0,C=0,B=0[D:Display,C:Cursor,B:Blink] }

//======设定光标所在位置==========

void LCD__setcursol(unsigned char x, unsigned char y)

{

cursol_x = x; /* cursor position (horizontal) */ cursol_y = y; /* cursor positon (vertical) */ CheckBF(); /* wait LCD process */ WriteW(0x80 | y*0x40 + x); /* address of the second line 0x40-0x4f */

}

//======后移光标=======

void move_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 */ cursol_y = 0; /* return to begin of the line */ }

LCD__setcursol(cursol_x, cursol_y); /* set cursor */

}

}

//======前移光标=======

void back_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 */

}

//=======写字符==========

void LCD__putchar(int c)

{

if((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 */ }

//=========写字符串========

void LCD__puts(const unsigned char *s)

{

for(; '\0' != *s; s++)

{ /* loop before null code */ LCD__putchar(*s); /* display character on LCD */

}

}

//=========写整数=======

void LCD__putdec(long dec) /* 可打印的数据小于99999 */

{

long num ; /* number to be displayed */ int i; /* loop counter */ unsigned char str_buf[5]; /* buffer for data display */

num = dec; /* save number to be displayed */

for(i = 0 ;num != 0; i++)

{ /* confirm digit */ str_buf[i] = 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__putchar(str_buf[i] + '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_Table[key];

return key_asc2;

}

4.I2C总线协议

I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。I2C总线在传送数据过程中共有三种类型信号,它们分别是:开始信号、结束信号和应答信号。

开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。 结束信号:SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。 应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。

协议代码:

sbit SCL=P1^0;

sbit SDA=P1^1;

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

//*功能:启动I2C总线

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

void i2c_start()

{

SDA=1;

SCL=1;

_nop_();

_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;

}

else

{

ack_flag=0;

}

SCL=0;

return ack_flag;

}

void i2c_send_ack(void)

{

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_();

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 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总线上器件指定地址开始写指定长度的数据 //***************************************

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_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_byte(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(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;

}

i2c_start(); // 重新发送I2C START信号 i2c_send_byte(sla|0x01); // 发送器件从器读命令 if(i2c_rec_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总线一位一位的发送,因此需要传两字节的数据,高地址中的低两位有效,低地址中的八位都有效,传送过程结合时序图进行编程。

模块使用的函数是模块驱动程序参考中的函数

sbit SCLK=P1^2;

sbit DIO=P1^3;

sbit ADCS=P1^4;

sbit DACS=P1^5;

void Before_Once_AD(void);//预采集

uint adc_1549(void) ;//读取AD输出的10bit数据

6. DA模块(SPI总线)

利用TLC5615实现的,TLC5615也是利用SPI总线一位一位的传送,并且要求传送的数据是12位,因此需要传两字节的数据,分别放在HIGHD和LOWD中,12位数据是HIGHD中的八位和LOWD中的高四位,但是12为数据中的低两位又是无效的,所以只有10位有效数字。模块使用的函数是模块驱动程序参考中的函数

//函数功能描述:驱动TLC5615开始DA转换

//dat为被转换的数字量

void tlc5615(uint dat) ;

7.日历芯片

PCF8563 是低功耗的CMOS 实时时钟/日历芯片,它提供一个可编程时钟输出,一个中断输出和掉电检测器,所有的地址和数据通过I2 C 总线接口串行传递。每次读写数据后,内嵌的字地址寄存器会自动产生增量。按I2C 总线协议规约PCF8563 有唯一的器件地址0A2H。因此,可以由CPU把初始化的日历时钟通过总线接口串行传递写入PCF8563,由PCF8563以此为起点自动计时,再通过I2C总线串行接口从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)>>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);

if(i==0||i==1) //去掉无效位 //秒,分

temp&=0x7f;

if(i==2||i==3) //时,日

temp&=0x3f;

if(i==4) //星期

temp&=0x07;

if(i==5) //月

temp&=0x1f;

time[i]=temp;

//Delay_ms(50);

Delay_us(100);

addr=addr+1; //页读须软件累加地址

}

}

8.语音芯片

这部分直接使用了模块驱动程序参考中的函数,ISD_WR_APC2(uchar voiceValue)函数可以调节音量,0xa8对应最大音量,0xaf对应最小音量。play_open(unsigned int AddST,unsigned int AddEN)函数可以根据播放的首尾地址播放不同的音乐。

9.库文件定义和使用

一个模块的文件包括头文件(*.h)和源文件(*.c)。在头文件中进行函数的声明,在对应源文件中将头文件首先包含进来,然后对函数进行具体定义实现。使用时用到了某个模块,先将头文件include进来,然后在工程中添加对应的C文件。

千万不要忽略了头文件中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。

还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:

#ifndef <标识>

#define <标识>

……….

#endif

四、实验过程:

1.键盘和LCD的测试

功能描述:

初始状态:LCD上第一行显示"0:get char",第二行显示"1:get decimal"。按0进入获取字符并显示的状态,按字符’F’退出返回初始状态,按1进入获取整数并显示状态(整数范围:0~99999),当键入99999时退出返回初始状态。 主要代码:

###[lcdtest.c]###

void main(void)

{

unsigned char key,flag;

long 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__putchar(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 char show[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};//led显示数值表

unsigned char time[7]={0x01};//秒,分,时,日,星期,月,年(BCD码) /*-----------------------------------------------

函数说明:软件设定时间:秒,分,时,日,星期,月,年,BCD码

-----------------------------------------------*/

void set_time(unsigned char *time)

{

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("Set year(0~99):");

LCD__setcursol(0,1);

time[6]=NUM2BCD((unsigned char)(GetDec()));

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("Set month(1~12):");

LCD__setcursol(0,1);

time[5]=NUM2BCD((unsigned char)(GetDec()));

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("Set day:");

LCD__setcursol(0,1);

time[3]=NUM2BCD((unsigned char)(GetDec()));

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("Set weekday(0~6):");

LCD__setcursol(0,1);

time[4]=NUM2BCD((unsigned char)(GetDec()));

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("Set hour(0~23):");

LCD__setcursol(0,1);

time[2]=NUM2BCD((unsigned char)(GetDec()));

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("Set minute(0~59):");

LCD__setcursol(0,1);

time[1]=NUM2BCD((unsigned char)(GetDec()));

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("Set second(0~59):");

LCD__setcursol(0,1);

time[0]=NUM2BCD((unsigned char)(GetDec()));

}

/*-----------------------------------------------

函数说明:软件设定缺省时间:秒,分,时,日,星期,月,年,BCD码 -----------------------------------------------*/

//将2011 年6 月13 日星期一下午3 点(15 点)59 分30 秒的时间写入PCF8563 void set_default_time(unsigned char *t)

{

t[0]=0x30;

t[1]=0x59;

t[2]=0x15;

t[3]=0x13;

t[4]=0x01;

t[5]=0x06;

t[6]=0x11;

}

//--------------日历显示--------------

void CalendarDisp(unsigned char * time)

{

//---------------LCD显示-----------------------

LCD__setcursol(0,0);

//year

LCD__putchar('2');

LCD__putchar('0');

LCD__putchar(Key_ASC2((time[6]>>4)&0x0f));

LCD__putchar(Key_ASC2(time[6]&0x0f));

LCD__putchar('-');

//month

LCD__putchar(Key_ASC2((time[5]>>4)&0x0f));

LCD__putchar(Key_ASC2(time[5]&0x0f));

LCD__putchar('-');

//day

LCD__putchar(Key_ASC2((time[3]>>4)&0x0f)); LCD__putchar(Key_ASC2(time[3]&0x0f)); LCD__putchar(' ');

//weekday

switch(time[4])

{

case 0:LCD__puts("Sun");break;

case 1:LCD__puts("Mon");break;

case 2:LCD__puts("Tue");break;

case 3:LCD__puts("Wed");break;

case 4:LCD__puts("Thu");break;

case 5:LCD__puts("Fri");break;

case 6:LCD__puts("Sat");break;

}

LCD__setcursol(0,1);

//hour

LCD__putchar(Key_ASC2((time[2]>>4)&0x0f)); LCD__putchar(Key_ASC2(time[2]&0x0f)); LCD__putchar(':');

//minute

LCD__putchar(Key_ASC2((time[1]>>4)&0x0f)); LCD__putchar(Key_ASC2(time[1]&0x0f)); LCD__putchar(':');

//second

LCD__putchar(Key_ASC2((time[0]>>4)&0x0f)); LCD__putchar(Key_ASC2(time[0]&0x0f)); //---------------LCD显示_end----------------------- //---------------LED显示----------------------- show[7]=show[6]=0;

show[5]=time[2]>>4;

show[4]=time[2]&0x0f;

show[3]=time[1]>>4;

show[2]=time[1]&0x0f;

show[1]=time[0]>>4;

show[0]=time[0]&0x0f;

display(show);

//Delay_ms(20);

//---------------LED显示_end----------------------- }

//*********main***************** void main(void)

{

unsigned char key,i;

LCD_Init();//lcd初始化

Key_Init();

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("----Calendar----");

LCD__setcursol(0,1);

LCD__puts("press F to start");

while(GetChar()!='F');

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("0 autoset");

LCD__setcursol(0,1);

LCD__puts("1 manualset");

while(1)

{

key=GetChar();

if(key=='0')

{

set_default_time(time);

break;

}

if(key=='1')

{

set_time(time);

break;

}

}

wt_time(time);

LCD__clear();

while(1)

{

rd_time(time);

CalendarDisp(time);

if(GetKey()!=0xff)break;//当按任意键时跳出

}

}

//*********main_end*****************

3.D/A通道锯齿波发生器

功能描述:

初始状态LCD显示界面,按1产生方波,按2产生锯齿波。调节示波器扫描周期和幅值可以观察到DA的输出端口的输出的波形。

主要代码:

###[da.c]###

void main(void)

{

uint dat=0x0000;

uchar key;

LCD_Init();

LCD__setcursol(0,0);

LCD__puts("1square"); LCD__setcursol(0,1);

LCD__puts("2sawtooth"); while(1)

{

key=GetChar();

if(key=='1'||key=='2')break; }

LCD__clear();

while(1)

{

if(key=='1')//方波 {

LCD__setcursol(0,0); LCD__puts("square"); tlc5615(0);

Delay_us(100); tlc5615(512); Delay_us(100); }

if(key=='2')//锯齿波 {

LCD__setcursol(0,0); LCD__puts("sawtooth"); if(dat<512)

dat=dat+10; //步进 else dat=0;

tlc5615(dat); Delay_us(5); }

if((GetKey())!=0xff){break;} }

}

4.A/D通道读取电压显示在LCD上 功能描述:

将J3口的1,2用导线短接,调节电位器R20,使电压从0~5v改变。初始

状态下LCD显示界面,按1进行均值滤波,按2键进行中值滤波,按3键进行滑动平均滤波。假设采样数据为N个,均值滤波是将N个数据求取平均值,中值滤波是先将N个数据排序,然后取中值,滑动平均滤波是每次用新采样的m个数据替换最老的m个数据(m<N),然后将N个数据进行均值滤波。每次按一个键更新一次电压显示值,按’F’键返回主界面。

主要代码:

###[ad.c]###

#define NUM 4//滤波样本数据个数

//函数功能描述;预先采集;

void Before_Once_AD(void)

{

uchar i;

SCLK=DIO=0;

ADCS=0; //开启控制电路,使能DATA OUT和I/O CLOCK

for(i=1;i<=10;i++)

{

SCLK=1;

_nop_();

SCLK=0;

_nop_();

}

ADCS=1;

Delay_us(25);//两次转换间隔大于21us

}

//排序函数

void sort(uint *Array)

{

uchar i,j;

uint temp;

for(i=0;i<NUM-1;i++)

{

for(j=i+1;j<NUM;j++)

{

if(Array[i]>Array[j])

{

temp=Array[i];

Array[i]=Array[j];

Array[j]=temp;

}

}

}

}

//平均值滤波

uint ad_FilterAverage(uint *Array)

{

uchar i;

uint sum=0;

for (i=0;i<NUM;i++)sum+=Array[i]; return sum/NUM;

}

//中值滤波

uint ad_FilterMedia(uint *Array) {

sort(Array);

return Array[NUM/2+1];

}

//滑动平均滤波

uint ad_FilterSlide(uint *Array)

{

uchar i;

for(i=0;i<NUM-1;i++)Array[i]=Array[i+1]; Array[NUM-1]=adc_1549();

return ad_FilterAverage(Array); }

void main(void)

{

uint ad,da;

uchar temp,i,key;

uint Array[NUM];

float fad;

uint lad;

LCD_Init();

LCD__setcursol(0,0);

LCD__puts("1average 2media");

LCD__setcursol(0,1);

LCD__puts("3slide");

while(1)

{

key=GetChar();

if(key=='1'||key=='2'||key=='3')break; }

Before_Once_AD();

for(i=0;i<NUM;i++)Array[i]=adc_1549(); LCD__clear();

while(1)

{

Before_Once_AD();

switch (key)

{

case '1'://平均值滤波

for(i=0;i<NUM;i++)Array[i]=adc_1549();

ad=ad_FilterAverage(Array);

LCD__setcursol(0,0);

LCD__puts("Average filter");

break;

case '2'://中值滤波

for(i=0;i<NUM;i++)Array[i]=adc_1549();

ad=ad_FilterMedia(Array);

LCD__setcursol(0,0);

LCD__puts("Medium filter");

break;

case '3'://滑动平均滤波

ad=ad_FilterSlide(Array);

LCD__setcursol(0,0);

LCD__puts("Slide filter");

break;

}

fad=(float)(ad)/1024.0*5.0; //转化为模拟电压值

lad=(uint)(fad*10000);//放大

LCD__setcursol(0,1);

LCD__putdec(lad);

if(GetChar()=='F')break;

}

}

5.语音芯片模块

功能描述:

按0~B键选择不同声音播放,按C键减音量,按D键加音量。 主要代码:

###[voice.c]###

//--------------主函数,可选择录音,调节音量------------------------------------ void main(void)

{

uchar key=0xff;

LCD_Init();

ISD_Init();

ISD_WR_APC2(voice);

while(1){

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("voice1-13");

LCD__setcursol(0,1);

LCD__puts("chvo:down13/up14");

select_voice(key);

key=0xff;

while(key==0xff)

{

key=GetKey();

}

}

}

//根据键值选择播放的音乐

void select_voice(uchar key)

{

switch(key)

{

case 13:changevoice(0); //调低音量

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("voice down");break;

case 14:changevoice(1);//调高音量

LCD__clear();

LCD__setcursol(0,0);

LCD__puts("voice up");break;

case 15:break;

default:play_open(Audio_Addr[key],Audio_Addr[key+1]);break;//选择歌曲 }

}

//音量调节函数

void changevoice(uchar flag)

{

if (flag==0&&voice<0xaf)//调小音量

{

voice++;

}

else if(flag==1&&voice>0xa8)//调大音量

{

voice--;

}

ISD_WR_APC2(voice);

}

五、心得体会:

本次实验主要学习了一些单片机与CPU与外设通信和控制协议,包括I2C总

线,SPI总线,DS18B20的单总线通信等。通过实验,让我认识到实验板的强大功能,也让我看到了单片机等嵌入式系统的广泛应用。

最后感谢老师在实验中的耐心指导和帮助!

更多相关推荐:
电子电路设计实验报告

电专业班级二班学号姓名贺成林11级应用电子技术1103720xx307子线路实验报告日期20xx年11月12日PSpice92电子电路设计与仿真实验报告一实验目的学会用PSpice92设计与仿真一个单级共射放大...

电子设计与实习实验报告

电子实习与设计报告姓名张伟学号20xx0612专业机械工程及自动化一目的与要求电子实习与设计是一门重要的实践课程通过实习加深对课堂知识的理解初步了解和掌握一般电子产品安装焊接工艺的基本知识和操作方法掌握部分专用...

电子设计实验报告

《简易正弦波发生器设计、调试报告》第五组成员:一.设计目标1.频率可调,分辨率为1Hz2.频率由LED数码管显示并可按位置数3.输出幅度:1Vp-p(1kohm)4.提高部分:即可能拓展频率范围(低端和高端),…

电子设计竞赛实验报告

电子设计竞赛报告题目多功能测量仪专业电子信息工程小组飞翔一队姓名学号张勇08021231李翔08021211王赓08021204指导教师王薇完成日期20xx年5月目录一选题与设计要求二电路设计方案论证三程序设计...

电子设计实验报告

成都理工大学电子技术课程设计报告GM计数管读出电路设计20xx06090112左卓核技术工程系二一二年六月成都理工大学20xx级本科课程设计报告GM计数管读出电路设计作者姓名左卓学号20xx06090112摘要...

电子设计实验报告

电子系统设计实验报告姓名李浩然指导老师贾立新班级自动化0903学院信息工程学院提交日期20xx124一设计题目基于SOC单片机的数字化语音存储与回放系统设计要求1前置放大器增益可调功率放大器输出功率05W2带通...

数字时钟设计实验报告

电子课程设计题目数字时钟数字时钟设计实验报告一设计要求设计一个24小时制的数字时钟要求计时显示精度到秒有校时功能采用中小规模集成电路设计发挥增加闹钟功能二设计方案由秒时钟信号发生器计时电路和校时电路构成电路秒时...

电子设计自动化实验报告 7段数码显示译码器

电子设计自动化实验报告学号姓名实验一1实验名称7段数码显示译码器2实验目的学习7段数码显示译码器的Verilog硬件设计3实验原理7段数码是纯组合电路通常的小规模专用IC如74或4000系列的器件只能作十进制B...

数字电子技术课程设计实验报告+基于交通灯的设计

数字电子技术课程设计实验报告lt一gt课程性质数字逻辑课程设计lt二gt课程目的训练学生综合地运用所学的数字逻辑的基本知识使用电脑EWB仿真技术独立完整地设计一定功能的电子电路以及仿真和调试等的综合能力本次电脑...

厦门大学电子技术实验报告

实验二电路元器件的认识与测量一实验目的1认识电路元器件的性能和规格学会正确选用元器件2掌握电路元器件的测量方法了解它们的特性和参数3了解晶体管特性图示仪基本原理和使用方法二实验原理一电阻1电阻器电位器的型号命名...

电子技术实验报告_基本共射放大电路

学生实验报告电子技术实验报告_基本共射放大电路

电子技术实验报告

学生实验报告

电子设计实验报告(25篇)