我用的是两块MSP430的板子,经过很蛋疼的调试之后,终于可以实现无线通信。
话说这个蛋疼,就疼在这个模块是国产的。具体的说明书很不详细,有很多说明书直接给出的51的不完整代码。
直到找到了这份说明书,有寄存器的读写方法,和SPI的时序图,以及发送接收流程。
不多说废话,上图:
这个图不解释...
这些是对模块内部的寄存器操作指令,这次实现的无线通信是用Enhanced ShockBurst模式,这些寄存器和相关数据的值已经写在define.h之中了,之后附上代码
终于图完了,有好多寄存器啊,不很会用live writer...
以上的图就是所有寄存器的地址和他们内部每位的含义,寄存器的地址写在头文件了.
模块采用的是SPI和MCU进行通讯。时序图在下面:
这个是读操作
这个是写操作
这个是各个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要设置为输入。
读数据可以用中断来做,一般也是用中断做的。
还有一些问题没有彻底搞清楚,在学习提高中。
希望大家多多支持我,大神来了一定要留下宝贵的意见和建议呀。