电子线路设计专题实验报告西安交通大学.docx
《电子线路设计专题实验报告西安交通大学.docx》由会员分享,可在线阅读,更多相关《电子线路设计专题实验报告西安交通大学.docx(31页珍藏版)》请在冰豆网上搜索。
电子线路设计专题实验报告西安交通大学
XX交通大学
电子信息与工程学院自动化科学与技术系
电子线路设计专题实验报告
实验名称 :
电子线路设计专题实验
实验者XX:
XX
实验者学号:
21105040XX
所在班级:
自动化1X
报告完成日期:
2021年5月11日
一、实验目的;
〔1〕熟悉单片机原理;
〔2〕掌握开发板上常见芯片的功能与用法;
〔3〕掌握单片机的开发软件:
KELL
〔4〕应用单片机,做一些简单的小应用〔电子时钟等〕
二、实验内容:
〔1〕创立一个工程将键盘阵列定义为0.1.2------E.F,编程实现键盘设置当前时间,再调用系统时钟,显示在LED显示屏上〔注意仔细阅读PCF8563资料〕,键盘设置当前日期显示在LCD显示屏上。
〔2〕利用D/A转换通道〔下行通道〕实现锯齿波发生器;输出〔1~5V〕固定电压转换成〔4~20mA〕电流。
〔3〕利用A/D转换通道〔上行通道〕实现数据采集,将采集信号显示在LED屏上。
程序要求分别具有平均值滤波、中值滤波和滑动滤波功能。
三、开发板简介:
图1 PH-I型51MCU学习系统实物照片
简介:
四、功能实现与关键代码:
〔1〕电子时钟:
在这一局部,有几个很重要的的程序模块:
包含1602初始化、写控制字、写字符等几个函数的1602.h;包含根据
总线协议编写的字节及多字节传输和接收函数的viic.h;实现键盘读取操作的key.h;实现不断读取时间芯片的值并显示在1602和led上显示日期时间的read函数等.以下是这几个重要的模块以及主函数程序。
1602.h〔包含1602初始化、写控制字、写字符等函数〕
//********检测是否忙、写控制字、写数据等********//
voidWriteW(uinta)
{
ptr=0xAFF0;
*ptr=a;
}
voidCheckBF(void)
{
uinti;
while
(1)
{
ptr=0xAFF1;
i=*ptr;
i&=0x80;
if(i==0)
break;
}
}
voidLCD_Init(void)
{
CheckBF();
WriteW(0x38);
CheckBF();
WriteW(0x01);
CheckBF();
WriteW(0x06);
CheckBF();
WriteW(0x0F);
CheckBF();
WriteW(0x80);
}
voidLCD_Init2(void)
{
CheckBF();
WriteW(0x0F);
CheckBF();
WriteW(0xC0);
}
voidWritD(unsignedcharkey_asc2)
{
CheckBF();
ptr=0xAF02;
*ptr=key_asc2;
}
viic.h〔包含根据
总线协议编写的字节及多字节传输和接收函数〕
/*******************************************************************
字节数据传送函数
函数原型:
voidSendByte(ucharc);
功能:
将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进展操作.(不应答或非应答都使ack=0假)
发送数据正常,ack=1;ack=0表示被控器无应答或损坏。
********************************************************************/
voidSendByte(ucharc)
{
ucharBitt;
for(Bitt=0;Bitt<8;Bitt++)/*要传送的数据长度为8位*/
{
if((c<elseSDA=0;
_Nop();
SCL=1;/*置时钟线为高,通知被控器开场接收数据位*/
_Nop();
_Nop();/*保证时钟高电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
SDA=1;/*8位发送完后释放数据线,准备接收应答位*/
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)ack=0;
elseack=1;/*判断是否接收到应答信号*/
SCL=0;
_Nop();
_Nop();
}
/*******************************************************************
字节数据传送函数
函数原型:
ucharRcvByte();
功能:
用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数。
********************************************************************/
ucharRcvByte()
{
ucharretc;
ucharBitt;
retc=0;
SDA=1;/*置数据线为输入方式*/
for(Bitt=0;Bitt<8;Bitt++)
{
_Nop();
SCL=0;/*置时钟线为低,准备接收数据位*/
_Nop();
_Nop();/*时钟低电平周期大于4.7μs*/
_Nop();
_Nop();
_Nop();
SCL=1;/*置时钟线为高使数据线上数据有效*/
_Nop();
_Nop();
retc=retc<<1;
if(SDA==1)retc=retc+1;/*读数据位,接收的数据位放入retc中*/
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
return(retc);
}
/********************************************************************
应答子函数
原型:
voidAck_I2c(bita);
功能:
主控器进展应答信号,(可以是应答或非应答信号)
********************************************************************/
voidAck_I2c(bita)
{
if(a==0)SDA=0;/*在此发出应答或非应答信号*/
elseSDA=1;
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();/*时钟低电平周期大于4μs*/
_Nop();
_Nop();
_Nop();
SCL=0;/*清时钟线,钳住I2C总线以便继续接收*/
_Nop();
_Nop();
}
/*******************************************************************
向有子地址器件发送多字节数据函数
函数原型:
bitISendStr(ucharsla,ucharsuba,ucahr*s,ucharno);
功能:
从启动总线到发送地址,子地址,数据,完毕总线的全过程,从器件
地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
如果返回1表示操作成功,否那么操作有误。
注意:
使用前必须已完毕总线。
********************************************************************/
//*
bitISendStr(ucharsla,ucharsuba,uchar*s,ucharno)
{
uchari;
Start_I2c();//启动总线
SendByte(sla);//发送器件地址
if(ack==0)return(0);
SendByte(suba);//发送器件子地址
if(ack==0)return(0);
for(i=0;i{
SendByte(*s);//发送数据
if(ack==0)return(0);
s++;
}
Stop_I2c();//完毕总线
return
(1);
}
/*******************************************************************
向有子地址器件读取多字节数据函数
函数原型:
bitISendStr(ucharsla,ucharsuba,ucahr*s,ucharno);
功能:
从启动总线到发送地址,子地址,读数据,完毕总线的全过程,从器件
地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
如果返回1表示操作成功,否那么操作有误。
注意:
使用前必须已完毕总线。
********************************************************************/
bitIRcvStr(ucharsla,ucharsuba,uchar*s,ucharno)
{
uchari;
Start_I2c();/*启动总线*/
SendByte(sla);/*发送器件地址*/
if(ack==0)return(0);
SendByte(suba);/*发送器件子地址*/
if(ack==0)return(0);
Start_I2c();
SendByte(sla+1);
if(ack==0)return(0);
for(i=0;i{
*s=RcvByte();/*发送数据*/
Ack_I2c(0);/*发送就答位*/
s++;
}
*s=RcvByte();
Ack_I2c
(1);/*发送非应位*/
Stop_I2c();/*完毕总线*/
return
(1);
}
key.h〔实现键盘读取操作的〕
//**********************************有关键盘的函数********************************************//
unsignedcharcodeKey_Value_Table[16]=//有关行列值
{0xff,0x00,0x01,0xff,0x02,0xff,0xff,0xff,
0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff
};
bitbKeyUp_Flag;
voidKey_Init(void)
{
bKeyUp_Flag=1;//标志位置1
}
unsignedcharGetScanKey(void)
{
unsignedcharkey,i,temp;
unsignedcharxdata*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;
}
}
returnkey;//返回行位〔高四〕和列位〔低四〕
}
unsignedcharGetKey(void)
{
unsignedcharkey,temp;
if(!
bKeyUp_Flag)//判断标志,是0执行
/*按键程序执行一次后会将bKeyUp_Flag标志位清零,执行此段程序,长按键无效返回无效值
直至按键无效返回无效按键值,置"1"标志位。
按键输入恢复有效*/
{
key=GetScanKey();
if(key==0xff)//没有按键,置标志位
bKeyUp_Flag=1;
else//保持按键
return0xff;
}
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[key>>4];
/*行值有效位(键盘的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[key>>4]*4+Key_Value_Table[key&0x0f];
/*行列组合后的值大于15无效*/
if(key>15)
{
key=0xff;
returnkey;
}
bKeyUp_Flag=0;
returnkey;
}
}
实现不断读取时间芯片的值并显示在1602和led上显示日期时间的read函数
voidread()
{
unsignedcharrd[7];//作为读8563数据的缓存区
unsignedchari;
while
(1)
{
IRcvStr(0xA2,0x02,rd,0x7);
rd[0]=rd[0]&0x7f;//秒
rd[1]=rd[1]&0x7f;//分
rd[2]=rd[2]&0x3f;//时
rd[3]=rd[3]&0x3f;//日
rd[4]=rd[4];//
rd[5]=rd[5]&0x1f;//月
rd[6]=rd[6];//年
td_table[2]=rd[6]/16;//数据分解
td_table[3]=rd[6]%16;
td_table[4]=rd[5]/16;
td_table[5]=rd[5]%16;
td_table[6]=rd[3]/16;
td_table[7]=rd[3]%16;
td_table[8]=rd[2]/16;
td_table[9]=rd[2]%16;
td_table[10]=rd[1]/16;
td_table[11]=rd[1]%16;
td_table[12]=rd[0]/16;
td_table[13]=rd[0]%16;
//LED上显示
ptr=0x9fff;//先清零
*ptr=0x00;
ptr=0x8fff;
*ptr=0xff;
//依次显示秒、分、时
ptr=0x9fff;
*ptr=qiduan_table[td_table[13]];
ptr=0x8fff;
*ptr=0x01;
Delay_ms
(1);
ptr=0x9fff;
*ptr=qiduan_table[td_table[12]];
ptr=0x8fff;
*ptr=0x02;
Delay_ms
(1);
ptr=0x9fff;
*ptr=qiduan_table[td_table[11]];
ptr=0x8fff;
*ptr=0x08;
Delay_ms
(1);
ptr=0x9fff;
*ptr=qiduan_table[td_table[10]];
ptr=0x8fff;
*ptr=0x10;
Delay_ms
(1);
Delay_ms
(1);
ptr=0x9fff;
*ptr=qiduan_table[td_table[9]];
ptr=0x8fff;
*ptr=0x40;
Delay_ms
(1);
ptr=0x9fff;
*ptr=qiduan_table[td_table[8]];
ptr=0x8fff;
*ptr=0x80;
Delay_ms
(1);
ptr=0x9fff;//先清零
*ptr=0x00;
ptr=0x8fff;
*ptr=0xff;
//LCD上显示日期
LCD_Init();
LCD_Init2();
WritD(ASC2_Value_Table[td_table[0]]);
WritD(ASC2_Value_Table[td_table[1]]);
WritD(td_table[2]+29);
WritD(ASC2_Value_Table[td_table[3]]);
WritD(0x20);
WritD(0x20);
WritD(0x20);
WritD(ASC2_Value_Table[td_table[5]]);
WritD(0x20);
WritD(0x20);
WritD(0x20);
WritD(ASC2_Value_Table[td_table[6]]);
WritD(ASC2_Value_Table[td_table[7]]);
}
}
main函数
voidmain()
{
unsignedinti;
Key_Init();
ptr=0x9fff;//先清零
*ptr=0x00;
ptr=0x8fff;
*ptr=0xff;
LCD_Init();
for(i=0;i<13;i++)
{
WritD(tishi_table1[i]);
Delay_ms(200);
}
LCD_Init2();
for(i=13;i<23;i++)
{
WritD(tishi_table1[i]);
Delay_ms(200);
}
Delay_s(4);
if(Test_key())
{
Input_data();
inition();
read();
}
}
〔2〕利用D/A转换通道〔下行通道〕实现锯齿波发生器
这一局部重要的代码片段是对tlc5615的操作以及在main函数中实现正弦等波形,下面是实现正弦波
voidtlc5615()(实现DA转换)
voidtlc5615(unsignedintdat)
{
unsignedcharx;
CS=1;
SCLK=0;
Delay_us(500);
DIO=0;
CS=0;
dat=dat<<6;
for(x=0;x<12;x++)
{
DIO=dat&0x8000;
SCLK=1;
dat=dat<<1;
SCLK=0;
}
CS=1;
}
main函数
unsignedcharkey=0x0ff;
unsignedcharxdata*ptr;
unsignedfloatvol=0;
floatadd=0.000383;
floattemp=0;
intmain()
{
LCD_Init();
Key_Init();
ptr=0x8FF;
*ptr=0x00;
//屏幕全部归位
Delay_s(4);
Check_Busy();
write_(0x01);//显示屏清
Check_Busy();
while
(1)
{
for(i=0;i<6280;i++)
{
vol=500*(sin(i*0.01)+1)
//tlc5615(vol);
}
}
}
〔3〕利用A/D转换通道〔上行通道〕实现数据采集,将采集信号显示在LED屏上。
这一局部重要的代码片段有:
对1549芯片的操作,将电压显示在led上〔三位小数〕的display函数。
以下粘贴局部代码段:
adc_1549〔不断采集端口数据,并送至CPU〕
inttlc1549()
{
intdata_out=0;
unsignedchari;
DIO=0;
SCLK=0;
CS=1;
_nop_();
CS=0;//start
for(i=1;i<=10;i++)
{
SCLK=1;
data_out<<=1;
if(DIO)data_out|=0x01;
SCLK=0;
}
CS=1;
Delay_us(21);
return(data_out);
}
disp_voltage函数〔将电压显示在LED和LCD上〔三位小数〕的函数〕由于时间仓促只显示了小数点后两位
voiddisp_voltage(int*disp)
{
unsignedcharxdata*ptr;
if(disp[2]>=0x5)
{
disp[2]=0x5;
disp[1]=0x0;
disp[0]=0x0;
}
ptr=0x8fff;
*ptr=0x01;
ptr=0x9fff;
*ptr=map[*(disp)];
Delay_us(50);
*ptr=0x00;
ptr=0x8fff;
*ptr=0x02;
ptr=0x9fff;
*ptr=map[*(disp+1)];
Delay_us(50);
*ptr=0x00;
ptr=0x8fff;
*ptr=0x04;
ptr=0x9fff;
*ptr=(map[*(disp+2)])|0x80;
Delay_us(50