OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4843|回复: 2

两个NRF24L01收发模式轮流切换的程序很不稳定,急求帮助啊

[复制链接]

10

主题

27

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
333
金钱
333
注册时间
2015-12-18
在线时间
72 小时
发表于 2016-3-31 22:54:30 | 显示全部楼层 |阅读模式
10金钱
在做小车无线控制时发现程序经常会死在NRF24L01的接收或发送中,求大神帮忙解决啊。两个不同的单片机,主函数里的收发都差不多,一个现处于发送,一个先处于接收。
程序如下:
51单片机的
#ifndef _API_DEF_
#define _API_DEF_

// Define interface to nRF24L01
#define uchar unsigned char
#define uint unsigned int
#define TX_ADR_WIDTH   5  // 5字节宽度的发送/接收地址
#define RX_ADR_WIDTH   5  // 5字节宽度的发送/接收地址
#define TX_PLOAD_WIDTH 5  // 数据通道有效数据宽度
#define RX_PLOAD_WIDTH 5  // 数据通道有效数据宽度

// Define SPI pins
sbit CE   = P1^3;  // Chip Enable pin signal (output)
sbit CSN  = P1^4;  // Slave Select pin, (output to CSN, nRF24L01)
sbit IRQ  = P1^2;  // Interrupt signal, from nRF24L01 (input)
sbit MISO = P1^6;  // Master In, Slave Out pin (input)
sbit MOSI = P1^5;  // Serial Clock pin, (output)
sbit SCK  = P1^7;  // Master Out, Slave In pin (output)

uchar RX_BUF[TX_PLOAD_WIDTH];
uchar TX_BUF[TX_PLOAD_WIDTH]={0x01,0x01,0x01,0x01,0x01};

uchar bdata sta;
sbit  RX_DR  = sta^6;
sbit  TX_DS  = sta^5;
sbit  MAX_RT = sta^4;

uchar code RX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01};
uchar code TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01};

// SPI(nRF24L01) commands
#define READ_REG    0x00  // Define read command to register
#define WRITE_REG   0x20  // Define write command to register
#define RD_RX_PLOAD 0x61  // Define RX payload register address
#define WR_TX_PLOAD 0xA0  // Define TX payload register address
#define FLUSH_TX    0xE1  // Define flush TX register command
#define FLUSH_RX    0xE2  // Define flush RX register command
#define REUSE_TX_PL 0xE3  // Define reuse TX payload register command
#define NOP         0xFF  // Define No Operation, might be used to read status register

// SPI(nRF24L01) registers(addresses)
#define CONFIG      0x00  // 'Config' register address
#define EN_AA       0x01  // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR   0x02  // 'Enabled RX addresses' register address
#define SETUP_AW    0x03  // 'Setup address width' register address
#define SETUP_RETR  0x04  // 'Setup Auto. Retrans' register address
#define RF_CH       0x05  // 'RF channel' register address
#define RF_SETUP    0x06  // 'RF setup' register address
#define STATUS      0x07  // 'Status' register address
#define OBSERVE_TX  0x08  // 'Observe TX' register address
#define CD          0x09  // 'Carrier Detect' register address
#define RX_ADDR_P0  0x0A  // 'RX address pipe0' register address
#define RX_ADDR_P1  0x0B  // 'RX address pipe1' register address
#define RX_ADDR_P2  0x0C  // 'RX address pipe2' register address
#define RX_ADDR_P3  0x0D  // 'RX address pipe3' register address
#define RX_ADDR_P4  0x0E  // 'RX address pipe4' register address
#define RX_ADDR_P5  0x0F  // 'RX address pipe5' register address
#define TX_ADDR     0x10  // 'TX address' register address
#define RX_PW_P0    0x11  // 'RX payload width, pipe0' register address
#define RX_PW_P1    0x12  // 'RX payload width, pipe1' register address
#define RX_PW_P2    0x13  // 'RX payload width, pipe2' register address
#define RX_PW_P3    0x14  // 'RX payload width, pipe3' register address
#define RX_PW_P4    0x15  // 'RX payload width, pipe4' register address
#define RX_PW_P5    0x16  // 'RX payload width, pipe5' register address
#define FIFO_STATUS 0x17  // 'FIFO Status Register' register address

void delay_ms(uchar x)
{
    uchar i, j;
    i = 0;
    for(i=0; i<x; i++)
    {
       j = 250;
       while(--j);
    j = 250;
       while(--j);
    }
}
void delay_us(uint n)
{
    while(n--)
   ;
}
uchar SPI_RW(uchar byte)
{
uchar i;
    for(i=0; i<8; i++)          // 循环8次
    {
     MOSI = (byte & 0x80);   // byte最高位输出到MOSI
     byte <<= 1;             // 低一位移位到最高位
     SCK = 1;                // 拉高SCK,nRF24L01从MOSI读入1位数据,同时从MISO输出1位数据
     byte |= MISO;        // 读MISO到byte最低位
     SCK = 0;             // SCK置低
    }
    return(byte);            // 返回读出的一字节
}
uchar SPI_RW_Reg(uchar reg, uchar value)
{
uchar status;
   CSN = 0;                   // CSN置低,开始传输数据
   status = SPI_RW(reg);      // 选择寄存器,同时返回状态字
   SPI_RW(value);             // 然后写数据到该寄存器
   CSN = 1;                   // CSN拉高,结束数据传输
   return(status);            // 返回状态寄存器
}
uchar SPI_Read(uchar reg)
{
uchar reg_val;
   CSN = 0;                    // CSN置低,开始传输数据
   SPI_RW(reg);                // 选择寄存器
   reg_val = SPI_RW(0);        // 然后从该寄存器读数据
   CSN = 1;                    // CSN拉高,结束数据传输
   return(reg_val);            // 返回寄存器数据
}
uchar SPI_Read_Buf(uchar reg, uchar * pBuf, uchar bytes)
{
uchar status, i;
   CSN = 0;                    // CSN置低,开始传输数据
   status = SPI_RW(reg);       // 选择寄存器,同时返回状态字
   for(i=0; i<bytes; i++)
     pBuf = SPI_RW(0);    // 逐个字节从nRF24L01读出
   CSN = 1;                    // CSN拉高,结束数据传输
   return(status);             // 返回状态寄存器
}
uchar SPI_Write_Buf(uchar reg, uchar * pBuf, uchar bytes)
{
uchar status, i;
   CSN = 0;                    // CSN置低,开始传输数据
   status = SPI_RW(reg);       // 选择寄存器,同时返回状态字
   for(i=0; i<bytes; i++)
     SPI_RW(pBuf);        // 逐个字节写入nRF24L01
   CSN = 1;                    // CSN拉高,结束数据传输
   return(status);             // 返回状态寄存器
}
void SetRX_Mode(void)
{
CE=0;
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); //写接收地址
SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      //0通道自动应答
SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //数据通道0
SPI_RW_Reg(WRITE_REG + RF_CH,0);        //射频通道
SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);//写通道0 接受数据长度
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //0db 1M
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f); //接收模式
CE=1;        //开始接收
delay_us(300);//注意不能太小
}
uchar nRF24L01_RxPacket(uchar* rx_buf)
{
    uchar sta,flag=0;
    sta=SPI_Read(STATUS);      // 读取状态寄存其来判断数据接收状况  
    SPI_RW_Reg(WRITE_REG+STATUS,sta);
if(sta&0x40)                 // 判断是否接收到数据RX_DR==1?
    {
       CE=0;   // StandBy I模式
       SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);// read receive payload from RX_FIFO buffer
       SPI_RW_Reg(FLUSH_RX,0xff);
    CE=1;
    flag =1;   //读取数据完成标志
    }
    return (flag);
}
void nRF24L01_TxPacket(  uchar * tx_buf)
{
   uchar sta=0;
   uchar flag=0;
   CE=0;   //StandBy I模式
   SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);
   SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 装载接收端地址
   SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);     // 装载数据
   SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      //
   SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //
   SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1f); //500+86us
   SPI_RW_Reg(WRITE_REG + RF_CH, 0);        //
   SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);   //
   SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);      // IRQ收发完成中断响应,16位CRC,主发送
   delay_ms(2);
   CE=1;   //置高CE,激发数据发送
   delay_us(10);
   CE=0;
}

uchar CheckACK(void)
{  uchar sta1;
sta1=SPI_Read(STATUS);// 返回状态寄存器
if((sta1&0x20)||(sta1&0x10)) //发送完毕中断
{
    SPI_RW_Reg((READ_REG+STATUS),0xff);  // 清除TX_DS或MAX_RT中断标志
    CSN=0;
    SPI_RW(FLUSH_TX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!  
       CSN=1;
    return(0);
}
else
    return(1);
}
void init_io(void)
{
CE  = 0;// 待机
CSN = 1;// SPI禁止
SCK = 0;// SPI时钟置低
IRQ=1;
}

#endif
void main(void)
{
   TimerCofig();
   TFT_Init();
   TFT_ClearScrean(~White);
   Control_Interface();
   while(1)
   {
      TouchCheck();
   if(NRF_flg==0)
   {
     init_io();
     nRF24L01_TxPacket(TX_BUF);
  while(CheckACK());
  delay_ms(1);
  init_io();
        SetRX_Mode();
        while(!(nRF24L01_RxPacket(RX_BUF)));
  for(AQ=0;AQ<5;AQ++)
     {
       Accept[AQ]=RX_BUF[AQ];
     }
  NRF_flg=1;
   }  
   Buz_F();
   }
}
void Timer() interrupt 1
{
  TH0=0xB1;
  TL0=0xE0;
  T_F++;
  if(T_F==2)
  {
    T_F=0;
    if(NRF_flg==1)
{
   init_io();
   nRF24L01_TxPacket(TX_BUF);
      while(CheckACK());
   delay_ms(1);
   init_io();
      SetRX_Mode();
      while(!(nRF24L01_RxPacket(RX_BUF)));
   for(AQ=0;AQ<5;AQ++)
   {
     Accept[AQ]=RX_BUF[AQ];
   }
}
  }
}

ATmega16单片机的
#ifndef _NRF24L01_H
#define _NRF24L01_H
#include <iom16v.h>  
#include <macros.h>
#define uchar unsigned char
#define uint  unsigned int
//spi标志
#define DDR_SPI DDRB
#define DD_MOSI 5
#define DD_MISO 6
#define DD_SCK 7
#define DD_SS 4
#define CE PB3
#define IRQ PB2
#define   Hign_24L01_MISO    PORTB|=(1 << PB6)
#define   Low_24L01_MISO     PORTB &= ~(1 << PB6)
#define   Read_24L01_MISO    PINB & (1 << PB6)
#define   Hign_24L01_MOSI    PORTB |= (1 << PB5)
#define   Low_24L01_MOSI     PORTB &= ~(1 << PB5)
#define   Read_24L01_MOSI    PINB & (1 << PB5)
#define   Hign_24L01_SCK    PORTB |= (1 << PB7)  
#define   Low_24L01_SCK     PORTB &= ~(1 << PB7)   
#define   Read_24L01_SCK    PINB & (1 << PB7)
#define   Low_24L01_CSN     PORTB &= ~(1 << PB4)
#define   Hign_24L01_CSN    PORTB |= (1 << PB4)
#define   Hign_24L01_CE    PORTB |= (1 << PB3)
#define   Low_24L01_CE     PORTB &= ~(1 << PB3)  
#define   Read_24L01_CE    PINB & (1 << PB3)
//*********************************************NRF24L01*************************************
#define TX_ADR_WIDTH    5    // 发送地址长度,最大长度为5 5*8=40 bit
#define RX_ADR_WIDTH    5    // 接收地址长度
#define TX_PLOAD_WIDTH  5     // 发送字节长度,
#define RX_PLOAD_WIDTH  5   // 接收字节长度
uchar TX_ADDRESS[TX_ADR_WIDTH]={0x34,0x43,0x10,0x10,0x01};  //发送地址
uchar 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 NOP1             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 spi_init(void)
{
Hign_24L01_CSN;
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS)|(1 << CE);//设置MOSI,SCK,SS.CE 为OUTPUT,其它为INPUT
DDR_SPI&=~((1<<DD_MISO)|(1<<IRQ));
SPCR=(1<<SPE)|(1<<MSTR)|(1<<SPR0);//使能SPI接口,主机模式,MSB低位在前,模式0,16分频,SPI时钟1MHZ
SPSR=0;
}
void delay_us(uint n)
{
    while(n--)
   ;
}
void delay_ms(uint n)
{
    uint j;
while(n--)
   for(j=0;j<1140;j++);
}
//**************************************************
//*******  uchar SPI_RW(uchar date)  读写SPI
//**************************************************
uchar SPI_RW(uchar date)
{
SPDR=date;
    while(!(SPSR&(1<<SPIF)));
    return SPDR;
}

//**************************************************
//*******uchar SPI_Read(uchar reg)  读24L01寄存器
//**************************************************
uchar SPI_Read(uchar reg)
{
uchar reg_val;

Low_24L01_CSN;               
SPI_RW(reg);            
reg_val = SPI_RW(0);   
Hign_24L01_CSN;               

return(reg_val);      
}
//**************************************************
//*******  uchar SPI_RW_Reg(uchar reg, uchar value)
//          写24L01寄存器
//**************************************************
uchar SPI_RW_Reg(uchar reg, uchar value)
{
uchar status;

Low_24L01_CSN;                 
status = SPI_RW(reg);     
SPI_RW(value);            
Hign_24L01_CSN;                    
return(status);           
}
//**************************************************
//*******  uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar bites)
//          读24L01 寄存器BUFF
//**************************************************
uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar bites)
{
uint status1,uchar_ctr;

Low_24L01_CSN;                     
status1 = SPI_RW(reg);         

for(uchar_ctr=0;uchar_ctr<bites;uchar_ctr++)
  pBuf[uchar_ctr] = SPI_RW(0);   

Hign_24L01_CSN;                          

return(status1);                    
}
//**************************************************
//*******  uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar bites)
//          写24L01 寄存器BUFF
//**************************************************
uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar bites)
{
uchar status1,uchar_ctr;

Low_24L01_CSN;             //SPI使能      
status1 = SPI_RW(reg);  
for(uchar_ctr=0; uchar_ctr<bites; uchar_ctr++) //
SPI_RW(*pBuf++);
Hign_24L01_CSN;           //关闭SPI
return(status1);        //
}
//**************************************************
//*******  void SetRX_Mode(void)
//          接收模式设置
//**************************************************
void SetRX_Mode(void)
{
Low_24L01_CE;
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); //写接收地址
SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      //0通道自动应答
SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //数据通道0
SPI_RW_Reg(WRITE_REG + RF_CH,0);        //射频通道
SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);//写通道0 接受数据长度
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //0db 1M
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f); //接收模式
Hign_24L01_CE;        //开始接收
delay_us(200);//注意不能太小
}
//**************************************************
//*******  uchar nRF24L01_RxPacket(uchar* rx_buf)
//          接收数据包
//**************************************************
uchar nRF24L01_RxPacket(uchar* rx_buf)
{
    uchar sta,flag=0;
    sta=SPI_Read(STATUS);      // 读取状态寄存其来判断数据接收状况  
    if(sta&0x40)                 // 判断是否接收到数据RX_DR==1?
    {
       Low_24L01_CE;
       SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);// read receive payload from RX_FIFO buffer
       Hign_24L01_CE;
       flag =1;   //读取数据完成标志
    }
    SPI_RW_Reg(WRITE_REG+STATUS,sta);   //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志
    return (flag);
}
//*******  void nRF24L01_TxPacket(uchar * tx_buf)
//          发送数据包
//**************************************************
void nRF24L01_TxPacket(  uchar * tx_buf)
{
   uchar sta=0;
   uchar flag=0;
   Low_24L01_CE;   //StandBy I模式
   SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);
   SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 装载接收端地址
   SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);     // 装载数据
   SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      //
   SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  //
   SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1f); //500+86us
   SPI_RW_Reg(WRITE_REG + RF_CH, 0);        //
   SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);   //
   SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);      // IRQ收发完成中断响应,16位CRC,主发送
   delay_ms(2);
   Hign_24L01_CE;   //置高CE,激发数据发送
   delay_us(10);
   Low_24L01_CE;
}
uchar CheckACK(void)
{  uchar sta1;
sta1=SPI_Read(STATUS);                   // 返回状态寄存器
if((sta1&0x20)||(sta1&0x10)) //发送完毕中断
{
    SPI_RW_Reg((READ_REG+STATUS),0xff);  // 清除TX_DS或MAX_RT中断标志
    Low_24L01_CSN;
    SPI_RW(FLUSH_TX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!  
           Hign_24L01_CSN;
    return(0);
}
else
    return(1);
}
void init_NRF24L01(void)
{
  spi_init();
  Low_24L01_CE;    // 空闲模式
  Hign_24L01_CSN;   // SPI 关闭
  Low_24L01_SCK;   // 关闭时钟
}
#endif

无话可说
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165186
金钱
165186
注册时间
2010-12-1
在线时间
2106 小时
发表于 2016-4-1 21:58:23 | 显示全部楼层
回复

使用道具 举报

5

主题

110

帖子

0

精华

初级会员

Rank: 2

积分
152
金钱
152
注册时间
2013-9-16
在线时间
0 小时
发表于 2016-5-6 12:56:28 | 显示全部楼层
延时改改呢,因为收发需要同步才能通讯啊,一般发送尽量慢一点
RFinchina 团队欢迎无线方面的技术交流 QQ 474882985
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-9-28 23:23

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表