单片机实习报告书.docx
《单片机实习报告书.docx》由会员分享,可在线阅读,更多相关《单片机实习报告书.docx(38页珍藏版)》请在冰豆网上搜索。
单片机实习报告书
序号(学号):
0121009320418
学生实习报告书
实习类别
单片机应用实习
实习地址
武汉理工大学信息工程学院
学院
信息工程学院
专业
通信工程
班级
通信1004班
姓名
黄军忠
指导教师
刘新华
2012
年
12
月
29
日
单片机应用设计
摘要:
本文介绍了基于51单片机的应用设计,其中包括矩阵键盘、数码管显示、温度检测和串口通信等模块,矩阵键盘完成数字的输入和功能的选择,数码管作为当前输入数据以及当前状态的显示,温度检测模块能够实时采集环境温度,并通过数码管显示出来,串口通信实现了两个单片机最小系统之间的通信,辅系统能够同步显示主系统的数据与状态。
该系统能够实现设计要求的所有功能,在保证系统稳定性的前提下采用分模块设计,使得各个模块在此次设计验收后可留作他用,节约资源。
1设计要求
1.1最小系统
完成包含如下系统功能组件的单片机最小系统的设计、焊接、调试。
(1)键盘
一个4X4的矩阵键盘,其中,10个按键是0~9数字键;另外6个是功能键,用于功能选择和控制。
(2)显示电路
由6个7段LED数码管组成的显示电路。
(3)温度检测
利用DS18B20可编程1-Wire数字温度传感器芯片,或利用AD590温度传感器芯片和A/D转换器芯片采集温度温度信号。
(4)串口串行通信
利用51的串口实现串行通信接口电路。
1.2下载电路
完成ISP下载电路的设计、焊接。
1.3、软件设计要求
完成系统软件的设计,包括程序结构设计、流程图绘制、程序设计,实现如下功能
(1)功能选择
通过功能选择键,使得单片机处于不同的工作状态并通过LED显示相应的内容。
(2)温度显示
通过功能选择键选择温度检测、显示后,LED显示温度值。
(3)数据输入
通过功能选择键选择数据输入后,将通过键盘键入的0~9按键值显示在LED上,其中,最后输入的显示在最左边,之前键入向右移动一位。
(4)数据通信
将两个单片机最小系统通过串口连接起来,其中一个作为主系统,另一个作为辅系统。
当通过功能选择键选择数据通信后,当在主系统上进行功能
(2)、功能(3)的操作时,辅系统的LED上显示与主系统同样的内容。
1.4、仿真要求
利用仿真软件完成系统仿真工作。
1.5、硬件功能要求
在单片机最小系统硬件上实现任务3中规定的功能。
2设计方案
2.1硬件电路设计
2.1.1最小系统
按照设计要求,此部分包括主控芯片STC89C52的外围电路、矩阵键盘、6位数码管、温度检测模块的电路设计。
主控芯片的外围电路设计如图1所示。
图1STC89C52外围电路
该部分包括芯片的电源、复位以及时钟电路。
矩阵键盘采用16个点触开关进行4*4排列,电路连接方式如图2所示。
图2矩阵键盘
数码管显示电路采用两个3位共阴数码管组合成6位显示,由于单片机的I/O口输出电流较小,不能驱动数码管,所以需要使用驱动芯片,本次设计使用两片74HC537锁存器作为段选和为选,且作为数码管的驱动。
使用两个锁存器可以实现I/O口复用,节省单片机接口资源。
该模块电路如图3所示。
图3数码管显示电路
温度检测模块采用精密温度传感器DS18B20作为温度采集部分,其外围电路设计简单,仅需接一个10K电阻和电源即可工作,该模块电路如图4所示。
图4温度传感器电路
2.1.2下载电路
该模块采用MAX232作为电平转换芯片,把电脑电平变成TTL电平,下载接口采用九针串口,其电路如图5所示。
图5下载电路
2.2软件设计
2.2.1矩阵键盘的识别
每个按键有它的行值和列值 ,行值和列值的组合就是识别这个按键的编码。
矩阵的行线和列线分别通过两并行接口和CPU通信。
每个按键的状态同样需变成数字量“0”和“1”,开关的一端(列线)通过电阻接VCC,而接地是通过程序输出数字“0”实现的。
键盘处理程序的任务是:
确定有无键按下,判断哪一个键按下,键的功能是什么;还要消除按键在闭合或断开时的抖动。
两个并行口中,一个输出扫描码,使按键逐行动态接地,另一个并行口输入按键状态,由行扫描值和回馈信号共同形成键编码而识别按键,通过软件查表,查出该键的功能。
识别程序的流程图6所示,代码见附录。
图6矩阵键盘识别流程图
2.2.2数码管显示
要使多个数码管能同时显示内容,一般采用动态扫描法,动态接口采用各数码管循环轮流显示的方法,当循环显示频率较高时,利用人眼的暂留特性,看不出闪烁显示现象,这种显示需要一个接口完成字形码的输出(字形选择),另一接口完成各数码管的轮流点亮(数位选择)。
本设计在数码管的段端口和位端口都接了锁存器,所以只需一个接口就能实现上述功能。
在进行数码显示的时候,要对显示单元开辟6个显示缓冲区,每个显示缓冲区装有显示的不同数据即可。
对于显示的字形码数据我们采用查表方法来完成。
程序流程图如图7所示,程序代码见附录。
图7数码管动态扫描
2.2.3温度检测
该模块的温度传感器采用DS18B20,DS18B20的测温原理如图8所示,图中低温度系数晶振的振荡频率受温度的影响很小用于产生固定频率的脉冲信号送给减法计数器1,高温度系数晶振随温度变化其震荡频率明显改变,所产生的信号作为减法计数器2的脉冲输入,图中还隐含着计数门,当计数门打开时,DS18B20就对低温度系数振荡器产生的时钟脉冲后进行计数,进而完成温度测量.计数门的开启时间由高温度系数振荡器来决定,每次测量前,首先将-55℃所对应的基数分别置入减法计数器1和温度寄存器中,减法计数器1和温度寄存器被预置在-55℃所对应的一个基数值。
首先用DS1820提供的读暂存寄存器指令(BEH)读出以0.5℃为分辨率的温度测量结果,然后切去测量结果中的最低有效位(LSB),得到所测实际温度整数部分T整数,然后再用BEH指令读取计数器1的计数剩余值M剩余和每度计数值M每度,考虑到DS1820测量温度的整数部分以0.25℃、0.75℃为进位界限的关系,实际温度T实际可用下式计算得到:
T实际=(T整数-0.25)+(M℃每度-M剩余)/M每度。
图8DS18B20测温原理图
CPU对DS18B20的访问流程是:
先对DS18B20初始化,再进行ROM操作命令,最后才能对存储器操作,数据操作。
DS18B20读取温度程序流程图如图9所示,代码见附录。
图9DS18B20读取温度流程图
2.2.4串口通信
串口通信采用方式1,方式1是10位数据的异步通信口。
TXD为数据发送引脚,RXD为数据接收引脚,传送一帧数据的格式如图10所示。
其中1位起始位,8位数据位,1位停止位。
图10传送一帧数据的格式
用软件置REN为1时,接收器以所选择波特率的16倍速率采样RXD引脚电平,检测到RXD引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。
接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。
当RI=0,且SM2=0(或接收到的停止位为1)时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置RI=1,向CPU请求中断。
串口通信发送程序的流程图如图11所示,代码见附录。
图11串口通信发送流程图
接收程序流程图如图12所示,代码见附录。
图12串口通信接收流程图
3软件仿真
仿真软件使用PROTEUS,把电路按照设计方案连接起来,导入程序,开始仿真。
仿真结果如预期效果,说明设计方案是正确可行的,仿真截图如图13、图14所示。
图13数据输入
图14温度检测
4实物焊接及测试
实物制作采用PCB制板的方式,PCB设计软件为AltiumDesignerWinter09,该方法可大大缩短实物制作的时间,且板子更美观,最重要的是它可以减少一些偶然因素对板子性能的影响,实物展示以及调试结果都以图片贴出如下:
图15数据输入
图16温度检测
图17数据输入时进行串口通信
图18温度检测时进行串口通信
从以上实物调试拍摄图可知,本次设计的板子能够实现要求的所有功能,设计方案是正确可行的。
5设计总结
在单片机应用课程结课后,实训设计无疑是对我们的一次提升,让我们把理论的东西应用于实际,更加牢固掌握单片机的应用知识,也提升了我们的动手能力。
在串口通信的调试中,刚开始一直失败,明明仿真是可行的,于是怀疑板子焊接除了问题,但从单独调试上看,板子是正常工作的,经过一步步排查,发现原来两块板子使用的晶振频率不同,导致不能同步,换成同频率晶振后,云开雾散,一切搞定!
细节的东西往往容易被忽略,但它确实成功的关键,所以在今后的各种设计中,都要注重细节的设计,毕竟它决定了你的设计成败。
参考文献
[1]谢自美.电子线路设计·实验·测试(第三版).武汉:
华中科技大学出版社
[2]李群芳.单片微型计算机与接口技术(第3版).电子工业出版社,2008
[3]刘教瑜.单片机原理及应用.武汉理工大学出版社,2011
[4]张东亮.单片机原理与应用.人民邮电出版社,2009
[5]郭天祥.51单片机C语言教程.电子工业出版社,2009
附录
完整程序代码:
1、主系统程序:
#include
#defineNO_DEF20//声明无效键值
#defineSHOW_NUM1//声明显示数字的标志
#defineSHOW_TEP0//声明显示温度的标志
#defineCLEAR11//定义清0键
#defineSWITCH10//定义功能切换键
typedefunsignedcharuchar;
typedefunsignedintuint;
#defineSM_PORTP0//声明数码管数据端口
#defineKEYP3//声明矩阵键盘端口
sbitdula=P2^6;//声明数码管段选端口
sbitwela=P2^7;//声明数码管位选端口
sbitDS=P2^2;//声明温度传感器的数据端口
uinttemp;//variableoftemperature,用于接收来自DS18B20传回的温度数据
uintkey_value=20;
ucharshow_flag=SHOW_TEP;
ucharsend_cnt=0;
uchar*s;
uinttep_index[4]={0,0,0,0};//温度索引,因为用前4位数码管显示温度值,后两位分别显示-C,故温度索引之定义了4位
uchartem_value[6]={0x3f,0xbf,0x3f,0x3f,0x40,0x39};//温度值对应的,数码管显示码
uintnum_index[6]={13,13,13,13,13,13};//数字索引
ucharnum_value[6]={0,0,0,0,0,0};//要显示的数字对应的数码管显示码值
unsignedcharcodetable[14]={0x3f,0x06,0x5b,
0x4f,0x66,0x6d,
0x7d,0x07,0x7f,
0x6f,//数字:
0——9
0x39,//字母:
C数组第10个字符
0x40,//字符:
-数组第11个字符
0x80,//字符:
.数组第12个字符
0x00//无显示数组第13个字符
};
voiddelayms(uintcount);
voidkey_scan();
voiddisplay(ucharch[6]);
voidnum_shift(uint*num,uintnew_key_value);
voiddsreset(void);
bittmpreadbit(void);
uchartmpread(void);
voidtmpwritebyte(uchardat);
voidtmpchange(void);
voidtmp();
voidtoTmpIndex(uint*index);
voidindexToValue(uint*index,uchar*value,intflag);
voidshut_down();
voidmain()
{
TMOD=0x20;//设置定时器的工作方式为方式2
TH1=0xfd;//设置波特率为19200
TL1=0xfd;
SCON=0x40;//设置串口的工作方式为方式1
EA=1;
PCON=0x80;//串口波特率加倍
ES=1;
TR1=1;//开启定时器1,开始发送数据
while
(1)
{
key_scan();
delayms
(1);
if(key_value==SWITCH)//检测功能切换键是否被按下
{
shut_down();
key_value=NO_DEF;//将键值赋值为无效值
if(show_flag==SHOW_TEP)
show_flag=SHOW_NUM;
else
show_flag=SHOW_TEP;
}
switch(show_flag)
{
caseSHOW_NUM:
//key_scan();
if(key_value<=9)//检测数字键是否被按下
{
num_shift(num_index,key_value);
}
if(key_value==CLEAR)//检测清0键是否按下
{
uchari=6;
while(i>0)
num_index[--i]=13;
}
indexToValue(num_index,num_value,SHOW_NUM);
s=num_value;
//display(num_value);
key_value=NO_DEF;//将键值赋值为无效值
break;
caseSHOW_TEP:
tmpchange();
tmp();
toTmpIndex(tep_index);
indexToValue(tep_index,tem_value,SHOW_TEP);
s=tem_value;
//display(tem_value);
break;
default:
show_flag=SHOW_TEP;
break;
}
//delayms
(1);
display(s);
SBUF=0xee;//发送帧同步信号
while(!
TI);
TI=0;
while(send_cnt<6)
{
SBUF=s[send_cnt++];//发送数据
while(!
TI);//等待发送完成
TI=0;//清空发送标志
}
send_cnt=0;//清空发送计数器
}
}
/*
voidSend()interrupt4
{
if(send_cnt<6)
{
send_cnt=1;
SBUF=s[send_cnt];
}
else
{
TR1=0;
send_cnt=1;
}
}
*/
voiddelayms(uintcount)//delay
{
uinti;
while(count)
{
i=200;
while(i>0)
i--;
count--;
}
}
voidkey_scan()
{
uinttemp;
KEY=0xfe;
temp=KEY;
temp=temp&0xf0;
if(temp!
=0xf0)//扫描矩阵键盘第一行
{
delayms(10);
if(temp!
=0xf0)
{
temp=KEY;
switch(temp)
{
case0xee:
//扫描矩阵键盘第一行,第四列
key_value=NO_DEF;//无效键
break;
case0xde:
//扫描矩阵键盘第一行,第三列
key_value=3;
break;
case0xbe:
//扫描矩阵键盘第一行,第二列
key_value=2;
break;
case0x7e:
//扫描矩阵键盘第一行,第一列
key_value=1;
break;
}
while(temp!
=0xf0)//等待按键释放
{
temp=KEY;
temp=temp&0xf0;
}
}
}
KEY=0xfd;
temp=KEY;
temp=temp&0xf0;
if(temp!
=0xf0)//扫描矩阵键盘第二行
{
delayms(10);
if(temp!
=0xf0)
{
temp=KEY;
switch(temp)
{
case0xed:
//扫描矩阵键盘第二行,第四列
key_value=NO_DEF;//无效键
break;
case0xdd:
//扫描矩阵键盘第二行,第三列
key_value=6;
break;
case0xbd:
//扫描矩阵键盘第二行,第二列
key_value=5;
break;
case0x7d:
//扫描矩阵键盘第二行,第一列
key_value=4;
break;
}
while(temp!
=0xf0)//等待按键释放
{
temp=KEY;
temp=temp&0xf0;
}
}
}
KEY=0xfb;
temp=KEY;
temp=temp&0xf0;
if(temp!
=0xf0)//扫描矩阵键盘第三行
{
delayms(10);
if(temp!
=0xf0)
{
temp=KEY;
switch(temp)
{
case0xeb:
//扫描矩阵键盘第三行,第四列
key_value=NO_DEF;//无效键
break;
case0xdb:
//扫描矩阵键盘第三行,第三列
key_value=9;
break;
case0xbb:
//扫描矩阵键盘第三行,第二列
key_value=8;
break;
case0x7b:
//扫描矩阵键盘第三行,第一列
key_value=7;
break;
}
while(temp!
=0xf0)//等待按键释放
{
temp=KEY;
temp=temp&0xf0;
}
}
}
KEY=0xf7;
temp=KEY;
temp=temp&0xf0;
if(temp!
=0xf0)//扫描矩阵键盘第四行
{
delayms(10);
if(temp!
=0xf0)
{
temp=KEY;
switch(temp)
{
case0xe7:
//扫描矩阵键盘第四行,第四列
key_value=NO_DEF;
break;
case0xd7:
//扫描矩阵键盘第四行,第三列
key_value=CLEAR;
break;
case0xb7:
//扫描矩阵键盘第四行,第二列
key_value=SWITCH;
break;
case0x77:
//扫描矩阵键盘第四行,第一列
key_value=0;
break;
}
while(temp!
=0xf0)//等待按键释放
{
temp=KEY;
temp=temp&0xf0;
}
}
}
}
/*
函数功能描述:
数码管显示函数,参数ch[6]是数码管要显示的数字或字符
*/
voiddisplay(ucharch[6])
{
dula=1;//显示第一位数码管
SM_PORT=ch[0];
dula=0;
SM_PORT=0xff;
wela=1;
SM_PORT=0xfe;
wela=0;
delayms
(1);
dula=1;//显示第二位数码管
SM_PORT=ch[1];
dula=0;
SM_PORT=0xff;
wela=1;
SM_PORT=0xfd;
wela=0;
delayms
(1);
dula=1;//显示第三位数码管
SM_PORT=ch[2];
dula=0;
SM_PORT=0xff;
wela=1;
SM_PORT=0xfb;
wela=0;
delayms
(1);
dula=1;//显示第四位数码管
SM_PORT=ch[3];
dula=0;
SM_PORT=0xff;
wela=1;
SM_PORT=0xf7;
wela=0;
delayms
(1);
dula=1;//显示第五位数码管
SM_PORT=ch[4];
dula=0;
SM_PORT=0xff;
wela=1;
SM_PORT=0xef;
wela=0;
delayms
(1);
dula=1;//显示第六位数码管
SM_PORT=ch[5];
dula=0;
SM_PORT=0xff;
wela=1;
SM_PORT=0xdf;
wela=0;
delayms
(1);
}
/*
函数功能描述:
每按下一个键,数码管要显示的数字的索引向右移一位。
*/
voidnum_shift(uint*num