找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4091|回复: 13
收起左侧

基于NRF24L01的无线温度检测系统

  [复制链接]
ID:81066 发表于 2015-5-25 15:46 | 显示全部楼层 |阅读模式
#include <reg51.h>
#include <intrins.h>
#include "spi.h"
#include "ds18b20.h"

/***************************************************/
//#define uchar unsigned char
//#define uint unsigned int
#define TX_ADR_WIDTH    5   // 收发地址5 字节宽TX(RX)
#define TX_PLOAD_WIDTH  20  // 发送数据包20 字节

uchar const TX_ADDRESS[TX_ADR_WIDTH]  = {0x34,0x43,0x10,0x10,0x01};// 定义发送地址

uchar rx_buf[TX_PLOAD_WIDTH];//接收缓冲数组
uchar tx_buf[TX_PLOAD_WIDTH];//发送缓冲数组
uchar flag;//中断标志
/**************************************************/
//nRF24L01 SPI口定义//
sbit CE =  P1^7;
sbit CSN=  P1^6;
sbit SCK=  P1^5;
sbit MOSI= P1^4;
sbit MISO= P1^3;
sbit IRQ = P3^2;

sbit S2=   P1^2;//发送按钮
sbit LEDG= P3^7;
sbit LEDR= P3^5;

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

/**************************************************/

/**************************************************
函数: init_nRF24L01();
说明:
  nRF24L01待机模式,
  Spi 不能,Spi 时钟线高
/**************************************************/
void init_nRF24L01(void)
{
        CE=0;                        // 片选使能
        CSN=1;                        // Spi 禁止       
        SCK=0;                        // Spi 时钟初始化
       
}

/**************************************************/

/**************************************************
函数: init_int0();
说明:
  开int0中断;
/**************************************************/
void init_int0(void)
{
        EA=1;
        EX0=1;        //开int0中断.
}

/**************************************************/
void delay_ms(unsigned int x) //ms延时
{
    unsigned int i,j;
    i=0;
    for(i=0;i<x;i++)
    {
       j=108;
           ;
       while(j--);
    }
}
/**************************************************/

/**************************************************
函数: SPI_RW();
说明:
  写单字节到nRF24L01, 同时返回从nRF24L01读出的一字节
/**************************************************/
uchar SPI_RW(uchar byte)
{
        uchar bit_ctr;
           for(bit_ctr=0;bit_ctr<8;bit_ctr++)   // 输出 8-bit
           {
                   MOSI = (byte & 0x80);         // 输出字节到MOSI, 最高位开始
                   byte = (byte << 1);           // 左移一位
                   SCK = 1;                      // 时钟置高
                   byte |= MISO;                         // 由MISO读入1bit
                   SCK = 0;                              // 时钟置低
           }
    return(byte);                             // 返回读入的字节
}
/**************************************************/

/**************************************************
函数: SPI_RW_Reg();
说明:
  写一字节值'value'到地址为'reg'的寄存器
/**************************************************/
uchar SPI_RW_Reg(BYTE reg, BYTE value)
{
        uchar status;

          CSN = 0;                   // SPI 使能
          status = SPI_RW(reg);      // 选寄存器,并读状态值
          SPI_RW(value);             // 写该寄存器       
          CSN = 1;                   // SPI禁止

          return(status);            // 返回状态值
}
/**************************************************/

/**************************************************
函数: SPI_Read();
说明:
  从 nRF24L01内地址为 'reg'的寄存器读出一字节数据
/**************************************************/
BYTE SPI_Read(BYTE reg)
{
        BYTE reg_val;

          CSN = 0;                // SPI 使能
          SPI_RW(reg);            // 选寄存器
          reg_val = SPI_RW(0);    // 读寄存器
          CSN = 1;                // SPI 禁止

          return(reg_val);        // 返回寄存器值
}
/**************************************************/

/**************************************************
函数: SPI_Read_Buf();
说明:
  从地址为'reg'的寄存器中读出若干字节的数据到数组,例如从
  RX payload 中读出数据包。
/**************************************************/
uchar SPI_Read_Buf(BYTE reg, BYTE *pBuf, BYTE bytes)
{
        uchar status,byte_ctr;

          CSN = 0;                                    // SPI 使能
          status = SPI_RW(reg);                       // 选寄存器,并读状态值

          for(byte_ctr=0;byte_ctr<bytes;byte_ctr++)
            pBuf[byte_ctr] = SPI_RW(0);    // 由nRF24L01读出若干字节数据到数组

          CSN = 1;                           // SPI 禁止

          return(status);                    // 返回状态字
}
/**************************************************/

/**************************************************
函数: SPI_Write_Buf();
说明:
  把缓冲数组'*pBuf'中的数据写入nRF24L01中的TX payload
/**************************************************/
uchar SPI_Write_Buf(BYTE reg, BYTE *pBuf, BYTE bytes)
{
        uchar status,byte_ctr;

          CSN = 0;                 // SPI 使能
          status = SPI_RW(reg);    // 选寄存器,并读状态值
          for(byte_ctr=0; byte_ctr<bytes; byte_ctr++)// 把buffer(*pBuf)中的字节写入
            SPI_RW(*pBuf++);
          CSN = 1;                 // SPI 禁止
          return(status);          // 返回状态字节
}
/**************************************************/

/**************************************************
函数: RX_Mode();
说明:
  初始化nRF24L01 为RX Mode,设定接收地址、RX payload 长度,
  选择RF 通道, 数据速率和LNA HCURR。然后置CE为高, 等待接收数据包
/**************************************************/
void RX_Mode(void)
{
        CE=0;
// 收发设置相同的地址
          SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);
          SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      // 使能自动应答Pipe0
          SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  // Pipe0使能
          SPI_RW_Reg(WRITE_REG + RF_CH, 40);        // 选 射频通道40
// 设置接收和发送 payload宽度相同
          SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH);
// 发送功率:0dBm, 数据速率:2Mbps, LNA:HCURR
          SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);
// 置位 PWR_UP, 使能CRC(2 bytes) 和主接收Prim:RX. 使能RX_DR
          SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);     
          CE = 1; // 接收使能

  //  器件已经准备好由发送方发来的16字节数据
  //  自动应答'3443101001', 重发次数为10, 射频通道为 40,数据速率 = 2Mbps.

}
/**************************************************/

/**************************************************
函数: TX_Mode();
说明:
  初始化 nRF24L01 为TX mode, 设置 TX 地址、接收地址、自动应答,
  向TX payload写入数据, 选择 RF 通道, 数据速率和 TX 发送功率.
  加电, CRC(2 字节) 使能, 发送为PRIM:TX.当CE置高(>10us)之后
即发送数据包,然后转入接收模式等待接收方的应答。
/**************************************************/
void TX_Mode(void)
{
        CE=0;
        // 写发送地址TX_Address 到nRF24L01
          SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);
// 自动应答的接收地址RX_Addr0 和 TX_Adr 相同
          SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);
          SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH); // 写数据到 TX payload

          SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);      // 使能自动应答到Pipe0
          SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);  // 使能Pipe0
          SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x1a); // 500us + 86us, 10次重发
          SPI_RW_Reg(WRITE_REG + RF_CH, 40);        // 选射频通道 40
// 发送功率:0dBm, 数据速率:2Mbps, LNA:HCURR
          SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);   
// 置位 PWR_UP, 使能CRC(2 bytes) 和主发送Prim:TX. 使能MAX_RT 和 TX_DS
          SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);     

        CE=1;

}

/**************************************************/

/**************************************************
函数: Send_uart();
说明:
  写数据到串口 SBUF
/**************************************************/
void Send_uart(uchar x)
{
        SBUF=x;// write data x to SBUF
        while(TI==0);
        TI=0;
}

/**************************************************/

/**************************************************
函数: display();
说明:
  在 LED数码管上显示数据
/**************************************************/
void display(uchar idata *p)
{
  uchar code table[23]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,
0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0x8c,0xc1,0x89,0xc7,0x91,0xbf,0xff};
//共阳码表,前16位是0~F,后面的如下:
//0x8c,0xc1,0x89,0xc7,0x91,0xbf,0xff
//P,   U,   H,   L,   Y,   -,   不显示
//10H, 11H, 12H, 13H, 14H, 15H, 16H
  uchar adc,i;
  for(i=0;i<4;i++)
  { adc=table[*p];//segement code
        if(i==1)
        {
                adc=adc-0x80;//加小数点
        }
    Send_uart(adc);
    p++;
  }
}

/**************************************************/

/**************************************************
函数: CheckButtons();
说明:
  检查按钮 ,若按钮按下读ds18b20温度值并发送,绿灯闪亮。
  发送后清TX_DS中断标志并转入接收模式 RX Mode;
/**************************************************/
void CheckButtons()
{

        if(S2==0)
                {
                        delay_ms(10);
                        if(S2==0)
                        {
                               
                                Do_Temp();//读温度数据
                                tx_buf[0]=dis_buf[0];        // 存温度数据到显示缓存
                                tx_buf[1]=dis_buf[1];
                                tx_buf[2]=dis_buf[2];       
                                tx_buf[3]=dis_buf[3];
                                TX_Mode();                        // 发送模式
                                display(dis_buf);         //在LED显示温度数据
                                // 清中断标志(TX_DS)
                                SPI_RW_Reg(WRITE_REG+STATUS,SPI_Read(READ_REG+STATUS));
                                RX_Mode();                        // 转入接收模式
                               
                                LEDG=0;        //绿LED:亮
                                delay_ms(200);
                                LEDG=1;        //绿LED:灭       
                               
                                                               
                                       
                        }
                }
       
}
/**************************************************/

/**************************************************
函数: main();
说明:
  主函数;
/**************************************************/
void main(void)
{
       
        init_nRF24L01();// 初始化nRF24L01
        init_int0();        // int0 中断使能
        RX_Mode();                // 接收模式
        while(1)
        {
                CheckButtons(); // 等待发送按键并发送
                if(flag)                // 是否收到
                {
                        flag=0;                //收到标志清零
                        LEDR=0;                //红LED:亮
                        delay_ms(200);
                        LEDR=1;                //红LED:灭
                       
                        dis_buf[0]=rx_buf[0];//小数位
                        dis_buf[1]=rx_buf[1];//个位
                        dis_buf[2]=rx_buf[2];//十位
                        dis_buf[3]=rx_buf[3];//百位或负号
                        display(dis_buf);//在LED显示收到的温度值
                       
                }
        }
}
/**************************************************/

/**************************************************
函数: ISR_int0() interrupt 0;
说明:中断服务函数
  若 RX_DR=1,由RX_FIFO 读数据包并置位flag;
/**************************************************/
void ISR_int0(void) interrupt 0
{
        sta=SPI_Read(STATUS);        // 读状态 STATUS'值
        if(RX_DR)                                // 如果有接收数据中断(RX_DR)
        {        // 由 RX_FIFO 缓存读数据
                SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);
                flag=1;
        }
        if(MAX_RT) // 如果重发次数超过(MAX_RT)
        {
                SPI_RW_Reg(FLUSH_TX,0); //FLUSH_TX清零
        }
// 清零RX_DR 或 TX_DS 或 MAX_RT 中断标志
                SPI_RW_Reg(WRITE_REG+STATUS,sta);
}

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的积分奖励!

查看全部评分

回复

使用道具 举报

ID:1 发表于 2015-5-25 21:58 | 显示全部楼层
要是有电路图就完美了
回复

使用道具 举报

ID:75172 发表于 2015-5-25 22:14 | 显示全部楼层
好东西,只是程序太多太复杂,很难看清啊。
回复

使用道具 举报

ID:67844 发表于 2015-5-25 22:46 | 显示全部楼层
正在学习这个 无线  多谢
回复

使用道具 举报

ID:44267 发表于 2015-10-18 15:31 | 显示全部楼层
NRF2401有好几种,我买的不一样
回复

使用道具 举报

ID:92665 发表于 2015-10-25 11:40 | 显示全部楼层
有发射程序么???
回复

使用道具 举报

ID:92810 发表于 2015-11-3 19:52 | 显示全部楼层
是啊、太复杂了。。。
回复

使用道具 举报

ID:92810 发表于 2015-11-3 19:52 | 显示全部楼层
能否给出电路图出来啊???
回复

使用道具 举报

ID:92810 发表于 2015-11-3 19:52 | 显示全部楼层
为什么不做温湿度的呢??
回复

使用道具 举报

ID:92810 发表于 2015-11-3 19:53 | 显示全部楼层
有没有无线温湿度的啊??急需程序啊??能否给出程序给我啊??我的邮箱是294799014@QQ.COM
回复

使用道具 举报

ID:96006 发表于 2015-11-19 14:11 | 显示全部楼层

顶一个,能发个图片就好了
回复

使用道具 举报

ID:116999 发表于 2016-4-27 10:41 | 显示全部楼层
看看 咋样 能用吗
回复

使用道具 举报

ID:144022 发表于 2016-10-23 11:04 | 显示全部楼层
我也正在学习无线模块,很棒的资料
回复

使用道具 举报

ID:197273 发表于 2017-5-6 13:27 | 显示全部楼层
有电路图吗??
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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