基于stm32的LoRa模塊除錯教程
- 初識LoRa
- 上手LoRa
- 程式撰寫
- 結果演示
- 再見LoRa
初識LoRa
簡單來講,LoRa就是一種低功耗遠程無線通信技術,它是基于Semtech公司SX1276/1278芯片開發的無線數傳模塊,這種芯片集成規模小、效率高,從而讓LoRa模塊擁有高接收靈敏度,那么它相比于我們常用的藍牙和WiFi有什么優勢呢?總結而言,就是低功耗、遠距離、抗干擾,相同條件下,LoRa模塊比WIFI模塊傳輸距離更遠,多見的WIFI、藍牙等近距離無線通信技術,通信距離一般也就只有幾十米左右,如果要覆寫某個地區一個城市的網路,部署的成本會很高,不劃算,而作為低功耗廣域網的LoRa技術,無線通信距離可以達到幾公里,甚至十幾公里,相對WIFI模塊而言,距離要遠得多,而這些優勢,使得LoRa在現在的物聯網中應用廣泛,得到了很快的發展,
上手LoRa
本次教程使用的LoRa模塊是正點原子的ATK-LORA-01,實物圖就長這樣:
剛開始拿到手一看,不就是個無線串口嘛,寫一下串口的資料收發就完事了,應該很快就能調好了,可是最后前前后后調通大概花了我一天時間,這當然得歸功于正點那個又臭又長的例程,和講不明白重點的用戶手冊,我覺得大家用這些模塊肯定是想直接就可以拿來用的,程式應該是很方便移植的那種,可是正點偏不,非要在程式里面加各種各樣的顯示屏、外設模塊,然后寫一些復復雜雜的看著就頭大的程式,于是我又上網參考了一下別人的程式,結合自己的除錯經驗,又重新寫了LoRa模塊的程式,移植十分方便,
拿到一個模塊,在編程之前肯定是要看的用戶手冊和資料手冊,先要知道它要怎么用,我把正點給的資料中一些重要的地方(和編程使用模塊相關的地方)貼在這里,讀者如果還有其他需求可以自行查閱手冊,
首先便是引腳功能描述:除了串口常見的那四個引腳外,還多了兩個引腳,參考它的說明我們可以得出這兩個引腳是用于配置模塊通信的引腳,因為是無線串口,肯定兩個模塊得有相同的配置才能通信嘛,
接著就是這兩個配置引腳的描述了,它關系到我們如何讓模塊處于不同的作業狀態下:顯然,當AUX和MD0引腳都為低電平時,才是模塊的通信功能(即兩個LoRa模塊互相收發資料),而我們在剛開始給它配對的時候,需要進入配置功能,這時候需要MD0引腳為高電平,然后我們從手冊中得知,MD0、 AUX 引腳懸空下為低電平 ,
這也就是說,當我們已經配對好兩個模塊后,我們是可以不用接MD0、AUX這兩個引腳的線的,讓它們懸空處于低電平兩個模塊就可以通信了,這樣基本就和串口沒什么區別了,程式也會相應地簡化很多了,
那么如何配對兩個模塊呢?我個人的建議就是接一個USB轉TTL連到電腦上,然后用正點提供的上位機去設定,這樣可以不去關心那些AT指令的寫法及意義,達到最快速的上手使用LoRa模塊,這里連接好后修改模塊基本引數配置就好,作業模式配置和發送狀態先保持默認,模塊引數配置里面兩個模塊必須都保持一致,我個人建議把通信信道、模塊地址可以修改一下,這樣可以減少干擾(以防萬一嘛),
一旦我們的模塊配對好后,程式的撰寫邏輯就很簡單了,就只是串口的接收和發送了,當然,我們完全可以把模塊的配置之類的操作寫在程式里,不過試想我們需要再連兩個引腳的線,而且多寫很多的邏輯控制,為什么不先把它配對好后當個串口用呢?
程式撰寫
這里我的目的是使stm32和電腦通過兩個LoRa模塊實作無線通信,并都能顯示接收到和發送的資料,MCU端讓LoRa使用串口3,然后將串口3接收端的資料通過串口1在電腦上列印出來,
usart3.h的撰寫:
#ifndef __USART3_H
#define __USART3_H
#include "sys.h"
#define USART3_MAX_RECV_LEN 1024 //最大接收快取位元組數
#define USART3_MAX_SEND_LEN 600 //最大發送快取位元組數
#define USART3_RX_EN 1 //0,不接收;1,接收.
extern u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接識訓沖,最大USART3_MAX_RECV_LEN位元組
extern u8 USART3_TX_BUF[USART3_MAX_SEND_LEN]; //發送緩沖,最大USART3_MAX_SEND_LEN位元組
extern vu16 USART3_RX_STA; //接收資料狀態
void usart3_init(u32 bound); //串口2初始化
void usart3_set(u8 bps,u8 parity);
void usart3_rx(u8 enable);
void u3_printf(char* fmt,...);
#endif
usart3.c的撰寫:
#include "delay.h"
#include "usart3.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h"
#include "timer.h"
extern u8 Lora_mode;
//串口接收快取區
u8 USART3_RX_BUF[USART3_MAX_RECV_LEN]; //接識訓沖,最大USART3_MAX_RECV_LEN個位元組.
u8 USART3_TX_BUF[USART3_MAX_SEND_LEN]; //發送緩沖,最大USART3_MAX_SEND_LEN位元組
u8 Temp;
//通過判斷接收連續2個字符之間的時間差不大于10ms來決定是不是一次連續的資料.
//如果2個字符接收間隔超過timer,則認為不是1次連續資料.也就是超過timer沒有接收到
//任何資料,則表示此次接收完畢.
//接收到的資料狀態
//[15]:0,沒有接收到資料;1,接收到了一批資料.
//[14:0]:接收到的資料長度
vu16 USART3_RX_STA=0;
void USART3_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)//接收到資料
{
res =USART_ReceiveData(USART3);
if((USART3_RX_STA&(1<<15))==0) //接收完的一批資料,還沒有被處理,則不再接收其他資料
{
if(USART3_RX_STA<USART3_MAX_RECV_LEN) //還可以接收資料
{
if(!Lora_mode)//配置功能下(啟動定時器超時)
{
TIM_SetCounter(TIM7,0); //計數器清空
if(USART3_RX_STA==0) //使能定時器7的中斷
{
TIM_Cmd(TIM7,ENABLE); //使能定時器7
}
}
USART3_RX_BUF[USART3_RX_STA++]=res; //記錄接收到的值
}else
{
USART3_RX_STA|=1<<15; //強制標記接收完成
}
}
}
}
USART_InitTypeDef USART_InitStructure;
//初始化IO 串口3
//pclk1:PCLK1時鐘頻率(Mhz)
//bound:波特率
void usart3_init(u32 bound)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // GPIOB時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3時鐘使能
USART_DeInit(USART3); //復位串口3
//USART3_TX PB10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10
//USART3_RX PB11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB11
USART_InitStructure.USART_BaudRate = bound; //波特率一般設定為9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長為8位資料格式
USART_InitStructure.USART_StopBits = USART_StopBits_1; //一個停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //無奇偶校驗位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無硬體資料流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發模式
USART_Init(USART3, &USART_InitStructure); //初始化串口3
USART_Cmd(USART3, ENABLE); //使能串口
//使能接收中斷
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//開啟中斷
//設定中斷優先級
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//搶占優先級3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先級3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據指定的引數初始化VIC暫存器
TIM7_Int_Init(99,7199); //10ms中斷
USART3_RX_STA=0; //清零
TIM_Cmd(TIM7,DISABLE); //關閉定時器7
}
//串口3,printf 函式 發送端LORA模塊發送資料
//確保一次發送資料不超過USART3_MAX_SEND_LEN位元組
void u3_printf(char* fmt,...)
{
u16 i,j;
va_list ap;
va_start(ap,fmt);
vsprintf((char*)USART3_TX_BUF,fmt,ap); //使用引數串列發送格式化輸出到字串
va_end(ap);
i=strlen((const char*)USART3_TX_BUF); //此次發送資料的長度
for(j=0;j<i;j++) //回圈發送資料
{
while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //回圈發送,直到發送完畢
USART_SendData(USART3,USART3_TX_BUF[j]);
}
}
//串口接收使能控制
//enable:0,關閉 1,打開
void usart3_rx(u8 enable)
{
USART_Cmd(USART3, DISABLE); //失能串口
if(enable)
{
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收發模式
}else
{
USART_InitStructure.USART_Mode = USART_Mode_Tx;//只發送
}
USART_Init(USART3, &USART_InitStructure); //初始化串口3
USART_Cmd(USART3, ENABLE); //使能串口
}
lora.h的撰寫:
#ifndef __LORA_H
#define __LORA_H
#include "sys.h"
void LoRa_Process(void);
void LoRa_SendData(void);
void LoRa_ReceData(void);
void Lora_Test(void);
#endif
lora.c的撰寫:
#include "lora.h"
#include "sys.h"
#include "delay.h"
#include "usart3.h"
#include "string.h"
#include "stdio.h"
#include "usart.h"
#include "led.h"
#include "key.h"
//設備作業模式(用于記錄設備狀態)
u8 Lora_mode=0;//0:配置模式
extern u8 USART_RX_BUF[USART_REC_LEN]; //接識訓沖,最大USART_REC_LEN個位元組.
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//LORA模塊發送資料
void LoRa_SendData(void)
{
u8 temp[256] = "Hello Lora !!!";
u3_printf("%s\r\n",temp);
}
//Lora模塊接收資料
void LoRa_ReceData(void)
{
u16 len=0;
if(USART3_RX_STA&0x8000)
{
len = USART3_RX_STA&0X7FFF;
USART3_RX_BUF[len]=0;//添加結束符
USART3_RX_STA=0;
printf("接收到的資料為");
printf("%s\r\n",USART3_RX_BUF);
}
}
//發送和接收資料處理行程
void LoRa_Process(void)
{
u8 key=0;
u8 t=0;
static u8 n = 1;
while(1)
{
if(n==1)
{
printf("按下KEY0發送資料\r\n");
n++;
}
key = KEY_Scan(0);
if(key==KEY0_PRES)
{
if(n==2)
{
printf("KEY0已被按下\r\n");
LoRa_SendData();//發送資料
printf("資料已被發送\r\n");
}
}
LoRa_ReceData();
t++;
if(t==20)
{
t=0;
LED1=~LED1;
}
delay_ms(10);
}
}
void Lora_Test(void)
{
u8 t=0;
u8 key=0;
while(1)
{
printf("按下KEY_UP進入資料測驗\r\n");
key = KEY_Scan(0);
if(key==WKUP_PRES)
{
printf("進入資料測驗\r\n");
LoRa_Process();//開始資料測驗
}
t++;
if(t==30)
{
t=0;
LED1=~LED1;
}
delay_ms(10);
}
}
main.c的撰寫:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "led.h"
#include "lora.h"
#include "timer.h"
#include "usart3.h"
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//設定中斷優先級分組為組2:2位搶占優先級,2位回應優先級
delay_init(); //延時函式初始化
uart_init(115200); //串口初始化為115200
usart3_init(115200); //串口3初始化為115200
usart3_rx(1);//開啟串口3接收
LED_Init();
KEY_Init();
printf("LORA模塊測驗程式開始\r\n");
Lora_Test();//主測驗
}
在移植程式時,只需要將usart.h、usart.c、lora.h、lora.c包含進你的工程里即可,也可以只移植lora.c和lora.h然后將串口3修改為你使用的串口即可,(相比于正點那個復雜龐大的工程,我覺得這些模塊還是這樣好用)
結果演示
資料發送效果:
資料接收效果:
這里開兩個串口助手就可以,一個用于看和MCU相連的LoRa模塊的資料,一個用于看和電腦相連的LoRa模塊的資料,還是很好理解的,
再見LoRa
需要完整工程代碼的以及加LoRa配置代碼的私聊我獲取即可,助大家都能很快上手LoRa并使用!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/291724.html
標籤:其他
上一篇:crm系統讓企業更具競爭力
