LoRa通信案例

该文章已生成可运行项目,

1 前置知识准备

1.1 LoRa通讯原理

低功耗广域网通信 => 范围广 功耗低 传输速度慢

区分网关(主要接收数据) 节点(主要发送数据)

移植官方驱动 初始化启动之后就能发送数据

使用SPI通信

1.2 硬件原理图

(1) SPI1 => E220_400

(2) BUSY 读取忙状态 PE2

(3) RxEN 读使能 PE5

(4) TxEN 写使能 PE6

(5) CS片选 PG14

(6) NRST 重置为 PG13

1.3 项目准备

(1) 使用cube 构建代码

(2) 修改系统时钟 => 打开USART1 用于printf输出 => 打开SPI1用于和E220芯片通信

(3) 根据硬件电路 打开对应的GPIO引脚

(4) 修改项目名称 => 创建代码

(5) 添加Int_lora.c和Int_lora.h文件 移植官方驱动的9个文件

(5) 修改keil => 勾选lib => 修改debug => 添加对应的文件和目录

1.4 项目开发

1.4.1 选择使用的芯片型号

conf.c文件中 => 单选#define EBYTE_E220_400M22S

1.4.2 实现SPI和芯片E220的耦合

port.c文件中 => 根据提示 填写对应的读写 引脚高低电平变化函数 延时函数

1.4.3 实现收发消息之后的回调函数

callback.c文件 => 填写对应的打印逻辑到收发函数中

1.4.4 修改两个bug

(1) 回调函数中的状态码判断应该是 & 而不是&=

(2) 在e220x.c文件中 修改设置同步字的方法 Ebyte_E220x_SetLoraSyncWord => REG_LR_SYNCWORD

1.4.5 实现LoRa接口

直接调用Ebyte_RF中的方法即可

(1) init

(2) startPollTask

(3) send

1.4.6 设计发送信号的触发按键

(1) key3开启EXTI10的外部中断 => 系统滴答定时器的中断优先级要高于key3外部中断

(2) 在外部中断回调函数中设计 => 不能填写太多占用时间的函数 => 修改标志位为1

(3) 考虑消抖 => 进入中断之后 优先延时100ms => 提前确定按键按下是1 不按是0 需要接下拉

2 简介

2.1 LoRa分类

在这里插入图片描述

  • LPWAN(Low Power Wide Area Network)指的是低功耗广域网,其特点在于极低功耗,长距离以及海量连接,适用于物联网万物互联的场景。

在这里插入图片描述

2.2 芯片 E220-400M22S

E220-400M22S是EBYTE(亿佰特)公司是基于Semtech公司生产的全新一代LoRa"射频芯片。由于该模块是纯射频收发模块需要使用MCU驱动或使用专用的SPI调试工具。

2.2.1 引脚说明

引脚名称引脚方向引脚用途
RXEN输入射频开关接收控制脚,连接外部单片机IO,高电平有效
TXEN输入射频开关发射控制脚,连接外部单片机IO或 DIO2,高电平有效
BUSY输出用于状态指示
NRST输入芯片复位触发输入脚,低电平有效
MISO输出SPI数据输出引脚
MOSI输入SPI数据输入引脚
SCK输入SPI时钟输入引脚
NSS输入模块片选引脚,用于开始一个 SPI通信

2.2.2 同步字(Sync Word)

  • LoRa通信中的同步字(Sync Word)是用来区分和识别特定LoRa网络的一种机制。

  • 同步字的值通常可以自定义,允许用户根据需求设置不同的值以创建独立的LoRa网络。所有在同一个LoRa网络中的设备应该使用相同的同步字。

  • 本芯片驱动程序的同步字在ebyte_e220x.h文件下的第133行
#define LORA_MAC_PUBLIC_SYNCWORD                    0x1314    // 0x3444

3 案例

我们需要两个支持LoRa的开发板来完成实验。一个普通节点的角色,一个网关角色。在普通节点上,当我们按下按键时,给网关发送数据。网关收到数据后给普通节点回馈信息。

3.1 CubeMX配置

在这里插入图片描述
在这里插入图片描述

3.2 亿佰特官方驱动下载

下载地址:https://www.ebyte.com/product-view-news.html?id=1355

在这里插入图片描述

下载好后新建文件夹放驱动文件:

在这里插入图片描述

3.3 移植驱动

3.3.1 选择芯片
  • ebyte_conf.h 将本芯片前的注释去掉

在这里插入图片描述

3.3.2 修改 ebyte_port.c
  • 为了耦合stm32芯片

添加 SPI.h

在这里插入图片描述

uint8e_t Ebyte_Port_SpiTransmitAndReceivce( uint8e_t send )
{
    uint8e_t result = 0;
    
    /* !必须提供: SPI接口 */
    HAL_SPI_TransmitReceive(&hspi1,&send,&result,1,1000);
    
    return result;
}

/* !
 * @brief (可选)配置目标硬件平台SPI_CS(NSS)函数 
 */
void Ebyte_Port_SpiCsIoControl( uint8e_t cmd )
{
    if ( cmd == 1 )
    {
       /* !可选: SPI CS控制 E22xx高电平未选中 */  
        //将片选信号拉高
        HAL_GPIO_WritePin(LoRa_CS_GPIO_Port,LoRa_CS_Pin,GPIO_PIN_SET);
    }
    else
    {
       /* !可选: SPI CS控制 E22xx低电平选中 */  
        //将片选信号拉低
        HAL_GPIO_WritePin(LoRa_CS_GPIO_Port,LoRa_CS_Pin,GPIO_PIN_RESET);
    }
}

/* !
 * @brief 配置目标硬件平台复位引脚 NRST 控制函数 
 */
void Ebyte_Port_RstIoControl( uint8e_t cmd )
{
    if ( cmd == 1 )
    {
        /* !必须提供: NRST控制IO 输出高电平 */
        //将RST拉高
        HAL_GPIO_WritePin(LoRa_RST_GPIO_Port,LoRa_RST_Pin,GPIO_PIN_SET);
    }
    else
    {
        /* !必须提供: 目标硬件电路对应NRST控制IO 输出低电平 */
      //将RST拉低
        HAL_GPIO_WritePin(LoRa_RST_GPIO_Port,LoRa_RST_Pin,GPIO_PIN_RESET);
    }
}

/* !
 * @brief (可选)配置目标硬件平台发送使能引脚 TXEN 控制函数 
 */
void Ebyte_Port_TxenIoControl( uint8e_t cmd )
{
    if ( cmd == 1 )
    {
        /* !可选: 目标硬件电路对应TXEN控制IO 输出高电平 */
        //开启输出使能
        HAL_GPIO_WritePin(LoRa_TXEN_GPIO_Port,LoRa_TXEN_Pin,GPIO_PIN_SET);
    }
    else
    {
        /* !可选: 目标硬件电路对应TXEN控制IO 输出低电平 */
        HAL_GPIO_WritePin(LoRa_TXEN_GPIO_Port,LoRa_TXEN_Pin,GPIO_PIN_RESET);
    }
}

/* !
 * @brief 配置目标硬件平台接收使能引脚 RXEN 控制函数 
 */
void Ebyte_Port_RxenIoControl( uint8e_t cmd )
{
    if ( cmd == 1 )
    {
        /* !必须提供: 目标硬件电路对应RXEN控制IO 输出高电平 */
        HAL_GPIO_WritePin(LoRa_RXEN_GPIO_Port,LoRa_RXEN_Pin,GPIO_PIN_SET);
    }
    else
    {
        /* !必须提供: 目标硬件电路对应RXEN控制IO 输出低电平 */
        HAL_GPIO_WritePin(LoRa_RXEN_GPIO_Port,LoRa_RXEN_Pin,GPIO_PIN_RESET);
     
    }
}

/* !
 * @brief 配置目标硬件平台接收使能引脚 BUSY 控制函数 
 * 
 * @note EBYTE模块BUSY为高电平表示忙
 */
uint8e_t Ebyte_Port_BusyIoRead( void )
{
    uint8e_t result = 0 ;  
    
    /* !必须提供: 目标硬件电路对应BUSY IO 状态读取 */
    result = HAL_GPIO_ReadPin(LoRa_BUSY_GPIO_Port,LoRa_BUSY_Pin);
    return result;
}

/* !
 * @brief 配置目标硬件平台延时函数
 * 
 * @param time 期望延时毫秒 
 * @note 请注意时序,模块初始化时将调用此函数,请注意中断是否会影响到此函数
 */
void Ebyte_Port_DelayMs( uint16e_t time )
{
    /* !必须提供: 延时函数 */
    HAL_Delay(1000);

}

3.3.3 修改 ebyte_callbak.c
  • 导入头文件

    在这里插入图片描述

/* !
 * @brief 发送完成回调接口 由客户实现自己的发送完成逻辑
 */
void Ebyte_Port_TransmitCallback( uint16e_t state )
{
    /* 发送: 正常完成 */
    printf("发送完成的状态码:%d",state);

    //切换为接收模式
    Ebyte_RF.EnterReceiveMode(0);
    if( state & 0x0001 )
    {
        //To-do 实现自己的逻辑
        printf("发送成功\n");
    }
    /* 发送: 异常超时 */
    else if ( state & 0x0200 )
    {
        //To-do 实现自己的逻辑
        printf("发送异常超时\n");
    }
    /* 发送: 未知错误 */
    else
    {
        /* 发送状态标识不正确,请检查软硬件
           常见问题 1:SPI通信不正确 2:模块供电不足 */
           printf("发送状态标识不正确,请检查软硬件\n");
        while( 1 );
    }
}

/* !
 * @brief 接收完成回调接口 由客户实现自己的发送完成逻辑

 */
void Ebyte_Port_ReceiveCallback(  uint16e_t state, uint8e_t *buffer, uint8e_t length )
{
    printf("接收的状态码为:%d",state);
    /* 接收: 正常 */
    if( state & 0x0002 )
    {
        //To-do 实现自己的逻辑
        printf("接收到的length:%d,data:%s\n",length,buffer);

    }
    /* 接收: 异常超时 */
    else if ( state & 0x0200 )
    {
        //To-do 实现自己的逻辑
    printf("接收超时\n");
    }
    /* 接收: 未知错误 */
    else
    {
        /* 发送状态标识不正确,请检查软硬件
           常见问题 1:SPI通信不正确 2:模块供电不足 */
    printf("发送状态标识不正确,请检查软硬件\n");

        while( 1 );
    }
}

3.3.4 官方两个错误

(1)在ebyte_callback.c中,状态码判断的地方不应 &= 而是应该直接 &。否则如果第一个if 是false,则state直接就成了0。

(2)设置同步字的命令错了。ebyte_e200x.c

官方写的是REG_LR_SYNCWORDBASEADDRESS应改为REG_LR_SYNCWORD

在这里插入图片描述

3.4 实现接口 Inf_LoRa.c

#include "Inf_LoRa.h"

void Inf_LoRa_Init(void)
{
    Ebyte_RF.Init();
}
void Inf_LoRa_Start(void)
{
    Ebyte_RF.StartPollTask();
}
void Inf_LoRa_Send(uint8_t data[],uint8_t size)
{
    Ebyte_RF.Send(data,size,0);
}

3.5 主函数main.c

/* USER CODE BEGIN 0 */
uint8_t msg[128] = {0};
uint16_t count = 0;
uint8_t is_KeyPressed = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  // 按键产生中断
  if (GPIO_Pin == KEY_Pin)
  {
    // 消抖
    HAL_Delay(100);
    // 认为设定按下为1, 不按为0
    if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin))
    {
      is_KeyPressed = 1;
    }
  }
}
/* USER CODE END 0 */

int main(void)
{
 
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  Inf_LoRa_Init();
  printf("hello LoRa...\n");
  uint32_t name = Ebyte_RF.GetName();
  printf("设备编号为:0x%x\n", name);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    Inf_LoRa_Start();

    if (is_KeyPressed)
    {
      is_KeyPressed = 0;
      // 将count的次数+1打印出来发出去
      memset(msg, 0, sizeof(msg));
      count++;
      sprintf((char *)msg, "计数的次数为%d\n", count);

      Inf_LoRa_Send(msg, strlen((char *)msg));
    }

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

3.6 案例现象

节点按下按键3次,收到三次发送成功消息。

在这里插入图片描述

网关接收到三条数据,并且count只加了三次。

在这里插入图片描述

本文章已经生成可运行项目
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值