ATK-LORA是正点原子推出的一款小体积、微功率、低功耗、高性能的远距离 LoRa 无线串口模块,该模块采用高效的 ISM 频段射频 SX1278 扩频芯片,其工作频率为 410MHz~441MHz,信道以 1MHz 频率为步进,共有 32 个信道,可在线修改模块的串口速率、发射功率、空中速率、工作模式和自定义通讯密钥等各种参数。ATK-MW1278D 模块的各项基本参数,如下表所示:
LORA模块通过 6 个 2.54mm 间距的排针与外部相连接,方便用户使用和调试,模块外观如下图所示:
各个引脚的详细描述,如下表所示:
1. 一般模式
发射端: 在一般模式下,发射端模块接收来自串口的用户数据,当用户数据的数据量达到 58 字节时,发射端模块将启动无线发射,此时用户可以继续输入需要发射的数据,当用户输入的数据小于 58 字节时,发射端模块将等待 1 个字节的时间,若期间无用户数据输入,则将此时发射端模块接收到的所有用户数据通过无线发出。当发射端模块开始发送第一个用户数据包的时候,发射端模块的 AUX 引脚将输出高电平,在发射端模块发射出所有用户数据后,发射端模块的 AUX 引脚将输出低电平,此时表明数据包已全部发出,用户可以继续通过串口输出数据。在该模式下发出的数据包,可以被处于一般模式、唤醒模式、信号强度模式和中继模式下的接收端模块接收。
接收端: 在一般模式下,接收端模块将一直打开无线接收功能,可以接收来自一般模式、唤醒模式和信号强度模式下的发射端模块发出的数据包。在接收端模块接收到数据包后,接收端模块的 AUX 引脚将输出高电平,随后大约 2~3ms 后将接收到的数据包通过串口输出给外部控制器,在所有的无线数据都通过串口输出后,接收端的 AUX 引脚将输出低电平。
2. 唤醒模式
发射端: 在唤醒模式下,发射端模块的工作方式与一般模式下的发射端工作方式基本一致,唯一不同的地方在于,唤醒模式下的发射端模块会在每个数据包前自动地添加唤醒码(唤醒码地长度取决于休眠时间的配置)。添加唤醒码的目的是为了唤醒处于省电模式下的接收端模块,因此处于唤醒模式下的发射端模块相较于处于一般模式下的发射端模块,发出的数据包能被处于省电模式下的接收端模块接收。
接收端: 在唤醒模式下,接收端模块的工作方式于处于一般模式下的接收端模块一致。
3. 省电模式
发射端: 在省电模式下,发射端模块将处于休眠状态,期间串口的接收功能将被关闭,无法接收来自外部串口的数据,因此在该模块下,发射端模块不具有无线发射功能。
接收端: 在省电模式下,接收端模块仅能接收来自唤醒模式下发射端模块发出的无线数据。在该模式下,接收端模块将会定时监听唤醒码,一旦接收端模块监听到有效的唤醒码时,接收端模块将持续处于接收无线接收状态,待整个有效数据包接收完毕后,接收端模块的AUX 引脚将输出高电平,随后大约 2~3ms 后将接收到的数据包通过串口输出给外部控制器,在所有的无线数据都通过串口输出后,接收端的 AUX 引脚将输出低电平,随后,接收端模块将继续保持“休眠-监听”的工作状态,通过配置不同的唤醒时间,将使得处于省电模式下的接收端模块具有不同的接收响应延迟和功耗,用户应在通讯延迟和平均功耗之间取一个平衡点。
4. 信号强度模式
信号强度模式可查看通讯双方的信号强度,为评估通讯双方的通讯质量提供参考,实际应用应以实际的丢包率为评估标准。
发射端: 在信号强度模式下,发射端模块的工作方式于处于一般模式下的发射端模块的工作方式一致。
接收端: 在信号强度模式下,接收端模块将在接收到来自发射端的无线数据后输出信号强度的信息。
1. 透明传输
透明传输指的是传输的数据完全透明,发射端模块串口输入的发射数据与接收端模块串口输出的接收数据是一致的。
透明传输可以实现一个模块与一个或多个模块之间的无线数据传输,只要各个模块的配置的设备地址、信道和空中速率参数相同,那么这些模块之间就能够进行数据通讯,如下图所示:
2. 定向传输
定向传输指的是在发射端模块串口的输入数据中包含了指定传输对象模块的设备地址和信道信息,发射端模块会将数据发送给与之同一空中速率的指定接收端模块,指定接收端模块的串口仅输出不包含指定传输对象模块的设备地址和信号信息的数据。
定向传输可以在同一空中速率中实现发射端模块定点地向指定接收端模块发送数据,如下图所示:
3. 广播和监听
除了透明传输和定向传输,当接收端模块的设备地址配置为 0xFFFF 时,接收端模块能够监听相同网络地址和空中速率配置的所有数据传输(监听);同时,发射端模块发送的数据,能够发送给其他相同信道和空中速率配置的接收端模块(广播),如下图所示:
1. 透明传输下
保证模块之前的各配置项相等
发送数据时直接发送想要发送的数据即可
2. 定向传输下
模块地址和通信信道可以不同
发送数据时格式为 模块地址+通信信道+数据
1. 模块初始化
u8 LoRa_Init(void)
{
u8 retry=0;
u8 temp=1;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//禁止JTAG,从而PA15可以做普通IO使用,否则PA15不能做普通IO!!!
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //LORA_MD0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //LORA_AUX
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA.4
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource4);
EXTI_InitStructure.EXTI_Line=EXTI_Line4;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发
EXTI_InitStructure.EXTI_LineCmd = DISABLE; //中断线关闭(先关闭后面再打开)
EXTI_Init(&EXTI_InitStructure);//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //LORA_AUX
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;//抢占优先级2,
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE; //关闭外部中断通道(后面再打开)
NVIC_Init(&NVIC_InitStructure);
LORA_MD0=0;
LORA_AUX=0;
while(LORA_AUX)//确保LORA模块在空闲状态下(LORA_AUX=0)
{
//Show_Str(40+30,50+20,200,16,"模块正忙,请稍等!!",16,0);
printf("模块正忙请稍等\r\n");
delay_ms(500);
}
usart3_init(115200);//初始化串口3
LORA_MD0=1;//进入AT模式
delay_ms(40);
retry=3;
while(retry--)
{
if(!lora_send_cmd("AT","OK",70))
{
temp=0;//检测成功
break;
}
}
if(retry==0) temp=1;//检测失败
return temp;
}
2. 配置LORA的信道、速率、串口、发射功率、传输模式等
void Lora_set(void)
{
usart3_init(115200);
usart3_rx(1);//开启串口3接收
while(LORA_AUX);//等待模块空闲
LORA_MD0=1; //进入配置模式
delay_ms(40);
Lora_mode=0;//标记"配置模式"
//为防止通信产生干扰可以自己修改这里的模块配置参数,如果另一侧是用上位机接收,
//就在上位机调试APP中修改为对应的参数即可,不然两个模块无法通信
lora_send_cmd((u8 *)"AT+CWMODE=0",(u8 *)"OK",200); //设置为一般模式
lora_send_cmd((u8 *)"AT+TMODE=0",(u8 *)"OK",200); //设置为透明传输
lora_send_cmd((u8 *)"AT+TPOWER=3",(u8 *)"OK",200); //设置发射功率20db
lora_send_cmd((u8 *)"AT+WLRATE=24,2",(u8 *)"OK",200); //设置信道为24,空中速率2.4
lora_send_cmd((u8 *)"AT+WLTIME=0",(u8 *)"OK",200); //设置休眠时间为1S
lora_send_cmd((u8 *)"AT+ADDR=00,02",(u8 *)"OK",200); //设置模块地址为2
lora_send_cmd((u8 *)"AT+UART=7,0",(u8 *)"OK",200);//设置波特率115200,无校验
LORA_MD0=0;//退出配置,进入通信
delay_ms(40);
while(LORA_AUX);//判断是否空闲(模块会重新配置参数)
USART3_RX_STA=0;
Lora_mode=1;//标记"接收模式"
usart3_init(115200);
Aux_Int(1);//设置LORA_AUX上升沿中断
}
3. lora发送命令
//lora发送命令
//cmd:发送的命令字符串(不需要添加回车了),当cmd<0XFF的时候,发送数字(比如发送0X1A),大于的时候发送字符串.
//ack:期待的应答结果,如果为空,则表示不需要等待应答
//waittime:等待时间(单位:10ms)
//返回值:0,发送成功(得到了期待的应答结果)
// 1,发送失败
u8 lora_send_cmd(u8 *cmd,u8 *ack,u16 waittime)
{
u8 res=0;
USART3_RX_STA=0;
if((u32)cmd<=0XFF)
{
while((USART3->SR&0X40)==0);//等待上一次数据发送完成
USART3->DR=(u32)cmd;
}else u3_printf("%s\r\n",cmd);//发送命令
if(ack&&waittime) //需要等待应答
{
while(--waittime) //等待倒计时
{
delay_ms(10);
if(USART3_RX_STA&0X8000)//接收到期待的应答结果
{
if(lora_check_cmd(ack))break;//得到有效数据
USART3_RX_STA=0;
}
}
if(waittime==0)res=1;
}
return res;
}
4. 接收应答
//lora发送命令后,检测接收到的应答
//str:期待的应答结果
//返回值:0,没有得到期待的应答结果
//其他,期待应答结果的位置(str的位置)
u8* lora_check_cmd(u8 *str)
{
char *strx=0;
if(USART3_RX_STA&0X8000) //接收到一次数据了
{
USART3_RX_BUF[USART3_RX_STA&0X7FFF]=0;//添加结束符
strx=strstr((const char*)USART3_RX_BUF,(const char*)str);
}
return (u8*)strx;
}
5. AUX中断设置
//mode:配置的模式 0:关闭 1:上升沿 2:下降沿
void Aux_Int(u8 mode)
{
if(!mode)
{
EXTI_InitStructure.EXTI_LineCmd = DISABLE;//关闭中断
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
}else
{
if(mode==1)
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿
else if(mode==2)
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
}
Int_mode = mode;//记录中断模式
EXTI_Init(&EXTI_InitStructure);
NVIC_Init(&NVIC_InitStructure);
}
//LORA_AUX中断服务函数
void EXTI4_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line4))
{
if(Int_mode==1)//上升沿(发送:开始发送数据 接收:数据开始输出)
{
if(Lora_mode==1)//接收模式
{
USART3_RX_STA=0;//数据计数清0
}
Int_mode=2;//设置下降沿触发
LED0=0;//DS0亮
}
else if(Int_mode==2)//下降沿(发送:数据已发送完 接收:数据输出结束)
{
if(Lora_mode==1)//接收模式
{
USART3_RX_STA|=1<<15;//数据计数标记完成
}else if(Lora_mode==2)//发送模式(串口数据发送完毕)
{
Lora_mode=1;//进入接收模式
}
Int_mode=1;//设置上升沿触发
LED0=1;//DS0灭
}
Aux_Int(Int_mode);//重新设置中断边沿
EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE4上的中断标志位
}
}
6. 通信测试
m=LoRa_ReceData();
key=KEY_Scan(0);
if(key==WKUP_PRES)
u3_printf("Hello Lora");
if(m[0]=='1')
printf("yes \r\n");