天嵌 ARM开发社区

 找回密码
 注册
查看: 2343|回复: 3

哪位大哥有写过nrf24l01的驱动的,这里遇到问题了~

[复制链接]
维C1° 发表于 2013-11-30 14:27:43 | 显示全部楼层 |阅读模式
本帖最后由 维C1° 于 2013-11-30 20:05 编辑

nrf24l01是用普通引脚来模拟SPI时序的,在裸机上调试成功了,可以发射可以接收,但是把它丢到驱动里,就出问题了.发送数据不成功。以下是驱动内容,麻烦各位帮个忙看看,我调了好久了。
这里由于字数要求省去头文件的定义了
#define DEVICE_NAME  "NRF24L01"  //设备名称
//引脚相关的宏定义
#define CSN       S3C2410_GPG0
#define CSN_OUTP  S3C2410_GPG0_OUTP
#define CE        S3C2410_GPG3
#define CE_OUTP   S3C2410_GPG3_OUTP
#define MOSI      S3C2410_GPG5
#define MOSI_OUTP S3C2410_GPG5_OUTP
#define SCK       S3C2410_GPG6
#define SCK_OUTP  S3C2410_GPG6_OUTP
#define MISO      S3C2410_GPG7
#define MISO_INP  S3C2410_GPG7_INP
#define IRQ       S3C2410_GPG11
#define IRQ_INP   S3C2410_GPG11_INP

//NRF24L01端口定义
#define CE_OUT      s3c2410_gpio_cfgpin(CE, CE_OUTP)  
#define CE_UP       s3c2410_gpio_pullup(CE, 1)      
#define CE_L        s3c2410_gpio_setpin(CE, 0)         
#define CE_H        s3c2410_gpio_setpin(CE, 1)   
     
#define SCK_OUT     s3c2410_gpio_cfgpin(SCK, SCK_OUTP)
#define SCK_UP      s3c2410_gpio_pullup(SCK, 1)        
#define SCK_L       s3c2410_gpio_setpin(SCK, 0)         
#define SCK_H       s3c2410_gpio_setpin(SCK, 1)  
      
#define MISO_IN     s3c2410_gpio_cfgpin(MISO, MISO_INP)
#define MISO_STU    s3c2410_gpio_getpin(MISO)           

#define IRQ_IN      s3c2410_gpio_cfgpin(IRQ, IRQ_INP)
#define IRQ_STU     s3c2410_gpio_getpin(IRQ)         

#define MOSI_OUT    s3c2410_gpio_cfgpin(MOSI, MOSI_OUTP)
#define MOSI_UP     s3c2410_gpio_pullup(MOSI, 1)      
#define MOSI_L      s3c2410_gpio_setpin(MOSI, 0)   
#define MOSI_H      s3c2410_gpio_setpin(MOSI, 1)

#define CSN_OUT     s3c2410_gpio_cfgpin(CSN, CSN_OUTP)   
#define CSN_UP      s3c2410_gpio_pullup(CSN, 1)        
#define CSN_L       s3c2410_gpio_setpin(CSN, 0)   
#define CSN_H       s3c2410_gpio_setpin(CSN, 1)   
  
//NRF24L01
#define TX_ADDR_WITDH    5        // 5 uint8s TX address width
#define RX_ADDR_WITDH    5        // 5 uint8s RX address width
#define TX_DATA_WITDH    4        // 20 uint8s TX payload
#define RX_DATA_WITDH    4        // 20 uint8s TX payload
(因为字数的限制,这里略去一些NRF24L01寄存器指令 和寄存器地址的宏定义声明了)
...............................................

//全局变量
U8 TxBuf[4]={ 0x00,0x00,0x00,0x00};
U8 test_TxBuf[4]={ 0x01,0x01,0x00,0x00};   
U8 opencount = 0;
U8 TxAddr[]={0x34,0x43,0x10,0x10,0x01};//发送地址
U8 RevTempDate[5];//最后一位用来存放结束标志

void NRFDelay(U16 t)
{
   unsigned int x,y;
   for(x=t;x>0;x--)
    for(y=20;y>0;y--);
}
  
//NRF24L01初始化
U8 NRF24L01Int(void)
{
    NRFDelay(2);//让系统什么都不干
    CE_UP;
    CSN_UP;
    SCK_UP;
    MOSI_UP;
    CE_OUT;
    CSN_OUT;
    SCK_OUT;
    MOSI_OUT;
    MISO_IN;
    IRQ_IN;

    udelay(500);
    CE_L;     
    ndelay(60);
    CSN_H;     
    ndelay(60);
    SCK_L;   
    ndelay(60);                      这里我有一个疑问,这个延时函数好像延时不对, ndelay(1) ,ndelay(10)的延时时间一样,这是怎么回事?
    return 1;
}
//功能:NRF24L01的SPI写时序
U8 NRFSPI(U8 date)
{
    U8 i;
    for(i=0 ;i<8 ;i++)         
    {
        if(date & 0x80)         
            MOSI_H;
        else
            MOSI_L;
        date=date<<1;           
        SCK_H;                  
        ndelay(10);                                       在裸机上这些延时不需要写,在驱动上,有网友说要参照24l01的手册来加延时,但是
                                                                                                                                    加上必要的延时也没有什么作用啊        

        date |= MISO_STU;        
        SCK_L;                  
        ndelay(10);
    }
    return(date);                    
}
  

//NRF24L01的SPI时序
U8 NRFReadReg(U8 RegAddr)
{
    U8 BackDate;
    CSN_L;                 
    ndelay(10);
    NRFSPI(RegAddr);            
    BackDate=NRFSPI(0x00);   
    CSN_H;              
    ndelay(70);
    return(BackDate);         
}
  
//NRF24L01读写寄存器函数
U8 NRFWriteReg(U8 RegAddr,U8 date)
{
    U8 BackDate;
    CSN_L;                  
    BackDate=NRFSPI(RegAddr);//写入地址
    NRFSPI(date);//写入值
    CSN_H;                 
    return(BackDate);         
}
  
//SPI读取RXFIFO寄存器的值
U8 NRFReadRxDate(U8 RegAddr,U8 *RxDate,U8 DateLen)
{    U8 BackDate,i;
    CSN_L; //启动时序
    BackDate=NRFSPI(RegAddr);//写入要读取的寄存器地址
    for(i=0;i<DateLen;i++) //读取数据
    {
      RxDate=NRFSPI(0);
      ndelay(1);
    }
    CSN_H;
    return(BackDate);
}

//SPI写入TXFIFO寄存器的值
U8 NRFWriteTxDate(U8 RegAddr,U8 *TxDate,U8 DateLen)
{   U8 BackDate,i;
   CSN_L;  
   BackDate=NRFSPI(RegAddr);//写入要写入寄存器的地址
   for(i=0;i<DateLen;i++)//写入数据
   {
      NRFSPI(*TxDate++);
      ndelay(1);
   }
   CSN_H;
   return(BackDate);
}
//NRF设置为发送模式并发送数据
void NRFSetTxMode(U8 *TxDate)
{  //发送模式
    CE_L;
    NRFWriteTxDate(W_REGISTER+TX_ADDR,TxAddr,TX_ADDR_WITDH);//写寄存器指令+P0地址使能指令+发送地址+地址宽度
    NRFWriteTxDate(W_REGISTER+RX_ADDR_P0,TxAddr,TX_ADDR_WITDH);//为了应答接收设备,接收通道0地址和发送地址相同
    NRFWriteTxDate(W_TX_PAYLOAD,TxDate,TX_DATA_WITDH);//写入数据
    /******下面有关寄存器配置**************/
    NRFWriteReg(W_REGISTER+EN_AA,0x01);       // 使能接收通道0自动应答
    NRFWriteReg(W_REGISTER+EN_RXADDR,0x01);   // 使能接收通道0
    NRFWriteReg(W_REGISTER+SETUP_RETR,0x0a);  // 自动重发延时等待250us+86us,自动重发10次
    NRFWriteReg(W_REGISTER+RF_CH,0x40);         // 选择射频通道0x40
    NRFWriteReg(W_REGISTER+RF_SETUP,0x07);    // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益
    NRFWriteReg(W_REGISTER+CONFI_G,0x0e);      // CRC使能,16位CRC校验,上电   
    CE_H;
    mdelay(1);
}
//NRF设置为接收模式并接收数据
//接收模式
void NRFSetRXMode(void)
{
    CE_L;
    NRFWriteTxDate(W_REGISTER+RX_ADDR_P0,TxAddr,TX_ADDR_WITDH);  // 接收设备接收通道0使用和发送设备相同的发送地址
    NRFWriteReg(W_REGISTER+EN_AA,0x01);               // 使能接收通道0自动应答
    NRFWriteReg(W_REGISTER+EN_RXADDR,0x01);           // 使能接收通道0
    NRFWriteReg(W_REGISTER+RF_CH,0x40);                 // 选择射频通道0x40
    NRFWriteReg(W_REGISTER+RX_PW_P0,TX_DATA_WITDH);  // 接收通道0选择和发送通道相同有效数据宽度
    NRFWriteReg(W_REGISTER+RF_SETUP,0x07);            // 数据传输率1Mbps,发射功率0dBm,低噪声放大器增益
    NRFWriteReg(W_REGISTER+CONFI_G,0x0f);             // CRC使能,16位CRC校验,上电,接收模式     
    CE_H;
    NRFDelay(30);   
}
U8 CheckACK(void)
{
    U8 sta;
    sta=NRFReadReg(R_REGISTER+STATUS);
    if((sta&0x20)||(sta&0x10))
    {
       NRFWriteReg(W_REGISTER+STATUS,0XFF);
       CSN_L;
       NRFSPI(FLUSH_TX);//用于清空FIFO !!关键!!不然会出现意想不到的后果!!!大家记住!!
       CSN_H;
       return 0;
    }
    else
       return 1;
}  
//文件的写函数
static int nrf24l01_write(struct file *filp, const char *buffer,size_t count)
{
    if(copy_from_user(TxBuf,buffer,count))  //从内核空间复制到用户空间
    {
       printk("Can't Send Data! " ) ;
       return -EFAULT;
    }
    NRFSetTxMode(TxBuf);
    if(!CheckACK())
    {
       printk ( "Write Success!\n" ) ;
    }
    else
       printk ( "Write Faild!\n" ) ;
    return 1;
}
//的读函数
static int nrf24l01_read(struct file *filp, char *buffer,size_t count)
{
    U8 sta;
    NRFSetRXMode();
    sta=NRFReadReg(R_REGISTER+STATUS);//发送数据后读取状态寄存器
    if(sta & 0x40)               // 判断是否接收到数据
    {
       CE_L; //待机
       NRFReadRxDate(R_RX_PAYLOAD,RevTempDate,RX_DATA_WITDH);// 从RXFIFO读取数据 接收4位即可,后一位位结束位
       NRFWriteReg(W_REGISTER+STATUS,0xff); //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标
       //return(1);   //读取数据完成标志      
    }
    NRFWriteReg(W_REGISTER+STATUS,0xff);
    printk("read \n" ) ;
}
static int nrf24l01_open(struct inode *node, struct file *file)
{
  U8 flag = 0,a=1;
  if(opencount == 1) return -EBUSY;
   flag = NRF24L01Int();
  /*
  while(1)
  {
     CE_H;
     ndelay(10);                         我是在这里测延时函数的延时时间的,用示波器看引脚电平的变化,测出来 ndelay()延时不准确
     CE_L;
     ndelay(1);
  }
  */
  if(flag == 0)
  {
      printk("uable to open device!\n" ) ;
      return -1;
  }
  else
  {
      opencount++;
      printk("device opened !\n" ) ;
      return 0;
  }
}
static int nrf24l01_release(struct inode *node, struct file *file)
{
  opencount--;
  printk(DEVICE_NAME " released !\n");
  return 0;
}
static struct file_operations nrf24l01_fops = {
  .owner = THIS_MODULE,
  .write = nrf24l01_write,
  .read = nrf24l01_read,
  .release = nrf24l01_release,
  .open=nrf24l01_open,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &nrf24l01_fops,
};
static int __init nrf24l01_init(void)
{
    int ret;
    printk("Initial driver for NRF24L01......................\n" ) ;
    ret = misc_register(&misc);
    mdelay(10);
    if (ret < 0)
    {
        printk(DEVICE_NAME " can't register major number\n");
        return ret;
    }
    else
    {
    printk(DEVICE_NAME " register success\n");
    return 0;
    }
}
static void __exit nrf24l01_exit(void)
{
    misc_deregister(&misc);
    printk("NRF24L01 unregister success \n" ) ;
}
module_init(nrf24l01_init);
module_exit(nrf24l01_exit);

 楼主| 维C1° 发表于 2013-11-30 14:27:55 | 显示全部楼层
下面是我的测试程序
//linux下nrf24l01的测试程序 (省去头文件)

unsigned char TxBuf[4] = {1,2,3,4};
int main(void)
{
    int fd = -1;
    int count = 1;

    fd = open("/dev/NRF24L01", O_RDWR);
    if(fd < 0)
    {
        perror("Can't open /dev/nrf24l01 \n" ) ;
        exit(1);
    }
    printf("open /dev/nrf24l01 success \n" ) ;
    while( count<5)
    {
        write(fd, TxBuf , sizeof(TxBuf));  
        printf("Sending %d time \n",count);
        usleep(100*1000);   
        count++;
    }
    close(fd);
}


数据就是发送不成功,是怎么回事呢?我跑的是Linux系统,在nrf24l01的手册里有说明工作速率的0~8MHz,所以跟系统的运行速度有没有关系?因为系统是在高速运行的,裸机的速度并不快,如果真是跟运行速度有关,那我该怎么做,加延时吗?来减小引脚电平的变化速率?求求大家了,小弟的毕设卡在这里了,做不下去了,这是要挂的节奏啊?55555
 楼主| 维C1° 发表于 2013-11-30 20:04:32 | 显示全部楼层
我知道问题出在哪里了,所有问题都出在这个函数
U8 NRFSPI(U8 date)
{
U8 i;
for(i=0 ;i<8 ;i++)
{
if(date & 0x80)
MOSI_H;
else
MOSI_L;
date=date<<1;
SCK_H;
ndelay(10);
date |= MISO_STU;
SCK_L;
ndelay(10);
}
return(date);
}
在网上搜到一篇叫《关于NRF24L01的Linux驱动和s3c2410_getpin();函数问题》的帖子,date |= MISO_STU这是问题的根源,
之后我改为
if(MISO_STU) tmp |= 0x01 ; 问题解决了。
以下是帖子的连接
http://www.linuxidc.com/Linux/2011-06/36852.htm


亚瑟王 发表于 2013-12-2 08:59:12 | 显示全部楼层
维C1° 发表于 2013-11-30 20:04
我知道问题出在哪里了,所有问题都出在这个函数
U8 NRFSPI(U8 date)
{

下次有问题不用给我发私聊的帖子,建议直接在论坛发帖。
做一个应用程序,采集到按键按下后,就调用nrf24l01的驱动发送数据到单片机就行了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

i.MX8系列ARM cortex A53 M4 工控板上一条 /1 下一条

Archiver|手机版|小黑屋|天嵌 嵌入式开发社区 ( 粤ICP备11094220号 )

GMT+8, 2024-5-19 20:27 , Processed in 1.078125 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

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