目录

一、前言

二、板级收发

三、主机请求

四、从机接收及回复

五、主机接收


 本项目的交流QQ群:701889554

物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html

物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html

物联网实战--平台篇https://blog.csdn.net/ypp240124016/category_12653350.html

一、前言

        之前两篇分别介绍了modbus和sx1278的驱动,但是都并未具体讲解如何应用,那么这一篇就把两者结合起来,做个小demo,便于理解这两个驱动的使用方法。

        简单讲就是物理层的通讯链路用LoRa,协议层用modbus,由于有主机、从机,所以需要两套硬件设备,STM32F103C8T6系统板+SX1278模块,两套硬件是一样的,代码有差异,就是在软件层面定义身份是主机还是从机,分别对应下载进去就能实现主机请求从机数据的功能了。

        STM32F103C8T6就跟净化器项目那个一样就行了,SX1278模块需要有插针,这样才能用杜邦线链接,有能力的自己画PCB板也是可以的,可以参考这个链接的https://item.taobao.com/item.htm?abbucket=8&id=621186198228&ns=1&skuId=4892611431467&spm=a21n57.1.item.5.42d6523catPFYv

具体的接线如下:

二、板级收发

        为了方便应用层调用,我们再把收发函数封装一层,具体如下:


/*		
================================================================================
描述 : 设置无线参数
输入 : 
输出 : 
================================================================================
*/
void bsp_sx1278_set_param(u32 freq, u8 sf, u8 bw)
{
	drv_sx1278_set_rf_freq(&g_sDrvSx1278, freq);
	drv_sx1278_set_sf(&g_sDrvSx1278, sf);
	drv_sx1278_set_bw(&g_sDrvSx1278, bw);  
}


/*		
================================================================================
描述 : LORA底层发送函数
输入 : 
输出 : 
================================================================================
*/
u8 bsp_sx1278_send_level(u32 freq, u8 sf, u8 bw, u8 *buff, u16 len)
{
	static const u16 dly_time=15;
	u16 tx_timeout=drv_sx1278_calcu_air_time(sf, bw, len)*1.2+500;//计算发送时长
	u32 dly_cnts=tx_timeout/dly_time;
	u8 tx_len=0;

	bsp_sx1278_set_param(freq, sf, bw);
	drv_sx1278_send(&g_sDrvSx1278, buff, len);
	printf("drv_port_sx1278_send_level: time_out=%dms, P(%u, %u, %u)\n", tx_timeout,  freq, sf, bw);
//	printf_hex("send buff= ", buff, len);
	
	while(dly_cnts--)
	{
		delay_os(dly_time);
		if(drv_sx1278_send_check(&g_sDrvSx1278)==true)
		{
			drv_sx1278_recv_init(&g_sDrvSx1278);	//设置成接收模式
			tx_len=len;
			printf("app_sx1278_send: send ok, tx_len=%d\n", tx_len);
			break;
		}		
	}
	if(tx_len==0)
	{
		printf("app_sx1278_send: send failed!\n");
		drv_sx1278_recv_init(&g_sDrvSx1278);	//设置成接收模式
	}
	return tx_len;		
}

/*		
================================================================================
描述 : LORA接收检测
输入 : 
输出 : 
================================================================================
*/
void bsp_sx1278_recv_check(void)
{
	static u8 recv_buff[256]={0};
	u8 recv_len=0;	
	recv_len=drv_sx1278_recv_check(&g_sDrvSx1278, recv_buff);//LORA接收
	if(recv_len>0)
	{
//		printf_hex("recv_buff= ", recv_buff, recv_len); 
    if(SX1278_ROLE==SX1278_MASTER) //主机模式
    {
      app_sx1278_master_recv_parse(recv_buff, recv_len);//主机数据解析
    }
    else
    {
      app_sx1278_slaver_recv_parse(recv_buff, recv_len);//从机数据解析
    }
	}	

}

        这样,发送的时候就可以根据自己需要的无线参数灵活配置,发送函数内部自动完成了发送时间计算、无线参数配置、数据写入和延时等待等任务;对于接收,这里写得比较不严谨,收到数据后的解析处理正常要用回调函数的,但是为了方便测试也就没搞得那么麻烦了,不管主机还是从机,收到数据后会进入各自的解析函数。

        主机和从机的角色要在这里自己定义,更改后重新编译下载。

三、主机请求

        这种主从结构的网络,都是主机主动请求,从机被动回复的,理论上从机不能随意发送数据的,不然会让整个网络乱套的。下面是主机请求的代码:


/*		
================================================================================
描述 : 主机请求数据
输入 : 
输出 : 
================================================================================
*/
void app_sx1278_master_req_data(void)
{
  static u32 last_sec_time=0;
  u32 now_sec_time=drv_get_sec_counter();
  if(now_sec_time-last_sec_time>=5)//5秒请求一次
  {
    u8 make_buff[50]={0};
    u16 make_len=0;
    
    make_len=drv_modbus_send_fun03(1, 0x0000, 2, make_buff, sizeof(make_buff));//组合请求数据
    
    bsp_sx1278_send_level(434000000, 12, 9, make_buff, make_len);//根据无线参数发送modbus数据  
      
    last_sec_time=now_sec_time;
  }

}

        也是比较简单的,间隔5秒请求一次,请求的数据通过之前的modbus驱动函数来组合的,参数是从机地址1,起始寄存器0x0000,寄存器数量2个;无线参数是频率434MHz,SF=12,BW=9;最后就是等它发送完成了。

四、从机接收及回复

        从机的LoRa平时都是处于接收模式的,所以当主机发送数据后,只要信号没什么问题,正常都能接收到一个数据包的,记得两个模块不要放太近,天线要插上。接收解析和回复代码如下:

/*		
================================================================================
描述 : 从机回复数据
输入 : 
输出 : 
================================================================================
*/
void app_sx1278_slaver_ack_data(void)
{
    u8 make_buff[50]={0};
    u16 make_len=0;
    
    //在这里只是模拟测试,我们发送一个固定数据包就行了
    make_buff[make_len++]=0x01; //地址码
    make_buff[make_len++]=0x03; //功能码
    make_buff[make_len++]=0x04; //数据长度
    make_buff[make_len++]=0x02; 
    make_buff[make_len++]=0x92; 
    make_buff[make_len++]=0xFF;
    make_buff[make_len++]=0x9B; //4字节数据
    make_buff[make_len++]=0x5A;
    make_buff[make_len++]=0x3D; //CRC校验
    
    bsp_sx1278_send_level(434000000, 12, 9, make_buff, make_len);//根据无线参数发送回复数据    
}

/*		
================================================================================
描述 : 从机接收解析
输入 : 
输出 : 
================================================================================
*/
void app_sx1278_slaver_recv_parse(u8 *recv_buff, u16 recv_len)
{
  printf_hex("slaver recv= ", recv_buff, recv_len);//打印应用层数据
  app_sx1278_slaver_ack_data();//回复到主机
}

        从机这里没做过多的解析,直接就是回复一个固定的数据包就是了,自己可以添加一些地址码和校验码检测的内容,数据也可以添加一些随机数。从机回复的发送过程跟主机是一样的,无线参数是要一致的。

五、主机接收

        主机发送完成后会马上进入接收模式,等待从机的回复,收到回复后会进行modbus的解析,代码如下:

/*		
================================================================================
描述 : 主机接收解析
输入 : 
输出 : 
================================================================================
*/
void app_sx1278_master_recv_parse(u8 *recv_buff, u16 recv_len)
{
  u8 data_buff[20]={0};
  u16 data_len=drv_modbus_parse_fun03(1, recv_buff, recv_len, data_buff, sizeof(data_buff));//modbus解析
  if(data_len>0)
  {
    printf_hex("master recv= ", data_buff, data_len);//打印应用层数据
  }
}

        最后把数据区打印出来,这样一个完整的请求回复流程就完成了,剩下的就是不断重复这个过程。这里,我们单独开了一个线程用户LoRa的数据请求,代码如下:

/*		
================================================================================
描述 : 
输入 : 
输出 : 
================================================================================
*/
void app_sx1278_init(void)
{
	app_sx1278_hal_init();

  bsp_sx1278_set_param(434000000, 12, 9);//无线参数初始化
}

/*		
================================================================================
描述 : sx1278线程
输入 : 
输出 : 
================================================================================
*/
void app_sx1278_thread_entry(void *parameter) 
{
  app_sx1278_init();
  
  while(1)
  {
    if(SX1278_ROLE==SX1278_MASTER) //主机模式
    {
      app_sx1278_master_req_data(); //轮询从机数据
    }

    bsp_sx1278_recv_check();//数据接收
    
    delay_os(20);
  }
}

        在初始化的时候开启这个线程就能运行了。

下图是结构目录:

代码链接:https://download.csdn.net/download/ypp240124016/89101284

本项目的交流QQ群:701889554

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐