您的位置:首页 > 运维架构

51单片机-PC数据传输 温度 距离 监控系统设计

2014-06-24 23:59 411 查看
>_<:功能概述:

通过串口PC和单片机通信,可以询问单片机测得的温度,可以询问声呐测距的测量距离,同时把测量温度显示在数码管上。





>_<:PC部分

这里com.cpp和com.h是串口通信的函数封装,在主函数中:

刚开始调用封装好的串口通信函数,设置打开串口COM4,波特率设置为9600,超时设置:

if(openport("com4"))
printf("open comport success\n");
if(setupdcb(9600))
printf("setupDCB success\n");
if(setuptimeout(0,0,0,0,0)) //如果所有写超时参数均为0,那么就不使用写超时
printf("setuptimeout success\n");
clearall();//全清


接着循环接收控制台命令来与串口通信:这里用了串口通信函数WriteChar和ReceiveChar来与串口进行信息传送,注意这里的读写应和单片机的一致,否则就会出现错误。这里举a==5的例子说明:

[命令5表示改变距离阈值,当输入5时,PC将向串口发送字符’5’,然后等待输入改变后的温度,当输入改变温度时,将该温度传给串口[因为我们这里的范围是0-100]所以一个char类型就能表示,将这个值发送给串口,当单片机改变好距离阈值后会返回改好的命令,所以调用ReceiveChar接收返回信息。其他类似。]


while(1){
scanf("%d",&a);//1表示要温度,2表示要距离,3表示距离警报关闭,4温度警报关闭,5改变距离阈值,6改变温度阈值
if(a==5){         m_szWriteBuffer[0]='5';
WriteChar(m_szWriteBuffer,1);
printf("Please enter the num:(0-100cm) \n");
scanf("%d",&a);
m_szWriteBuffer[0]=(BYTE)(a);
WriteChar(m_szWriteBuffer,1);
ReceiveChar(m_szReceiveBuffer,20);
printf("%s\n",m_szReceiveBuffer);
}else if(a==6){
m_szWriteBuffer[0]='6';
WriteChar(m_szWriteBuffer,1);
printf("Please enter the num:(0-100℃) \n");
scanf("%d",&a);
m_szWriteBuffer[0]=(BYTE)(a);
WriteChar(m_szWriteBuffer,1);
ReceiveChar(m_szReceiveBuffer,20);
printf("%s\n",m_szReceiveBuffer);
}else{
m_szWriteBuffer[0]=(BYTE)(a+'0');
WriteChar(m_szWriteBuffer,1);

ReceiveChar(m_szReceiveBuffer,20);
printf("%s\n",m_szReceiveBuffer);
}
}


>_<:单片机部分

设备:

18B20温度传感器

8位数码管显示

串口通信

HC-SR04超声波测距仪

STC89C52[11.0952MHz]

蜂鸣器

连线:

  这里选用11.0592MHz的晶振,将8位7段数码管公共线接P0的8个端口,P2.3接位码,P2.2接段码;串口通信采用MAX232连接如图所示。



main函数介绍:

#初始化部分介绍:

1 unsigned int TempH,TempL,temp;
2 Init_Timer0();
3 UART_Init(); // 串口初始化
4 Init_Timer1();
5
6 ReadTemperature();//这里放置3个温度读取,防止出现初始化温度不稳定情况
7 ReadTemperature();
8 ReadTemperature();


第2行:初始定时器:MOD |= 0x01---T0定时16位模式

第3行:串口初始化:具体信息见注释

void UART_Init(void)
{
SCON = 0x50;         // 设定串行口工作方式,8位数据位,允许接收
T2CON = 0x34;         //设置定时器2,作为波特率发生器
RCAP2L = 0XDC;      //9600波特率的低8位
RCAP2H = 0XFF;        //9600波特率的高8位
ES = 1;                 //允许串口中断
EA = 1;                 //允许总中断
}


第6-8行: 在系统初始前先读取3次温度,防止系统初始时温度的值不正常而触发报警

#主循环介绍:

while (1)
{
if(isInclude || isAbove){
//LED_Show(2);
//if(freq==200);
SPK=!SPK;
}
if(uart_flag==1)   //接收到
{
ES=0;       //关串口中断
if(come=='1'){//接收并改变距离阈值
maxJuLi=(unsigned int)a;
come='0';
UART_Send_Byte('O');
UART_Send_Byte('K');
UART_Send_Byte('#');
UART_Send_Byte('\n');
}else if(come=='2'){//接收并改变温度阈值
maxWenDu=(unsigned int)a;
come='0';
UART_Send_Byte('O');
UART_Send_Byte('K');
UART_Send_Byte('#');
UART_Send_Byte('\n');
}else//其他操作
switch(a){//要温度
case '1':
for(i=0;i<17;i++)
{
UART_Send_Byte(SendData[i]);//将数据发给串口
}
UART_Send_Byte('\n');
break;
case '2'://要距离
for(i=0;i<16;i++)
{
UART_Send_Byte(SendData1[i]);//将数据发给串口
}
UART_Send_Byte('\n');
break;
case '3':
if(isInclude){
isInclude=0;
UART_Send_Byte('c');
UART_Send_Byte('l');
UART_Send_Byte('o');
UART_Send_Byte('s');
UART_Send_Byte('e');
UART_Send_Byte('#');
UART_Send_Byte('\n');
}else{
UART_Send_Byte('n');
UART_Send_Byte('o');
UART_Send_Byte(' ');
UART_Send_Byte('p');
UART_Send_Byte('e');
UART_Send_Byte('r');
UART_Send_Byte('s');
UART_Send_Byte('o');
UART_Send_Byte('n');
UART_Send_Byte('#');
UART_Send_Byte('\n');
}
break;
case '4':
if(isAbove){
isAbove=0;
UART_Send_Byte('c');
UART_Send_Byte('l');
UART_Send_Byte('o');
UART_Send_Byte('s');
UART_Send_Byte('e');
UART_Send_Byte('#');
UART_Send_Byte('\n');
}else{
UART_Send_Byte('n');
UART_Send_Byte('o');
UART_Send_Byte(' ');
UART_Send_Byte('f');
UART_Send_Byte('i');
UART_Send_Byte('r');
UART_Send_Byte('e');
UART_Send_Byte('#');
UART_Send_Byte('\n');
}
break;
case '5':
come='1';
break;
case '6':
come='2';
break;
default://错误操作
for(i=0;i<16;i++)
{
UART_Send_Byte(SendData2[i]);//将数据发给串口
}
UART_Send_Byte('\n');
break;
}
ES=1;    //允许串口中断
uart_flag=0;  //中断标志位置0
}
else if(ReadTempFlag==1)//通过定时器,每隔1200ms扫描一次温度
{
ReadTempFlag=0;
temp=ReadTemperature();
if(temp&0x8000)//第一位为1就表示为负要取反加1第一位弄个负号
{
TempData[0]=0x40;//负号标志
temp=~temp;  // 取反加1
temp +=1;
}
else
TempData[0]=0;//其他情况就该显示负号的不显示

TempH=temp>>4;//去除低四位
TempL=temp&0x0F;//获取温度低四位
TempL=TempL*6/10;//小数近似处理!

if(TempH>0 && TempH>maxWenDu)isAbove=1;//界限判断

if(TempH/100==0)//百位数据
TempData[1]=0;
else
TempData[1]=DuanMa[TempH/100]; //百位温度
if((TempH%100)/10==0)//十位温度
TempData[2]=0;
else
TempData[2]=DuanMa[(TempH%100)/10];
TempData[3]=DuanMa[(TempH%100)%10]|0x80; //个位温度,带小数点
TempData[4]=DuanMa[TempL];
TempData[6]=0x39;         //显示C符号

SendData[11]=(unsigned char)(TempH/100+'0');
SendData[12]=(unsigned char)(TempH%100/10+'0');
SendData[13]=(unsigned char)(TempH%100%10+'0');
SendData[14]='.';
SendData[15]=(unsigned char)(TempL+'0');
}else if(ReadTempFlag==2){
ReadTempFlag=0;
StartModule();        //测距
while(!RX);            //当RX为零时等待
TR1=1;                //开启计数
while(RX);            //当RX为1计数并等待
TR1=0;                //关闭计数
Conut();            //计算
}
}


第3-7行:当温度在阈值外或者距离在阈值内时就响铃

第8-103行:当串口通信发生串口中断时,会把uart_flag标志位置1,然后主程序就会处理PC端传送过来的数据,这里采用串口中断来检测是否收到PC发来的数据的:

void UART(void) interrupt 4
{
if(RI)                   //检测接收完成标志位置1
{
RI=0;            //清零接收完成标志位
a=SBUF;            //读取接收到的数据
uart_flag = 1;    //中断标志位置1
}
}


第11-25行:这里是要修改温度或者距离的阈值时用到的特殊处理,因为当收到修改阈值的命令之后还要等待要改成的值,为了区别这个值和命令值,于是用come标记是否是要修改阈值,如果不是修改阈值,就正常判断命令,否则就做相应的阈值修改。

第27-33行:将温度发送给PC,最后要发送一个换行,当做结束标志位[这是和PC端的接收程序有关,2个通信的协议要一致],其他类似,不做详解。

第41-86行:关闭报警命令,如果正在报警,就关闭报警,返回给电脑已经关闭的信息;如果没有报警,就回复电脑相应信息。

第87-92行:要修改阈值,就把come置成相应的值,等待接受要修改值,与第11-25行相对应

第104-141行:如果没有电脑命令传过来就进行温度采集和距离测试:

void Timer0_isr(void) interrupt 1
{
static unsigned int num;
TH0=(65536-2000)/256;//重新赋值 2ms
TL0=(65536-2000)%256;

Display(0,8);  // 调用数码管扫描
num++;
if(num==100){
ReadTempFlag=1;//读温度标志位置2
}else if(num==150)
{
num=0;
ReadTempFlag=2;//读距离标志位置1
}
}


第143-147行:测量时间差[用定时器TH1,TL1]

第148行:计算超声波测距的距离[根据上面计算的声波来回的时差]

void Conut(void)
{
time=TH1*256+TL1;
TH1=0;
TL1=0;
S=(time*1.87)/100;     //算出来是CM
if(flag==1)            //超出测量
{
flag=0;
//printf("-----\n");
}
if(S<maxJuLi)isInclude=1;//界限判断
//.......
}


全部资源连接:http://pan.baidu.com/s/1ntukZ8l
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: