忙活了好久终于做出了温湿度采集和485的多机通信,还有上位机。本系统完成的功能有:各个从机采集数据传送给主机再由主机传送到上位机,下位机同时可以接受上位机的控制,来改变温湿度。找了好久发现网上这方面的资料很不全,而且大部分不能用,现将资料全部共享,方便大家学习交流,有不足之处,还请各位多提意见建议。
先上几张作品图,预览预览,呵呵···
传感器是 奥松 的,型号为AM2301(又名DHT21),挺好用的,传输距离可达到20米,本人已通过实地验证。上位机是用VC做的,版本为VC6.0,界面做了简单的美化,用到了不少控件,按键类、Edit类、图表类等等。
上位机、下位程序、以及用到的芯片及参考资料现打包上传
界面图
连线组装图
主控特写
主程序代码
/***************************************************************************函数名称: AM2301多机通信主机部分 主控芯片: STC12C5A60S2,晶振11.0592MHz 功 能: 和从机及上位机通信,接收从机发送过来的温湿度,用1620显示出来并 将数据传送到上位机 创建日期: 2011.5.22 修改日志: 无 ****************************************************************************/ //#include <reg52.h> #include <STC12C5A.h> #include <intrins.h> #include "LCD1602.h" #define uchar unsigned char #define uint unsigned int #define _Nop() _nop_() sbit RDE =P3^2; // 485控制输入输出控制(与从机) sbit RDE2=P1^4; //485控制输入输出控制(与上位机) #define SlaveNum 2 //从机数量 uchar code dis1[]={"H: % T: C"} ; uchar code dis2[]={"h: % t: c"} ; #define num 8 //缓冲数据的长度 char Revdata[num];//接收到的数据缓存 uchar SLAVE_ID = 1;//从机地址 uchar rc;//串口1接收到和数据缓存 uchar Rev;//串口2接收数据 //---------------------------------------- uchar state = 0;//状态标志位。1-进入等待从机回应,2-更新显示数据 uchar recv_length = 0; bit recving_flag = 0; bit recfinish=0; bit recflag=0; bit minusflag=0,addflag=0,stopflag=0; //---------------------------------------- //////////////////////////////////////////////////////////////////////// //////////////////延时函数/////////////////////////////////////// //////////////////////////////////////////////////////////////////////// void Delay(unsigned int t) { while(t--); } ///////////////////////////////// void Delay_10us(unsigned int us) { do{ _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); }while(--us); } ////////////////////////////////// void Delay_ms(unsigned int ms) { do Delay_10us(131); while(--ms); } //////////////////////////////////////////////////////////////////////// //////////////////////串口1发送地址函数////////////////////////////// //////////////////////////////////////////////////////////////////////// void senda(unsigned char adra) //发送地址 { TB8 = 1;//发送地址帧 RDE = 1;//允许发送 Delay_10us(50); ES=0; //关串1口中断 TI = 0; //清标志位 SBUF = adra; while(!TI); TI = 0;//等待发送完毕 ES=1; //开串口1中断 RDE = 0;//485允许接收 Delay_10us(50); } //////////////////////////////////////////////////////////////////////// //////////////////////串口1发送数据函数////////////////////////////// ////////////////////////////////////////////////////////////////////// /**/ void sendata(unsigned char tdata) //发送地址 { TB8=0;//发送数据帧 RDE = 1;//允许发送 TI = 0; SBUF = tdata; while(!TI); TI=0; RDE = 0;//485允许接收 } ////////////////////////////////////////////////////////////////////// //////////////////////串口2发送数据函数/////////////////////////////// ////////////////////////////////////////////////////////////////////// void Uart2_senbyte(uchar val) { RDE2=1;//485发送状态 // Delay(50); IE2=0x00;//关串口2中断 S2BUF=val; while ((S2CON & 0x02) == 0); //等待发送完毕 S2CON &= 0xFD; //清标志位(S2TI=0) IE2=0x01;//开串口2中断 RDE2=0; // Delay(50); } //////////////////////////////////////////////////////////////////////// ///////////////////////////////显示函数///////////////////////////////// //////////////////////////////////////////////////////////////////////// ///////////显示字符/////// void showchar() { uchar string; //====显示字符1====== string=0; writecmd(0x80); while(dis1[string] != '\0')//显示字符 { writedata(dis1[string]) ; string++ ; }string = 0 ; //=====显示字符2===== writecmd(0xc0); while(dis2[string] != '\0')//显示字符 { writedata(dis2[string]) ; string++ ; }string = 0 ; } //////////////显示数据///////////// void showdata() { if(SLAVE_ID==1) { //=====显示湿度===== writecmd(0x82); writedata(Revdata[1]+0x30); writedata(Revdata[2]+0x30); writedata('.'); writedata(Revdata[3]+0x30); //=====显示温度===== writecmd(0x8b); writedata(Revdata[4]+0x30); writedata(Revdata[5]+0x30); writedata('.'); writedata(Revdata[6]+0x30); Delay_ms(400); } if(SLAVE_ID==2) { //=====显示湿度===== writecmd(0xc2); writedata(Revdata[1]+0x30); writedata(Revdata[2]+0x30); writedata('.'); writedata(Revdata[3]+0x30); //=====显示温度===== writecmd(0xcb); writedata(Revdata[4]+0x30); writedata(Revdata[5]+0x30); writedata('.'); writedata(Revdata[6]+0x30); Delay_ms(1000); } } //////////////////////////////////////////////////////////////////////// ///////////////////串口初始化函数//////////////////////////////// //////////////////////////////////////////////////////////////////////// void UARTinit() { //串口1初始化///////// TMOD|=0x21;//定时器1工作在方式2,定时器0工作在方式1 TH1=0xfa;TL1=0xfa; //波特率9600 SCON=0x50;//SCON:SM0,SM1,SM2,REN,TB8,RB8,TI,RI PCON|=0x80;//波特率倍增 TR1=1;//开定时器1 EA=1;//开总中断 ES=1;//串口1中断 //--------------------// //串口2初始化/////////// BRT = 0XDC; //设置独立的波特率发生器的重载数值,此数值的波特率为9600 AUXR = 0X14; //设置波特率的发生方式(允许波特率发生器运行,波特率不加倍,每个时钟计数一次) S2CON|=0x50;//串口2,方式1,允许接收 IE2|=0X01;//允许串口2中断 EA=1;//开总中断 //--------------------// Delay(10000); //热机时间 init_LCD(); //初始化液晶 } //========================================== //////////////////////////////////////////////////////////////////////// ///////////////////////////////主函数/////////////////////////////////// //////////////////////////////////////////////////////////////////////// void main() { // uchar i; UARTinit();//串口初始化 Delay(40000);//热机 while(1) { WDT_CONTR=0x3c;//启动看门狗,超过该时间未能喂狗则系统复位, //0011.1011---WDT_FLAG=0,EN_WDT=1,CLR_WDT=1,IDLE_WDT=0,PS2=1,PS1=1,PS0=0 //IDLE_WDT=1时,"空闲模式"计数,IDLE_WDT=0时"空闲模式"不计数 //0x38-71.1ms,0x39-142.2ms, 0x3a-284.4ms, 0x3b-568.8ms, //0x3c-1.1377s,0x3d-2.2755s,0x3e-4.5511s,0x3f-9.1022s showchar();//显示字符 if(state == 0) { senda(SLAVE_ID++); if(SLAVE_ID>SlaveNum)SLAVE_ID = 1; if(addflag==1&&SLAVE_ID==1){sendata(0xf1);addflag=0;}//发送指令给从机1 if(minusflag==1&&SLAVE_ID==2){sendata(0xf2);minusflag=0;}//发送指令给从机2 if((stopflag==1&&SLAVE_ID==1)||(stopflag==1&&SLAVE_ID==2)) {stopflag=0,sendata(0xf0);} // 发哦能够停止指令给从机1、2 Delay_ms(30); state = 1;// 状态转为等待从机应答,在串口中断 /* if(recfinish==1) { recfinish=0; if(recflag == 0) {// recflag =0; // senda(SLAVE_ID); senda(SLAVE_ID++); Delay_ms(4000); if(SLAVE_ID>SlaveNum) { SLAVE_ID = 1; senda(SLAVE_ID); Delay_ms(4000); } }//end of recving_flag =0 }//end of recfinish=1 */ } //end of state=0 if(state == 2) // 状态 转为 显示 { showdata();//更新数据显示 Delay_ms(800); //发送数据到上位机 Uart2_senbyte('R');//上位机识别湿度的标志 Uart2_senbyte(Revdata[1]+0x30);// Uart2_senbyte(Revdata[2]+0x30); Uart2_senbyte('.'); Uart2_senbyte(Revdata[3]+0x30); Uart2_senbyte('T');//上位机识别温度的标志 Uart2_senbyte(Revdata[4]+0x30); Uart2_senbyte(Revdata[5]+0x30); Uart2_senbyte('.'); Uart2_senbyte(Revdata[6]+0x30); if(SLAVE_ID==1)Uart2_senbyte('A');//上位机识别从机的标志 if(SLAVE_ID==2)Uart2_senbyte('B'); /* //////////////////////////////////////////////////////////////// for(i = 1; i<num-1; i++) { senda(Revdata[i]); //把收到的数据往PC机回送(串口助手调试用) Delay_ms(20); } */ //////////////////////////////////////////////////////////////// Delay_ms(20); state = 0; // 状态转为0,重新查询从机 }//end of state=2 WDT_CONTR=0x3c;//喂狗,若超过时间不喂狗,则系统复位 }//end of while(1) }//end of main() //////////////////////////////////////////////////////////////////////// ///////////////////串口 1接收 中断 函数////////////////////////////////// //////////////////////////////////////////////////////////////////////// void Recv_int(void)interrupt 4 //using 2 { RDE=0; if(RI) { RI=0; rc=SBUF; if(state==1) { if((recv_length == 0)&&(rc == 0xf7 ) ) //这里判断发送的第一个字节 { recving_flag = 1; recflag=1; } if(recving_flag == 1) { Revdata[recv_length++] = rc; if(rc == 0xf3)//判断结束帧 { recv_length = 0; recving_flag = 0; recfinish=1; state = 2; //接收完毕,置标志位,准备显示 }//end of rc=0xf3 }//end of recving_flag = 1 }//end of state=1 }//end of RI }//end of interrupt //////////////////串口2中断服务子程序//////////////////////////// void Uart2() interrupt 8 //using 1 { RDE2=0;//485保持为接收状态 if (S2CON & S2RI) { S2CON &= ~S2RI; //清除接收完成标志 Rev = S2BUF; switch(Rev) { case 'a': //加大湿度 addflag=1; break; case 'm': //降低湿度 minusflag=1; break; case 's': //停止 stopflag=1; break; default: break; }//end of swtich } //end of if RDE2=1;//485允许发送 } ////////////////////////////////End/////////////////////////////////////
复制代码