打印
[其他]

【21ic第二届设计大赛】+ 环境量信息无线采集系统

[复制链接]
1171|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 地瓜patch 于 2018-8-19 11:52 编辑

1. [综述]
这是一个环境量信息采集监控系统,采用2.4G无线星型拓扑结构,实现对多点采集的信息收集与监控。本设计项目仅实现环境温度与湿度的信息采集。

2. [结构]
系统层次结构图:


系统分为三层,由上位机作为总控制台,通过RS485总线与接收机进行通信。可将多个接收机同时挂接在RS485总线上。单个接收机理论上可与256个节点进行通信。接收机选用 6dBi的鞭状天线,节点选用自带板载天线的射频模块,通信室外实测距离80米,丢包数大约35%-40%。接收机和节点均选用 6dBi的鞭状天线,实测通信距离将近200米,丢包率在50%左右。
控制信息及报警阈值在上位机设置并判断,根据判断结果将控制命令下发给接收机在转发到节点,节点可触发特定外设,以LED灯代替外设。
1)每个接收机以一个字节的485地址作为识别码,在程序中预制。接收机之间没有数据交互
上位机与接收机的通信数据格式定义如下:
同步头
命令标识
数据标识
数据
校验
同步头:6字节,A5 5A A5 5A A5 5A。
命令标识16进制,1字节,表示本命令的含义。
数据标识:16进制,5字节,第1,2个字节表示接收机的485地址标识码,第3,4个字节表示节点的识别码,第5个字节表示传输数据总字节数N。
数据:16进制,N字节。传输的实际数据。
校验:16进制,1个字节。帧类型到数据以字节为单位进行异或校验。
2)每个节点以五个字节的数据作为识别码,在程序中预制。节点之间没有数据交互
接收机与节点的通信数据格式定义如下:
  同步头
节点标识
数据
校验
同步头:2字节,A5 5A。

节点标识16进制,2字节:表示本节点的识别码,。

数据:16进制,6字节。传输的实际数据。上行输温度2字节,湿度2字节,电压2字节。下行2字节控制信息。

校验:16进制,1个字节。帧类型到数据以字节为单位进行异或校验


相关帖子

沙发
地瓜patch|  楼主 | 2018-7-19 09:00 | 只看该作者
本帖最后由 地瓜patch 于 2018-8-19 17:49 编辑

3. [方案]
1)用上位机作为控制主机,通过RS232转RS485或USB转RS232等串行总线来下挂接收机,所有接收机为从机。两者的通信协议可以参考现有比较成熟的ModBus协议,当然也可自订协议。上位机功能规划如下:
接收节点:显示收到的节点地址标识
节点总数:显示收到的节点数量
       '*******************节点信息统计
        If no_repeat_numb = 0 Then
                        remenber_data_buffer(0) = recdata_buffer(9)
                       remenber_data_buffer(1) = recdata_buffer(10)

                       no_repeat_numb = 1
                       Text7.Text = no_repeat_numb
                        Text6.SelStart = Len(Text6.Text)
                        Text6.Text = Text6.Text + vbCrLf
                        Text6.Text = Text6.Text & "Node" & no_repeat_numb & ":" & H_add & Space(1) & L_add & vbCrLf _
                                         & Space(4) & "Temperature:" & t_temp & "℃" & vbCrLf _
                                         & Space(4) & "Humidity:" & h_temp & "%RH" & vbCrLf _
                                         & Space(4) & "Votage:" & v_temp & "V"
                                         '& "Time:" & Now
                       Text6.SelLength = 1
                       Text6.SelStart = Len(Text6.Text)
                       Length_1 = Len(Text6.Text)

                       recdata_buffer(9) = 0
                       recdata_buffer(10) = 0
        ElseIf no_repeat_numb = 1 Then
                        remenber_data_buffer(2) = recdata_buffer(9)
                       remenber_data_buffer(3) = recdata_buffer(10)

                       no_repeat_numb = 2
                       Text7.Text = no_repeat_numb
                        Text6.SelStart = Len(Text6.Text)
                        Text6.Text = Text6.Text + vbCrLf
                        Text6.Text = Text6.Text & "Node" & no_repeat_numb & ":" & H_add & Space(1) & L_add & vbCrLf _
                                         & Space(4) & "Temperature:" & t_temp & "℃" & vbCrLf _
                                         & Space(4) & "Humidity:" & h_temp & "%RH" & vbCrLf _
                                         & Space(4) & "Votage:" & v_temp & "V"
                                         '& "Time:" & Now
                       Text6.SelLength = 1
                       Text6.SelStart = Len(Text6.Text)
                       Length_1 = Len(Text6.Text)

                       recdata_buffer(9) = 0
                       recdata_buffer(10) = 0
        Else
                For i = 0 To no_repeat_numb - 1
                   If (recdata_buffer(10) <> remenber_data_buffer(2 * i + 1)) Then
                        no_repeat_temp = no_repeat_temp + 1
                   ElseIf (recdata_buffer(9) <> remenber_data_buffer(2 * i)) Then
                        no_repeat_temp = no_repeat_temp + 1
                   Else
                       i = no_repeat_numb + 1
                   End If
                Next

                If (no_repeat_numb = no_repeat_temp) Then
                       remenber_data_buffer(2 * no_repeat_numb) = recdata_buffer(9)
                       remenber_data_buffer(2 * no_repeat_numb + 1) = recdata_buffer(10)

                       no_repeat_numb = no_repeat_numb + 1
                       Text7.Text = no_repeat_numb
                        Text6.SelStart = Len(Text6.Text)
                        Text6.Text = Text6.Text + vbCrLf
                        Text6.Text = Text6.Text & "Node" & no_repeat_numb & ":" & H_add & Space(1) & L_add & vbCrLf _
                                         & Space(4) & "Temperature:" & t_temp & "℃" & vbCrLf _
                                         & Space(4) & "Humidity:" & h_temp & "%RH" & vbCrLf _
                                         & Space(4) & "Votage:" & v_temp & "V"
                                         '& "Time:" & Now
                       Text6.SelLength = 1
                       Text6.SelStart = Len(Text6.Text)
                       Length_1 = Len(Text6.Text)

                       recdata_buffer(9) = 0
                       recdata_buffer(10) = 0
                       no_repeat_temp = 0
                Else
                End If
        End If
End If

repeat_numb = repeat_numb + 1 '收到节点总数量
Text13.Text = repeat_numb
End If

串口port:填写虚拟串口端口号,范围从1-16
节点编号:显示当前收到的节点地址标识
温度:显示当前收到节点的温度
湿度:显示当前收到节点的湿度
电压:显示当前收到节点的电压
时间:显示当前收到节点的时间
报警阈值:用来设定某节点的温度、湿度阈值及上传数据的时间间隔
外设控制:用来控制某节点的外设的开启关闭
右侧的栅格用来描点显示温度湿度值。蓝色为湿度,红色为温度
将接收到的有效数据保存在HEX.txt文本文件中

上位机程序及发布包的压缩包: VB.T.H.V.G.V1.0.rar (1.65 MB) 无线温湿度节点数据信息采集上位机软件V1.0.rar (423.05 KB)


2)接收机主要2.45GHz的无线收发模块和主控控制MCU组成。采用RS485总线与上位主机进行通讯。由外部提供3.3V电源。结构图如下
接收机外接电源,功耗基本不用考虑,我采用的是以前项目的用过的样板,用pic的18系列片子,f4680.该片子性能没的说,只是价格不是很美丽。其实完全可以考虑其他厂家的片子。射频模块采用NF-01-N模块,spi接口,中断传输,可由mcu控制其省电状态。
最小系统如下图:

RS485接口采用带电源隔离的全双工3535,安全可靠,缺点还是价格。RTC实时时钟电路用来计算并存储时间,图纸如下:

该图纸是在现有电路板的基础上改造使用的,版子上需要添加射频模块NF-01-N,射频天线选用增益6dBi的2.4G鞭状天线。焊接中如下图。射频模块使用SPI接口,但是MCU的SPI接口没有引出,所以只能用线飞出来。规划中,接收机采用RS485接入PC机,为了测试方便用USB转USART,并提供3.3V电源。
接收机程序比较简单主要是接收主机控制信息并下发,接收无线节点信息并上传。接到无线节点数据后,对该节点标识进行判别是否有该节点的控制信息,若有则下发,没有则顺序执行程序。为保证节点数据的及时接收与控制,无线模块采用中断接收数据,程序流程如下:
/*********初始化spi接口************/

void SPI_Init(void)
{  

                        INTCON2bits.INTEDG0 =0; //下降沿触发
                        INTCON2bits.INTEDG1 =0; //下降沿触发
                 /*************串行通讯中断接收接收初始化子程序***********/
                        UART_Init();
                        RCONbits.IPEN = 1;//使能中断高低优先级
                        T0CON = 0x47;                 //8位寄存器set up timer0 - prescaler 1:256
                        INTCONbits.INT0IF = 0;//清零中断标志位
                        INTCON3bits.INT1IF = 0;//清零中断标志位
                        INTCONbits.TMR0IF = 0;
                        INTCONbits.INT0IE = 1; //开中断
                        INTCON3bits.INT1IE = 1; //开中断
                        INTCONbits.T0IE=0;//关闭定时器
                        INTCON3bits.INT1IP = 1; //INT1高优先级
                        INTCON2bits.TMR0IP=0;//TMR0低优先级中断
                        IPR1bits.RCIP=0;//设置SCI接收中断为高优先级级中断
                         /*************spi使能,spi模式2***********/
                SSPCON1bits.SSPEN=1;
                SSPCON1bits.SSPM3=0;
                SSPCON1bits.SSPM2=0;
                SSPCON1bits.SSPM1=0;
                SSPCON1bits.SSPM0=0;
                SSPCON1bits.CKP=0;//spi模式0
                SSPSTATbits.CKE=1;//空闲状态时电平         
                SSPSTATbits.SMP=1;//MISO采样输入数据的时间,末端采样
               /******I\O端口配置*************************/
                TRISCbits.TRISC5=0;//MOSI输出,RC5
                TRISCbits.TRISC3=0;//SCK输出,RC3
                TRISCbits.TRISC4=1;//MISO输入,RC4
                TRISCbits.TRISC1=0;//CE1为输出,CE1-RDO
                TRISCbits.TRISC2=0;//CSN1为输出,CSN1-RD1
                LATCbits.LATC2=1;
                TRISBbits.TRISB1=1;//IRQ1为输入,IRQ1-RBO
                TRISDbits.TRISD0=0;//CE0为输出,CE1-RDO
                TRISDbits.TRISD1=0;//CSN0为输出,CSN1-RD1
                LATDbits.LATD1=1;
                TRISBbits.TRISB0=1;//IRQ0为输入,IRQ1-RBO
                TRISDbits.TRISD6=0;//使能ltc1535发送
}
//发送模式
void TX_Mode(unsigned char TX_FIFO_BUF[])
{
        spi_ce = 0;//待机模式  
        spi_ce1 = 0;
          SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_Address, TX_Addr_Width);     // 写入发送地址
          SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_Address, RX_Addr_Width);  // 为了应答接收设备
          SPI_Write_Buf(WR_TX_PLOAD, TX_FIFO_BUF, TX_PayLoad_Width);         // 写数据包到TX FIFO
          SPI_RW_Reg(WRITE_REG + EN_AA, 0x00);       // 禁止通道自动应答
           SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x03);  // 禁止自动重发
          SPI_RW_Reg(WRITE_REG + RF_CH,0x66);         
          SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x26);    // 数据传输率250kps,发射功率0dBm,低噪声放大器增益
        SPI_RW_Reg(WRITE_REG + SETUP_AW, 0x03);
        SPI_RW_Reg(WRITE_REG + FEATURE, 0x04);
        SPI_RW_Reg(WRITE_REG + DYNPD, 0x01);
        SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); // CRC使能,16位CRC校验 ,上电,发射模式
        Delay1KTCYx(10);//延时2ms
        spi_ce = 1;//置高,数据发送
        spi_ce1 = 1;
        Delay100TCYx(10);//延时10us
}
////接收模式
void RX_Mode(void)
{
     spi_ce = 0;//待机模式  
            SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_Address, RX_Addr_Width);//0通道接收地址,地址宽度5
         SPI_RW_Reg(WRITE_REG + EN_AA, 0x00);      //0通道自动应答禁止
         SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //0通道接收
         SPI_RW_Reg(WRITE_REG + FEATURE, 0x04);//动态字节长度使能
         SPI_RW_Reg(WRITE_REG + DYNPD, 0x01);//通道0动态数据长度
         SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x26);//传送速率250kps,发射功率0dbm,
            SPI_RW_Reg(WRITE_REG + CONFIG, 0x3F);//CRC使能,16位CRC校验,上电,接收模式
}
具体例程见附件1和2 附件1.2.rar (3.99 KB, 下载次数: 0)

使用特权

评论回复
板凳
地瓜patch|  楼主 | 2018-8-4 22:28 | 只看该作者
本帖最后由 地瓜patch 于 2018-8-19 18:48 编辑

3)在整个设计中,对无线节点有低功耗要求。因此其功能尽量简化,并且需要选用低功耗元件。微控制器通过SPI总线与射频芯片连接,射频收发电路由2.4GHz射频收发集成芯片、晶体振荡器和天线匹配电路组成。节点功能框图如下

节点选用手头上的几块Mcu核心板还热乎的,程序流程在头脑里比较清晰并且有些函数可以直接使用,但需要扩展射频接口和传感器。该核心板外接接口只留了电源地和两个IO口,所以该接口作为传感器的接口。给传感器提供电源,用IO口做模拟IIC连接数字传感器。开始一直使用带板载天线的射频模块RF_N_2401,经测试其距离有限,后来又买了两个外接天线的模块NRF-01-N.。两种模块的射频芯片都是采用挪威的NRF24L01.在程序上可以统一。只要注意连接线的接续顺序即可。
开始测试用碱性电池做测试,发现耗电太快了,后来换成手机电池,充电方便还省电池,当了个当。
微控制器通过SPI总线发送命令来读写射频芯片实现数据在无线信道上的接收和发送,并且按照设定的通信调度算法运行,传感节点瞬时发送一次信息后进入长时间休眠。在数据采集期间,微控制器会将环境量传感器配置在高分辨率模式来保证环境量的采集精度;在数据发送期间,微控制器会将射频收发器配置在全功率模式来保证无线收发的长距离;在休眠期间,微控制器会将所有电子元件配置为掉电模式来保证装置的低功耗。掉电时间越长,数据采集和传输时间相对越短,在保证无线装置精度和性能的前提下节约电池能源开支,实现超低功耗。
上电初始,微控制器配置所有电子元件进入掉电模式,自身也进入低功耗模式并开始计时。计时时间到后,微控制器环境量传感器唤醒并开始数据转换,转换完成后由处理器来实现将转换结果丢弃、保存或直接发送,此后环境量传感器进入掉电模式并将射频收发器唤醒配置为全功率模式进行数据发送传输,待传输结束后节点进入射频接收模式,等待1mS,在此时间内接收上位机的配置,并改写内部变量。然后进入掉电模式。以上为一个工作循环。程序流程图如下图所示
模拟IIC程序

void Start_SHT75(void)
{
TRISBbits.TRISB7 = 0;        //0定义为输出
SHT_SD_OUT = 1;
SHT_CK = 0;
Delay10TCY;//延时5次
Delay10TCY;Delay10TCY;Delay10TCY;Delay10TCY;
SHT_CK = 1;
Delay10TCY;//延时1次
SHT_SD_OUT = 0;
Delay10TCY;//延时1次
SHT_CK = 0;
Delay10TCY;//延时1次
SHT_CK = 1;
Delay10TCY;//延时1次
SHT_SD_OUT = 1;
Delay10TCY;//延时1次
SHT_CK = 0;
}
//******************************************************
//通讯中断后,用以下时序重新连接
//sda---------------------------------------____--
//                1        2        3        4        5        6         7         8        9
//scl__--__--__--__--__--__--__--__--__--__--__--__
void Connect_SHT75(void)
{
  unsigned char i;
TRISBbits.TRISB7 = 0;        //0定义为输出
  SHT_SD_OUT =1;
  SHT_CK = 0;
Delay10TCY;Delay10TCY;//延时2次
  for(i=0;i<9;i++)
    {
         SHT_CK = 1;
Delay10TCY;//延时5次
Delay10TCY;Delay10TCY;Delay10TCY;Delay10TCY;
         SHT_CK = 0;
Delay10TCY;//延时1次
         }
//  Start_SHT75();
}        

//****************************************************************
unsigned char Write_SHT75(unsigned char value)
{
unsigned char i;
unsigned char error = 0;

for(i=0x80;i>0;i/=2)
    {TRISBbits.TRISB7 = 0;        //0定义为输出

         if(i & value)
            SHT_SD_OUT = 1;
         else
            SHT_SD_OUT = 0;
                Delay10TCY;//延时1次
                SHT_CK = 1;CLRWDT();
                Delay10TCY;//延时1次
                SHT_CK = 0;
                Delay10TCY;//延时1次
  }

//SHT_SD = 1;//这个电平没高上去,只有1v
SHT_SD_OUT = 1;
TRISBbits.TRISB7 = 1;        //1定义为输入
//ANSELbits.ANS3 = 0;
SHT_CK = 1;
error = SHT_SD_IN;                              //if SHT_SD == '0 ',sht75 ack
//  Delay10TCYx(1);
  SHT_CK = 0;        CLRWDT();
Delay10TCY;//延时5次
Delay10TCY;Delay10TCY;Delay10TCY;Delay10TCY;
  return(error);
}
//*******************************************************************
unsigned char Read_SHT75(unsigned char ack)
{

unsigned char i , value = 0 ;
TRISAbits.TRISA5 = 0;        //0定义为输出
SHT_SD_OUT = 1;
TRISBbits.TRISB7 = 1;        //1定义为输出入
//ANSELbits.ANS3 = 0;

for(i=0x80;i>0;i/=2)
   {
        SHT_CK = 1;
        Delay10TCY;//延时1次
        if(SHT_SD_IN)                                //从sd上读取8位数据
          value = value | i;
        SHT_CK = 0;CLRWDT();
    Delay10TCY;//延时1次
        }
TRISBbits.TRISB7 = 0;        //0定义为输出
        NOP();
   SHT_SD_OUT = !ack;                        
   SHT_CK = 1;
   Delay10TCY;//延时5次
Delay10TCY;Delay10TCY;Delay10TCY;Delay10TCY;
   SHT_CK = 0;CLRWDT();
   Delay10TCY;//延时1次
   SHT_SD_OUT = 1;
   Delay10TCY;//延时1次
  return value;
}
//设置WDT休眠时间,以1S为时基
void wdt_sleep_T(unsigned char slp_T)
{
unsigned char i;
CONFIG2Hbits.WDTEN=1;//使能WDT
OSCCONbits.IRCF=0;
OSCTUNEbits.INTSRC=0;//选择LFINTOSC低频振荡器
CONFIG2Hbits.WDTPS=8;//设置WDT分频

        for(i=0;i<slp_T;i++)
        {
                OSCCONbits.IDLEN = 0;//执行SLEEP 后进入休眠模式
                Sleep();
        }
}
//控制IO口
#define CTL_IO_bit   LATCBbits.LATC3
TRISCbits.TRISC3 = 0;        //0定义为输出

void CTL_peripheral_IO(unsigned char ctl_IO)
{
        if(ctl_IO==1)
        {
                CTL_IO_bit=1;
        }
        else
        {
                CTL_IO_bit=0;
        }
}

代码见附件: version_pic18lf13k22 - widthcon.rar (43.03 KB)

使用特权

评论回复
地板
caijie001| | 2018-8-5 00:15 | 只看该作者
点赞支持

使用特权

评论回复
5
21ic小喇叭| | 2018-8-17 15:45 | 只看该作者
比赛还有三天就结束啦,还请及时更新哦,这样才不会影响到时候的评委打分~

使用特权

评论回复
6
地瓜patch|  楼主 | 2018-8-17 16:38 | 只看该作者
21ic小喇叭 发表于 2018-8-17 15:45
比赛还有三天就结束啦,还请及时更新哦,这样才不会影响到时候的评委打分~ ...

快了快了,正在加班加点

使用特权

评论回复
7
地瓜patch|  楼主 | 2018-8-19 16:29 | 只看该作者
本帖最后由 地瓜patch 于 2018-8-19 21:10 编辑

4. 节点用fluke15B测量休眠时的电流为1.3uA,根据各元件数据手册估算节点发射时总电流在12mA左右,接收时电流在13mA左右。以休眠时间5S估算平均功耗在20uA左右。
[存在问题]1)任一接收机可以接收其自身范围内的任一节点数据,那么就存在多个接收机接收到同一节点同一时刻的同一包数据。没想到好的解决办法。
2)节点的标识码是在写入程序时写入,即每写一个节点的程序都要改写一次标识码。不利于大量程序写入。也没想到好的解决办法。
3)还有一些其他问题待优化。

总结:
1. [基本项目] 设计一个信息采集监控系统,采用无线通信相互连接,实现对多点采集点的信息收集与监控。【星型网络。单点对多点
2. [基本项目] 系统由一个中央控制台(右边)与多个节点(左边)组成.组网方式宜采用低功耗/长距离的通信方式,如LoRa/SigFox,或者其它协议【自定义协议】。中央控制台与节点的通信距离要长于50米【外接天线可达200米】。 中央控制台的功耗不做要求,但是越低越好【未测试】。中央控制台可以采用PC扩展,也可以使用其他带显示+输入的任何的任何系统扩展【pc做控制台】。 样机中节点数最少2个,系统要设计为能扩展至少8个节点【接入5个节点,理论可接入256个】。
3. [基本项目] 无线通信要实现双向通信,平时节点间歇地向中央控制台发送采集的信息(温度,湿度,光线,空气质量等等)【上传温度、湿度、电压数据】。中央控制台也可以至少控制每个节点的一个IO口(比如使用LED表示控制状态)【可控制一个IO口】。双向通信可以采用单/双通信模块实现,最好使用单通信模块实现【单通信模块】。节点之间可以不实现互相通信【节点间不通信】。
4. [基本项目] 中央控制台平时能通过图表(如曲线的形式)实时显示采集的数据【曲线显示数据】。节点到中央控制台的信息发送至少要达到0.2Hz(即上传数据间隔最多为5秒一次)【时间可调,1秒时基】。节点的数据与中央控制台显示的延迟越短越好。
5. [基本项目] 中央控制台要有输入手段,控制每个节点的至少一个IO口【可控IO】。控制频率至少为5秒一次,控制延迟不超过2秒。
6. [基本项目] 节点采用电池供电,功耗至少能达到:两节5号电池能使用一天以上,功耗越低越好,节点能上传当前节点电量【估算平均功耗20uA】。
7. [加分项目]
系统要显示可扩展性、可配置性,如可以动态增加减少节点。【可显示增加节点,目前不能显示减少节点
节点有两种工作方式:正常工作方式/低功耗方式(仅仅监听主机的控制指令)。【一种工作方式:休眠->发送->等待1mS接收->休眠
数据可以保存文本或者数据库形式,传输到其他存储体上(如每天备份当天数据到SD卡)。【可保存为*.txt文件
中央控制台能与互联网通信,如将数据上传到云上,在网页上显示实时数据。【未实现
中央控制台可以根据采集值定制自动控制Policy(如采集值高于某点,低于某点自动发送IO控制命令,并且在中央控制台显示报警)。【已规划,未实现
节点可以按照一定的作息切换工作模式与低功耗模式,如采集光线的应用可以仅仅在8:30-20:30工作,其余时间段低功耗。该作息Policy可以配置。【未实现
其他参数上的优化。


使用特权

评论回复
评论
地瓜patch 2018-8-20 21:09 回复TA
手机拍的视频,在电脑上是反转180度。上传到优酷后,竟然反转回来了,优酷真棒(广告) 
8
地瓜patch|  楼主 | 2018-8-20 21:08 | 只看该作者
周末两天下雨,正好不用带孩子出去玩,把之前的工作总结了一下。写完帖子。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:出一块TI-PLABS-AMP-EVM

1163

主题

11139

帖子

26

粉丝