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只加了三次。

6250

被折叠的 条评论
为什么被折叠?



