基于STM32的LoRa PINGPONG系统设计
本次分享一种LoRa PINGPING系统的设计。 单片机:STM32F103C8T6 LORA模组:LLCC68
文章目录
基于STM32的LoRa PINGPONG系统设计1 设计需求2 通信机制3 软件流程3.1 主体流程3.2 Master流程3.3 Slaver流程
4 软件代码编写4.1 参数配置4.2 发送完成处理4.3 接收完成处理4.4 主函数
5 试验验证
1 设计需求
将LoRa终端定义成两种角色:Master和SlaveMaster主动发送PING数据,接收PANG数据Slave如果接收到PING数据,回应PANG数据printf打印终端类型及收发数据包个数
2 通信机制
3 软件流程
3.1 主体流程
3.2 Master流程
3.3 Slaver流程
4 软件代码编写
4.1 参数配置
LoRa参数配置,必须确保主机和从机的参数一致,否则额会通讯异常。
//--------------------------------------------- 测试默认配置 ---------------------------------------------
#define LORA_FRE 470000000 // 收发频率
#define LORA_TX_OUTPUT_POWER 20 // 测试默认使用的发射功率,126x发射功率0~22dbm,127x发射功率2~20dbm
#define LORA_BANDWIDTH 2 // [0: 125 kHz, 测试默认使用的带宽,LLCC68:[0: 125 kHz,1: 250 kHz,2: 500 kHz,3: Reserved]
#define LORA_SPREADING_FACTOR 8 // 测试默认使用的扩频因子范围7~12
#define LORA_CODINGRATE 2 // 测试默认使用的纠错编码率[1: 4/5,2: 4/6,3: 4/7,4: 4/8]
#define LORA_PREAMBLE_LENGTH 10 // 前导码长度
#define LORA_LLCC68_SYMBOL_TIMEOUT 0 // Symbols(LLCC68用到的是0,127x用到的是5)
#define LORA_FIX_LENGTH_PAYLOAD_ON false // 是否为固定长度包(暂时只是LLCC68用到了)
#define LORA_IQ_INVERSION_ON false // 这个应该是设置是否翻转中断电平的(暂时只是LLCC68用到了)
#define LORA_RX_TIMEOUT_VALUE 5000
4.2 发送完成处理
static void LLCC68OnTxDone( void )
{
#ifdef MASTER
Radio.Rx( 0 ); //进入接收模式
//发送完成闪烁一下led提示
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
Master_TxNumber++;
#else
//发送完成闪烁一下led提示
Radio.Rx( 0 ); //进入接收模式
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
Slave_TxNumber++;
#endif
}
4.3 接收完成处理
static void LLCC68OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
uint8_t Buffer[BUFFERSIZE];
#ifdef MASTER
Radio.Standby();
Radio.Rx(0);
if(size!=strlen((const char*)PongMsg)){
printf("recive size !=4 is error\r\n");
}else{
memcpy(&Buffer,payload,4);
printf("MASTER recive:%s\r\n",Buffer);
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
//接收包数
Master_RxNumber++;
printf("MASTER recive packet:%d\r\n",Master_RxNumber);
Radio.Send(PingMsg,strlen((const char*)PingMsg));
}
#else
Radio.Standby();
Radio.Rx(0);
if(size!=strlen((const char*)PingMsg)){
printf("recive size !=4 is error\r\n");
}else{
memcpy(&Buffer,payload,4);
printf("Slave recive:%s\r\n",Buffer);
//接收成功闪烁一下led提示
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
//接收包数
Slave_RxNumber++;
printf("Slave recive packet:%d\r\n",Slave_RxNumber);
Radio.Send(PongMsg,strlen((const char*)PongMsg));
}
#endif
}
4.4 主函数
#include "stm32f10x.h"
#include "delay.h"
#include "HAL_uart.h"
#include "stdio.h"
#include "stm32f10x_it.h"
#include "project_config.h"
#include "radio.h"
#include "string.h"
/*
wiring setting
spi bus:
LoRa modules STM32
NSS_PIN PA4
MOSI_PIN PA7
MISO_PIN PA6
SCK_PIN PA5
RESET_PIN PB1
DIO1_PIN PB11
DIO4_BUSY_PIN PA0
波特率:115200
UART:
USB to TTL STM32
Tx PA_9
Rx PA_10
*/
#define BUFFERSIZE 4
uint8_t PingMsg[] = "PING";
uint8_t PongMsg[] = "PONG";
uint16_t BufferSize = BUFFERSIZE;
#ifdef MASTER
uint8_t EnbleMaster = true;
#else
uint8_t EnbleMaster = false;
#endif
uint32_t Master_TxNumber = 0;
uint32_t Master_RxNumber = 0;
uint32_t Slave_TxNumber = 0;
uint32_t Slave_RxNumber = 0;
uint8_t OCP_Value = 0;
static RadioEvents_t LLCC68RadioEvents;
static void LLCC68OnTxDone( void );
static void LLCC68OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
static void LLCC68OnTxTimeout( void );
static void LLCC68OnRxTimeout( void );
static void LLCC68OnRxError( void );
//硬件初始化
void SysInit(void){
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); //NVIC(中断优先级管理)分组配置,注意:这个分组整个程序只能有一次,配置后不要修改,否则会出现很多问题 这里直接用4,0~15优先级
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //JTAG复用为GPIO需要使用 RCC_APB2Periph_AFIO 时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //关闭JTAG功能(需要打开 RCC_APB2Periph_AFIO 时钟)
//led指示灯
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_0); //PB.0 输出高
HALUart1Init();
SysTick_Config(SystemCoreClock/1000);
}
int main(void){
SysInit(); //硬件初始化
//判断SPI是否连接成功
OCP_Value = Radio.Read(REG_OCP);
printf("[%s()-%d]read OCP register value:0x%04X\r\n",__func__,__LINE__,OCP_Value);
//初始化LoRa参数
LLCC68RadioEvents.TxDone = LLCC68OnTxDone;
LLCC68RadioEvents.RxDone = LLCC68OnRxDone;
LLCC68RadioEvents.TxTimeout = LLCC68OnTxTimeout;
LLCC68RadioEvents.RxTimeout = LLCC68OnRxTimeout;
LLCC68RadioEvents.RxError = LLCC68OnRxError;
Radio.Init( &LLCC68RadioEvents );
Radio.SetChannel(LORA_FRE);
//参数:lora模式,发射功率,fsk用的lora设置为0就可以,带宽,纠错编码率,前导码长度,固定长度数据包(一般是不固定的所以选false),
//crc校验,0表示关闭跳频,跳频之间的符号数(关闭跳频这个参数没有意义),这个应该是表示是否要翻转中断电平的,超时时间
Radio.SetTxConfig( MODEM_LORA, LORA_TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
LORA_SPREADING_FACTOR, LORA_CODINGRATE,
LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );
Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
LORA_LLCC68_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
0, true, 0, 0, LORA_IQ_INVERSION_ON, false );
printf("all setting\r\n");
printf("freq: %d\r\n Tx power: %d\r\n band width: %d\r\n FS: %d\r\n CODINGRATE: %d\r\n PREAMBLE_LENGTH: %d\r\n",LORA_FRE,LORA_TX_OUTPUT_POWER,LORA_BANDWIDTH,LORA_SPREADING_FACTOR,LORA_CODINGRATE,LORA_PREAMBLE_LENGTH);
#ifdef MASTER
Radio.Send(PingMsg,strlen((const char*)PingMsg));
printf("I am Master!\n");
#else
Radio.Rx( 0 ); //进入接收模式
printf("I am Slave!\n");
#endif
printf("SysInit OK,version:%s\r\n",SOFT_VERSION);
while(1)
{
Radio.IrqProcess( ); // Process Radio IRQ
delay_ms(1);
}
}
static void LLCC68OnTxDone( void )
{
#ifdef MASTER
Radio.Rx( 0 ); //进入接收模式
//发送完成闪烁一下led提示
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
Master_TxNumber++;
#else
//发送完成闪烁一下led提示
Radio.Rx( 0 ); //进入接收模式
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
Slave_TxNumber++;
#endif
}
static void LLCC68OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
uint8_t Buffer[BUFFERSIZE];
#ifdef MASTER
Radio.Standby();
Radio.Rx(0);
if(size!=strlen((const char*)PongMsg)){
printf("recive size !=4 is error\r\n");
}else{
memcpy(&Buffer,payload,4);
printf("MASTER recive:%s\r\n",Buffer);
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
//接收包数
Master_RxNumber++;
printf("MASTER recive packet:%d\r\n",Master_RxNumber);
Radio.Send(PingMsg,strlen((const char*)PingMsg));
}
#else
Radio.Standby();
Radio.Rx(0);
if(size!=strlen((const char*)PingMsg)){
printf("recive size !=4 is error\r\n");
}else{
memcpy(&Buffer,payload,4);
printf("Slave recive:%s\r\n",Buffer);
//接收成功闪烁一下led提示
GPIO_ResetBits(GPIOB,GPIO_Pin_0);
delay_ms(100);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
//接收包数
Slave_RxNumber++;
printf("Slave recive packet:%d\r\n",Slave_RxNumber);
Radio.Send(PongMsg,strlen((const char*)PongMsg));
}
#endif
}
static void LLCC68OnTxTimeout( void )
{
printf("TxTimeout\r\n");
}
static void LLCC68OnRxTimeout( void )
{
Radio.Standby();
printf("RxTimeout retry recive\r\n");
Radio.Rx( LORA_RX_TIMEOUT_VALUE );
}
static void LLCC68OnRxError( void )
{
Radio.Standby();
printf("RxError retry recive\r\n");
Radio.Rx(LORA_RX_TIMEOUT_VALUE);
}
5 试验验证
–验证流程: 将主机程序刷到主机中,将从机程序刷到从机中,通过宏定义进行区分。 观察主机和从机的打印情况。 主机: 从机: 完整代码: https://download.csdn.net/download/qq_39742246/88629477 已经过验证
|