目录
一、前言
二、板级收发
三、主机请求
四、从机接收及回复
五、主机接收
一、前言
之前两篇分别介绍了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