【21ic第二届设计大赛】+局域物联网

[复制链接]
2269|11
 楼主| yongruru 发表于 2018-8-14 22:01 | 显示全部楼层 |阅读模式
本帖最后由 yongruru 于 2018-8-21 13:35 编辑

  根据网络容量大小本文提出两种网络方案。第一种针对小型网络10个节点以内,使用MESH网络,主机轮询从机通信。第二种针对10个节点以上网络,采用LoRaWAN网络。下面逐个对两种方案的结构拓扑、优点和限制、设计细节、功能演示等几个方面深入研究。

一、基于lora无线通信构建的MESH网络,实现局域物联网。

结构拓扑

设计概述
  系统分为主机和从机,主机由主控、显示和lora通信模块组成,从机由主控、通信模块和多种传感器组成。工作流程为,从机采集传感器数据存储,主机轮训从机,当被询问到时,根据命令上传传感器数据或者控制IO口输出。主机收到从机数据后处理显示。

优点和限制
优点:1通信逻辑简单,使用现成模块更加简单。2成本低,sx1276相较网关价格有数量级差距。
限制:1网络容量低,随着网络容量增加,轮训的时间变长,实时性变差2增加新节点需要修改主机程序。

电路设计
MCU最小系统,我用的芯片是Microchip的ATSAMC21
电池充电电路,充电电压4.2v,给锂离子电池充电。芯片 EAT6003
电源管理,一个给MCU供电,另一个给传感器供电,由MCU控制是否供电,控制功耗。
传感器电路,两路I2C、两路UART、两路ADC。分别是空气质量CCS811、气压BMP180、GPS模块(备用,可应用于农场都能场景)、lora通信模块、TEMT光敏电阻、NTC热敏电阻。

硬件搭建
8.18补充
一个主机,依次询问两个从机,间隔为2s。
软件设计
8.18补充
主程序流程图,关键函数
  1. /**
  2. 项目:21IC
  3. 角色:中心设备
  4. 功能:询问从机,控制IO
  5. */
  6. #include <asf.h>
  7. #include "my_driver/my_driver.h"
  8. int main (void)
  9. {
  10.         system_init();                        //时钟
  11.         delay_init();                        //延时
  12.         my_io_init();                        //io初始化
  13.         sercom_lora_init();                //lora串口
  14.         sercom_test_init();                //测试串口
  15.         system_interrupt_enable_global();                //开中断
  16.         while(1)
  17.         {
  18.                 ask_slave();                //询问从机2s中一次
  19.         }
  20. }
  1. void ask_slave(void)
  2. {
  3.         //发送给终端03
  4.         static uint8_t i;
  5.         for (i=0;i<16;i++)
  6.         {
  7.                 usart_write_wait(&usart_lora,test_cmd_ASK_03[i]);
  8.         }
  9.         write_2s=2000;
  10.         while(write_2s)
  11.         {
  12.                 delay_ms(1);
  13.                 write_2s--;
  14.                 recieve_lora();        
  15.         }
  16.         //需要添加从机再添加上述代码
  17.         //发送给终端05
  18.         for (i=0;i<16;i++)
  19.         {
  20.                 usart_write_wait(&usart_lora,test_cmd_ASK_05[i]);
  21.         }
  22.         write_2s=2000;
  23.         while(write_2s)
  24.         {
  25.                 delay_ms(1);
  26.                 write_2s--;
  27.                 recieve_lora();
  28.         }
  29. }
  1. static void recieve_lora(void)
  2. {
  3.         if (cmd_flag)
  4.         {
  5.                 cmd_flag=0;
  6.                 static uint8_t i;
  7.                 for (i=1;i<cmd_count-2;i++)
  8.                 {
  9.                         usart_write_wait(&usart_test,cmd_message[i]);
  10.                 }
  11.         }        
  12. }


从程序流程图,关键函数
  1. #include <asf.h>
  2. #include "my_driver/my_driver.h"
  3. int main (void)
  4. {
  5.         system_init();                        //时钟
  6.         delay_init();                        //延时函数
  7.         my_io_init();                        //LED
  8.         tc_100ms_init();                //100ms
  9.         sercom_test_init();                //调试串口
  10.         sercom_lora_init();                //lora通信的串口
  11.         sercom_i2c_init();                //I2C初始化
  12.         system_interrupt_enable_global();                //开中断
  13.         adc_ntc_init();
  14.         adc_light_init();
  15.         bmp180_init();
  16.         ccs811_init();                        //空气质量传感器初始化
  17.         while(1)
  18.         {
  19.                 task_senser();   //读各种传感器的值
  20.                 answer_host();                //收到主机询问,回复传感器值
  21.         }        
  22. }
  1. void task_senser(void)
  2. {
  3.         if (task_count>10)
  4.         {
  5.                 task_count=0;
  6.                 read_ALG();
  7.                 read_light();
  8.                 read_ntc();
  9.                 read_UT_UP();
  10.                 port_pin_toggle_output_level(LED_1);
  11.         }
  12. }
  1. void answer_host(void)
  2. {
  3.         //判断串口是否有数据
  4.         if (cmd_flag)
  5.         {
  6.                 cmd_flag=0;
  7.                 //解释命令
  8.                 if(hand_center("#ASK[        DISCUZ_CODE_5        ]quot;))
  9.                 {
  10.                         pack_message();                                        //按模块格式封装数据
  11.                         send_message();                                        //发送封装数据
  12.                         port_pin_toggle_output_level(LED_3);
  13.                 }
  14.         }
  15. }

功能演示
8月18日补充

主机测试串口输出03和05两个设备上传的不同数据。

8月19日更新,为主机加入了屏幕显示,将串口打印的代码,改成在屏幕显示即可。

可以显示co2的值和累计曲线。


二、基于loraWAN无线网络,实现局域物联网

结构拓扑

设计概述
  节点采集传感器信息,上报给网关。网关发送给应用服务器,应用服务器做出显示。本方案中,网关和应用服务器都部署在linux电脑上,实物上是一个,对外输出HDMI接口做显示。

优点和限制
优点:1网络容量大。2添加节点简单。3节点功耗更低
限制:1网关成本高。2LoraWAM网络复杂,需要多方面知识

传感器部分和方案一相同,只是在无线通信的时候换成带LoRaWAN的协议栈的模块。服务器通过网关收到节点数据后,再写个web程序展示出来。
具体设计见3楼。

  说明:今天刚看见这个活动,还有一周的时间。所以不打算购买器件和制作电路板,有什么器件用什么,没有器件而不能实现的功能也不在纠结,争取能将两个方案制作出来,这才是最重要的。其中MCU采集传感器部分是相同的,通信部分和显示部分会有区别。两个方案的通信部分我计划做完。显示会做方案一的,方案二只在终端显示节点原始数据,不做进一步处理了。希望能够按计划完成^_^

  说明2:两种方案使用的模块通信距离都可以达到1公里以上(直线距离)。可以说是远距离低功耗的无线通信方案,有一定的应用价值。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| yongruru 发表于 2018-8-14 22:02 | 显示全部楼层
本帖最后由 yongruru 于 2018-8-19 20:52 编辑

8月15日,今天翻箱倒柜找板子和器件。有几块以前工程剩下的MCU板子,还翻出来一个空气质量传感器CSS811、一个气压传感器BMP180、一个GPS模块、光敏电阻。最重要的还有几个lora模块。下面展示出来

MCU板子

依次是:LoRa模块、GPS、CSS811、BMP180、TEMT

找好了这些材料,今天就先把原理图画出来,更新到上面,然后硬件连通,明天开始写程序

--------------------------------------------------------------------------------------------------------------------------------

8月16日,今天看了看板子的引脚定义,把部分器件先连起来了,有空气质量传感器,和lora通信模块,还有测试的串口,如下图


然后把程序的框架建立起来:添加所需要的驱动,建立自己的模块列表。下面简单展示下步骤

在ASF库中选择自己需要的驱动包

创建自己的模块列表,如上图标志1,今天只完成了ccs811的程序模块。上图中2是设备的初始化,3是ccs811的初始化,4是读取C02和有机物

最后是程序运行结果

传感器暂时先到这里,明天先把lora通信部分搞出来,等全部程序写完,我整理整理,再一起上传。23:08,晚安

---------------------------------------------------------------------------------------------------------------------------------------------------

8月17日,今天来弄lora通信

首先配置lora模块,写入频率,网络地址,节点地址,串口波特率。相同频率和网络、不同地址的模块才可以通信。

配置出主机和从机。

将Lora模块连接到MCU板,左边从机,右边主机

下面开始主机软件编写
main.c
  1. /**
  2. 项目:21IC
  3. 角色:中心设备
  4. 功能:询问从机,控制IO
  5. */
  6. #include <asf.h>
  7. #include "my_driver/my_driver.h"
  8. int main (void)
  9. {
  10.         system_init();                        //时钟
  11.         delay_init();                        //延时
  12.         my_io_init();                        //io初始化
  13.         sercom_lora_init();                //lora串口
  14.         sercom_test_init();                //测试串口
  15.         system_interrupt_enable_global();                //开中断
  16.         while(1)
  17.         {
  18.                 ask_slave();                //询问从机2s中一次
  19.         }
  20. }

ask_slave()轮训从机函数
  1. void ask_slave(void)
  2. {
  3.         //发送给终端A
  4.         static uint8_t i;
  5.         for (i=0;i<16;i++)
  6.         {
  7.                 usart_write_wait(&usart_lora,test_cmd_ASK_03[i]);
  8.         }
  9.         write_2s=2000;
  10.         while(write_2s)
  11.         {
  12.                 delay_ms(1);
  13.                 write_2s--;
  14.                 recieve_lora();        
  15.         }
  16.         
  17.         //需要添加从机再添加上述代码
  18. }

recieve_lora()接收从机回复
  1. static void recieve_lora(void)
  2. {
  3.         if (cmd_flag)
  4.         {
  5.                 cmd_flag=0;
  6.                 static uint8_t i;
  7.                 for (i=1;i<cmd_count-2;i++)
  8.                 {
  9.                         usart_write_wait(&usart_test,cmd_message[i]);
  10.                 }
  11.         }        
  12. }

lora串口中断服务,接收字节,解析出从机数据
  1. /LoRa中断函数
  2. ISR(SERCOM4_Handler){
  3.         uint16_t temp;
  4.         if (usart_read_wait(&usart_lora, &temp) == STATUS_OK) {
  5.                 lora_buffer=temp;        
  6.                 if (lora_buffer==0x23)                //遇到两个#判定为头
  7.                 {
  8.                         cmd_head_count++;
  9.                 }else
  10.                 {
  11.                         cmd_head_count=0;
  12.                 }
  13.                 if(cmd_head_count==2)        //开始存储
  14.                 {
  15.                         cmd_start=1;
  16.                         cmd_count=0;
  17.                         cmd_flag=0;
  18.                 }
  19.                 if (cmd_start)
  20.                 {
  21.                         cmd_message[cmd_count]=lora_buffer;
  22.                         cmd_count++;
  23.                 }
  24.                 if (lora_buffer==0X24)
  25.                 {
  26.                         cmd_end_count++;
  27.                 }else
  28.                 {
  29.                         cmd_end_count=0;
  30.                 }
  31.                 if (cmd_end_count==2)
  32.                 {
  33.                         cmd_start=0;
  34.                         cmd_flag=1;
  35.                 }
  36.         }
  37. }

从机软件修改
main函数中,注销之前的应用函数,添加answer_host()函数
  1. while(1)
  2.         {
  3. //                 delay_ms(1000);
  4. //                 read_ALG();                        //读ccs811
  5.                 answer_host();                //收到主机询问,回复传感器值
  6.         }        
answer_host()函数,解主机询问,后续可以添加控制IO等
  1. void answer_host(void)
  2. {
  3.         //判断串口是否有数据
  4.         if (cmd_flag)
  5.         {
  6.                 cmd_flag=0;
  7.                 //解释命令
  8.                 if(hand_center("#ASK[        DISCUZ_CODE_5        ]quot;))
  9.                 {
  10.                         pack_message();                                        //按模块格式封装数据
  11.                         send_message();                                        //发送封装数据
  12.                         port_pin_toggle_output_level(LED_3);
  13.                 }
  14.         }
  15. }
实现通信后,下一步工作是添加主机HMI人机交互界面,丰富传感器。
今天就先到这里,明天周六争取完成方案一。
今天是七夕祝愿有情人终成眷属,不多说了,老婆喊我了

--------------------------------------------------------------------------------------------------------------------------------
8月18日上午,先把所填程序运行的结果补上

S03表示从机的编号,主机询问03号,03号回复上来的值
下面在添加一台从机,演示一主多从,轮训查询,避免碰撞
  1. void ask_slave(void)
  2. {
  3.         //发送给终端03
  4.         static uint8_t i;
  5.         for (i=0;i<16;i++)
  6.         {
  7.                 usart_write_wait(&usart_lora,test_cmd_ASK_03[i]);
  8.         }
  9.         write_2s=2000;
  10.         while(write_2s)
  11.         {
  12.                 delay_ms(1);
  13.                 write_2s--;
  14.                 recieve_lora();        
  15.         }
  16.         //需要添加从机再添加上述代码
  17.         //发送给终端05
  18.         for (i=0;i<16;i++)
  19.         {
  20.                 usart_write_wait(&usart_lora,test_cmd_ASK_05[i]);
  21.         }
  22.         write_2s=2000;
  23.         while(write_2s)
  24.         {
  25.                 delay_ms(1);
  26.                 write_2s--;
  27.                 recieve_lora();
  28.         }
  29. }
主机程序,添加代码,
从机程序程序由于没有更多的传感器,用固定值模拟。
最后演示如下

主机收到了上S03和S05两个从机的数据。
下午来丰富下,传感器的内容。

8月18日下午,首先看了下bmp180,也是i2c接口,读取寄存器的值也比较简单,复杂一点的是,读出来的值需要计算。而且计算量还不小,不过按他的公式来基本就能算出来了

数据手册关于计算的部分
  1. void read_UT_UP(void)
  2. {
  3.         port_pin_toggle_output_level(LED_3);
  4.         //读取I2C
  5.         write_data[0]=0xF4;
  6.         write_data[1]=0x2E;
  7.         i2c_master_write_packet_wait(&i2c_master_instance, &bmp180_write2);
  8.         delay_ms(5);
  9.         write_data[0]=0xF6;
  10.         i2c_master_write_packet_wait_no_stop(&i2c_master_instance, &bmp180_write1);
  11.         i2c_master_read_packet_wait(&i2c_master_instance, &bmp180_read2);
  12.         //存储
  13.         unsigned int u_temp;
  14.         unsigned long u_pressure;
  15.         long x1,x2,b5,b6,x3,b3,p;
  16.         unsigned long b4,b7;
  17.         
  18.         u_temp=read_data[0];
  19.         u_temp=u_temp<<8;
  20.         u_temp=u_temp+read_data[0];

  21.         //计算温度
  22.         x1 = (((long)u_temp - (long)ac6)*(long)ac5) >> 15;
  23.         x2 = ((long) mc << 11) / (x1 + md);
  24.         b5 = x1 + x2;
  25.         temperature = ((b5 + 8) >> 4);
  26.         //////////////////////////////////////////////
  27.         write_data[0]=0xF4;
  28.         write_data[1]=0x34;
  29.         i2c_master_write_packet_wait(&i2c_master_instance, &bmp180_write2);
  30.         delay_ms(5);
  31.         write_data[0]=0xF6;
  32.         i2c_master_write_packet_wait_no_stop(&i2c_master_instance, &bmp180_write1);
  33.         i2c_master_read_packet_wait(&i2c_master_instance, &bmp180_read3);
  34.         
  35.         u_pressure=read_data[0];
  36.         u_pressure=u_pressure<<8;
  37.         u_pressure=u_pressure+read_data[1];
  38.         
  39.         //计算气压
  40.         b6 = b5 - 4000;
  41.         x1 = (b2 * (b6 * b6)>>12)>>11;
  42.         x2 = (ac2 * b6)>>11;
  43.         x3 = x1 + x2;
  44.         b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;
  45.         x1 = (ac3 * b6)>>13;
  46.         x2 = (b1 * ((b6 * b6)>>12))>>16;
  47.         x3 = ((x1 + x2) + 2)>>2;
  48.         b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
  49.         b7 = ((unsigned long)(u_pressure - b3) * (50000>>OSS));
  50.         if (b7 < 0x80000000)
  51.         {
  52.                 p = (b7<<1)/b4;
  53.         }
  54.         else
  55.         {
  56.                 p = (b7/b4)<<1;
  57.         }
  58.         x1 = (p>>8) * (p>>8);
  59.         x1 = (x1 * 3038)>>16;
  60.         x2 = (-7357 * p)>>16;
  61.         pressure = p+((x1 + x2 + 3791)>>4);
  62.         //usart_write_buffer_wait(&usart_test," pres=",6);
  63. //         usart_write_wait(&usart_test,pressure/100000+0x30);
  64. //         usart_write_wait(&usart_test,pressure%100000/10000+0x30);
  65. //         usart_write_wait(&usart_test,pressure%10000/1000+0x30);
  66. //         usart_write_wait(&usart_test,pressure%1000/100+0x30);
  67. //         usart_write_wait(&usart_test,pressure%100/10+0x30);
  68. //         usart_write_wait(&usart_test,pressure%10+0x30);
  69. //         usart_write_wait(&usart_test,0x0a);
  70.         
  71.         //绝对高度计算
  72.         //         height = 44330 * (1-powf(((pressure) / 101325),(1.0/5.255)));
  73. }
我的程序,气压值出来了,绝对高度还算的不对,后续再看吧

然后弄了下光敏电阻和热敏电阻,光敏电阻随光强度变强阻值变小,热敏电阻也是温度低时阻值比较大。原理是一样的,只是配的分压电阻需要实际选择下。单片机ADC采集传感器的电压再经过公式或者查表转换成相应的单位。下面我的程序值写到读ADC的值,后面转换的单位的工作暂时没有做,有兴趣的朋友可以自己查查,网上也不较多。
  1. //热敏电阻adc初始化
  2. void adc_ntc_init(void)
  3. {
  4.         struct adc_config config_adc_ntc;
  5.         adc_get_config_defaults(&config_adc_ntc);                                                //获取默认配置
  6.         config_adc_ntc.positive_input        =        ADC_POSITIVE_INPUT_PIN0;
  7.         config_adc_ntc.negative_input   =        ADC_NEGATIVE_INPUT_GND;
  8.         config_adc_ntc.reference        =        ADC_REFERENCE_INTVCC2;                //选择基准电压
  9.         adc_init(&adc_instance, ADC0, &config_adc_ntc);                                        //初始化
  10.         adc_enable(&adc_instance);                                                                                //使能        
  11. }
  1. static void read_ntc(void)
  2. {
  3.         adc_set_positive_input(&adc_instance,ADC_POSITIVE_INPUT_PIN0);
  4.         uint16_t ntc_result;
  5.         adc_start_conversion(&adc_instance);                //开始转换
  6.         while (adc_read(&adc_instance,&ntc_result)==STATUS_OK);
  7. }


到现在实现了主从的轮训通讯,从机可以采集到4个传感器的值。到此方案一先告一段落。稍后将这几天的内容更新到1楼,完整的程序还是要整理后再放出来(完善功能,编写注释)。朋友们的回复是我最大的动力,欢迎交流、批评、灌水、斧正、提问。
楼下开始方案二LoRaWAN网络研究。
-------------------------------------------------------------------------------------------------------------------------------------------------

8月19日更新,主机还有块屏幕,给忘记了。屏幕用最简单的串口屏,DIY嘛。串口屏会提供开发软件,将界面便捷好后,下载到屏幕中,然后主机给屏传递需要限制的值就可以了,下面大致坐下演示

添加了三个控件,一个文本显示“CO2”,一个数字是CO2的值,还有一个曲线是根据每次CO2的值绘制出来的。
单片机向屏幕串口发送“n0.val=**”可以给数字控件赋值,发送“add 1 0 **”给曲线赋值,**为CO2的实际值。下面是实物演示


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评分

参与人数 1威望 +4 收起 理由
arima + 4 很给力!

查看全部评分

 楼主| yongruru 发表于 2018-8-14 22:03 | 显示全部楼层
本帖最后由 yongruru 于 2018-8-21 13:29 编辑

方案一的网络基本上算是小打小闹,不是说看不起第一种方案,这就像单片机系统和PC电脑一样,各有特点,各有适合的应用场景,只不过电脑更通用一些。同样的LoRaWAN网络应用的场景也更为广阔。
简单介绍介绍,lora是无线电射频技术,方案一和方案二物理上都是lora技术。LoRaWAN是网络技术,更多的是软件技术。

本方案使用class a模式,可以更节能。5秒钟上报一次数据,上报数据后会收下发命令。因为对距离要求不是很高,对实时性还有一定要求,所以设置SF=7,BW=250。这种配置下网络容量差不多能到100左右,如果要增加网络容量,可以增加网关或者把节点上报时间间隔再加大些。


下面展示下硬件

网关
网关大致由一个linux电脑和SX1301射频模块组成,linux电脑里有SX1301驱动服务和LoRaWAN网络服务。这是一个单网关的一体方案,集成了NS服务。也可以将NS服务放在云端,基本上这两种方式的比较多。然后呢,将我的应用服务也放在这个linux电脑里,用HDMI连接显示器,访问浏览器显示数据。物理上中心只是一个设备,但却包含了一个网关和服务器,服务器里有包含了3个服务。



节点
节点是一个stm32+sx1278,其中stm32包含了LoRaWAN协议栈。
这里插入一条,为什么两个方案中节点我都选择了现成模块?其实硬件原理上不是很难,一共就一二十个器件,完全可自己画板子做,成本低,使用也更灵活,但是为什么不这样做呢?因为射频对布局、布线、阻抗有一定要求,需要设计时考虑,需要射频工程师来完成。即便设计PCB没有问题,购买器件的参数差别、精度、甚至不同批次都可能产生影响。一般大厂都是和升特公司合作共同开发,升特公司提供指导。市面上的模块性能差别还是挺大的,多数达不到宣传的通信距离。
继续说节点的功能,在升特提供的协议栈上修改,协议栈是一个状态机,负责初始化、入网,发送数据等。



我添加一个任务,串口收到数据,修改状态标志,通过协议栈发送数据,如下

串口中断中解处我的数据。

修改状态标志,发送数据。

8月20日,补充演示内容:串口助手输入数据,通过上面程序的节点发送出去,网关接收到数据给服务器,应用访问服务器显示出来。
演示:

1、节点上电,自动入网(网关打开的情况下)。之后就可以发数据了。

2、中心设备上电,自动打开lorawan的服务。浏览器登录应用服务,输入ID,连接后就可以和节点收发数据了。
如上图,中心已经收到节点发过来的数据“CO2=100 VOL=50”,显示的是16进制,感兴趣的朋友可以对照下ACSII码表,确认下。




本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
21ic小喇叭 发表于 2018-8-15 07:59 | 显示全部楼层
期待后续继续分享哦~
小小电子爱好者 发表于 2018-8-15 08:42 | 显示全部楼层
603820434 发表于 2018-8-15 10:05 | 显示全部楼层
点赞  
 楼主| yongruru 发表于 2018-8-17 09:15 | 显示全部楼层
21ic小喇叭 发表于 2018-8-15 07:59
期待后续继续分享哦~

好的,争取截止前每天有更新
 楼主| yongruru 发表于 2018-8-17 09:16 | 显示全部楼层
 楼主| yongruru 发表于 2018-8-17 09:16 | 显示全部楼层
21ic小喇叭 发表于 2018-8-17 15:42 | 显示全部楼层
比赛还有三天就结束啦,还请及时更新哦,这样才不会影响到时候的评委打分~
 楼主| yongruru 发表于 2018-8-20 11:10 | 显示全部楼层
21ic小喇叭 发表于 2018-8-17 15:42
比赛还有三天就结束啦,还请及时更新哦,这样才不会影响到时候的评委打分~ ...

麻烦将我的帖子链接也放到活动参赛帖里吧。

评论

好的  发表于 2018-8-20 13:42
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

72

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部