本帖最后由 e来e去 于 2023-4-25 19:04 编辑

忙活了好久终于做出了温湿度采集和485的多机通信,还有上位机。本系统完成的功能有:各个从机采集数据传送给主机再由主机传送到上位机,下位机同时可以接受上位机的控制,来改变温湿度。找了好久发现网上这方面的资料很不全,而且大部分不能用,现将资料全部共享,方便大家学习交流,有不足之处,还请各位多提意见建议。
先上几张作品图,预览预览,呵呵···

    传感器是 奥松 的,型号为AM2301(又名DHT21),挺好用的,传输距离可达到20米,本人已通过实地验证。上位机是用VC做的,版本为VC6.0,界面做了简单的美化,用到了不少控件,按键类、Edit类、图表类等等。
上位机、下位程序、以及用到的芯片及参考资料现打包上传


image.png

界面图

image.png

连线组装图

image.png

主控特写

主程序代码

/***************************************************************************
  • 函数名称: 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/////////////////////////////////////
  • 复制代码