LORA-B1S——串口透传

Lora DK45

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专栏

源码下载地址,最新文档都会更新在专栏内,欢迎大家订阅收藏

https://www.yuque.com/eemaker/lora-b1s

喜欢 (27)