环境:Nordic NRF24L01+发送数据,无需自动应答;NRF52832接收收据。
问题一:NRF24L01+发送地址与NRF52832接收地址
一般情况下可以如下设置:
NRF24L01+发送地址设置:
void SPI1_Write_Buf(uint8_t address, uint8_t *pBuf, uint8_t datalen)
{
uint8_t tmp,i;
CSN_L;
SPI1_DR = address;//写入需要操作的寄存器地址,
while(!(SPI1_SR_RXNE));
tmp = SPI1_DR; //读取数据,仅仅是为了清除标志位
while(!(SPI1_SR_TXE));//等待发送寄存器为空
for(i=0;i<datalen;i++)
{
SPI1_DR = pBuf[i];
while(!(SPI1_SR_TXE));
}
CSN_H;
}
#define TX_ADR_WIDTH 5; //发射地址长度
const uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x11, 0x22, 0x33, 0x44, 0x55}; //发射地址
SPI1_Write_Buf(SPI_WRITE_REG+TX_ADDR, (uint8_t*)TX_ADDRESS, TX_ADR_WIDTH);
NRF52832接收地址设置:
#define RX_ADR_LENGTH 5; //接收地址长度
const uint8_t addr_prefix[1] = {0x11};
const uint8_t base_addr_0[RX_ADR_LENGTH -1] = {0x22, 0x33, 0x44, 0x55};
nrf_esb_set_address_length(RX_ADR_LENGTH);
nrf_esb_set_prefixes(addr_prefix, 1);
nrf_esb_set_base_address_0(base_addr_0);
但是当把地址长度改为4时(如下),就会出现问题,NRF52832接收不到数据,这是因为地址设置错误。
//NRF24L01+发射地址
#define TX_ADR_WIDTH 4; //发射地址长度
const uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x11, 0x22, 0x33, 0x44}; //发射地址
//NRF52832接收地址
#define RX_ADR_LENGTH 4; //接收地址长度
const uint8_t addr_prefix[1] = {0x11};
const uint8_t base_addr_0[RX_ADR_LENGTH -1] = {0x22, 0x33, 0x44};
看一下NRF24L01+的TX_ADDR寄存器说明:
地址 | 参数 | 位 | 复位值 | 类型 | 描述 |
---|---|---|---|---|---|
0x10 | TX_ADDR | 39:0 | 0xE7E7E7E7E7 | R/W | 发送地址(先写低字节) |
当把4个字节的地址写入TX_ADDR寄存器前后变化是:
//TX_ADDR写入前:
[39:0] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}
//TX_ADDR写入后:
[39:0] = {0xE7, 0x44, 0x33, 0x22, 0x11}
但是当NRF24L01+发射时,却取用4个高字节。这意味着NRF52832按着4个高字节的地址设置接收地址才能接收到数据,如下:
//NRF24L01+实际发射地址:
[39:8] = {0xE7, 0x44, 0x33, 0x22}
//NRF52832应该接收地址:
const uint8_t addr_prefix[1] = {0x22};
const uint8_t base_addr_0[RX_ADR_LENGTH -1] = {0x33, 0x44, 0xE7}
如要纠正上述问题,可以在写入寄存器时候,把低位的先写一个字节0xE7,然后再写4位实际地址,把NRF24L01+设置函数改为如下:
void SPI1_Write_ADDR(uint8_t address, uint8_t *pBuf, uint8_t datalen)
{
uint8_t tmp,i;
CSN_L;
SPI1_DR = address;//写入需要操作的寄存器地址,
while(!(SPI1_SR_RXNE));
tmp = SPI1_DR; //读取数据,仅仅是为了清除标志位
while(!(SPI1_SR_TXE));//等待发送寄存器为空
//先写入0xE7占位
if(TX_ADR_WIDTH==4)
{
SPI1_DR=0xE7;
while(!(SPI1_SR_TXE));
}
for(i=0;i<datalen;i++)
{
SPI1_DR = pBuf[i];
while(!(SPI1_SR_TXE));
}
CSN_H;
}
#define TX_ADR_WIDTH 4; //发射地址长度
const uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x11, 0x22, 0x33, 0x44}; //发射地址
SPI1_Write_ADDR(SPI_WRITE_REG+TX_ADDR, (uint8_t*)TX_ADDRESS, TX_ADR_WIDTH);
这时NRF52832接收地址才是如下:
#define RX_ADR_LENGTH 4; //接收地址长度
const uint8_t addr_prefix[1] = {0x11};
const uint8_t base_addr_0[RX_ADR_LENGTH -1] = {0x22, 0x33, 0x44};
nrf_esb_set_address_length(ADDRESS_LENGTH);
nrf_esb_set_prefixes(addr_prefix, 1);
nrf_esb_set_base_address_0(base_addr_0);
问题二:发送与接收过程中产生数据左移1bit
当NRF24L01+向NRF52832发送数据时候,会循环左移1bit,即从低字节的高位开始所有bit左移1bit,低字节的高位bit填充到高字节的低位空缺,如下:
//NRF24L01+发送数据{0x99, 0x88, 0x77}
uint8_t TX_DATA[3] = {0b10011001, 0b10001000, 0b01110111};
//NRF52832收到的数据{0x33, 0x10, 0xef},即把TX_DATA[1][8]=1填充到RX_DATA[2][0]
uint8_t RX_DATA[3] = {0b00110011, 0b00010000, 0b11101111};
解决的办法有两种,一种是在NRF52832接收时循环右移动回来,另外一种在NRF24L01+发送前先循环右移。两种操作都差不多了,视具体情况而采用哪种,参考代码如下:
uint8_t tbit = TX_DATA[2]<<7;
TX_DATA[2] = TX_DATA[2]>>1 | TX_DATA[1]<<7;
TX_DATA[1] = TX_DATA[1]>>1 | TX_DATA[0]<<7;
TX_DATA[0] = TX_DATA[0]>>1 | tbit;