#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);
}
|