Lora串口透传例程说明
这个例程实现了串口和lora之间的数据透传。
两块Lora-B1s A和B烧录一样的串口透传固件。A板收到串口的数据以后会通过Lora透传出去,B板Lora收到数据以后会通过串口输出。反过来当B串口收到数据最终也可以通过A板的串口输出。
并且该例程也可以多于两块板子同时工作,这样一个发送,其他的几块都可以收到。
测试时候串口波特率设置为:115200
工作模型如下图所示:

基于LADK工程创建实现步骤
- 拷贝lora-ADK并重新命名为lora-UART
- 在
./user/app
文件夹中新建三个文件uart_lora.c
uart_lora.h
- 把
uart_lora.c
uart_lora.h
添加到MDK工程分组App中 - 在
uart_lora.c
uart_lora.h
中添加应用代码,实现uart透传功能
- 修改main.c 调用uart_lora 接口
- 在stm32g0xx_it.c 中调用串口中断处理函数
- 编译烧录到开发板中
代码分析
app_buffer的关键性
为什么需要一个app_buffer?实际上就是一个缓冲区,因为从串口收过来的数据Lora可能还来不及发送。所以就构成一个生产快,消费慢的情况。
这样设计一个缓冲区就可以很好的解决这个问题,把来不得发送的数据都先缓存起来,在空闲的时候慢慢再发出去。

app_buffer的具体实现就不再详细探讨,有兴趣可以读读我们的源码,可以参考我们另一篇文章《app_buffer的设计》,提供的接口如下:
//用来定义一个app_buffer
#define APP_BUFFER_DEF(buffer_obj_name) buffer_obj_t buffer_obj_name;
void app_buffer_create(buffer_obj_t* obj, uint8_t *buf,uint16_t buf_len);
void app_buffer_flush(buffer_obj_t* obj);
uint16_t app_buffer_write_bytes(buffer_obj_t* obj,uint8_t *pdata,uint16_t data_len);
uint16_t app_buffer_read_bytes(buffer_obj_t* obj,uint8_t *pdata,uint16_t data_len);
uint16_t app_buffer_peek_bytes(buffer_obj_t *obj,uint8_t *pdata,uint16_t data_len);
uint16_t app_buffer_write_message(buffer_obj_t* obj,uint8_t *pdata,uint16_t data_len);
uint16_t app_buffer_read_message(buffer_obj_t* obj,uint8_t *pdata,uint16_t data_max_len);
- app_buffer_create:创建一个buffer
- app_buffer_flush:清除buffer内容
- app_buffer_write_bytes:按照bytes写入数据,不可以和buffer_write_message混用
- app_buffer_read_bytes:按照bytes读取数据,不可以和buffer_read_message混用
- app_buffer_write_message:按照message写入数据,这样读取的时候也是直接读出一条message的数据
- app_buffer_read_message:读取一条message的数据
uart_lora的代码实现
lora的发送和接收前面例子已经用的次数比较多,比较熟悉,重点就在于串口数据的接收。
串口可能会同时收到多个byte数据,那总不能一个个byte通过lora往外传,这样的效率太低。所以接收一帧串口数据,就把这一帧的数据统一通过Lora发送出去。
这一帧数据的区分,就用到了stm32G0系列的一个接收超时中断。当连续接收时候把收到的数据先存入数组,然后一旦产生了超时中断。则把数组中的一包数据通过buffer_write_message
写入到buffer。
在主循环里面就不断的调用buffer_read_message
从buffer中取一条message数据,如果取到就从Lora发送出去。
这是串口中断服务函数的代码,用到三个中断:
- 接收溢出出错中断
- 接收完成中断
- 接收超时中断
void u2l_handler(void)
{
uint8_t ch=0;
if ((__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_RXNE)) &&
(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE)))
{
__HAL_UART_CLEAR_FLAG(&huart1,UART_CLEAR_OREF);
}
if ((__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_RXNE)) &&
(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE)))
{
ch= huart1.Instance->RDR;
if(rx_counter<UART_RX_BUF_SIZE)
{
rx_buf[rx_counter++]=ch;
}
}
if ((__HAL_UART_GET_IT_SOURCE(&huart1, UART_IT_RTO)) &&
(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RTOF)))
{
__HAL_UART_CLEAR_FLAG(&huart1,UART_CLEAR_RTOF);
buffer_write_message(&u2l_buf_obj,rx_buf,rx_counter);
rx_counter=0;
}
}
主逻辑代码就很简单了,被while(1)循环不停调用就可以:
void u2l_process()
{
Radio.IrqProcess();
if(lora_sending==false)
{
tx_counter=buffer_read_message(&u2l_buf_obj,tx_buf,LORA_TX_BUF_SIZE);
if(tx_counter>0)
{
lora_sending=true;
Radio.Send(tx_buf,tx_counter);
}
}
}
在Lora接收完成回调函数里面,可以直接把数据通过串口发送接口函数发出:
static void lora_rx_done_callback( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
HAL_UART_Transmit(&huart1,payload,size,0xffff);
Radio.Rx(5000);
}
LORA-B1S支持
淘宝购买地址:
https://item.taobao.com/item.htm?&id=657480900713
Lora技术支持群:
QQ群:603253865
LORA-B1S专栏
源码下载地址,最新文档都会更新在专栏内,欢迎大家订阅收藏