基于CC2530的Zstack协议栈的SX1278调试记录

SX1278Lora模块串口调试记录

  • 串口调试代码
    • 串口获取调试信息
    • SPI驱动IO口模拟,加深理解用
    • SX1278的通讯时序
    • SX1278 SPI通讯间隔要求
    • SX1278 寄存器设置,实例
  • 实际调试
  • LORA信道划分建议
  • 关于带宽

只是写个自己调试SX1278模块的记录!

串口调试代码

在串口处已经编写了,解析串口命令的代码,直接输入相关命令可以直接操作寄存器。
在协议栈串口MT_UART.c文件中RX处代码如下:

//这里面接收串口数据读取,串口传过来数据解析成对应的处理函数!
//最终实现使用串口命令:
//1.F1获取帮助信息
//2.A1设置寄存器,读取寄存器
//3.A2发送数据 (hex 和 字符串)
//4.A3取得数据 清空数据

void serial_process( uint8 port, uint8 event )
{
    (void)port;

    if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)))
    {
        if (SerialApp_TxLen < 80)
        {
            SerialApp_TxLen = HalUARTRead(port, Serial_Lora_Control_Buff, 80);
            if (SerialApp_TxLen)
            {
				if(Serial_Lora_Control_Buff[0] == 0xF1)LORA_Help();
                if(Serial_Lora_Control_Buff[0] == 0xA1)
                {
                    if(SerialApp_TxLen >= 2)存在数据
                    {
                        LORA_A1(Serial_Lora_Control_Buff,SerialApp_TxLen);
                    } 
                    else
                    {
                        LORA_Help_A1();
                    }
                }
                if(Serial_Lora_Control_Buff[0] == 0xA2)//A2
                {
                     if(SerialApp_TxLen >= 2)//存在数据
                     {
                        LORA_A2(Serial_Lora_Control_Buff,SerialApp_TxLen,0);
                     }
                     else
                     {
                        LORA_Help_A2();
                     }
                }
                if (Serial_Lora_Control_Buff[0] == 65 && Serial_Lora_Control_Buff[1] == 50)//字符A2
                {
                  if(Serial_Lora_Control_Buff[2] == '"')
                  {
                     LORA_A2(Serial_Lora_Control_Buff,SerialApp_TxLen,1);
                  }
                  else 
                  {
                     LORA_Help_A2_str();
                  }
                }
                if(Serial_Lora_Control_Buff[0] == 0xA3)//A3
                {
                  if(SerialApp_TxLen >= 2)//存在数据
                  {
                    LORA_A3(Serial_Lora_Control_Buff,SerialApp_TxLen);
                  }
                  else
                  {
                    LORA_Help_A3();
                  }
                }

处理函数如下:

/*
配合串口命令,反馈、帮助、配置
*/
void LORA_Help(void)
{
    HalUARTWrite(0, "\nSend_Hex_Format", strlen("\nSend_Hex_Format"));
    HalUARTWrite(0, "\nA1-Set-Reg", strlen("\nA1-Set-Reg"));
    HalUARTWrite(0, "\nA2", strlen("\nA2"));
    HalUARTWrite(0, "->", strlen("->"));
    HalUARTWrite(0, "\nA3", strlen("\nA3"));
    HalUARTWrite(0, "<-", strlen("<-"));
}
void LORA_Help_A1(void)
{
    HalUARTWrite(0, "\nSend_Hex_Format", strlen("\nSend_Hex_Format"));
    HalUARTWrite(0, "\nA1空格ADR空格DATA", strlen("\nA1空格ADR空格DATA"));
    HalUARTWrite(0, "\nA1空格ADR", strlen("\nA1空格ADR"));
}
void LORA_Help_A2(void)
{
    HalUARTWrite(0, "\nSend_Hex_Format", strlen("\nSend_Hex_Format"));
    HalUARTWrite(0, "\nA2空格DATA", strlen("\nA2空格DATA"));
    HalUARTWrite(0, "\nA2“字符串”", strlen("\nA2“字符串”"));
}
void LORA_Help_A2_str(void)
{
    HalUARTWrite(0, "\nSend_Char_Format", strlen("\nSend_Char_Format"));
    HalUARTWrite(0, "\nA2“字符串”", strlen("\nA2“字符串”"));
}
void LORA_Help_A3(void)
{
    HalUARTWrite(0, "\nSend_Hex_Format", strlen("\nSend_Hex_Format"));
    HalUARTWrite(0, "\nA3空格01/00", strlen("\nA3空格空格01/00"));
}
/*
配合串口命令 A1 配置
格式:A1 adress data
*/
void LORA_A1(uint8 *lora_Order_buff,uint16 SerialApp_TxLen)
{
  if(SerialApp_TxLen == 3 )
  {
    SX1278WriteBuffer(lora_Order_buff[1],lora_Order_buff[2]);
    //SX1278ReadBuffer(lora_Order_buff[1]);
  }
  else
  {
    SX1278ReadBuffer(lora_Order_buff[1]);
  }  
}

/*
配合串口命令 A2 send
格式:A2"字符串" OR A2空格DATA
*/
void LORA_A2(uint8 *lora_Order_buff,uint16 SerialApp_TxLen,bool state)
{
  if(state == 1)//A2"字符串" 
  {
    if (lora_Order_buff[2] == '"' && lora_Order_buff[SerialApp_TxLen-1] == '"')
    {
        HalUARTWrite(0, "\nA2“字符串OK”\n", strlen("\nA2“字符串OK”\n"));
        HalUARTWrite(0, ":", strlen(":"));
        HalUARTWrite(0, lora_Order_buff+3, SerialApp_TxLen-4);//
        FUN_RF_SENDPACKET(lora_Order_buff+2,SerialApp_TxLen-2);//2个双引号和数据留下
        HalUARTWrite(0, "\nSend_Done!\n", strlen("\nSend_Done!\n"));
    }
  }
  if(state == 0)//A2空格DATA
  {
      uint8 i;
      HalUARTWrite(0, "\nA2“HexOK”\n", strlen("\nA2“HexOK”\n"));
      for(i = 1;i<SerialApp_TxLen;i++)
      {
          HexToChar(lora_Order_buff[i],HEX_String_Value);//转为字符
          HalUARTWrite(0, HEX_String_Value,2);
          HalUARTWrite(0, " ", 1);
      }
      FUN_RF_SENDPACKET(lora_Order_buff+1,SerialApp_TxLen-1);//hex发送
      HalUARTWrite(0, "\nSend_Done!\n", strlen("\nSend_Done!\n"));
      FIFO_Flag_String = 0;
  }
}

void LORA_A3(uint8 *lora_Order_buff,uint16 SerialApp_TxLen)
{
  if(lora_Order_buff[1]==0x01)
  {
    if(DIO0 == 1 && FIFO_Flag == 0)//lora 中断触发 未读取数据
    {  
          spi_receiver();
          FIFO_Flag = 1;
    }
    else if(FIFO_Flag == 1 && FIFO_Flag_String == 0)//第二次读
    {
        HalUARTWrite(0, recv_dest_hex, RF_REC_RLEN_i*3);//-16-》字符数据地址 数据间有空格
    }
    else if(FIFO_Flag == 1 && FIFO_Flag_String == 1)
    {
        HalUARTWrite(0, recv_dest+1, RF_REC_RLEN_i-2);//--数据地址
    }
  }
  if(lora_Order_buff[1]==0x00)
  {
      SX1278LoRaSetOpMode(Sleep_mode);//清空13rx获取的字节数
      SX1278LoRaSetOpMode(Stdby_mode);//FIFO指向地址不变、地址内容不变、
      RF_RECEIVE();
      SX1278ReadBuffer(0x0E);
      HalUARTWrite(0, "\nClear_FIFO_Done!\n", strlen("\nClear_FIFO_Done!\n"));
      HalUARTWrite(0, "\nNothing!\n", strlen("\nNothing!\n"));
      FIFO_Flag = 0;

  }  
}

串口获取调试信息

//写入或读取寄存器时,发送信息
void SEND_UART_Information(unsigned char *dst_V,unsigned char *dst_A,u8 addr,u8 value,bool state)
{
  if(state == 0)
  {
    HalUARTWrite(0, "\nR:", strlen("\nR:"));
    HexToChar(addr,dst_A);//读取地址:dst_A 数据为:dst_V
    HalUARTWrite(0, HEX_String_Addr,2);
    HalUARTWrite(0, "-:", strlen("-:"));
    HexToChar(value,dst_V);
    HalUARTWrite(0, HEX_String_Value,2);
  }
  if(state == 1)
  {
    HalUARTWrite(0, "\n-W:", strlen("\n-W:"));
    HexToChar(addr,dst_A);//写入地址:dst_A 数据为:dst_V
    HalUARTWrite(0, HEX_String_Addr,2);
    HalUARTWrite(0, "-:", strlen("-:"));
    HexToChar(value,dst_V);
    HalUARTWrite(0, HEX_String_Value,2);
  }
  //转为字符
  static bool HexToChar(u8 temp,unsigned char *dest)
{
    u8 hb,lb;
    char buf[2] = {0};
    hb=(temp&0xf0)>>4;  	//保留高位,右移去掉低位   

    if( hb<=9 )
      hb += 0x30;  				//相当于+'0'转为字符了
    else if( hb>=10 &&hb <=15 )  
      hb = hb -10 + 'A';	//转成字符A--F  
    else  
      return 0; 
    
    lb = temp&0x0f;

    if( lb<=9 )
      lb += 0x30;//decimal  48 
    else if( lb>=10 && lb<=15 )
      lb = lb - 10 + 'A';
    else
      return 0;
    
    buf[0] = hb;
    buf[1] = lb;
    memcpy(dest,buf,2);
    return 1;
}

//SX1278读写
@fn SX1278写入 
*/
void  SX1278WriteBuffer(u8 addr,u8 buffer) 
{
	SPI_Write(addr | 0x80);//MSB=1 WRITE
	SPI_Write(buffer);//写入数据	 
	NSS = 1; //不使能 NSS = 1;
    SEND_UART_Information(HEX_String_Value,HEX_String_Addr,addr,buffer,1);//调试用--写入-发送到串口
}

/*
@fn SX1278读取 
*/
unsigned char  SX1278ReadBuffer(unsigned char addr) //读取寄存器中的数据
{
	unsigned char Value;
	SPI_Write(addr & 0x7F);//WRITE写入一个字节数据  MSB=0-->read_data 
  	Value = SPI_Read();
	NSS = 1;
  	SEND_UART_Information(HEX_String_Value,HEX_String_Addr,addr,Value,0);//调试用--读取-发送到串口
	return Value;
}

SPI驱动IO口模拟,加深理解用

SPI通讯时序
具体可参考:https://blog.csdn.net/weixin_42509369/article/details/83096349
时钟极性CPOL=1则时钟初始为高电平,0则低电平
时钟相位CPHA=1则第二个时钟沿采集数据,0则第一个时钟沿
以上都是设置为1则:时钟第一个沿为下降沿,第二个为上升沿,此时采集数据

基于CC2530的Zstack协议栈的SX1278调试记录_第1张图片

SX1278的通讯时序

SCK初始为低电平,第一个沿为上升,读取数据
若使用标准SPI驱动需要设置:CPOL=0,CPHA=0
基于CC2530的Zstack协议栈的SX1278调试记录_第2张图片

SX1278 SPI通讯间隔要求

基于CC2530的Zstack协议栈的SX1278调试记录_第3张图片
基于CC2530的Zstack协议栈的SX1278调试记录_第4张图片
则SPI驱动代码如下:

#define NSS  P0_4 //使能引脚
#define MISO P1_7 //MISO
#define SCLK P1_5 //SCLK
#define MOSI P1_6 //MOSI
#define DIO0 P1_3 //DIO0 RX接收done TX done中断标志
#include "lora.h"
/*******************************************************************************
MOSI, Master out slave in,主出从进。主控端发数据,从端接收,用于主控端写。
MISO, Master in slave out.主进从出。主控端接收数据,从端发送数据,用于主控端读。
时钟口==上升沿读取数据,下降沿写入数据
低高复位芯片
write:wnr[1] 6 5 4 3 2 1 0  自定义写数据(字节) read:wnr[0] 6 5 4 3 2 1 0 读取此地址数据(字节) MSB先传
Fsclk=MAX_10Mhz 100ns 最低允许间隔上50ns下50ns
*******************************************************************************/  

  
/*SPI-init*/
void SPI_INIT(void)
{
    P1DIR &= ~BV(7);//MISO配置为输入
    P1DIR &= ~BV(3);//P1_3配置为输入,采集DIO0-LORA数据接收中断标志
    P1INP &= ~BV(3);//打开P1.3上下拉模式
    P2INP |=  BV(6);//打开P1端口下拉
    P1DIR |= BV(5);//SCLK配置为输出
    P1DIR |= BV(6);//MOSI 配置为输出
    P0DIR |= BV(4);//NSS配置为输出
    NSS = 1;//不使能模块
    SCLK = 0;
}
/********************************

从SPI器件写入一个字节数据,NSS不在此停止使能,由调用程序段停止

********************************/
void SPI_Write(unsigned char data)
{
    unsigned char i;
    NSS = 0;//NSS=0 使能
    for(i = 0;i < 8;i++)
    {
        SCLK = 0;//SCLK=0
        if((data & 0x80)==0x80)MOSI = 1;
        else MOSI = 0;       
        _Delay_nus(100);
        SCLK = 1 ;
        data =(data<<1);
        _Delay_nus(100);
    }
    //NSS = 1; //不使能
}
/********************************

从SPI器件读出一个字节数据,由调用程序段使能NSS,结束后本函数自动停止

********************************/
unsigned char SPI_Read(void)
{
    unsigned char i,SPI_DATA;
    for(i = 0; i<8 ;i++)
    {
        SCLK = 0;
        _Delay_nus(100);
        SPI_DATA = (SPI_DATA<<1);
        SCLK = 1;
        _Delay_nus(100);
        if(MISO == 1)SPI_DATA |=0x01;
        else SPI_DATA &=~0x01;
    }
    SCLK = 0;
    NSS = 1;
    return SPI_DATA;
}

SX1278 寄存器设置,实例

/*
@fn 运行模式切换 
    寄存器地址0x01
*/
#define REG_LR_OPMODE   0x01
typedef enum 
{
   Sleep_mode	        = (u8)0x00, 
   Stdby_mode	        = (u8)0x01, 
   TX_mode 	        	= (u8)0x02,
   Transmitter_mode		= (u8)0x03,
   RF_mode 				= (u8)0x04,
   Receiver_mode		= (u8)0x05,
   receive_single		= (u8)0x06,
   CAD_mode				= (u8)0x07,
}RFMode_SET;

void  SX1278LoRaSetOpMode(RFMode_SET opMode)//运行模式选择 
{
	u8 opModePrev;
	opModePrev = SX1278ReadBuffer(REG_LR_OPMODE);//寄存器地址0X01
	opModePrev &= 0xf8;
	opModePrev |= (u8) opMode;
	SX1278WriteBuffer( REG_LR_OPMODE, opModePrev);
}

实际调试

使2个设备初始化!
基于CC2530的Zstack协议栈的SX1278调试记录_第5张图片
基于CC2530的Zstack协议栈的SX1278调试记录_第6张图片
使用串口命令:
F1获取帮助信息
A1设置寄存器
A2发送数据
A3取得数据
基于CC2530的Zstack协议栈的SX1278调试记录_第7张图片
使用串口命令:A1获取设置寄存器命令格式:
A1空格地址空格数据 –》这是设置
A1空格地址 –》这是读取
寄存器地址:
0D 读取FIFO-ptr地址
00 获取0D指向地址的数据
13 读取RX到的字节数
10 获取最后一包数据的首地址(只发了一包很长的的数据,10内数据为00首地址)
12 获取中断标志位
01 获取运行模式,其值设置为: 88为睡眠、89为待机、8D为持续接收、8B为使能发送
基于CC2530的Zstack协议栈的SX1278调试记录_第8张图片
使用串口命令:A2 发送数据
A2空格数据 –》这是发送16进制数据
A2”字符串” –》这是发送非16进制数据
基于CC2530的Zstack协议栈的SX1278调试记录_第9张图片
使用串口命令A3获取数据或清除数据
A3空格01 –》这是获取数据
A3空格00 –》这是清除数据
基于CC2530的Zstack协议栈的SX1278调试记录_第10张图片
示范:设置接收端 0D 为00首地址
基于CC2530的Zstack协议栈的SX1278调试记录_第11张图片
发送端也设置
基于CC2530的Zstack协议栈的SX1278调试记录_第12张图片
发送端发送数据 55 55 55 三个字节的16进制数:
基于CC2530的Zstack协议栈的SX1278调试记录_第13张图片
接收端收到数据:
基于CC2530的Zstack协议栈的SX1278调试记录_第14张图片
获取数据包长度:
基于CC2530的Zstack协议栈的SX1278调试记录_第15张图片
获取最后一包数据首地址:
基于CC2530的Zstack协议栈的SX1278调试记录_第16张图片
获取数据:
基于CC2530的Zstack协议栈的SX1278调试记录_第17张图片
这时再看下地址变化:自动增加了1,代表下次访问00内数据是访问指向01这个里面的数据
基于CC2530的Zstack协议栈的SX1278调试记录_第18张图片
我们再次访问00获取数据:还是55这个字节
基于CC2530的Zstack协议栈的SX1278调试记录_第19张图片
这时再看下地址变化:自动增加了1,代表下次访问00内数据是访问指向02这个里面的数据
我们可以通过命令 A1 0D 03 改变00指向的地址,从而获取指定地址数据!
也可:不修改0D,直接读取00,这时是未读数据地址(不是最新数据!)
基于CC2530的Zstack协议栈的SX1278调试记录_第20张图片

LORA信道划分建议

PS此处摘取新浪文档:原文地址
基于CC2530的Zstack协议栈的SX1278调试记录_第21张图片
实际操作:
1、设置寄存器地址:0x01 = 0x88 睡眠
2、设置寄存器地址:0x06至0x08 设置相应频率数值 具体计算方法参考手册page:112典型的32Mhz晶振,分辨率为61.035hz(Fstep=Focsc/2^19 == Fstep = 32 000 000 Hz / 524 288 = 61.035 Hz)
3、频率是Fstep这个数x Frf(0x06至0x08设置的值,hex=6c8000十进制=7110656)即434 000 000 Hz, 即频率为434 MHz
基于CC2530的Zstack协议栈的SX1278调试记录_第22张图片

关于带宽

PS此处参考其他博主文档:原文地址
关于LORA的CAD检测参考其他博主文档:原文地址
关于LORA的更多功能参考其他博主文档:原文地址

END!

你可能感兴趣的:(Lora)