2012.6月18日—2012.6月30日終于完成了無線遙控小車的程序和整理。再次特別感謝我的鐵哥們-張文為這個程序的后續完善所打下的堅實基礎和程序設計的指導和領路人-柳飛大哥的友情幫助以及好友-彭飛兄的C的語法幫助!正是有你們,我的小車才能完工,程序才能穩定運行!拍些照片留作紀念~
*************************************************************************發射部分****************************************************************************
#include <reg52.h>
#include <Intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit MISO=P1^4; //主收從發
sbit MOSI=P1^3; //主發從收
sbit SCK=P1^2; //串行時鐘信號
sbit CE=P1^1; //芯片使能
sbit CSN=P1^5; //片選信號
sbit IRQ=P1^6; //中斷查詢
/*************************************************************/
uchar seg[10]={~0x3f,~0x06,~0x5b,~0x4f,~0x66};
bit TxBufEndFlg = 1; //數據發送完成標志
uchar checkack();
uchar TxBuf[20]={0};
uchar RxBuf[20]={0};
uchar SPI_RW(uchar uchars);
uchar SPI_Read(uchar reg);
uchar SPI_RW_Reg(uchar reg, uchar value);
uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars);
uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars);
uchar KeyScanPrg();
uchar KeyInState,KeyStateCnt;
/************************************************************/
#define TX_ADR_WIDTH 5 //發送地址長度為5個字節
#define RX_ADR_WIDTH 5 //接收地址長度為5個字節
#define TX_PLOAD_WIDTH 20 //發送數據長度為20個字節
#define RX_PLOAD_WIDTH 20 //接收數據長度為20個字節
uchar code TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址
uchar code RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //接收地址
//SPI命令
#define READ_REG 0x00 //讀第0個寄存器
#define WRITE_REG 0x20 //寫第0個寄存器
#define RD_RX_PLOAD 0x61 //在接收模式下使用,讀有效數據
#define WR_TX_PLOAD 0xA0 //在發送模式下使用,寫有效數據
#define FLUSH_TX 0xE1 //在發送模式下使用,清TX FIFO寄存器
#define FLUSH_RX 0xE2 //在接收模式下使用,清RX FIFO寄存器
#define REUSE_TX_PL 0xE3 //發送方使用,重復發送最后的數據
#define NOP 0xFF //空操作,用于讀狀態寄存器STATUS的值
//NRF24L01寄存器地址
#define CONFIG 0x00 //配置寄存器,8bit
#define EN_AA 0x01 //自動應答設置寄存器,8bit
#define EN_RXADDR 0x02 //接收地址設置寄存器,8bit
#define SETUP_AW 0x03 //地址寬度設置寄存器,8bit
#define SETUP_RETR 0x04 //自動重復發送設置寄存器,8bit
#define RF_CH 0x05 // RF通道寄存器,8bit(工作頻率設置)
#define RF_SETUP 0x06 //RF設置寄存器,8bit(發射速率、功耗功能設置)
#define STATUS 0x07 //狀態寄存器,8bit
#define OBSERVE_TX 0x08 //發送檢測寄存器,8bit
#define CD 0x09 //載波檢測寄存器,8bit
#define RX_ADDR_P0 0x0A //接收地址數據通道0,40bit
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10 //發送地址,發送方使用,40bit
#define RX_PW_P0 0x11 //通道0接收的有效數據字節長度(1-32字節),8bit
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define FIFO_STATUS 0x17 //FIFO棧入棧出狀態寄存器,8bit
//*********************************************************************************
void Delay(uint s);
void delayms(uchar z);
void inerDelay_us(uchar n);
void init_NRF24L01();
void nRF24L01_TxPacket(uchar * tx_buf);
void KeyDealPrg(uchar KeyState);
//**********************************************************************************
void inerDelay_us(uchar n)
{
for(;n>0;n--)
_nop_();
}
//************************************************************************************
uchar bdata sta; //狀態標志
sbit RX_DR =sta^6;
sbit TX_DS =sta^5;
sbit MAX_RT =sta^4;
//***************************checkack函數********************************************
uchar checkack()
{
sta=SPI_Read(STATUS); // 返回狀態寄存器
if(TX_DS || MAX_RT) // 發送完畢中斷
{
if(MAX_RT)
init_NRF24L01();
TxBufEndFlg = 1;
SPI_RW_Reg(WRITE_REG+STATUS,0xff); // 清除TX_DS或MAX_RT中斷標志
CSN=0;
SPI_RW(FLUSH_TX); //在接收模式下,清空RX FIFO寄存器。在傳輸應答信號時不應執行此操作,否則不能傳輸完整的應答信號
CSN=1;
return(1);
}
else
return(0);
}
//***************************NRF24L01初始化********************************************
void init_NRF24L01(void)
{
inerDelay_us(100);
CE=0; //芯片啟動
CSN=1; //終止SPI讀寫
SCK=0; //低電平為空閑時刻
SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); //寫本地地址
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); //寫接收端地址
SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x4a); //自動延時1250us,自動重發10次
SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); //ENAA_P0=1,數據通道0自動應答
SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // EN_RXADDR=1,接收地址允許
SPI_RW_Reg(WRITE_REG + RF_CH, 0); //設置信道工作為2.4GHZ,收發必須一致
SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //設置接收數據長度,本次設置為20字節
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //設置發射速率為1MHZ,發射功率為0dBm,低噪聲放大器增益
}
//***************************************SPI操作***********************************************
uchar SPI_RW(uchar uchars)//寫一個字節到NRF24L01,并返回此時NRF24L01的狀態及數據
{
uchar bit_ctr;
for(bit_ctr=0;bit_ctr<8;bit_ctr++) //先寫字節的高位,再寫低位
{
MOSI = (uchars & 0x80); //MOSI取uhcars最高位
uchars = (uchars << 1); //uchars左移一位
SCK = 1; //SCK從高到低時開始寫入
uchars |= MISO; // 獲取MISO位,從MOSI寫命令的同時,MISO返回NRF24L01的狀態及數據
SCK = 0;
}
return(uchars);
}
uchar SPI_Read(uchar reg)//讀寄存器reg狀態字
{
uchar reg_val;
CSN = 0; //CSN為0時,才能進行SPI讀寫
SPI_RW(reg); //選擇寄存器reg
reg_val = SPI_RW(0); //寫0,什么操作也不進行,僅僅為了讀寄存器狀態
CSN = 1; //終止SPI讀寫
return(reg_val);
}
uchar SPI_RW_Reg(uchar reg, uchar value)//將字節value寫入寄存器reg
{
uchar status;
CSN = 0; //CSN為0時,才能進行SPI讀寫
status = SPI_RW(reg); //選擇寄存器reg
SPI_RW(value); //寫字節value到該寄存器.
CSN = 1; //終止SPI讀寫
return(status);
}
uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)//從寄存器reg讀出數據,典型應用是讀RX數據或RX/TXF地址
{
uchar status,uchar_ctr;
CSN = 0; //CSN為0時,才能進行SPI讀寫
status = SPI_RW(reg); //選擇寄存器reg并返回其狀態字
for(uchar_ctr=0;uchar_ctr<uchars;uchar_ctr++)
pBuf[uchar_ctr] = SPI_RW(0); //從寄存器讀數據
CSN = 1; //終止SPI讀寫
return(status); //返回狀態值
}
uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)//將數據寫入寄存器,如TX數據,RX/TX地址等
{
uchar status,uchar_ctr;
CSN = 0; // CSN為0時,才能進行SPI讀寫
status = SPI_RW(reg); //選擇寄存器reg并返回其狀態字
for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++)
SPI_RW(*pBuf++); //寫數據到寄存器
CSN = 1; //終止SPI讀寫
return(status); //返回狀態值
}
/***********************************************************************************************************
/*函數:void nRF24L01_TxPacket(unsigned char * tx_buf)
/*功能:發送 tx_buf中數據
/**********************************************************************************************************/
void nRF24L01_TxPacket(unsigned char * tx_buf)
{
if(TxBufEndFlg)
{
CE=0; //待機模式I
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); //裝載接收端地址
SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH); //裝載數據
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); //CRC使能,CRC校驗值為2字節,上電,設置為發射模式
CE=1; //置高CE,激發數據發送
TxBufEndFlg = 0; //標志位清0
inerDelay_us(1000);
}
}
/*****************************************************************************/
/*函數:
/*功能:按鍵采集掃描
/*****************************************************************************/
uchar KeyScanPrg(void)
{
uchar KeyStateRAM,KeyState=0;
KeyStateRAM = P2;
KeyStateRAM &= 0xf0; //用到的其實是P2.7 2.6 2.5 2.4這四個按鍵
if(KeyStateRAM==KeyInState)
{
if(KeyStateCnt>20)
{
KeyState = KeyInState;
}
else
KeyStateCnt++;
}
else
{
KeyInState = KeyStateRAM;
KeyStateCnt = 0;
}
return(KeyState);
}
/*****************************************************************************/
/*函數:
/*功能:按鍵處理
/*****************************************************************************/
void KeyDealPrg(uchar KeyState)
{
switch(KeyState&0xf0)
{
case 0x70:P3=seg[1];TxBuf[1]=1;TxBuf[5]=0;
break;
case 0xb0:P3=seg[2];TxBuf[2]=1;TxBuf[5]=0;
break;
case 0xd0:P3=seg[3];TxBuf[3]=1;TxBuf[5]=0;
break;
case 0xe0:P3=seg[4];TxBuf[4]=1;TxBuf[5]=0;
break;
default :P3=seg[0];
TxBuf[1]=0;
TxBuf[2]=0;
TxBuf[3]=0;
TxBuf[4]=0;
TxBuf[5]=1;
}
nRF24L01_TxPacket(TxBuf);
checkack();
}
/*****************************************************************************/
/*函數:
/*功能:主函數
/*****************************************************************************/
void main(void)
{
init_NRF24L01();
while(1)
{
KeyDealPrg(KeyScanPrg());
}
}
//**************************************************************************接收部分**********************************************************************
#include <reg52.h>
#include <intrins.h>
typedef unsigned char uchar; //等同于#define uchar unsigned char
typedef unsigned char uint;
sbit IRQ=P1^5; //中斷查詢
sbit MISO=P1^4; //主收從發
sbit MOSI=P1^3; //主發從收
sbit SCK=P1^2; //串行時鐘信號
sbit CSN=P1^1; //片選信號
sbit CE=P1^0; //芯片使能
sbit ENB=P0^5;
sbit ENA=P0^4;
sbit EN4=P0^3;
sbit EN3=P0^2;
sbit EN2=P0^1;
sbit EN1=P0^0;
//**************************************************************************************
uchar seg[10]={~0x3f,~0x06,~0x5b,~0x4f};
#define TX_ADR_WIDTH 5 //發送地址長度為5個字節
#define RX_ADR_WIDTH 5 //接收地址長度為5個字節
#define TX_PLOAD_WIDTH 20 //發送數據長度為20個字節
#define RX_PLOAD_WIDTH 20 //接收數據長度為20個字節
uchar code TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址
uchar code RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //接收地址
//SPI命令
#define READ_REG 0x00 //讀第0個寄存器
#define WRITE_REG 0x20 //寫第0個寄存器
#define RD_RX_PLOAD 0x61 //在接收模式下使用,讀有效數據
#define WR_TX_PLOAD 0xA0 //在發送模式下使用,寫有效數據
#define FLUSH_TX 0xE1 //在發送模式下使用,清TX FIFO寄存器
#define FLUSH_RX 0xE2 //在接收模式下使用,清RX FIFO寄存器
#define REUSE_TX_PL 0xE3 //發送方使用,重復發送最后的數據
#define NOP 0xFF //空操作,用于讀狀態寄存器STATUS的值
//NRF24L01寄存器地址
#define CONFIG 0x00 //配置寄存器,8bit
#define EN_AA 0x01 //自動應答設置寄存器,8bit
#define EN_RXADDR 0x02 //接收地址設置寄存器,8bit
#define SETUP_AW 0x03 //地址寬度設置寄存器,8bit
#define SETUP_RETR 0x04 //自動重復發送設置寄存器,8bit
#define RF_CH 0x05 // RF通道寄存器,8bit(工作頻率設置)
#define RF_SETUP 0x06 //RF設置寄存器,8bit(發射速率、功耗功能設置)
#define STATUS 0x07 //狀態寄存器,8bit
#define OBSERVE_TX 0x08 //發送檢測寄存器,8bit
#define CD 0x09 //載波檢測寄存器,8bit
#define RX_ADDR_P0 0x0A //接收地址數據通道0,40bit
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10 //發送地址,發送方使用,40bit
#define RX_PW_P0 0x11 //通道0接收的有效數據字節長度(1-32字節),8bit
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define FIFO_STATUS 0x17 //FIFO棧入棧出狀態寄存器,8bit
//**************************************************************************************
uchar SPI_RW(uchar uchars);
uchar SPI_Read(uchar reg);
uchar SPI_RW_Reg(uchar reg, uchar value);
uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars);
uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars);
uchar nRF24L01_RxPacket(uchar* rx_buf);
//*****************************************電機驅動*****************************************
void zhengzhuan()
{ENA=1;
ENB=1;
EN1=1;
EN2=0;
EN3=0;
EN4=1;
}
void fanzhuan()
{ENA=1;
ENB=1;
EN1=0;
EN2=1;
EN3=1;
EN4=0;
}
void tingzhi()
{ENA=1;
ENB=1;
EN1=0;
EN2=0;
EN3=0;
EN4=0;
}
void zuozhuan()
{ENA=1;
ENB=1;
EN1=1;
EN2=0;
EN3=1;
EN4=0;
}
void youzhuan()
{ENA=1;
ENB=1;
EN1=0;
EN2=1;
EN3=0;
EN4=1;
}
//***************************************************************************************
void inerDelay_us(uchar n)
{
for(;n>0;n--)
_nop_();
}
//******************************************************************************************
uint bdata sta; //狀態標志
sbit RX_DR =sta^6;
sbit TX_DS =sta^5;
sbit MAX_RT =sta^4;
//****************************************************************************************************
uchar SPI_RW(uchar uchars)//寫一個字節到NRF24L01,并返回此時NRF24L01的狀態及數據
{
uchar bit_ctr;
for(bit_ctr=0;bit_ctr<8;bit_ctr++) //先寫字節的高位,再寫低位
{
MOSI = (uchars & 0x80); //MOSI取uhcars最高位
uchars = (uchars << 1); //uchars左移一位
SCK = 1; //SCK從高到低時開始寫入
uchars |= MISO; // 獲取MISO位,從MOSI寫命令的同時,MISO返回NRF24L01的狀態及數據
SCK = 0;
}
return(uchars);
}
uchar SPI_Read(uchar reg)//讀寄存器reg狀態字
{
uchar reg_val;
CSN = 0; //CSN為0時,才能進行SPI讀寫
SPI_RW(reg); //選擇寄存器reg
reg_val = SPI_RW(0); //寫0,什么操作也不進行,僅僅為了讀寄存器狀態
CSN = 1; //終止SPI讀寫
return(reg_val);
}
uchar SPI_RW_Reg(uchar reg, uchar value)//將字節value寫入寄存器reg
{
uchar status;
CSN = 0; //CSN為0時,才能進行SPI讀寫
status = SPI_RW(reg); //選擇寄存器reg
SPI_RW(value); //寫字節value到該寄存器.
CSN = 1; //終止SPI讀寫
return(status);
}
uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar uchars)//從寄存器reg讀出數據,典型應用是讀RX數據或RX/TXF地址
{
uchar status,uchar_ctr;
CSN = 0; //CSN為0時,才能進行SPI讀寫
status = SPI_RW(reg); //選擇寄存器reg并返回其狀態字
for(uchar_ctr=0;uchar_ctr<uchars;uchar_ctr++)
pBuf[uchar_ctr] = SPI_RW(0); //從寄存器讀數據
CSN = 1; //終止SPI讀寫
return(status); //返回狀態值
}
uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)//將數據寫入寄存器,如TX數據,RX/TX地址等
{
uchar status,uchar_ctr;
CSN = 0; // CSN為0時,才能進行SPI讀寫
status = SPI_RW(reg); //選擇寄存器reg并返回其狀態字
for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++)
SPI_RW(*pBuf++); //寫數據到寄存器
CSN = 1; //終止SPI讀寫
return(status); //返回狀態值
}//功能: 用于寫數據:為寄存器地址,pBuf:為待寫入數據地址,uchars:寫入數據的個數
/****************************************************************************************************/
/*函數:void SetRX_Mode(void)
/*功能:數據接收配置
/****************************************************************************************************/
void SetRX_Mode()
{
CE=0;
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f); // IRQ收發完成中斷響應,CRC使能,CRC校驗值為2字節,上電,接收模式
CE = 1;
inerDelay_us(130);
}
/******************************************************************************************************/
/*函數:unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)
/*功能:數據讀取后放如rx_buf接收緩沖區中
/******************************************************************************************************/
uchar nRF24L01_RxPacket(uchar* rx_buf)
{
uchar revale=0;
sta=SPI_Read(STATUS); // 讀取狀態寄存其來判斷數據接收狀況
if(RX_DR) // 判斷是否接收到數據
{
CE = 0; //SPI使能
SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);
revale =1; //讀取數據完成標志
CSN=0;
SPI_RW(FLUSH_RX); //在接收模式下,清空RX FIFO 寄存器,并寫入NRF2401
CSN=1;
}
SPI_RW_Reg(WRITE_REG+STATUS,sta); //接收到數據后RX_DR,TX_DS,MAX_PT都置高為1,通過寫1來清楚中斷標志
CSN=0;
SPI_RW(FLUSH_RX);
CSN=1;
return revale;
}
//***************************NRF24L01初始化********************************************
void init_NRF24L01(void)
{
inerDelay_us(100);
CE=0; //芯片啟動
CSN=1; //終止SPI讀寫
SCK=0; //低電平為空閑時刻
SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); //寫本地地址
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); //寫接收端地址
SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x4a); //自動延時1250us,自動重發10次
SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); //ENAA_P0=1,數據通道0自動應答
SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // EN_RXADDR=1,接收地址允許
SPI_RW_Reg(WRITE_REG + RF_CH, 0); //設置信道工作為2.4GHZ,收發必須一致
SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //設置接收數據長度,本次設置為20字節
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //設置發射速率為1MHZ,發射功率為0dBm,低噪聲放大器增益
}
//**********************************************************************************************
void main()
{
uchar TxBuf[20]={0};
uchar RxBuf[20]={0};
init_NRF24L01();
while(1)
{
SetRX_Mode();
nRF24L01_RxPacket(RxBuf);
if(RxBuf[1]|RxBuf[2]|RxBuf[3]|RxBuf[4]|RxBuf[5])
{
if(RxBuf[1]==1)
{
P3=seg[1];
zhengzhuan();RxBuf[5]=0;
}
else if(RxBuf[2]==1)
{
P3=seg[2];
fanzhuan();RxBuf[5]=0;
}
else if(RxBuf[3]==1)
{
P3=seg[3];
zuozhuan();RxBuf[5]=0;
}
else if(RxBuf[4]==1)
{
P3=seg[4];
youzhuan();RxBuf[5]=0;
}
else if(RxBuf[5]==1)
{
P3=seg[0];
tingzhi();RxBuf[5]=0;
}
}
RxBuf[1]=0;
RxBuf[2]=0;
RxBuf[3]=0;
RxBuf[4]=0;
RxBuf[5]=0;
}
}