基于STC12单片机实现nRF24L01遥控器发射机和接收机开源程序分享
- ✨这是一个来源于开源的基于nRF24L01控制的项目,资料齐全,仅供个人学习研究使用,其其可靠性自行验证。
-
📌该项目基于
STC12C5A60S2
单片机。 -
📑发射端原理图部分
-
📜接收端原理图
🌼发射端程序说明
- 🌿
Keil
编译设置
由于程序代码过长贴出来了。
- 编译信息
🌻接收端
//#include<reg51.h>
#include <STC89C5xRC.H>
#define u8 unsigned char
#define u16 unsigned int
sfr IAP_DATA=0xe2;
sfr IAP_ADDRH=0xe3;
sfr IAP_ADDRL=0xe4;
sfr IAP_CMD=0xe5;
sfr IAP_TRIG=0xe6;
sfr IAP_CONTR=0xe7;
//sfr AUXR=0x8e;
sfr BRT=0x9c;
sbit LED=P2^2;
//sbit LED=P2^3;
sbit CH1=P2^1;
sbit CH2=P2^0;
sbit CH3=P1^7;
sbit CH4=P1^6;
sbit CH5=P1^5;
sbit CH6=P1^4;
sbit CH7=P1^3;
sbit CH8=P1^1;
sbit CHB=P1^0;
sbit CHC=P3^7;
sbit CHD=P2^7;
sbit CHE=P2^6;
sbit MDO=P3^5;
sbit SCK=P2^4;
sbit CE=P2^5;
sbit IRQ=P3^4;
sbit MDI=P3^3;
sbit CSN=P3^2;
sfr P1M1=0x92;
sfr P3M1=0xb2;
sfr P2M1=0x96;
u8 code random[100]={4,1,3,2,2,1,0,0,2,2,2,3,4,1,2,1,4,3,3,4,//随机跳频序列
2,0,2,2,3,1,2,3,2,2,2,4,2,4,0,3,4,2,3,1,
0,3,1,3,3,0,2,0,4,3,3,3,3,3,4,1,1,4,3,0,
1,0,3,2,3,2,3,3,4,4,1,3,0,0,3,1,3,3,3,0,
3,3,4,1,2,4,1,3,0,1,3,4,4,3,2,3,1,2,3,3};
u16 timer1,timer2,timer3;
u8 rx_num,receive;
u8 rx[11]; //接收的11字节数据
u8 tx[11];
u8 m;
u8 hopping_turn,hopping_num,hopping_count;
//u8 missing_data[4];
u8 address[5]={0xe7,0xe7,0xe7,0xe7,0xe7};
u8 code address_0[5]={'L','O','V','E','!'};//使用LOVE作为对频暗语
u8 hopping[5]={10,35,60,85,110};
bit first,restar;
bit connecting,lose;
bit jump_1,jump_2,jump_mode;
u8 NRF_error;
u16 CH_data[8]={0,1024,0,1024,0,1024};
u16 data buff[8];
u16 temp1,temp2;
u8 t_output;
u8 TX_power=3;
bit LED_flash;
bit out_control_change;
u16 idata out_control_data[8];
void Delay1ms() //@12.000MHz
{
unsigned char i, j;
i = 12;
j = 168;
do
{
while (--j);
} while (--i);
}
void delay_ms(u8 i)
{
while(i--)
Delay1ms();
}
u8 EEPROM_read(u8 address)
{
IAP_CMD=0x01;
IAP_ADDRH=0;
IAP_ADDRL=address;
IAP_TRIG=0x46;
IAP_TRIG=0xb9;
return IAP_DATA;
}
void EEPROM_write(u8 address,u8 byte)
{
IAP_CMD=0x02;
IAP_DATA=byte;
IAP_ADDRH=0;
IAP_ADDRL=address;
IAP_TRIG=0x46;
IAP_TRIG=0xb9;
}
void EEPROM_clean(u8 address)
{
IAP_CMD=0x03;
IAP_ADDRH=0;
IAP_ADDRL=address;
IAP_TRIG=0x46;
IAP_TRIG=0xb9;
}
void DATA_read()
{
IAP_CONTR=0x82;
if((EEPROM_read(0)!=0xe4)||(EEPROM_read(1)!=0xa5))
{
first=1;
}
else
{
hopping[0]=EEPROM_read(2);
hopping[1]=EEPROM_read(3);
hopping[2]=EEPROM_read(4);
hopping[3]=EEPROM_read(5);
hopping[4]=EEPROM_read(6);
address[0]=EEPROM_read(7);
address[1]=EEPROM_read(8);
address[2]=EEPROM_read(9);
address[3]=EEPROM_read(10);
address[4]=EEPROM_read(11);
}
if((EEPROM_read(12)!=0xe4)||(EEPROM_read(13)!=0xa5))
{
out_control_data[0]=512;
out_control_data[1]=512;
out_control_data[2]=80;
out_control_data[3]=512;
out_control_data[4]=512;
out_control_data[5]=512;
out_control_data[6]=512;
out_control_data[7]=512;
}
else
{
out_control_data[0]=EEPROM_read(14);
out_control_data[0]<<=8;
out_control_data[0]+=EEPROM_read(15);
out_control_data[1]=EEPROM_read(16);
out_control_data[1]<<=8;
out_control_data[1]+=EEPROM_read(17);
out_control_data[2]=EEPROM_read(18);
out_control_data[2]<<=8;
out_control_data[2]+=EEPROM_read(19);
out_control_data[3]=EEPROM_read(20);
out_control_data[3]<<=8;
out_control_data[3]+=EEPROM_read(21);
out_control_data[4]=EEPROM_read(22);
out_control_data[4]<<=8;
out_control_data[4]+=EEPROM_read(23);
out_control_data[5]=EEPROM_read(24);
out_control_data[5]<<=8;
out_control_data[5]+=EEPROM_read(25);
out_control_data[6]=EEPROM_read(26);
out_control_data[6]<<=8;
out_control_data[6]+=EEPROM_read(27);
out_control_data[7]=EEPROM_read(28);
out_control_data[7]<<=8;
out_control_data[7]+=EEPROM_read(29);
}
IAP_CONTR=0;
}
void DATA_save()
{
IAP_CONTR=0x82;
EEPROM_clean(0);
EEPROM_write(0,0xe4);
EEPROM_write(1,0xa5);
EEPROM_write(2,hopping[0]);
EEPROM_write(3,hopping[1]);
EEPROM_write(4,hopping[2]);
EEPROM_write(5,hopping[3]);
EEPROM_write(6,hopping[4]);
EEPROM_write(7,address[0]);
EEPROM_write(8,address[1]);
EEPROM_write(9,address[2]);
EEPROM_write(10,address[3]);
EEPROM_write(11,address[4]);
if(out_control_change)
{
EEPROM_write(12,0xe4);
EEPROM_write(13,0xa5);
EEPROM_write(14,out_control_data[0]>>8);
EEPROM_write(15,out_control_data[0]);
EEPROM_write(16,out_control_data[1]>>8);
EEPROM_write(17,out_control_data[1]);
EEPROM_write(18,out_control_data[2]>>8);
EEPROM_write(19,out_control_data[2]);
EEPROM_write(20,out_control_data[3]>>8);
EEPROM_write(21,out_control_data[3]);
EEPROM_write(22,out_control_data[4]>>8);
EEPROM_write(23,out_control_data[4]);
EEPROM_write(24,out_control_data[5]>>8);
EEPROM_write(25,out_control_data[5]);
EEPROM_write(26,out_control_data[6]>>8);
EEPROM_write(27,out_control_data[6]);
EEPROM_write(28,out_control_data[7]>>8);
EEPROM_write(29,out_control_data[7]);
}
IAP_CONTR=0;
}
/**************************************************************************/
//NRF24L01
u8 SPI(u8 byte)
{
u8 i;
for(i=0;i<8;i++)
{
MDI=(byte&0x80);
SCK=1;
byte<<=1;
byte|=MDO;
SCK=0;
}
return byte;
}
void REG_write(u8 address,u8 command)
{
CSN=0;
SPI(0x20+address);
SPI(command);
CSN=1;
}
void FIFO_write(u8 DATA_OUT[],u8 lengh)
{
u8 i;
CSN=0;
SPI(0xa0);
for(i=0;i<lengh;i++)
SPI(DATA_OUT[i]);
CSN=1;
}
void FIFO_read(u8 DATA_IN[],u8 lengh) //读取接收数据缓冲区
{
u8 i;
CSN=0;
SPI(0x61); //读取命令
for(i=0;i<lengh;i++)
DATA_IN[i]=SPI(0);
CSN=1;
}
void TX_address(u8 DATA_IN[])
{
CSN=0;
SPI(0x20+0x10);
SPI(DATA_IN[0]);
SPI(DATA_IN[1]);
SPI(DATA_IN[2]);
SPI(DATA_IN[3]);
SPI(DATA_IN[4]);
CSN=1;
}
void RX_address(u8 DATA_IN[])
{
CSN=0;
SPI(0x20+0x0a);
SPI(DATA_IN[0]);
SPI(DATA_IN[1]);
SPI(DATA_IN[2]);
SPI(DATA_IN[3]);
SPI(DATA_IN[4]);
CSN=1;
}
void RX_mode()
{
CE=0;
REG_write(0x00,0x3b); //CRC,8 bit,Power on,RX
CE=1;
}
void TX_mode()
{
CE=0;
REG_write(0x00,0x0a);
CE=1;
}
void NRF_power(u8 P) //发射功率设置 250k
{
CE=0;
if(P==3)REG_write(0x06,0x27); //0db 修正之前注释错误
else if(P==2)REG_write(0x06,0x25); //-6db
else if(P==1)REG_write(0x06,0x23); //-12db
else if(P==0)REG_write(0x06,0x21); //-18db
CE=1;
}
void NRF_size(u8 l)
{
CE=0;
REG_write(0x11,l);
CE=1;
}
void NRF_channel(u8 c)
{
CE=0;
REG_write(0x05,c);
CE=1;
}
void NRF_init()
{
CE=0;
SCK=0;
REG_write(0x01,0x00); //禁止 自动应答
REG_write(0x02,0x01); //允许 P0信道
REG_write(0x04,0x00); //禁止 自动重发
RX_mode();
NRF_channel(66);
NRF_power(TX_power);
NRF_size(11);
RX_address(address);
TX_address(address);
}
void NRF_test() //无线模块终极测试
{
u8 reset_err=0;
CE=0;
SCK=0;
CSN=0;
if(SPI(0x20)!=0x0e){reset_err=1;}
SPI(0x0a);
CSN=1;
CSN=0;
SPI(0x00);
if(SPI(0x00)!=0x0a){NRF_error|=0x02;}//MOSI bad
CSN=1;
REG_write(0x01,0x00);
REG_write(0x04,0x00);
REG_write(0x11,1);
FIFO_write(tx,1);
CE=1;
delay_ms(2);
CSN=0;
if(SPI(0x00)!=0x2e){NRF_error|=0x04;}//CE bad
CSN=1;
if(IRQ)NRF_error|=0x18; //IRQ bad
else
{
if(NRF_error&0x04==0)NRF_error|=0x10; //MISO bad
}
CE=1;
if(reset_err&&NRF_error>1)NRF_error|=0x01;//CSN,CLK bad
REG_write(0x07,0x20); //清除TX中断信号
}
void data_check(int x,int max,int min)
{
if(x>max)x=max;
if(x<min)x=min;
}
void initial()
{
u8 t;
CH5=0; //如果CH5与CH6被短接,重新对码
Delay1ms();
if(CH6==0) //新增修正通道6插上舵机不能用的BUG
{
P1M1=0x08; //插上舵机也会使CH6为0,所以将CH5设为推挽
CH5=1;
Delay1ms();
if(CH6)restar=1; //如果CH6被拉高,说明5/6通道短接,启动重新对码
}
LED=0; //点亮指示灯再关闭,表示单片机正常工作
delay_ms(100);
P1M1=0xfb;
P2M1=0xc7;
P3M1=0x80; //将6通道输出IO口配置为大电流推挽模式,保证正常驱动电调与舵机
TMOD=0x11; //允许两个定时器中断
IE=0x8a;
IP=0x08;
if(restar)first=1;
DATA_read();
data_check(out_control_data[0],1023,0);
data_check(out_control_data[1],1023,0);
data_check(out_control_data[2],1023,0);
data_check(out_control_data[3],1023,0);
data_check(out_control_data[4],1023,0);
data_check(out_control_data[5],1023,0);
data_check(out_control_data[6],1023,0);
data_check(out_control_data[7],1023,0);
NRF_test();
if(NRF_error)
{
t=10;
while(t)
{
LED=0; //模块错误闪灯
delay_ms(50);
LED=1; //模块错误闪灯
delay_ms(50);
t--;
}
}
NRF_init();
if(first)
{
NRF_power(0);
NRF_channel(33);
TX_address(address_0);
RX_address(address_0);
while(IRQ);
FIFO_read(rx,11); //读取接收数据
CE=0;
REG_write(0x07,0x40); //清除无线模块中断信号
CE=1;
if(rx[0]==0xa0)
{
hopping[0]=rx[1];
hopping[1]=rx[2];
hopping[2]=rx[3];
hopping[3]=rx[4];
hopping[4]=rx[5];
address[0]=rx[6];
address[1]=rx[7];
address[2]=rx[8];
address[3]=rx[9];
address[4]=rx[10];
}
tx[0]='O',tx[1]='K';
connecting=1;
while(connecting)
{
TX_mode();
NRF_channel(33);
TX_address(address_0);
RX_address(address_0);
FIFO_write(tx,11);
Delay1ms();
RX_mode();
NRF_channel(hopping[0]);
TX_address(address);
RX_address(address);
while(1)
{
Delay1ms();
if(IRQ==0)
{
FIFO_read(rx,11); //读取接收数据
CE=0;
REG_write(0x07,0x40); //清除无线模块中断信号
CE=1;
connecting=0;break;
}
t++;if(t>100){t=0;break;}
}
}
DATA_save();
RX_address(address);
TX_address(address);
NRF_power(3);
}
}
main()
{
delay_ms(200);delay_ms(200);//开机延时以避过电源波动
initial();
PCON |= 0x80; //使能波特率倍速位SMOD
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x04; //独立波特率发生器时钟为Fosc,即1T
BRT = 0xF3; //设定独立波特率发生器重装值
AUXR |= 0x01; //串口1选择独立波特率发生器为波特率发生器
AUXR |= 0x10;
TR0=1; //打开定时器
NRF_channel(hopping[0]);
while(IRQ);
TR1=1;
lose=1;
LED=1;
while(1)
{
while(IRQ&lose);
if(lose)
{
jump_1=0;jump_2=0;hopping_count=0;//收到有效信号后刷新跳频器
receive++;timer1=0;timer3=0;m=0;
FIFO_read(rx,11); //读取接收数据
CE=0;
REG_write(0x07,0x40); //清除无线模块中断信号
CE=1;
TX_mode();
tx[0]=rx_num;
tx[1]=0;
tx[2]=0;
tx[3]=0;
tx[4]=0;
FIFO_write(tx,11);
Delay1ms();
RX_mode();
if(jump_mode)
{
jump_mode=0;
hopping_turn=random[hopping_num];
}
hopping_turn++;
if(hopping_turn>4)hopping_turn=0;
NRF_channel(hopping[hopping_turn]);
if(rx[0]==0xa0)
{
LED_flash=1,LED=0;
buff[0]=rx[1];
buff[0]<<=2;
buff[0]+=rx[2]>>6;
buff[1]=rx[2]&0x3f;
buff[1]<<=4;
buff[1]+=rx[3]>>4;
buff[2]=rx[3]&0x0f;
buff[2]<<=6;
buff[2]+=rx[4]>>2;
buff[3]=rx[4]&0x03;
buff[3]<<=8;
buff[3]+=rx[5];
buff[4]=rx[6];
buff[4]<<=2;
buff[4]+=rx[7]>>6;
buff[5]=rx[7]&0x3f;
buff[5]<<=4;
buff[5]+=rx[8]>>4;
buff[6]=rx[8]&0x0f;
buff[6]<<=6;
buff[6]+=rx[9]>>2;
buff[7]=rx[9]&0x03;
buff[7]<<=8;
buff[7]+=rx[10];
data_check(buff[0],1023,0);
data_check(buff[1],1023,0);
data_check(buff[2],1023,0);
data_check(buff[3],1023,0);
data_check(buff[4],1023,0);
data_check(buff[5],1023,0);
data_check(buff[6],1023,0);
data_check(buff[7],1023,0);
out_control_data[0]=buff[0];
out_control_data[1]=buff[1];
out_control_data[2]=buff[2];
out_control_data[3]=buff[3];
out_control_data[4]=buff[4];
out_control_data[5]=buff[5];
out_control_data[6]=buff[6];
out_control_data[7]=buff[7];
out_control_change=1;
DATA_save();
out_control_change=0;
}
else if(rx[0]==0xa1)
{
buff[0]=rx[1];
buff[0]<<=2;
buff[0]+=rx[2]>>6;
buff[1]=rx[2]&0x3f;
buff[1]<<=4;
buff[1]+=rx[3]>>4;
buff[2]=rx[3]&0x0f;
buff[2]<<=6;
buff[2]+=rx[4]>>2;
buff[3]=rx[4]&0x03;
buff[3]<<=8;
buff[3]+=rx[5];
buff[4]=rx[6];
buff[4]<<=2;
buff[4]+=rx[7]>>6;
buff[5]=rx[7]&0x3f;
buff[5]<<=4;
buff[5]+=rx[8]>>4;
buff[6]=rx[8]&0x0f;
buff[6]<<=6;
buff[6]+=rx[9]>>2;
buff[7]=rx[9]&0x03;
buff[7]<<=8;
buff[7]+=rx[10];
data_check(buff[0],1023,0);
data_check(buff[1],1023,0);
data_check(buff[2],1023,0);
data_check(buff[3],1023,0);
data_check(buff[4],1023,0);
data_check(buff[5],1023,0);
data_check(buff[6],1023,0);
data_check(buff[7],1023,0);
CH_data[0]=buff[0];
CH_data[1]=buff[1];
CH_data[2]=buff[2];
CH_data[3]=buff[3];
CH_data[4]=buff[4];
CH_data[5]=buff[5];
CH_data[6]=buff[6];
CH_data[7]=buff[7];
}
}
else
{
hopping_count++;
if(hopping_count>5)jump_mode=1;
if(jump_mode)
{
hopping_num++;
if(hopping_num>99)hopping_num=0;
NRF_channel(hopping[random[hopping_num]]);
lose=1;
}
else
{
hopping_turn++;
if(hopping_turn>4)hopping_turn=0;
NRF_channel(hopping[hopping_turn]);
lose=1;
}
}
}
}
void et0()interrupt 1 //跳频定时器 3ms
{
TL0=0x47;TH0=0xf4;
timer1++;
if(timer1>333) //每秒统计有效信号,小于20个点亮LED示警,表示信号微弱
{
timer1=333;
rx_num=0;LED=0;
}
else LED=1;
timer2++;
if(timer2>333)
{
timer2=0;
rx_num=receive;
receive=0;
}
timer3++;
if(timer3>666)
{
timer3=666;
CH_data[0]=out_control_data[0];
CH_data[1]=out_control_data[1];
CH_data[2]=out_control_data[2];
CH_data[3]=out_control_data[3];
CH_data[4]=out_control_data[4];
CH_data[5]=out_control_data[5];
CH_data[6]=out_control_data[6];
CH_data[7]=out_control_data[7];
}
if(LED_flash)
{
}
m++; //两个标志位循环跳频
if(jump_1==0)
{
if(m>7)lose=0,jump_1=1,jump_2=0; //未收到信号,开始第一跳
}
else
{
if(jump_2==0)
{
if(m>14)lose=0,jump_2=1; //第一跳之后仍无信号,开始第二跳
}
else
{
if(m>22)m=0,lose=0,jump_1=0; //第二跳之后仍无信号,复位重新跳。
}
}
}
void et1()interrupt 3 //定时器1用作信号输出
{
TR1=0;CHE=!CHE;
t_output++;
switch(t_output)
{
case 1:CH1=1;temp1=64750-CH_data[0]*27/20;
TL1=temp1,TH1=temp1>>8;break;
case 2:CH1=0;temp2=128600-temp1;
TL1=temp2,TH1=temp2>>8;break;
case 3:CH2=1;temp1=64750-CH_data[1]*27/20;
TL1=temp1,TH1=temp1>>8;break;
case 4:CH2=0;temp2=128600-temp1;
TL1=temp2,TH1=temp2>>8;break;
case 5:CH3=1;temp1=64750-CH_data[2]*27/20;
TL1=temp1,TH1=temp1>>8;break;
case 6:CH3=0;temp2=128600-temp1;
TL1=temp2,TH1=temp2>>8;break;
case 7:CH4=1;temp1=64750-CH_data[3]*27/20;
TL1=temp1,TH1=temp1>>8;break;
case 8:CH4=0;temp2=128600-temp1;
TL1=temp2,TH1=temp2>>8;break;
case 9:CH5=1;temp1=64750-CH_data[4]*27/20;
TL1=temp1,TH1=temp1>>8;break;
case 10:CH5=0;temp2=128600-temp1;
TL1=temp2,TH1=temp2>>8;break;
case 11:CH6=1;temp1=64750-CH_data[5]*27/20;
TL1=temp1,TH1=temp1>>8;break;
case 12:CH6=0;temp2=128600-temp1;
TL1=temp2,TH1=temp2>>8;break;
case 13:CH7=1;temp1=64750-CH_data[6]*27/20;
TL1=temp1,TH1=temp1>>8;break;
case 14:CH7=0;temp2=128600-temp1;
TL1=temp2,TH1=temp2>>8;break;
case 15:CH8=1;temp1=64750-CH_data[7]*27/20;
TL1=temp1,TH1=temp1>>8;break;
case 16:CH8=0;temp2=128600-temp1;
TL1=temp2,TH1=temp2>>8;t_output=0;break;
}
TR1=1;CHE=!CHE;
}
项目资源
链接:https://pan.baidu.com/s/10pIrI1faPqnzoxdwXafR7g
提取码:fgcj