单片机实验报告.docx
《单片机实验报告.docx》由会员分享,可在线阅读,更多相关《单片机实验报告.docx(30页珍藏版)》请在冰豆网上搜索。
单片机实验报告
《51单片机》实验报告
学院计通学院
专业班级 物联1401
姓 名 廖攀
学 号 41458027
2016年12月
一、实验要求:
以STC89开发板为硬件平台,开发温度采集、动态数码管显示、按键响应、与PC串口通讯的综合程序,实现以下功能:
1)PC上的串口调试助手通过串口给STC89开发板发送“GetTemp”命令
2) STC89开发板从串口接收到“GetTemp”命令后启动温度传感器DS18B20的测温程序获取当前温度,测试完成时将所测得温度数据显示在动态数码管上。
(动态数码管在温度获取之前应该显示“NOTEMP”,只有在获取温度后才显示温度值)
3) 动态数码管显示出温度数据后,请通过按键触发STC89开发板通过串口回送步骤2所测的温度数据给PC上串口调试助手,同时恢复动态数码管显示为“NOTEMP”。
为保证每个同学的实验都独立完成,要求回送的数据包含自己的学号,即如果你的学号是20150809,当前温度值是19.6摄氏度,那么在PC上的串口调试助手应该显示:
ID:
20150809,Temp:
19.6degC.
二、程序设计思路:
该实验是一个综合实验,需要结合很多的知识来解决。
具体来说可以分成这三个方面,第一个方面是用温度传感器DS18B20测量外界的温度,这个课本第十六章有十分详细的操作过程,第二个方面是如何运用串口助手来解决串口问题,第三个方面是实验中会出现一些中断,需要注意很多细节。
具体实验过程先使用温度传感器DS18B20测量出外界的温度(可以参考教科书317-321,也可以参考实验课学到的实验16),然后在此基础上运用起串口(可以参考实验课所学到的实验15),最后整合起来,实现所有功能。
原理图:
CPU管脚电路晶振电路
(2)数码管部分
1、数码管显示
(1)数码管的显示原理
数码管的显示原理是靠点亮内部的发光二极管来发光,下面就来我们讲解一个数码管是如何亮起来的。
数码管内部电路如下图所示,从右图可看出,一位数码管的引脚是10个,显示一个8字需要7个小段,另外还有一个小数点,所以其内部一共有8个小的发光二极管,最后还有一个公共端,生产商为了封装统一,单位数码管都封装10个引脚,其中第3和第8引脚是连接在一起的。
而它们的公共端又可分为共阳极和共阴极,中间图为共阴极内部原理图,右图为共阳极内部原理图。
上图展出了常用的两种数码管的引脚排列和内部结构。
总所周知,点亮发光二极管就是要给予它足够大的正向压降。
所以点亮数码管其实也就是给它内部相应的发光二极管正向压降。
如上图左(一共a、b、c、d、e、f、g、DP八段),如果要显示“1”则要点亮b、c两段LED;显示“A”则点亮a、b、c、e、f、g这六段LED;我们还知道,既然LED加载的是正向压降,它的两端电压必然会有高低之分:
如果八段LED电压高的一端为公共端,我们称之为共阳极数码管(如上图中);如果八段LED电压低的一段为公共端,则称之为共阴极数码管(上图右)。
所以,要点亮共阳极数码管,则要在公共端给予高于非公共端的电平;反之点亮共阴极数码管,则要在非公共端给予较高电平。
动态显示是多个数码管,交替显示,利用人的视觉暂停作用使人看到多个数码管同时显示的效果。
数码管
(3)DS18B20温度传感器部分
(1)工作原理
DS18B20内部的低温度系数振荡器是一个振荡频率随温度变化很小的振荡器,为计数器1提供一频率稳定的计数脉冲。
高温度系数振荡器是一个振荡频率对温度很敏感的振荡器,为计数器2提供一个频率随温度变化的计数脉冲。
初始时,温度寄存器被预置成-55℃,每当计数器1从预置数开始减计数到0时,温度寄存器中寄存的温度值就增加1℃,这个过程重复进行,直到计数器2计数到0时便停止。
初始时,计数器1预置的是与-55℃相对应的一个预置值。
以后计数器1每一个循环的预置数都由斜率累加器提供。
为了补偿振荡器温度特性的非线性性,斜率累加器提供的预置数也随温度相应变化。
计数器1的预置数也就是在给定温度处使温度寄存器寄存值增加1℃计数器所需要的计数个数。
DS18B20内部的比较器以四舍五入的量化方式确定温度寄存器的最低有效位。
在计数器2停止计数后,比较器将计数器1中的计数剩余值转换为温度值后与0.25℃进行比较,若低于0.25℃,温度寄存器的最低位就置0;若高于0.25℃,最低位就置1;若高于0.75℃时,温度寄存器的最低位就进位然后置0。
这样,经过比较后所得的温度寄存器的值就是最终读取的温度值了,其最后位代表0.5℃,四舍五入最大量化误差为±1/2LSB,即0.25℃。
温度寄存器中的温度值以9位数据格式表示,最高位为符号位,其余8位以二进制补码形式表示温度值。
测温结束时,这9位数据转存到暂存存储器的前两个字节中,符号位占用第一字节,8位温度数据占据第二字节。
DS18B20测量温度时使用特有的温度测量技术。
DS18B20内部的低温度系数振荡器能产生稳定的频率信号;同样的,高温度系数振荡器则将被测温度转换成频率信号。
当计数门打开时,DS18B20进行计数,计数门开通时间由高温度系数振荡器决定。
芯片内部还有斜率累加器,可对频率的非线性度加以补偿。
测量结果存入温度寄存器中。
一般情况下的温度值应该为9位,但因符号位扩展成高8位,所以最后以16位补码形式读出。
(4)串口通信部分
(1)串行通信方式
串行通信是将数据字节分成一位一位的形式在一条传输线上逐个地传送,此时只需要一条数据线,外加一条公共信号地线和若干控制信号线。
因为一次只能传送一位,所以对于一个字节的数据,至少要分S位才能传送完毕。
串行通信的必要过程是:
发送时,要把并行数据变成串行数据发送到线路上去,接收时,要把串行信号再变成并行数据,这样才能被计算机及其他设备处理。
串行通信传输线少,长距离传送时成本低,且可以利用电话网等现成的设备,但数据的传送控制比并行通信复杂。
(2)同步串行通信方式
我们采用的是同步串行通信的方式,同步通信时要建立发送方时钟对接收方时钟的直接控制,使双方达到完全同步。
此时,传输数据的位之间的距离均为“位间隔”的整数倍,同时传送的字符间不留间隙,即保持位同步关系,也保持字符同步关系。
(3)波特率
单片机或计算机在串口通信时的速率用波特率表示,它定义为每秒传输二进制代码的位数,即1波特=1位/秒,单位是bps(位/秒)。
如每秒钟传送240个字符,而每个字符格式包含10位((1个起始位、1个停止位、8个数据位),这时的波特率为10位X240个/秒=2400bps.
串行接口或终端直接传送串行信息位流的最大距离与传输速率及传输线的电气特性也有关。
当传输线使用每0.3m(约1英尺)有50pF电容的非平衡屏蔽双绞线时,传输距离随传输速率的增加而减小。
当比特率超过1000bps时,最大传输距离迅速下降,如9600bps时最大距离下降到只有76m(约250英尺)。
因此我们在做串口通信实验选择较高速率传输数据时,尽量缩短数据线的长度,为了能使数据安全传输,即使是在较低传输速率下也不要使用太长的数据线。
4:
实验代码
/******************************************************************************
*实验名:
温度显示实验
*个人信息:
物联1401廖攀41458027
*实验效果:
使用单片机串口助手,输入GetTemp,此时数码管显示外界温度,同时将温度反馈到电脑。
*******************************************************************************/
#include
#include"temp.h"
#include"string.h"
#defineDIGP0
sbitLSA=P2^2;
sbitLSB=P2^3;
sbitLSC=P2^4;
sbitK2=P3^0;
unsignedcharcodeDIG_CODE[18]={0x06,0x66,0x3f,0x06,0x06,0x5b,0x4f,0x6d};//定义1~9和英文字母的显示(显示000000)
unsignedcharNum=0;
unsignedcharcodeC[]="0123456789.";
unsignedcharA[10];
unsignedintdisp[8]={0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f};
unsignedcharreceiveData[8];
unsignedcharcodedanpianji[]="ID:
41458027Temp:
";
unsignedcharm=0;
voidLcdDisplay(int);
voidTimer0Configuration();
voidUsartConfiguration();
voidDigDisplay1();
voidDelay(unsignedintn);
voidTurn();
/*******************************************************************************
*函数名:
main
*函数功能:
主函数
*输入:
无
*输出:
无
*******************************************************************************/
voidmain()
{
unsignedchari;
Timer0Configuration();//调用计时器
UsartConfiguration();//启用计时器
for(i=0;i<8;i++)
{
disp[i]=DIG_CODE[i+10];
}
while(strcmp(receiveData,"GetTemp"))
{
voidDigDisplay1();
}
while
(1)
{
LcdDisplay(Ds18b20ReadTemp());
if(K2==0)
{
Delay
(1);
if(K2==0)break;
}
}
A[6]='d';
A[7]='c';
A[8]='g';
A[9]='C';
Turn();
}
/*******************************************************************************
*函数名:
LcdDisplay()
*函数功能:
LCD显示读取到的温度
*输入:
v
*输出:
无
*******************************************************************************/
voidLcdDisplay(inttemp)//lcd显示温度
{
unsignedchardatas[]={0,0,0,0,0};//定义数组
floattp;
if(temp<0)
{
disp[2]=0x40;
temp=temp-1;
temp=~temp;
tp=temp;
temp=tp*0.0625*100+0.5;
}
else
{
disp[2]=0;
tp=temp;
temp=tp*0.0625*100+0.5;
}
disp[0]=0;
disp[1]=0;
disp[3]=DIG_CODE[temp/10000];
disp[4]=DIG_CODE[temp%10000/1000];
disp[5]=DIG_CODE[temp%1000/100]|0x80;
disp[6]=DIG_CODE[temp%100/10];
disp[7]=DIG_CODE[temp%10];
A[0]=temp/10000+'0';
A[1]=temp%10000/1000+'0';
A[2]=temp%1000/100+'0';
A[3]='.';
A[4]=temp%100/10+'0';
A[5]=temp%10+'0';
}
/*******************************************************************************
*函数名:
DigDisplay()interrupt1
*函数功能:
中断数码管显示
*输入:
无
*输出:
无
******************************************************************************/
voidDigDisplay()interrupt1
{
//定时器在工作方式二会自动重装初,所以不用在赋值。
//TH0=0X9c;//给定时器赋初值,定时1ms
//TL0=0X00;
DIG=0;//消隐
switch(Num)//位选,选择点亮的数码管
{
case(7):
LSA=0;LSB=0;LSC=0;break;
case(6):
LSA=1;LSB=0;LSC=0;break;
case(5):
LSA=0;LSB=1;LSC=0;break;
case(4):
LSA=1;LSB=1;LSC=0;break;
case(3):
LSA=0;LSB=0;LSC=1;break;
case
(2):
LSA=1;LSB=0;LSC=1;break;
case
(1):
LSA=0;LSB=1;LSC=1;break;
case(0):
LSA=1;LSB=1;LSC=1;break;
}
DIG=disp[Num];//段选,选择显示的数字。
Num++;
if(Num>7)
Num=0;
}
/*******************************************************************************
*函数名:
Timer0Configuration()
*函数功能:
设置计时器
*输入:
无
*输出:
无
*******************************************************************************/
voidTimer0Configuration()
{
TMOD=0X22;//选择为定时器模式,工作方式2,仅用TRX打开启动。
TH0=0X9C;//给定时器赋初值,定时100us
TL0=0X9C;
ET0=1;
EA=1;
TR0=1;
}
/*******************************************************************************
*函数名:
UsartConfiguration()
*函数功能:
设置串口
*输入:
无
*输出:
无
*******************************************************************************/
voidUsartConfiguration()
{
SCON=0X50;
PCON=0X80;
TH1=0xF3;
TL1=TH1;
ES=1;
EA=1;
TR1=1;
}
/*******************************************************************************
*函数名:
voidUsart()interrupt4
*函数功能:
串口中断函数
*输入:
无
*输出:
无
*******************************************************************************/
voidUsart()interrupt4
{
if(RI==1)
{
receiveData[m++]=SBUF;
receiveData[m]='\0';
RI=0;
}
}
/*******************************************************************************
*函数名voidDigDisplay1()
*函数功能:
在数码管上显示"6-319gdh"
*输入:
无
*输出:
无
*******************************************************************************/
voidDigDisplay1()
{
unsignedchari;
unsignedintj;
for(i=0;i<8;i++)
{
switch(i)//位选,选择点亮的数码管,
{
case(0):
LSA=0;LSB=0;LSC=0;break;//显示第0位
case
(1):
LSA=1;LSB=0;LSC=0;break;//显示第1位
case
(2):
LSA=0;LSB=1;LSC=0;break;//显示第2位
case(3):
LSA=1;LSB=1;LSC=0;break;//显示第3位
case(4):
LSA=0;LSB=0;LSC=1;break;//显示第4位
case(5):
LSA=1;LSB=0;LSC=1;break;//显示第5位
case(6):
LSA=0;LSB=1;LSC=1;break;//显示第6位
case(7):
LSA=1;LSB=1;LSC=1;break;//显示第7位
}
DIG=disp[i];
j=10;
while(j--);
DIG=0x00;//消隐
}
}
/*******************************************************************************
*函数名:
Delay(unsignedintn)
*函数功能:
延时
*输入:
n
*输出:
无
*******************************************************************************/
voidDelay(unsignedintn)//延时50us误差0us
{
unsignedchara,b;
for(;n>0;n--)
{
for(b=1;b>0;b--)
for(a=22;a>0;a--);
}
}
/*******************************************************************************
*函数名:
voidTurn()
*函数功能:
向电脑回传数据
*输入:
无
*输出:
无
*******************************************************************************/
voidTurn()
{
unsignedchari,j;
ES=0;
for(i=0;i<17;i++)
{
SBUF=danpianji[i];
while(!
TI);
TI=0;
}
for(j=0;j<10;j++)
{
SBUF=A[j];//将接收到的数据放入到发送寄存器
while(!
TI);//等待发送数据完成
TI=0;
}
}
/*******************************************************************************
*函数名:
Delay1ms
*函数功能:
延时函数
*输入:
无
*输出:
无
*******************************************************************************/
voidDelay1ms(unsignedinty)
{
unsignedintx;
for(y;y>0;y--)
for(x=110;x>0;x--);
}
#include"temp.h"
/*******************************************************************************
*函数名:
Ds18b20Init
*函数功能:
初始化
*输入:
无
*输出:
初始化成功返回1,失败返回0
*******************************************************************************/
unsignedcharDs18b20Init()
{
unsignedinti;
EA=0;
DSPORT=0;//将总线拉低480us~960us
i=70;
while(i--);//延时642us
DSPORT=1;//然后拉高总线,如果DS18B20做出反应会将在15us~60us后总线拉低
i=0;
EA=1;
while(DSPORT)//等待DS18B20拉低总线
{
i++;
if(i>5000)/