研究了几天然后根据论坛上兄弟的程序改的,现在还有一个问题。要接收必须先发一次才能接收,也就是首次发的会超过最大发送次数。互发过一次之后就没问题了。希望有遇到类似情况的给解释一下。发上程序大家交流一下。这个用的是C8051F020,用的硬件SPI
#include "C8051F020.h"
#include "intrins.h"
typedef unsigned char uchar;
typedef unsigned int uint;
//****************************************NRF24L01端口定义***************************************
//sbit SCK =P0^2;
//sbit MISO =P0^3;
//sbit MOSI =P0^4;
unsigned char TxBuf[4]={0}; //
unsigned char RxBuf[4]={0};
unsigned int num_20us;
bit tf =0;
bit RX_flag=0;
bit led_on_off;
//******************************************************************************************
uchar bdata sta; //状态标志
sbit RX_DR =sta^6; //接收中断标志
sbit TX_DS =sta^5; //发送完成数据中断标志
sbit MAX_RT =sta^4; //达到最多允许从发次数中断标志
/******************************************************************************************/
sbit CE =P0^6; //模式选择
sbit CSN =P0^7; //SPI片选信号,使用通用IO口
sbit IRQ =P1^0; //中断引脚
//************************************按键***************************************************
sbit KEY1=P2^0;
sbit KEY2=P2^1;
//************************************数码管位选*********************************************
sbit led1=P3^4;
sbit led2=P3^5;
//*********************************************NRF24L01*************************************
#define TX_ADR_WIDTH 5 // 5 uints TX address width
#define RX_ADR_WIDTH 5 // 5 uints RX address width
#define TX_PLOAD_WIDTH 4 // 20 uints TX payload
#define RX_PLOAD_WIDTH 4 // 20 uints TX payload
uchar code TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址
uchar code RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址
//***************************************NRF24L01寄存器指令*******************************************************
#define READ_REG 0x00 // 读寄存器指令
#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 // 定义重复装载数据指令
#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栈入栈出状态寄存器设置
//**************************************************************************************
//void Delay(unsigned int s);
void Delay_20us(uint i);
//void NRFSetTxMode(uchar *tx_buf);
void NRFSetRXMode();
uchar NRFRevDate(uchar *rx_buf);
uchar CheckACK();
uchar NRFSPI(uchar dat);
uchar NRF_Read_Reg(uchar reg);
uchar NRF_Write_Reg(uchar reg, uchar value);
uchar SPI_Read_Buf(uchar RegAddr, uchar *rx_buf, uchar num);
uchar SPI_Write_Buf(uchar RegAddr, uchar *tx_buf, uchar num);
void Oscillator_Init()
{
OSCICN = 0x07;//16M内部
}
void Port_IO_Init()
{
// P0.0 - TX0 (UART0), Open-Drain, Digital
// P0.1 - RX0 (UART0), Open-Drain, Digital
// P0.2 - SCK (SPI0), Open-Drain, Digital
// P0.3 - MISO (SPI0), Open-Drain, Digital
// P0.4 - MOSI (SPI0), Open-Drain, Digital
// P0.5 - NSS (SPI0), Open-Drain, Digital
XBR0 = 0x06;
XBR2 = 0x40;
}
void SPI_Init()
{
SPI0CFG &= 0x3F;//时钟周期第一个边沿采样,空闲低电平
SPI0CN = 0x03;//主模式 ,使能SPI SPIEN=1
SPI0CKR =0x07;//时钟频率1M
}
void Timer4_Init() //20us
{
CKCON = 0x40;
RCAP4L = 0xBF;
RCAP4H = 0xFE;
}
void Init_Device(void)
{
Port_IO_Init();
Oscillator_Init();
SPI_Init();
Timer4_Init();
}
/*延时函数
/******************************************************************************************/
void Delay_20us(uint i)
{
TL4=0xBF;
TH4=0xFE;
T4CON = 0x04;//使能
EIE2 |= 0x04;//开中断
while(num_20us<i);
num_20us=0;
T4CON &=~0x04;//禁止
EIE2 &=~0x04;//关中断
}
/****************************************************************************************************
/*函数:uint SPI_RW(uint dat)
/*功能:NRF24L01的SPI写时序
/****************************************************************************************************/
uchar NRFSPI(uchar dat)
{
// Delay_20us(1);
uchar status;
// CSN=0;
while(TXBSY);
SPI0DAT=dat;
while(!SPIF);
SPIF=0;
status=SPI0DAT;
// CSN =1;
return(status);
// return read uchar
}
/****************************************************************************************************
/*函数:uchar NRF_Read_Reg(uchar reg)
/*功能:NRF24L01的SPI时序
/****************************************************************************************************/
uchar NRF_Read_Reg(uchar reg) //接收时读状态寄存器数据用
{
uchar reg_val;
CSN = 0; // CSN low, initialize SPI communication...
// Delay_20us(1);
NRFSPI(reg); // Select register to read from..
reg_val = NRFSPI(0); // ..then read registervalue
CSN = 1; // CSN high, terminate SPI communication
// Delay_20us(1);
return(reg_val); // return register value
}
/****************************************************************************************************/
/*功能:NRF24L01写寄存器函数
/****************************************************************************************************/
uchar NRF_Write_Reg(uchar reg, uchar value)
{
uchar status;
CSN = 0; // CSN low, init SPI transaction
// Delay_20us(1);
status = NRFSPI(reg); // select register
NRFSPI(value); // ..and write value to it..
CSN = 1; // CSN high again
return(status); // return nRF24L01 status uchar
}
/****************************************************************************************************/
/*函数:uint SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)
/*功能: 用于读数据,reg:为寄存器地址,pBuf:为待读出数据地址,uchars:读出数据的个数
/****************************************************************************************************/
uchar SPI_Read_Buf(uchar RegAddr, uchar *rx_buf, uchar num)
{
uchar status,i;
CSN = 0; // Set CSN low, init SPI tranaction
// Delay_20us(1);
status = NRFSPI(RegAddr); // Select register to write to and read status uchar
for(i=0;i<num;i++)
rx_buf = NRFSPI(0); //
CSN = 1;
return(status); // return nRF24L01 status uchar
}
/*********************************************************************************************************
/*函数:uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
/*功能: 用于写数据:为寄存器地址,pBuf:为待写入数据地址,uchars:写入数据的个数
/*********************************************************************************************************/
uchar SPI_Write_Buf(uchar RegAddr, uchar *tx_buf, uchar num)
{
uchar status,i;
CSN = 0;
status = NRFSPI(RegAddr);
for(i=0; i<num; i++) //
NRFSPI(*tx_buf++);
CSN = 1; //关闭SPI
return(status); //
}
//void NRF_Init()//NRF初始化
//{
// CE=0; // 待机模式
// SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 写本地地址
// /******下面有关寄存器配置**************/
//// NRF_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置0通道接收数据长度
// NRF_Write_Reg(WRITE_REG + EN_AA, 0x01); //01 频道0自动 ACK应答允许
// NRF_Write_Reg(WRITE_REG + EN_RXADDR, 0x01); // 允许接收地址只有频道0,如果需要多频道可以参考Page21
// NRF_Write_Reg(WRITE_REG + RF_CH, 0x40); // 选择射频通道0x40
//// NRF_Write_Reg(WRITE_REG + SETUP_RETR, 0xFA); //FA 自动重发延时等待250us+86us,自动重发10次
// NRF_Write_Reg(WRITE_REG + RF_SETUP, 0x07); //设置发射速率为1MHZ,发射功率为最大值0dB
//// NRF_Write_Reg(WRITE_REG+CONFIG,0x0f); //20,0F CRC使能,16位CRC校验,上电,接收模式
// CE=1;
//
//}
//****************************************************************************************
/*NRF设置为接收模式并接收数据*/
//***************************************************************************************/
void NRFSetRXMode()
{//接收模式
CE=0;
// SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 写本地地址
SPI_Write_Buf(WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_PLOAD_WIDTH); // 接收设备接收通道0使用和发送设备相同的发送地址
NRF_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //31,04设置0通道接收数据长度
NRF_Write_Reg(WRITE_REG + EN_AA, 0x01); //21,01 频道0自动 ACK应答允许
NRF_Write_Reg(WRITE_REG + EN_RXADDR, 0x01); //22,01 允许接收地址只有频道0,如果需要多频道可以参考Page21
NRF_Write_Reg(WRITE_REG + RF_CH, 0x40); //25,40 选择射频通道0x40
NRF_Write_Reg(WRITE_REG + RF_SETUP, 0x07); //26,07设置发射速率为1MHZ,发射功率为最大值0dB
NRF_Write_Reg(WRITE_REG+CONFIG,0x0f); //20,0F CRC使能,16位CRC校验,上电,接收模式
CE = 1;
RX_flag=1;
}
//****************************************************************************************
/****************************检测是否发送完毕******************************/
uchar CheckACK()
{ //用于发射
sta=NRF_Read_Reg(READ_REG+STATUS); // 返回状态寄存器
if(TX_DS||MAX_RT) //发送完毕中断
{
CE=0;
// NRF_Write_Reg(WRITE_REG+CONFIG,0x0f); // 发送完数据立即转入接收模式,非常重要
// RX_flag=1; //接收模式标志置1
NRF_Write_Reg(WRITE_REG+STATUS,0xff); // 清除TX_DS或MAX_RT中断标志
//中断标志为什么无法清除呢?????
CSN=0;
NRFSPI(FLUSH_TX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!
CSN=1;
CE=1;
return(0);
}
else
return(1);
}
/******************判断是否接收收到数据,接到就从RX取出*********************/
//用于接收模式
uchar NRFRevDate(uchar *rx_buf)
{
uchar RevFlags=0;
sta=NRF_Read_Reg(READ_REG+STATUS);//发送数据后读取状态寄存器
if(RX_DR) // 判断是否接收到数据
{
CE=0; //SPI使能
// NRF_Write_Reg(WRITE_REG + CONFIG, 0x0e); //接收完数据立即转入发送模式
// RX_flag=0; //接收模式标志置0
SPI_Read_Buf(RD_RX_PLOAD,rx_buf,RX_PLOAD_WIDTH);// 从RXFIFO读取数据
RevFlags=1; //读取数据完成标志
NRF_Write_Reg(WRITE_REG+STATUS,0xff); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标
CSN=0;
NRFSPI(FLUSH_RX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!
CSN=1;
CE=1;
}
return(RevFlags);
}
/*发送数据*/
void NRFSendDate(uchar *tx_buf)
{
CE=0; //StandBy I模式
// Delay_20us(1);
SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 写本地地址
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); // 写接收端地址
SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);//写入数据
NRF_Write_Reg(WRITE_REG + EN_AA, 0x01); //21,01 频道0自动 ACK应答允许
NRF_Write_Reg(WRITE_REG + EN_RXADDR, 0x01); //22,01 允许接收地址只有频道0,如果需要多频道可以参考Page21
NRF_Write_Reg(WRITE_REG + RF_CH, 0x40); //25,40 选择射频通道0x40
NRF_Write_Reg(WRITE_REG + RF_SETUP, 0x07); //26,07设置发射速率为1MHZ,发射功率为最大值0dB
NRF_Write_Reg(WRITE_REG + SETUP_RETR, 0xFA); //FA 自动重发延时等待250us+86us,自动重发10次
NRF_Write_Reg(WRITE_REG + CONFIG, 0x0e); // IRQ收发完成中断响应,16位CRC,发送模式
RX_flag=0;
CE=1; //置高CE,激发数据发送
Delay_20us(1); //CE高电平大于10us发送模式
CE=0;//进入待机模式I(低功耗模式)
}
void main()
{
bit led_on_off=1;
bit rece_flag=0;
WDTCN = 0xDE;
WDTCN = 0xAD;
Init_Device();
NRFSetRXMode();
// NRF_Init();
EA=1;
while(1)
{
if(KEY1==0)
{
Delay_20us(500);
if(KEY1==0)
{
tf=1;
while(!KEY1);
}
Delay_20us(500);
while(!KEY1);
}
if(tf==1)
{
TxBuf[0] =led_on_off;
NRFSendDate(TxBuf);
while(CheckACK()); //检测是否发送完毕
led_on_off=!led_on_off;
tf=0;
}
else
{
if(RX_flag==0)//如果不是接收模式
NRFSetRXMode();
rece_flag=NRFRevDate(RxBuf);
if(rece_flag)
{
if(RxBuf[0]==1)
led1=0;
else
led1=1;
}
}
}
}
void Time4_ISR() interrupt 16
{
T4CON &=~0x80;
num_20us++;
// WDTCN=0xA5;
}
|