数日前,笔者在淘宝买了一对NR24L01模块。这两天突发奇想了一个项目,需实现无线通信。于是便想到了驱动NR24L01。
首先,我同大家一样。按照程序连电路,烧写卖家给的驱动。上电,串口调试,没反应!囧……读程序,发现波特率不对。调整串口助手波特率,上电,没反应!囧……查电路,发现晶振与程序不匹配。换晶振,上电,没反应!囧……此时,我首先想到的是模块是坏的。淘宝卖家为了节省时间,没测试。于是我就决定再买一对。正当我在淘宝搜索时,忽然想到!我换晶振是貌似少焊了一面(电路板是双面板,中间过孔的铜在我拆晶振的时候弄带掉了)。重新焊了一块最小系统板。连电路,上电,测试,成功!!!
然后,删改主程序,使其实现我要的功能。试了几次,程序就正常了(实现的功能较简单)。回头看了两遍程序,自以为掌握了该模块的驱动方法。可是,当我将其移植到AVR中时,发现AVR的驱动我根本看不懂!于是,回过头来看51的程序,打算将两者比较。悲剧的是,51程序我只是明白了子程序间的逻辑关系,操作的实质并未掌握。(谦虚使人进步,骄傲使人落后。毛主席说的对啊!)于是,根据数据重新读程序。特将此过程记录下来,一是告诫自己不要犯同样的错误。二是帮助在此遇到困难的初学者。
首先是这个子程序:
/*函数:uint SPI_RW(uint uchar)
/*功能:NRF24L01的SPI写时序
/*********************************************/
uint SPI_RW(uint uchar)
{
uint bit_ctr;
for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit
{
MOSI = (uchar &0x80); // output 'uchar', MSB toMOSI
uchar = (uchar<< 1); // shift next bitinto MSB..
SCK = 1; // Set SCK high..
uchar |= MISO; //capture current MISO bit
SCK = 0; // ..then set SCK low again
}
return(uchar); // return read uchar
}
乍一看很简单,可当我仔细读时,
uchar |= MISO;
这句话不能理解,uchar和MISO相或之后,它的值不就变了吗?然后,我查看了NR24L01的数据手册,好几十页的英文手册看的我头都大了也没明白(笔者英语很差,四级考了两次没过。囧……)找到一份中文的,仔细读了两遍,大致明白了。
file:///C:/Users/kira/AppData/Local/Temp/msohtmlclip1/01/clip_image002.jpg
Cn——指令位;Sn——状态寄存器位;Dn——数据位;
那么假设我们要发的数据是10101010,首先定义变量uchar=0xAA;执行MOSI =(uchar & 0x80);(1010 1010&1000 0000)=1000 000不为零;则MOSI=1。Uchar移位,uchar=0101 0100; SCK拉高,写入MOSI中数据。接下来就奇怪了!uchar |= MISO; uchar和MISO相或之后,它的值不就变了吗?我查看了相关寄存器,如下:
file:///C:/Users/kira/AppData/Local/Temp/msohtmlclip1/01/clip_image004.jpg
此时,MISO寄存器为:0000 0000;(读者可逐个比较,在此不一一赘述)。
因此,uchar的值未改变。那为何要有此语句呢?当uchar的数据传输结束时,MISO数据发生改变。MISO=1000 1110;ucahr值为0000 0000;执行 uchar |= MISO;uchar则读走MISO中数据,即返回了状态寄存器中的数据。
/***********************************************
/*函数:uchar SPI_Read(ucharreg)
/*功能:NRF24L01的SPI时序
/*********************************************/
uchar SPI_Read(uchar reg)
{
uchar reg_val;
CSN = 0; // CSN low, initialize SPI
SPI_RW(reg); // Select register to read from..
reg_val = SPI_RW(0); // ..then read registervalue
CSN = 1; // CSN high, terminate SPIcommunication
return(reg_val); // return register value
}
/********************************************/
/*功能:NRF24L01读写寄存器函数
/******************************************/
uint SPI_RW_Reg(uchar reg, uchar value)
{
uint status;
CSN = 0; // CSN low, init SPI transaction
status = SPI_RW(reg); // select register
SPI_RW(value); // ..and write value to it..
CSN = 1; // CSN high again
return(status); // return nRF24L01 status uchar
}
这两个函数据能够理解了。读写数据,返回状态寄存器的值。
其他的子程序大同小异,有些涉及到其他寄存器,在宏定义中。在此不一一赘述。小弟初学乍练,欢迎各位大侠,各位高手批评指正。大家共同进步。小弟一定虚心接受。同时感谢在QQ群中回答我我问题的高手们。哪里写的不对,请大家一定要提出来,感激不尽。%>_<%