我用的是两块MSP430的板子,经过很蛋疼的调试之后,终于可以实现无线通信。

话说这个蛋疼,就疼在这个模块是国产的。具体的说明书很不详细,有很多说明书直接给出的51的不完整代码。

直到找到了这份说明书,有寄存器的读写方法,和SPI的时序图,以及发送接收流程。

不多说废话,上图:

M~A6L5~`R2ZGMAZVRG875MH

这个图不解释...

image

这些是对模块内部的寄存器操作指令,这次实现的无线通信是用Enhanced ShockBurst模式,这些寄存器和相关数据的值已经写在define.h之中了,之后附上代码

image

image

image

image

image

image

image

image

image

image

终于图完了,有好多寄存器啊,不很会用live writer...

以上的图就是所有寄存器的地址和他们内部每位的含义,寄存器的地址写在头文件了.

模块采用的是SPI和MCU进行通讯。时序图在下面:

image

这个是读操作

image

这个是写操作

image

这个是各个SPI参数

/****************************************特殊的分割线*****************************************/

具体别的细节可以参考说明书,模块的电位要控制好,否则会烧掉,MSP中不需要做更改。

关于SPI:

          SPI通信有4跟线MOSI, MISO,SCK,SCN.

          通信分为主机和从机,其实主从没有什么大区别,关键是看谁掌握着时钟线的电位(SCK).

          MOSI是主机的输出,MISO是主机的输入,SCN是从机的使能

          SPI通信的时候是将两个寄存器中的值交换,有的模块是时钟沿上升时读写数据,有的是下降时读写。在这个实例中是上升沿读写。

          具体有关SPI自己查资料。

关于引脚:

         引脚的定义推荐自己测量。有时候光盘里的电路图写的引脚有错误。

         引脚的定义已经写入头文件,对于不同的板子可能需要更改引脚定义。

头文件:

//**********************************************引脚的定义******************************************************
#define CE_HIGH   P5OUT|=BIT1
#define CE_LOW    P5OUT&=~BIT1
#define SCK_HIGH  P5OUT|=BIT2
#define SCK_LOW   P5OUT&=~BIT2
#define MISO      P5IN&BIT0
#define MOSI_HIGH P2OUT|=BIT6
#define MOSI_LOW  P2OUT&=~BIT6
#define CSN_HIGH  P5OUT|=BIT3
#define CSN_LOW   P5OUT&=~BIT3
#define IRQ       P2OUT&BIT7
#define RX_DR     BIT6
#define TX_DS     BIT5
#define MAX_RT    BIT4
#define SHUTED    0x00
#define SLEEP     0X01
#define TXMODE    0X02
#define RXMODE    0X03
//********************************************无线参数的定义*****************************************************
#define TX_ADR_WIDTH    5       // 5 uints TX address width
#define RX_ADR_WIDTH    5       // 5 uints RX address width
#define TX_PLOAD_WIDTH  32      // 32 uints TX payload
#define RX_PLOAD_WIDTH  32      // 32 uints TX payload
unsigned char TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01};    //本地地址
unsigned char RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01};    //接收地址
//***************************************NRF24L01寄存器指令*******************************************************
#define READ_REG        0x00      // 读寄存器指令 000AAAAA    AAAAA为操作寄存器地址
#define WRITE_REG       0x20     // 写寄存器指令 同上
#define RD_RX_PLOAD     0x61      // 读取接收数据指令
#define WR_TX_PLOAD     0xA0      // 写待发数据指令
#define FLUSH_TX        0xE1     // 冲洗发送 FIFO指令  用于发射模式
#define FLUSH_RX        0xE2      // 冲洗接收 FIFO指令  用于接收模式
#define REUSE_TX_PL     0xE3      // 重发上一包,CE为1时不断重发
#define NOP             0xFF      // 空操作  可用来读状态寄存器
//*************************************SPI(nRF24L01)寄存器地址****************************************************
#define CONFIG          0x00  // 配置收发状态,CRC校验模式以及收发状态响应方式
#define EN_AA           0x01  // 自动应答功能设置
#define EN_RXADDR       0x02  // 可用信道设置
#define SETUP_AW        0x03  // 收发地址宽度设置
#define SETUP_RETR      0x04  // 自动重发功能设置
#define RF_CH           0x05  // 工作频率设置
#define RF_SETUP        0x06  // 发射速率、功耗功能设置
#define STATUS          0x07  // 状态寄存器
#define OBSERVE_TX      0x08  // 发送监测功能
#define CD              0x09  // 地址检测          
#define RX_ADDR_P0      0x0A  // 频道0接收数据地址
#define RX_ADDR_P1      0x0B  // 频道1接收数据地址
#define RX_ADDR_P2      0x0C  // 频道2接收数据地址
#define RX_ADDR_P3      0x0D  // 频道3接收数据地址
#define RX_ADDR_P4      0x0E  // 频道4接收数据地址
#define RX_ADDR_P5      0x0F  // 频道5接收数据地址
#define TX_ADDR         0x10  // 发送地址寄存器
#define RX_PW_P0        0x11  // 接收频道0接收数据长度
#define RX_PW_P1        0x12  // 接收频道0接收数据长度
#define RX_PW_P2        0x13  // 接收频道0接收数据长度
#define RX_PW_P3        0x14  // 接收频道0接收数据长度
#define RX_PW_P4        0x15  // 接收频道0接收数据长度
#define RX_PW_P5        0x16  // 接收频道0接收数据长度
#define FIFO_STATUS     0x17  // FIFO栈入栈出状态寄存器设置

//以下的函数是在RF24L01.c中的,这里做一个声明
unsigned char SPITrans(unsigned char);
unsigned char WReg(unsigned char,unsigned char);
unsigned char RReg(unsigned char);
unsigned char WRegBuf(unsigned char,unsigned char*,unsigned char);
unsigned char RRegBuf(unsigned char,unsigned char*,unsigned char);
void RFTrans(unsigned char*);
void RFRead(unsigned char*);
void SetMode(unsigned char);
void usDelay(int);
void msDelay(int);
void initRf(void);

模块的驱动函数:

unsigned char SPITrans(unsigned char byte)      //这个是通过SPI时序实现的模拟SPI通信,是最底层的函数
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        if(byte&BIT7)
            MOSI_HIGH;
        else
            MOSI_LOW;
        byte<<=1;
        SCK_HIGH;
        byte|=MISO;
        SCK_LOW;
    }
    return byte;
                        
}
unsigned char WReg(unsigned char reg, unsigned char value)      //这个函数是向指定的寄存器reg中写入value值的函数
{
    unsigned char status;
    CSN_LOW;                                                                                             //每次使用SPI的时候要使能从端。
    status=SPITrans(reg);
    SPITrans(value);
    CSN_HIGH;
    return status;
}
unsigned char RReg(unsigned char reg)                                  //读取reg寄存器中的值
{
    unsigned char status;
    CSN_LOW;
    SPITrans(reg);
    status=SPITrans(0);
    CSN_HIGH;
    return status;   
}
unsigned char WRegBuf(unsigned char reg, unsigned char* wBuf,unsigned char quantity)        //在reg寄存器中写入长度为quantity的数据
{
    unsigned char i,status;                                                                                  //数据再wBuf指向的地址里
    CSN_LOW;
    status=SPITrans(reg);
    for(i=0;i<quantity;i++)
        SPITrans(*wBuf++);
    CSN_HIGH;
    return status;
}
unsigned char RRegBuf(unsigned char reg,unsigned char* rBuf,unsigned char quantity)   //在reg寄存器中读出长度为quantity的值
{
    unsigned char i,status;
    CSN_LOW;
    status=SPITrans(reg);
    for(i=0;i<quantity;i++)
        rBuf[i]=SPITrans(0);
    CSN_HIGH;
    return status;
}
void RFTrans(unsigned char* tBuf)                                                                       //用无线模块发射tBuf指向的数据
{
    CE_LOW;
        WRegBuf(WRITE_REG+RX_ADDR_P0,TX_ADDRESS,TX_ADR_WIDTH);
    WRegBuf(WR_TX_PLOAD,tBuf ,TX_PLOAD_WIDTH);               
        WReg(WRITE_REG +CONFIG, 0x0E);
    CE_HIGH;
    usDelay(600);
}
void RFRead(unsigned char* rBuf)                                        //用无线模块接受数据,存在rBuf指向的地址
{
    unsigned char status;
    usDelay(130);
        status=RReg(STATUS);
    if(status&RX_DR)
    {
        CE_LOW;   
        RRegBuf(RD_RX_PLOAD,rBuf,RX_PLOAD_WIDTH);
    }
    WReg(WRITE_REG+STATUS,status);
}
void SetMode(unsigned char mod)                        //设置无线模块的工作模式
{
    switch (mod)
    {
    case 0x00:                                                             //掉电
        CE_LOW;
        WReg(WRITE_REG +CONFIG, 0x0D);              //默认16位CRC
        break;
    case 0x01:                                                   //待机模式
        CE_LOW;       
        break;
    case 0x02:                                                 //发送模式
        CE_LOW;
        WReg(WRITE_REG +CONFIG, 0x0E);
        CE_HIGH;
        break;
    case 0x03:                                                   //接收模式
        CE_LOW;
        WReg(WRITE_REG +CONFIG, 0x0F);
        CE_HIGH;
        break;   
    default:
        break;
    }   
}
void usDelay(int s)      //assumed 8mhz      微妙级延时
{
    unsigned int i;
    for(i=0;i<s*8;i++);
}
void msDelay(int s)     //毫秒级别延时,没有用上
{
    unsigned int i,j;
    for(i=0; i<1000; i++)
        for(j=0; j<s*8; j++);
}
void initRf(void)       //初始化
{
      //默认为掉电模式,重新测试时须给模块彻底掉电,才允许重新写入
    WRegBuf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);        //发送端地址
    WRegBuf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH);    //接收端地址
    WReg(WRITE_REG+EN_AA,0X01);                   //频道0,ACK自动应答
    WReg(WRITE_REG+EN_RXADDR,0X01);               //仅仅允许频道0
    WReg(WRITE_REG + RF_CH, 0x00);                    //信道2.4GHZ
    WReg(WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    WReg(WRITE_REG+RF_SETUP,0x07);
    WReg(WRITE_REG +CONFIG, 0X0F);    
       
}

 

具体的主函数直接调用这些函数就好。有问题需要注意..一个是引脚IRQ要设置为输入方向,一个是MISO要设置为输入。

读数据可以用中断来做,一般也是用中断做的。

还有一些问题没有彻底搞清楚,在学习提高中。

希望大家多多支持我,大神来了一定要留下宝贵的意见和建议呀。