我是靠谱客的博主 欢喜煎蛋,这篇文章主要介绍基于stm32的正点原子Lora模块教程,现在分享给大家,希望可以做个参考。

基于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的编写:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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的编写:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#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的编写:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
#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的编写:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#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("%srn",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("%srn",USART3_RX_BUF); } } //发送和接收数据处理进程 void LoRa_Process(void) { u8 key=0; u8 t=0; static u8 n = 1; while(1) { if(n==1) { printf("按下KEY0发送数据rn"); n++; } key = KEY_Scan(0); if(key==KEY0_PRES) { if(n==2) { printf("KEY0已被按下rn"); LoRa_SendData();//发送数据 printf("数据已被发送rn"); } } 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进入数据测试rn"); key = KEY_Scan(0); if(key==WKUP_PRES) { printf("进入数据测试rn"); LoRa_Process();//开始数据测试 } t++; if(t==30) { t=0; LED1=~LED1; } delay_ms(10); } }

main.c的编写:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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模块测试程序开始rn"); Lora_Test();//主测试 }

在移植程序时,只需要将usart.h、usart.c、lora.h、lora.c包含进你的工程里即可。也可以只移植lora.c和lora.h然后将串口3修改为你使用的串口即可。(相比于正点那个复杂庞大的工程,我觉得这些模块还是这样好用)

结果演示

数据发送效果:

数据接收效果:

这里开两个串口助手就可以,一个用于看和MCU相连的LoRa模块的数据,一个用于看和电脑相连的LoRa模块的数据,还是很好理解的。

再见LoRa

需要完整工程代码的以及加LoRa配置代码的私聊我获取即可。助大家都能很快上手LoRa并使用!

最后

以上就是欢喜煎蛋最近收集整理的关于基于stm32的正点原子Lora模块教程的全部内容,更多相关基于stm32内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(81)

评论列表共有 0 条评论

立即
投稿
返回
顶部