单片机实习报告书

单片机实习报告书本文简介:序号(学号):0121009320418学生实习报告书实习类别单片机应用实习实习地址武汉理工大学信息工程学院学院信息工程学院专业通信工程班级通信1004班姓名黄军忠指导教师刘新华2012年12月29日目录1设计要求31.1最小系统31.2下载电路41.3、软件设计要求41.4、仿真要求41.5、硬件
单片机实习报告书本文内容:
序号(学号):
0121009320418
学生实习报告书
实习类别
单片机应用实习
实习地址
武汉理工大学信息工程学院
学
院
信息工程学院
专
业
通信工程
班
级
通信1004班
姓
名
黄军忠
指导教师
刘新华
2012
年
12
月
29
日
目录
1
设计要求3
1.1
最小系统3
1.2
下载电路4
1.3、软件设计要求4
1.4、仿真要求4
1.5、硬件功能要求4
2设计方案5
2.1
硬件电路设计5
2.1.1
最小系统5
2.1.2
下载电路8
2.2
软件设计9
2.2.1
矩阵键盘的识别9
2.2.2
数码管显示10
2.2.3
温度检测11
2.2.4
串口通信12
3
软件仿真14
4
实物焊接及测试16
5
设计总结19
参考文献20
附录21
单片机应用设计
摘要:本文介绍了基于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所示。
图1
STC89C52外围电路
该部分包括芯片的电源、复位以及时钟电路。
矩阵键盘采用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个数码管显示完否?
延时2ms,并指向下一个偏移量
查表并送出显示
置字形码偏移量和位选代码
置显示字形码首地址
开始
要使多个数码管能同时显示内容,一般采用动态扫描法,动态接口采用各数码管循环轮流显示的方法,当循环显示频率较高时,利用人眼的暂留特性,看不出闪烁显示现象,这种显示需要一个接口完成字形码的输出(字形选择),另一接口完成各数码管的轮流点亮(数位选择)。本设计在数码管的段端口和位端口都接了锁存器,所以只需一个接口就能实现上述功能。
在进行数码显示的时候,要对显示单元开辟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每度。
图8
DS18B20测温原理图
CPU对DS18B20的访问流程是:先对DS18B20初始化,再进行ROM操作命令,最后才能对存储器操作,数据操作。DS18B20读取温度程序流程图如图9所示,代码见附录。
图9
DS18B20读取温度流程图
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设计软件为Altium
Designer
Winter
09,该方法可大大缩短实物制作的时间,且板子更美观,最重要的是它可以减少一些偶然因素对板子性能的影响,实物展示以及调试结果都以图片贴出如下:
图15
数据输入
图16
温度检测
图17
数据输入时进行串口通信
图18
温度检测时进行串口通信
从以上实物调试拍摄图可知,本次设计的板子能够实现要求的所有功能,设计方案是正确可行的。
5
设计总结
在单片机应用课程结课后,实训设计无疑是对我们的一次提升,让我们把理论的东西应用于实际,更加牢固掌握单片机的应用知识,也提升了我们的动手能力。在串口通信的调试中,刚开始一直失败,明明仿真是可行的,于是怀疑板子焊接除了问题,但从单独调试上看,板子是正常工作的,经过一步步排查,发现原来两块板子使用的晶振频率不同,导致不能同步,换成同频率晶振后,云开雾散,一切搞定!细节的东西往往容易被忽略,但它确实成功的关键,所以在今后的各种设计中,都要注重细节的设计,毕竟它决定了你的设计成败。
参考文献
[1]
谢自美.电子线路设计·实验·测试(第三版).武汉:华中科技大学出版社
[2]
李群芳.单片微型计算机与接口技术(第3版).电子工业出版社,2008
[3]
刘教瑜.单片机原理及应用.武汉理工大学出版社,2011
[4]
张东亮.单片机原理与应用.人民邮电出版社,2009
[5]郭天祥.51单片机C语言教程.电子工业出版社,2009
附录
完整程序代码:
1、主系统程序:
#include
#define
NO_DEF20
//声明无效键值
#define
SHOW_NUM
1
//声明显示数字的标志
#define
SHOW_TEP
0
//声明显示温度的标志
#define
CLEAR
11
//定义清0键
#defineSWITCH
10
//定义功能切换键
typedef
unsigned
char
uchar;
typedef
unsigned
int
uint;
#define
SM_PORT
P0
//声明数码管数据端口
#define
KEY
P3
//声明矩阵键盘端口
sbit
dula
=
P2^6;
//声明数码管段选端口
sbit
wela
=
P2^7;
//声明数码管位选端口
sbit
DS
=
P2^2;
//声明温度传感器的数据端口
uint
temp;
//
variable
of
temperature,用于接收来自DS18B20传回的温度数据
uint
key_value=20;
uchar
show_flag=SHOW_TEP;
uchar
send_cnt=0;
uchars;
uint
tep_index[4]={0,0,0,0};
//温度索引,因为用前4位数码管显示温度值,后两位分别显示-C,故温度索引之定义了4位
uchar
tem_value[6]={0x3f,0xbf,0x3f,0x3f,0x40,0x39};//温度值对应的,数码管显示码
uint
num_index[6]={13,13,13,13,13,13};//数字索引
uchar
num_value[6]={0,0,0,0,0,0};//要显示的数字对应的数码管显示码值
unsigned
char
code
table[14]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,//数字:0——9
0x39,//字母:C
数组第10个字符
0x40,//字符:-
数组第11个字符
0x80,//字符:.
数组第12个字符
0x00
//无显示
数组第13个字符
};
void
delayms(uint
count);
void
key_scan();
void
display(uchar
ch[6]);
void
num_shift(uintnum,uint
new_key_value);
void
dsreset(void);
bit
tmpreadbit(void);
uchar
tmpread(void);
void
tmpwritebyte(uchar
dat);
void
tmpchange(void);
void
tmp();
void
toTmpIndex(uintindex);
void
indexToValue(uintindex,ucharvalue,int
flag);
void
shut_down();
void
main()
{
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)
{
case
SHOW_NUM://key_scan();
if(key_value0)
num_index[--i]
=
13;
}
indexToValue(num_index,num_value,SHOW_NUM);
s
=
num_value;
//display(num_value);
key_value=NO_DEF;
//将键值赋值为无效值
break;
case
SHOW_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_cnt0)
i--;
count--;
}
}
void
key_scan()
{
uint
temp;
KEY
=
0xfe;
temp
=
KEY;
temp
=
temp
if(temp!=0xf0)
//扫描矩阵键盘第一行
{
delayms(10);
if(temp!=0xf0)
{
temp
=
KEY;
switch(temp)
{
case
0xee:
//扫描矩阵键盘第一行,第四列
key_value=NO_DEF;
//无效键
break;
case
0xde:
//扫描矩阵键盘第一行,第三列
key_value=3;
break;
case
0xbe:
//扫描矩阵键盘第一行,第二列
key_value=2;
break;
case
0x7e:
//扫描矩阵键盘第一行,第一列
key_value=1;
break;
}
while(temp!=0xf0)//等待按键释放
{
temp
=
KEY;
temp=temp
}
}
}
KEY
=
0xfd;
temp
=
KEY;
temp=temp
if(temp!=0xf0)
//扫描矩阵键盘第二行
{
delayms(10);
if(temp!=0xf0)
{
temp
=
KEY;
switch(temp)
{
case
0xed:
//扫描矩阵键盘第二行,第四列
key_value=NO_DEF;
//无效键
break;
case
0xdd:
//扫描矩阵键盘第二行,第三列
key_value=6;
break;
case
0xbd:
//扫描矩阵键盘第二行,第二列
key_value=5;
break;
case
0x7d:
//扫描矩阵键盘第二行,第一列
key_value=4;
break;
}
while(temp!=0xf0)
//等待按键释放
{
temp
=
KEY;
temp=temp
}
}
}
KEY
=
0xfb;
temp
=
KEY;
temp=temp
if(temp!=0xf0)
//扫描矩阵键盘第三行
{
delayms(10);
if(temp!=0xf0)
{
temp
=
KEY;
switch(temp)
{
case
0xeb:
//扫描矩阵键盘第三行,第四列
key_value=NO_DEF;
//无效键
break;
case
0xdb:
//扫描矩阵键盘第三行,第三列
key_value=9;
break;
case
0xbb:
//扫描矩阵键盘第三行,第二列
key_value=8;
break;
case
0x7b:
//扫描矩阵键盘第三行,第一列
key_value=7;
break;
}
while(temp!=0xf0)
//等待按键释放
{
temp
=
KEY;
temp
=
temp
}
}
}
KEY
=
0xf7;
temp
=
KEY;
temp=temp
if(temp!=0xf0)
//扫描矩阵键盘第四行
{
delayms(10);
if(temp!=0xf0)
{
temp
=
KEY;
switch(temp)
{
case
0xe7://扫描矩阵键盘第四行,第四列
key_value=NO_DEF;
break;
case
0xd7://扫描矩阵键盘第四行,第三列
key_value=CLEAR;
break;
case
0xb7://扫描矩阵键盘第四行,第二列
key_value=SWITCH;
break;
case
0x77:
//扫描矩阵键盘第四行,第一列
key_value=0;
break;
}
while(temp!=0xf0)//等待按键释放
{
temp
=
KEY;
temp=temp
}
}
}
}
/*
函数功能描述:数码管显示函数,参数ch[6]是数码管要显示的数字或字符/
void
display(uchar
ch[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);
}
/*
函数功能描述:每按下一个键,数码管要显示的数字的索引向右移一位。/
void
num_shift(uintnum,uint
new_key_value)
{
uint
i;
for(i=5;i>0;i--)
num[i]=num[i-1];
num[0]
=
new_key_value;
}
/*
函数功能描述:DS18B20初始化函数。实现原理参看DS18B20初始化时序图/
void
dsreset(void)
//send
reset
and
initialization
command
{
uint
i;
DS=0;
i=103;
while(i>0)i--;
DS=1;
i=4;
while(i>0)i--;
}
/*
//函数功能描述:读取DS18B20的温度位值。实现原理参看DS18B20读时序图/
bit
tmpreadbit(void)
//read
a
bit
{
uint
i;
bit
dat;
DS=0;i++;
//i++
for
delay
DS=1;i++;i++;
dat=DS;
i=8;while(i>0)i--;
return
(dat);
}
/*
//函数功能描述:读取DS18B20的温度字节值。/
uchar
tmpread(void)
//read
a
byte
date
{
uchar
i,j,dat;
dat=0;
for(i=1;i>1);
//读出的数据最低位在最前面,这样刚好一个字节在DAT里
}
return(dat);
}
/*
//函数功能描述:写DS18B20函数。实现原理参看DS18B20写时序图/
void
tmpwritebyte(uchar
dat)
//write
a
byte
to
ds18b20
{
uint
i;
uchar
j;
bit
testb;
for(j=1;j>1;
if(testb)
//write
1
{
DS=0;
i++;i++;
DS=1;
i=8;while(i>0)i--;
}
else
{
DS=0;
//write
0
i=8;while(i>0)i--;
DS=1;
i++;i++;
}
}
}
/*
//函数功能描述:开始温度转换的功能函数。/
void
tmpchange(void)
//DS18B20
begin
change
{
dsreset();
delayms(1);
tmpwritebyte(0xcc);
//
address
all
drivers
on
bus
tmpwritebyte(0x44);
//
initiates
a
single
temperature
conversion
}
/*
//函数功能描述:将从DS18B20读取的数值转换成实际的温度位值。/
void
tmp()
//get
the
temperature
{
float
tt;
//uint
temp;
uchar
a,b;
dsreset();
delayms(1);
tmpwritebyte(0xcc);
tmpwritebyte(0xbe);
a=tmpread();
b=tmpread();
temp=b;
temp
#define
SM_PORT
P0
//声明数码管数据端口
sbit
dula
=
P2^6;
//声明数码管段选端口
sbit
wela
=
P2^7;
//声明数码管位选端口
#define
uchar
unsigned
char
#define
uint
unsigned
int
uchar
receive_cnt
=
0;
uchar
r_syn_code
=
0x00;
//接收帧同步码
uchar
receive[6]
=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,};
//接收数据缓冲数组,初始化什么也不显示
void
delayms(uint
count);
void
display(uchar
ch[6]);
void
main()
{
TMOD
=
0x20;
//设置定时器的工作方式为方式2
TH1
=
0xfd;
//设置波特率为19200
TL1
=
0xfd;
SM0=0;
SM1=1;
REN=1;
//SCON
=
0x50;
//设置串口的工作方式为方式1,允许接收
EA
=
1;
PCON
=
0x80;
//串口波特率加倍
ES
=
1;
//SBUF
=
0x00;
//清空接收缓冲区
TR1
=
1;
//开启定时器1,开始发送数据
//SBUF
=
0x00;
//
while(1)
{
//while(r_syn_code!=0xee)
//判断帧同步码,如果不同步,等待同步码到来
//{
//while(!RI);
//RI
=
0;
//r_syn_code
=
SBUF;
//}
//while(receive_cnt0)
i--;
count--;
}
}
void
display(uchar
ch[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);
}
