关于ATmega16与NRF24L01通信

发布者:知音学友最新更新时间:2015-07-02 来源: 51hei关键字:ATmega16  NRF24L01  通信 手机看文章 扫描二维码
随时随地手机看文章
这阵子搞了NRF24L01与ATmega16之间的通信,不知道程序有没有问题,只有上电那刻接收模块两个LED才会亮,把发送模块电源关掉,LED还是会亮,还有复位了接收模块后,接收模块的LED都不亮,模块都是自己焊的,没有PCB,不知道是硬件还是软件出问题了,求高手看下,指点下迷津啊。。另外单片机用的是12M晶振,电源电压4.3V左右下面是发送跟接收程序:

这是发送的程序:

#include
#include
#define uchar unsigned char
#define uint  unsigned int

#define Hign_24L01_MISO  PORTB|=BIT(PB6);
#define Low_24L01_MISO  PORTB&=~BIT(PB6);
#define Read_24L01_MISO  PINB&BIT(PB6);

#define Hign_24L01_MOSI  PORTB|=BIT(PB5);
#define Low_24L01_MOSI  PORTB&=~BIT(PB5);
#define Read_24L01_MOSI  PINB&BIT(PB5);

#define Hign_24L01_SCK  PORTB|=BIT(PB7);
#define Low_24L01_SCK  PORTB&=~BIT(PB7);
#define Read_24L01_SCK  PINB&BIT(PB7);

#define Hign_24L01_CSN  PORTB|=BIT(PB4);
#define Low_24L01_CSN  PORTB&=~BIT(PB4);
#define Read_24L01_CSN  PINB&BIT(PB4);

#define Hign_24L01_CE  PORTB|=BIT(PB2);
#define Low_24L01_CE PORTB&=~BIT(PB2);
#define Read_24L01_CE  PINB&BIT(PB2);

#define TX_ADR_WIDTH 5//发送地址长度
#define RX_ADR_WIDTH 5//接受地址长度
#define TX_PLOAD_WIDTH 32//发送字节的长度
#define RX_PLOAD_WIDTH 32//接受字节的长度
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   // 定义重复装载数据指令
//*************************************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  // 接收频道1接收数据长度
#define RX_PW_P2        0x13  // 接收频道2接收数据长度
#define RX_PW_P3        0x14  // 接收频道3接收数据长度
#define RX_PW_P4        0x15  // 接收频道4接收数据长度
#define RX_PW_P5        0x16  // 接收频道5接收数据长度
#define FIFO_STATUS     0x17  // FIFO栈入栈出状态寄存器设置

void delay1ms(uint n)
{
 uint i;
 while(n--)
     for(i=1;i<1714;i++);
}

void delay1us(uint n)
{
 while(n--)
     asm("nop");
}

void SPI_init(void)
{
  Hign_24L01_CSN;
  DDRB|=BIT(PB5)|BIT(PB7)|BIT(PB4)|BIT(PB2);//将单片机MOSI CSN CE SCK置为输出
  DDRB&=~BIT(PB6)&~BIT(PB3);//将单片机MISO IRQ置为输入
  SPCR|=BIT(SPE)|BIT(MSTR)|BIT(SPR0);//单片机SPI接口寄存器设置:使能SPI,主机模式,数据MSB先发送,0模式,16分频
  SPSR=0;//状态寄存器
}

uchar SPI_RW(uchar data)//读写SPI
{
  SPDR=data;
  while(!(SPSR&BIT(SPIF)));//SPSR状态寄存器SPI中断标志位
  return SPDR;
}

uchar SPI_Read(uchar reg)//读24L01寄存器
{
  uchar reg_val;
  
  Low_24L01_CSN;
  SPI_RW(reg);//向24L01写入寄存器地址
  reg_val=SPI_RW(0X00);//0X00为读指令
  Hign_24L01_CSN;
  return (reg_val); //返回读取的数据
}

uchar SPI_RW_Reg(uchar reg,uchar value)//写24L01
{
  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 bit)//连续向24L01读多个数据
{
  uchar status1,uchar_ctr;
  
  Low_24L01_CSN;
  status1=SPI_RW(reg);
  
  for(uchar_ctr=0;uchar_ctr       pBuf[uchar_ctr]=SPI_RW(0x00);
  Hign_24L01_CSN;
  return(status1);
}

uchar SPI_Write_Buf(uchar reg,uchar*pBuf,uchar bit)//连续向24L01写多个数据

  uchar status1,uchar_ctr;
  
  Low_24L01_CSN;
  status1=SPI_RW(reg);
  
  for(uchar_ctr=0;uchar_ctr      SPI_RW(*pBuf++);
  Hign_24L01_CSN;
  return(status1);
}

void nRF24L01_TxPacket (uchar *tx_buf)
{
  uchar sta=0;
  uchar flag=0;
  
  Low_24L01_CE; //待机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); //为了应答接收设备,接收通道0地址和发送地址相同
  SPI_Write_Buf(WR_TX_PLOAD,tx_buf,TX_PLOAD_WIDTH);//装载数据
  SPI_RW_Reg(WRITE_REG+EN_AA,0X01);//数据通道0自动应答允许
  SPI_RW_Reg(WRITE_REG+EN_RXADDR,0X01);//接收通道0允许
  SPI_RW_Reg(WRITE_REG+SETUP_RETR,0X0A);//自动重发延时
  SPI_RW_Reg(WRITE_REG+RF_CH,0X40);
  SPI_RW_Reg(WRITE_REG+RF_SETUP,0X07);//发射频率0dBm
  SPI_RW_Reg(WRITE_REG+CONFIG,0X0E);//IRQ收发完成中断响应 16位CRC 主发送
  
  Hign_24L01_CE;
  delay1us(16);//必须大于10us 激发发送
  //Low_24L01_CE; 


void init_NRF24L01(void)//NRF24L01初始化
{
  SPI_init();
  Low_24L01_CE;
  Low_24L01_SCK;
  Hign_24L01_CSN;   
}

void main(void)
{
  uchar TX_BUF[32]={0X01};
  
  init_NRF24L01();
  while(1)
  {
     nRF24L01_TxPacket(TX_BUF);
  delay1ms(200);
  }
}

[page]

这是接收程序:

 

#include
#include
#define uchar unsigned char
#define uint  unsigned int

#define Hign_24L01_MISO  PORTB|=BIT(PB6);
#define Low_24L01_MISO  PORTB&=~BIT(PB6);
#define Read_24L01_MISO  PINB&BIT(PB6);

#define Hign_24L01_MOSI  PORTB|=BIT(PB5);
#define Low_24L01_MOSI  PORTB&=~BIT(PB5);
#define Read_24L01_MOSI  PINB&BIT(PB5);

#define Hign_24L01_SCK  PORTB|=BIT(PB7);
#define Low_24L01_SCK  PORTB&=~BIT(PB7);
#define Read_24L01_SCK  PINB&BIT(PB7);

#define Hign_24L01_CSN  PORTB|=BIT(PB4);
#define Low_24L01_CSN  PORTB&=~BIT(PB4);
#define Read_24L01_CSN  PINB&BIT(PB4);

#define Hign_24L01_CE  PORTB|=BIT(PB2);
#define Low_24L01_CE PORTB&=~BIT(PB2);
#define Read_24L01_CE  PINB&BIT(PB2);

#define TX_ADR_WIDTH 5//发送地址长度
#define RX_ADR_WIDTH 5//接受地址长度
#define TX_PLOAD_WIDTH 32//发送字节的长度
#define RX_PLOAD_WIDTH 32//接受字节的长度
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   // 定义重复装载数据指令
//*************************************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  // 接收频道1接收数据长度
#define RX_PW_P2        0x13  // 接收频道2接收数据长度
#define RX_PW_P3        0x14  // 接收频道3接收数据长度
#define RX_PW_P4        0x15  // 接收频道4接收数据长度
#define RX_PW_P5        0x16  // 接收频道5接收数据长度
#define FIFO_STATUS     0x17  // FIFO栈入栈出状态寄存器设置

void delay1ms(uint n)
{
 uint i;
 while(n--)
     for(i=1;i<1714;i++);
}

void delay1us(uint n)
{
 while(n--)
     asm("nop");
}

void SPI_init(void)
{
  Hign_24L01_CSN;
  DDRB|=BIT(PB5)|BIT(PB7)|BIT(PB4)|BIT(PB2);//将单片机MOSI CSN CE SCK置为输出
  DDRB&=~BIT(PB6)&~BIT(PB3);//将单片机MISO IRQ置为输入
  SPCR|=BIT(SPE)|BIT(MSTR)|BIT(SPR0);//单片机SPI接口寄存器设置:使能SPI,主机模式,数据MSB先发送,0模式,16分频
  SPSR=0;//状态寄存器
}

uchar SPI_RW(uchar data)//读写SPI
{
  SPDR=data;
  while(!(SPSR&BIT(SPIF)));//SPSR状态寄存器SPI中断标志位
  return SPDR;
}

uchar SPI_Read(uchar reg)//读24L01寄存器
{
  uchar reg_val;
  
  Low_24L01_CSN;
  SPI_RW(reg);//向24L01写入寄存器地址
  reg_val=SPI_RW(0X00);//0X00为读指令
  Hign_24L01_CSN;
  return (reg_val); //返回读取的数据
}

uchar SPI_RW_Reg(uchar reg,uchar value)//写24L01
{
  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 bit)//连续向24L01读多个数据
{
  uchar status1,uchar_ctr;
  
  Low_24L01_CSN;
  status1=SPI_RW(reg);
  
  for(uchar_ctr=0;uchar_ctr       pBuf[uchar_ctr]=SPI_RW(0x00);
  Hign_24L01_CSN;
  return(status1);
}

uchar SPI_Write_Buf(uchar reg,uchar*pBuf,uchar bit)//连续向24L01写多个数据

  uchar status1,uchar_ctr;
  
  Low_24L01_CSN;
  status1=SPI_RW(reg);
  
  for(uchar_ctr=0;uchar_ctr      SPI_RW(*pBuf++);
  Hign_24L01_CSN;
  return(status1);
}

void init_NRF24L01(void)//NRF24L01初始化
{
  SPI_init();
  Low_24L01_CE;//空闲模式
  Hign_24L01_CSN; //SPI关闭
  Low_24L01_SCK;//关闭时钟  
}

void SetRX_Mode(void)//接收模式配置
{
  Low_24L01_CE;
  //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);//为了应答接收设备,接收通道0地址和发送地址相同
  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,0X40);//射频通道 2.4GHZ
  SPI_RW_Reg(WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//写通道0接收数据长度
  SPI_RW_Reg(WRITE_REG+RF_SETUP,0X07);//发射频率0dBm 发射速率1MHZ
  SPI_RW_Reg(WRITE_REG+CONFIG,0X0F);//接收模式
  Hign_24L01_CE;//开始接收
  delay1us(200);
}

uchar nRF24L01_RxPacket(uchar *rx_buf)//接收数据包
{
  uchar sta,flag;
  
  flag=0;
  sta=SPI_Read(STATUS);//读取状态寄存器的值判断数据接收情况
  if(sta&0X40)
  {
     Low_24L01_CE;//待机I模式
  SPI_Read_Buf(RD_RX_PLOAD,rx_buf,RX_PLOAD_WIDTH);//单片机读取寄存器的数据
  flag=1;//接收成功标志
  SPI_RW_Reg(WRITE_REG+STATUS,sta);//接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志
  SPI_Read(FLUSH_RX);
  }
  return(flag);
}

void main(void)
{
  uchar RX_BUF[32];
  
  DDRA=0XFF;
  PORTA&=~BIT(PA7)&~BIT(PA6);
  init_NRF24L01();
  SetRX_Mode();
  while(1)
  {
     if(nRF24L01_RxPacket(RX_BUF))
 {
   PORTA|=BIT(PA7)|BIT(PA6);
   delay1ms(200);
 }
  }
}

  完整程序的下载地址:http://www.51hei.com/bbs/dpj-19028-1.html

关键字:ATmega16  NRF24L01  通信 引用地址:关于ATmega16与NRF24L01通信

上一篇:单片机智能循迹小车制作
下一篇:AVR单片机I/O寄存器的C语言源程序及剖析详解

推荐阅读最新更新时间:2024-03-16 14:23

德州仪器全新SoC系列降低多协议工业以太网通信成本
采用德州仪器(TI)新推出的Sitara™ AMIC SoC系列,可实现成本优化的工业以太网通信。 AMIC110 SoC 是一种多协议工业通信处理器,提供支持10多个工业以太网和现场总线通信标准的即用型解决方案。该器件利用TI统一的软件平台、处理器SDK和TI工业通信子系统(PRU-ICSS)的可编程性在工厂自动化和控制应用中支持工业通信。 TI新推出的Sitara AMIC110 SoC可帮助开发人员通过增加工业以太网将现有的非网络设计(如电机驱动器)转换为网络系统。与只支持一个单一工业以太网标准的专用集成电路(ASIC)不同的是,AMIC110 SoC可编程实时单元(PRU-ICSS)支持多种不同的协议,包括EtherC
[网络通信]
SPI nRF24L01 无线简单程序 1
main.c 1 #include reg51.h 2 #include api.h 3 4 #define uchar unsigned char 5 6 /***************************************************/ 7 #define TX_ADR_WIDTH 5 // 5字节宽度的发送/接收地址 8 #define TX_PLOAD_WIDTH 4 // 数据通道有效数据宽度 9 #define LED P2 10 11 uchar code TX_ADDRESS = {0x34,0x43,0x10,0x10,0x01}; // 定义一个静态发送地
[单片机]
一文解析S7-1200与S7-1500 S7通信
S7-1200 与 S7-1200/S7-1500 S7 通信 S7-1200 的 PROFINET 通信口可以做 S7 通信的服务器端或客户端(CPU V2.0及以上版本)。S7-1200 仅支持 S7 单边通信,仅需在客户端单边组态连接和编程,而服务器端只准备好通信的数据就行。 硬件: CPU 1214C DC/DC/DC,V2.0 CPU 1214C DC/DC/DC,V4.1 软件: Step7 V13 SP1 所完成的通信任务: S7-1200 CPU Clinet 将通讯数据区 DB1 块中的 10 个字节的数据发送到 S7-1200 CPU server 的接收数据区 DB1 块中; S7-1200 CPU Cl
[嵌入式]
一文解析S7-1200与S7-1500 S7<font color='red'>通信</font>
msp430g2553与串口通信的驱动程序
#include uart.h #include msp430g2553.h #include typedef.h rece_data uart_buf; //串口缓冲区 void init_uart_buf(void) { uart_buf.head = 0; uart_buf.tail = uart_buf.head; } //获取串口数据 u8 get_uart_data(u8* data) { if(uart_buf.tail == uart_buf.head) { return 0; } *data = uart_buf.buf ; uart
[单片机]
基于LPC2365和嵌入式μC/OS-II下的多串口通信编程方法教程
本文介绍了以LPC2365为核心处理器、嵌入式实时操作系统μC/OS-II下的多串口通信编程方法。对于固定长度的短字节帧数据,通过设置合适的字节触发深度,一次中断完成数据接收任务;对于变长的长字节帧数据,则通过多次中断和等待延时的方法判断数据稳定并完成帧数据的接收;对于大量数据的接收和发送采用建立FIFO数据队列的方法。 通过这些措施较好地完成了多串口较大数据量的通信任务。 国产某掠海恒高硬体拖靶在拖曳飞行时,需要将自身的各种参数通过无线链路实时上传至拖曳母机,同时实时接收拖曳母机的遥控指令完成相应的动作。拖靶自身的参数包括:开关高控状态、蓄电池电压、无线电高度表值、飞行高度装定值、垂向加速度值、舵翼角、温度值、普通性能G
[单片机]
基于LPC2365和嵌入式μC/OS-II下的多串口<font color='red'>通信</font>编程方法教程
Matlab环境下PC与单片机的串行通信及数据处理
摘要:结合单片机和Matlab两者的优点,基于事件驱动的中断通信机制,提出一种Matlab环境下PC机与单片机实时串行通信及数据处理的方法;完成单片机数据采集系统与PC机的RS-232/RS-485串行通信及其通信数据的分析处理、文件存储、FIR滤波及图形显示;简化系统开发流程,提高开发效率。该方法已成功应用于一个PIC16F876单片机应用系统实例之中。 关键词:PIC16F876 Matlab 串口通信 RS-232 事件驱动 回调函数 引言 Matlab是由美国Mathworks公司开发的面向理论分析研究、工程计算数据处理和缓图的一套具有强大功能的软件系统。其中Matlab语言是一种以矩阵为基本运算单元的解释执行的高
[工业控制]
剖析通信电源产业链发展现状与趋势
  希望文中有关内容可供相关决策部门参考借鉴,共同把我国的通信电源产业做大做强。   1 概 述   通信 电源 是通信系统必不可少的重要组成部分,其设计目标是安全、可靠、高效、稳定、不间断地向通信设备提供能源。通信电源必须具备智能监控、无人值守和电池自动管理等功能,从而满足网络时代的需求。   通信电源咨询设计是通信行业咨询设计单位业务单元中的常规业务之一,伴随通信网络的发展,设计师们见证了通信电源技术中设备和材料的发展演变。虽然通信电源一直被视为网络配套部分,但通信电源设备的投资占比、占机房空间比例、可靠性影响面都已经不能仅仅作为1个辅助专业来看待。目前行业的竞争往往趋于产业链之间的竞争,无论是用户、设备商、咨询设计商都在
[电源管理]
基于AT89C51应用系统的串行通信设计
1 引 言 在红外成像技术的电力设备状态检测系统中,基于AT89C51单片机的应用系统,采用美国雷态公司的型号为3iLRL3的非接触式红外测温仪.该测温仪采用的是RS232C串行通信标准接口,该接口在很多通信设备中通用,目前与PC机的直接串行通信也是RS 232C接口。尽管RS232C性能指标并非很好,但还是有广泛的市场支持。串行通信技术在测控系统中占有很重要的地位,只用三根线.就可以方便的在2个数字设备之间进行信息的交换,实现全双工的传送数据,硬件成本低.而且通用性好。 2 串行通信的硬件设计 在所开发的系统中.红外测温仪将检测电力没备的工作和环境温度,通过RS 232C串口传给单片机,同时由单片机控制检测装置的在线工作组态
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved