精华内容
下载资源
问答
  • SPI通信

    2021-01-06 05:20:37
    SPI通信 3. LCD所使用的接口为—》SPI,所以先了解SPI通信 tip: 1.看原理图找对应引脚 3线SPI: CS SCK SDA 4线SPI: CS (片选引脚) SCK (时钟同步引脚) MOSI、MISO 2.看手册了解 1.数据是高位先行还是低位先行 2...
  • SPI 通信

    2021-02-04 11:53:31
    串行外围设备接口(SPI:Serial Peripheral Interface)总线是由Motorola开发的,用于在从设备之间提供全双工同步串行通信SPI总线通常用于与闪存,传感器,实时时钟(RTC),模数转换器等进行通信SPI是一主多从...

    一.简介

    串行外围设备接口(SPISerial Peripheral Interface总线是由Motorola开发的,用于在从设备之间提供全双工同步串行通信。 SPI总线通常用于与闪存,传感器,实时时钟(RTC),模数转换器等进行通信SPI是一主多从的总线。

    标准SPI主机通过SCKMOSIMISOSS线与从机通信。 从站可以共享SCKMOSIMISO信号,而每个从站都有唯一的SS线,SSSPI中与其他总线协议中的从机地址具有同样的功能。

    SPI优点
    支持全双工
    通信,通信简单,数据传输速率块,多从机。

    缺点
    没有指定的流控制,没有应答机制确认是否接收到
    数据,没有检验位确认数据传输是否出错,所以跟IICUART相比较数据可靠性上有一定的缺陷。

    二.通信协议

    2.1  Polarity and Clock Phase

    SPI总线没有为数据交换定义任何协议,从而限制了开销并允许高速数据流。 可以将时钟极性(CPOL:空闲时电平值)和时钟相位(CPHA:第几个时钟边沿采样)指定为“ 0”或“ 1”,以形成四个独特的模式,以提供主从之间的通信灵活性,如图2所示。

    2.2 SPI Transactions

    SPI协议没有定义数据流的结构。 数据的组成完全取决于组件设计者。 但是,许多设备使用相同的基本格式来发送和接收数据,从而允许不同供应商的零件之间实现互操作性。

    2.3  standard Configurations

    SPI信号包括标准串行时钟(SCLK),主机输入从机输出(MISO),主机输出从机输入(MOSI),双向串行数据(SDAT)和从机选择(SS)。

    2.4 3-Wire Configurations

    除了标准的4线配置之外,SPI总线已扩展为包括各种IO标准,包括用于减少引脚数的3线和用于提高吞吐量的双或四路I / O

    3线模式下,MOSIMISO线合并为一条双向数据线,如图3所示。事务是半双工的,以允许双向通信。 减少数据线的数量并以半双工模式运行还会降低最大可能的吞吐量。 许多3线器件对性能的要求较低,因此在设计时应考虑到低引脚数

    2.5 Multi-IO Configurations

    I/O和四I/O之类I/O变体在标准SPI基础上增加了额外的数据线,以提高吞吐量。 利用多种I/O模式的组件可以与并行设备的读取速度相媲美,同时仍可以减少引脚数。 这种性能的提高使得可以从闪存(就地执行)中进行随机访问并直接执行程序

    当与高速设备通信时,Quad I/O设备可以提供的性能是标准4线SPI4倍。 图4显示了一个单Quad IO从设备配置的示例。

    2.6  Multi slave  standard configuration

    SPI支持一主多从,最简单的连接方式如下图所示,时钟线与信号线多从机共用,片选信号CS单独与主机相连,CS的作用与其他通信协议中的地址作用相同。

    3.7 Multi slave Daisy chain configuration

    某些实现SPI的产品可能以菊花链配置连接,第一个从设备输出连接到第二个从设备输入,依此类推。每个从设备的SPI端口设计为在第二组时钟脉冲期间发出与之完全相同的副本。 在第一组时钟脉冲期间接收到的数据。 整个链充当通信移位寄存器; 菊花链通常通过移位寄存器完成,以通过SPI提供一组输入或输出。 每个从机在下一个时钟周期将输入复制到输出,直到低电平有效SS线变为高电平为止。 这样的功能仅需要来自主机的一条SS线,而不需要每个从机的一条单独的SS线

     

     

    展开全文
  • spi通信

    千次阅读 2016-03-20 15:17:34
    SPI的模式进行配置后(配置不算复杂,过程可以参照野火教程),通过SPI, MCU可以发送命令和数据与从机进行通信了。SPI协议中,先发指令,再发送需要写入的数据(如果进行写操作的话),这些指令,对主机来说,...
    声明:本文章是小伙伴在看完坑爹的数据手册之后为了后来人更方便运用2.4G模块用心写的,非本人作品,转载请标明引用处。后面附程序、2.4G、本文等资料,资料下载分为两个途径,坛友直接下载,也有网盘下载的。
    近来课程的项目需要用到NRF24L01,用来做基本的收发,虽然资料拿到不少,但是,很多资料并不是很清晰、所带的例程并不够简洁或有不少冗余的部分,再加上对应的中文数据手册部分没翻译出来,翻译出来的不够有条理,很多地方模糊,甚至关键的地方看一两次还看不出来,导致了在学NRF24L01时花费了较多时间,所以,学完NRF24L01后,萌生了写个尽量清晰的教程的想法。
    教程中的例程虽然是库开发方式,但基本都是最底层的操作才用到库函数譬如发一字节数据、GPIO置位等,虽然用的STM32,但我在看其他板子的例程时,发觉内容与流程都是差不多的,只是不同板引脚不同所导致的引脚配置的不同,不管用什么方式开发,用什么芯片,了解清楚NRF24L01如何配置,了解清楚其收发流程,基本上就会开发了,所以此文档虽然写的是以STM32为例,但看完此文档用NRF24L01基本也没什么大问题了。
    教程说明:这教程是基于STMF103ZET6的,是野火的板子,例程也是从野火提供修改例程得来,用的是库开发的方式。

    学习NRF24L01的步骤:
    1.学习 SPI,SPI就是NRF24L01传送数据到单片机的一种协议,类似于 USB,
    当然 USB还是比较有难度的。
    2.了解 NRF24L01相关寄存器,结合中文数据手册了解NRF24L01的基本配置,收发数据前后的操作(如何启动发送接收、寄存器清空、标志位重置等)。
    3.分析具体代码

    SPI的简介:
    具体的SPI教程,大家可以去野火的教程进行学习,在此只是简略介绍一下,SPI是一种一对多协议:一个主机(MCU)对应对多个从机,可以分时与多个从机通讯
    SPI 总线包含 4 条总线,分别为 SS、SCK、MOSI、MISO,其含义分别为
    SS:Slave Select,片选信号线,主机借此信号线选择一个从机,低电平有效。
    MOSI:Master Output,Slave Input,主机数据从此线输出到从机,数据方向从主机到从机。
    MISO:Master Input, Slave Output,主机从此线读取从机数据,数据方向从从机到主机。
    SCK:Serial Clock,时钟频率线,主机时钟频率输出到从机。           
    对SPI的模式进行配置后(配置不算复杂,过程可以参照野火教程),通过SPI, MCU可以发送命令和数据与从机进行通信了。SPI协议中,先发指令,再发送需要写入的数据(如果进行写操作的话),这些指令,对主机来说,只是它遵守最基本的通讯协议发送出的数据。但设备把这些数据解释成不同的意义(指令编码),所以才成为指令。
    介绍一下NRF24L01的管脚:


    管脚名称        说明
    GND        接地
    VCC        VCC脚接电压范围为1.9V~3.6V之间
    CE        置高会启动发送(发送模式下)或者接收(接收模式下)
    CSN        置低使能,SPI片选使能引脚,MCU的每条指令都要经历CSN从低到高
    SCK        时钟信号引脚
    MOSI        主机数据输出、从机数据输入线
    MISO        主机数据输入、从机数据输出线
    IRQ        中断引脚、当发送数据成功或者接收数据成功IRQ置低

    管脚接法介绍:
    GND与VCC对应板上的接即可,MISO、MOSI、SCK、CSN(有些SPI片选段写着的是SS) 对应SPI模块相应引脚即可。CE引脚接上一GPIO口,MCU通过此GPIO口控制CE高低电平即可,同理,IRQ引脚接上另一GPIO口,MCU通过此读取GPIO口的高低电平来判断是否中断。
    下面介绍NRF24L01的工作模式和具体的发送与接收流程

    工作模式:
    NRF24L01有两种工作模式,一种ShockBurst™,一种是Enhanced ShockBurst™,两种模式的差别仅在于Enhanced ShockBurst™模式中在发送过程中会要求接收设备产生应答信号,以便发送方检测数据是否丢失,一旦丢失将重发丢失数据包将丢失的数据恢复。也因为Enhanced ShockBurst™模式有此优点,将很大程度上防止数据的丢失,因此较多选择Enhanced ShockBurst™模式,注意:选择Enhanced ShockBurst™模式,无需自己再写代码设置接收模式接收应答信号或者写代码让其重发,产生应答信号与自动重发(如果数据丢失),都是在设置为Enhanced ShockBurst™模式后自动进行的。

    Enhanced ShockBurst™的发送模式下的流程:
    ① MCU通过SPI对NRF24L01进行基本配置,,配置自动应答通道使能(发送完一包数据后自动进入接收应答信号状态,发送一次发一包数据,一包数据格式见文档最后),设置自动重发次数不为0(在此设置可以重发数据包)注:此两步是开启Enhanced ShockBurst™模式的关键。设置为发送模式,还有其他配置等等
    ② MCU把要发送的数据和接收数据设备的地址通过SPI写入NRF24L01
    ③ CE引脚置高,启动发送
    ④ 此时有两种情况:
    1.在有限时间内收到应答信号,则TX_DS置高(发送数据成功标志位),并引发IRQ中断(引脚IRQ置低),并清除TX FIFO(此为发送缓冲寄存器,自行写代码清除),IRQ中断需要写状态寄存器进行复位(因为此处IRQ由TX_DS引发,将TX_DS复位即可使IRQ复位)
    2.重发数据次数超过设定值,则MAX_RT置高(达到最多重发次数标志位),并引发IRQ中断(引脚IRQ置低),不清除TX FIFO,IRQ中断需要写状态寄存器进行复位(因为此处IRQ由MAX_RT引发,将MAX_RT复位即可使IRQ复位)
    ⑤ 接收到应答信号产生中断或者达到最大重发次数产生中断后,NRF24L01继续发下一包数据。
    ⑥ 当TX FIFO为空时,进入待机模式二(当CE为高,TX FIFO为空时,进入待机模式二;NRF24L01的工作模式图表在最后,工作模式不需过多理会,只要在适当时候拉高CE进行发送即可,配置NRF24L01时CE置低)

    Enhanced ShockBurst™的接收模式下的流程:
    ① 与发送模式一样,一开始MCU通过SPI对NRF24L01进行基本配置,设置数据通道自动应答使能(在EN_AA寄存器进行设置,即收到数据后,向主机发送应答信号),注:此步是开启从机Enhanced ShockBurst™模式的关键。还有进行接收数据通道使能(在EN_RXADDR寄存器配置,即选择六个接收通道的某一通道来接收数据,六个接收通道具体情况下面会说到),设置为接收模式,还有其他等配置。
    ② 拉高CE引脚(CE置高),启动接收状态
    ③ 接收到一个有效数据包后,数据存储在RX FIFO,并产生RX_DR中断(RX_DR为接收数据成功标志位,接收成功置1),中断和发送模式一样,同样需要复位。
    ④ 接收设备自动向发送设备发送确认信号(无需自己写代码)
    ⑤ 设置CE引脚为低,NRF24L01进入待机模式一
    ⑥ MCU通过SPI读取NRF24L01收到的数据

            根据NRF24L01的发送数据流程与接收数据流程,我们可以归纳出编写NRF24L01发送代码与接收代码的流程
            发送过程: 
    a.        MCU通过SPI对NRF24L01进行基本配置,配置好NRF24L01
    b.        MCU将要发送的数据与接收数据设备的地址写入NRF24L01
    c.        CE引脚置高,启动发送                

            接收过程:                         
    a.                MCU通过SPI对NRF24L01进行基本配置,配置好NRF24L01                
    b.        CE引脚置高,启动接收
    c.        MCU对        NRF24L01进行数据读取

    分析具体代码

    发送模式:
    首先我们来看一下例程发送模式下的mian.c 文件

    1 #include "stm32f10x.h"
    2 #include "bsp_usart1.h"
    3 #include "bsp_spi_nrf.h"

    5 /*
    6  * PA2  -  PG8   ce使能
    7  * PA1  -  PG15  cs片选
    8  * PA3  -  PC4   irq中断
    9  */
    10 u8 status;  //用于判断接收/发送状态
    11 u8 txbuf[4]= {0,1,2,3};  //发送缓冲
    12 u8 rxbuf[4];       //接收缓冲
    13 int i=0;
    14 
    15 /**
    16  * @brief  主函数
    17  * @param  无
    18  * @retval 无
    19  */
    20 int main(void)
    21 {
    22     SPI_NRF_Init();
    23 
    24     /* 串口1初始化 */
    25     USART1_Config();
    26 
    27     printf("\r\n 这是一个 NRF24L01 无线传输实验 \r\n");
    28     printf("\r\n 这是无线传输 主机端 的反馈信息\r\n");
    29      
    30            
    31 
    32 
    33     NRF_TX_Mode();
    34 
    35     while (1) {
    36         printf("\r\n 主机端 进入自应答发送模式\r\n");
    37 
    38 
    39         /*开始发送数据*/
    40         status = NRF_Tx_Dat(txbuf);
    41 
    42         /*判断发送状态*/
    43         switch (status) {
    44         case MAX_RT:
    45             printf("\r\n 主机端 
    46                    没接收到应答信号,发送次数超过限定次数
    47                     ,发送失败。 \r\n");
    48             break;
    49 
    50         case ERROR:
    51             printf("\r\n 未知原因导致发送失败。 \r\n");
    52             break;
    53 
    54         case TX_DS:
    55             printf("\r\n 主机端 接收到 从机端 
    56                    的应答信号,发送成功! \r\n");
    57             break;
    58         }
    59 
    60 
    61     }
    62 } 

    我们来分析一下mian函数里面的代码
    开头的调用的第一个函数就是SPI_NRF_Init(),跟踪这个函数的内容,我们可以发现这函数主要是进行SPI的有关配置与NRF24L01引脚接入STM32 GPIO的有关配置;有关SPI配置内容,读者可以前去SPI的有关教程了解,这里不展开了。有关GPIO口的配置,这里不是重点,所以亦不展开,可以去读关于LED灯的配置,了解学习GPIO配置的内容。
    同理调用的第二个函数 USART1_Config()亦不作展开.

    NRF_TX_Mode()函数的分析:

    我们来看一下NRF_TX_Mode()这个函数,这是配置NRF24L01作为发送设备的函数,我们跟踪其定义可以看到如下代码:

    1 void NRF_TX_Mode(void)
    2 {
    3     NRF_CE_LOW();

    5     SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,TX_ADDRESS,TX_ADR_WIDTH);   
    6                      //写TX节点地址

    8     SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH);
    9                      //设置TX节点地址,主要为了使能ACK
    10 
    11     SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x01);     
    12                      //使能通道0的自动应答
    13 
    14     SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x01); 
    15                      //使能通道0的接收地址
    16 
    17     SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_RETR,0x1a);
    18                      //设置自动重发间隔时间:500us + 86us;
    19                      最大自动重发次数:10次
    20 
    21     SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,CHANAL);       
    22                      //设置RF通道为CHANAL
    23 
    24     SPI_NRF_WriteReg(NRF_WRITE_REG+RF_SETUP,0x0f);  
    25                      //设置TX发射参数,0db增益,2Mbps,
    26                      低噪声增益开启
    27 
    28     SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG,0x0e);    
    29                      //配置基本工作模式的参数;PWR_UP,EN_CRC,
    30                      16BIT_CRC,发射模式,开启所有中断
    31 
    32 }

    函数第一行代码NRF_CE_LOW()根据函数名我们就可以获悉它的作用是将CE引脚置低,此作用是确保CE是低电平,处于待机模式一下进行配置

    SPI_NRF_WriteBuf()函数分析:

    第二行代码SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,TX_ADDRESS,TX_ADR_WIDTH)从函数我们可以得知其是向NRF24L01写入一串数据。我们跟踪它,代码如下:
    1 /**
    2   * @brief   用于向NRF的寄存器中写入一串数据
    3   * @param
    4   *   @arg reg : NRF的命令+寄存器地址
    5   *   @arg 
    6   pBuf:存储了将要写入写寄存器数据的数组,外部定义
    7   
    8   *   @arg bytes: pBuf的数据长度
    9   * @retval  NRF的status寄存器的状态
    10   */
    11 u8 SPI_NRF_WriteBuf(u8 reg ,u8 *pBuf,u8 bytes)
    12 {
    13     u8 status,byte_cnt;
    14 
    15     /*置低CSN,使能SPI传输*/
    16     NRF_CSN_LOW();
    17 
    18     /*发送寄存器号*/
    19     status = SPI_NRF_RW(reg);
    20 
    21     /*向缓冲区写入数据*/
    22     for (byte_cnt=0; byte_cnt<bytes; byte_cnt++)
    23         SPI_NRF_RW(*pBuf++);  //写数据到缓冲区
    24 
    25     /*CSN拉高,完成*/
    26     NRF_CSN_HIGH();
    27 
    28     return (status);  //返回NRF24L01的状态
    29 } 
    第一行NRF_CSN_LOW()是将CSN置低,CSN是片选使能的作用,低电平有效,此在强调一下,NRF24L01的每一条指令的执行都要经过CSN置低后再置高,这就是为什么26行代码NRF_CSN_HIGH()置高CSN的原因。

    SPI_NRF_RW(reg)函数分析:

    19行代码status = SPI_NRF_RW(reg)调用了函数SPI_NRF_RW(reg)我们追踪其代码
    1 /**
    2   * @brief   用于向NRF读/写一字节数据
    3   * @param   写入的数据
    4   *   @arg dat
    5   * @retval  读取得的数据
    6   */
    7 u8 SPI_NRF_RW(u8 dat)
    8 {
    9     /* 当 SPI发送缓冲器非空时等待 */
    10     while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
    11 
    12     /* 通过 SPI2发送一字节数据 */
    13     SPI_I2S_SendData(SPI1, dat);
    14 
    15     /* 当SPI接收缓冲器为空时等待 */
    16     while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
    17 
    18     /* Return the byte read from the SPI bus */
    19     return SPI_I2S_ReceiveData(SPI1);
    20 } 
    此函数用到了很多库函数,在此我们就不分析库函数了,我们了解此函数功能即可,从这函数的说明,我们就能知道,这函数是写入或者读取一字节数据用的。

    回到SPI_NRF_WriteBuf(u8 reg ,u8 *pBuf,u8 bytes)函数,我们发觉,它向SPI_NRF_RW(reg)传入的参数是reg,SPI_NRF_WriteBuf()的函数介绍里,reg是指 NRF的命令+寄存器地址,但是这是怎么回事,其实,这里传递的一个字节数据对NRF24L01来说是指令,上面的SPI简介就提到,一些数据对主机来说仅仅是数据,但对从机而言便是指令了。
    下面了解一下NRF24L01的指令:


       其中,读配置寄存器一个字节的指令后五位是该寄存器地址,写配置寄存器的一个字节指令后五位是该寄存器地址,第六位是1,这就是为什么SPI_NRF_WriteBuf()函数传入的参数是NRF_WRITE_REG+TX_ADDR了,其中NRF_WRITE_REG = 0x20(即0010 0000),TX_ADDR就是寄存器的地址。以上的NRF24L01其他指令,在以下的代码将有用到。

       写入命令后,接下来u8 SPI_NRF_WriteBuf(u8 reg ,u8 *pBuf,u8 bytes)的22、23代码即是向寄存器写数据的过程。

    5     SPI_NRF_WriteBuf(NRF_WRITE_REG+TX_ADDR,TX_ADDRESS,TX_ADR_WIDTH);   
    6                      //写TX节点地址
    由此,我们了解次此两行代码的作用是写入TX的地址,即告知发送设备即将接收数据设备的地址。

    8     SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH);
    9                      //设置TX节点地址,主要为了使能ACK
    同理是为了写明NRF24L01接收通道0的地址,接收通道0为接收应答信号用,在此说明NRF24L01在接收模式下可以接收6路不同的数据,有6个通道,6个通道的地址有5个通道地址有一定限制,详情参照数据手册。

    11     SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x01);     
    12                      //使能通道0的自动应答
    11行代码中使用了新的函数SPI_NRF_WriteReg()跟踪其定义发现其作用与 SPI_NRF_WriteBuf()差别在于SPI_NRF_WriteReg()是写入一个字节的数据由此可知11行代码的功能是将EN_AA寄存器配置为0x01,查阅手册可知其是使能通道0自动应答。

    14     SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x01); 
    15                      //使能通道0的接收地址
    同理可知其功能是使能接收通道0能够接收数据

    17     SPI_NRF_WriteReg(NRF_WRITE_REG+SETUP_RETR,0x1a);
    18                      //设置自动重发间隔时间:500us + 86us;
    19                      最大自动重发次数:10次
    此为有关重发次数和重发时间间隔的配置

    21     SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,CHANAL);       
    22                      //设置RF通道为CHANAL
    23 
    24     SPI_NRF_WriteReg(NRF_WRITE_REG+RF_SETUP,0x0f);  
    25                      //设置TX发射参数,0db增益,2Mbps,
    26                      低噪声增益开启
    此处读者编程时按一般例程写即可,可不深究,注意接收设备与发送设备相等。

    28     SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG,0x0e);    
    29                      //配置基本工作模式的参数;PWR_UP,EN_CRC,
    30                      16BIT_CRC,发射模式,开启所有中断
    此处是对NRF24L01的配置寄存器进行配置,设置为发送状态,上电、允许所有中断(TX_DS、RX_DR、MAX_RT)等
    至此,发送模式配置完毕。

    NRF_Tx_Dat(txbuf)函数分析:

    我们接着看main函数的39与40行代码
    39         /*开始发送数据*/
    40         status = NRF_Tx_Dat(txbuf);
    根据发送流程,大家都知道这是MCU写入数据到NRF24L01了,我们具体跟踪此函数代码,代码如下:
    1 /**
    2   * @brief   用于向NRF的发送缓冲区中写入数据
    3   * @param
    4   *   @arg 
    5   txBuf:存储了将要发送的数据的数组,外部定义
    6   * @retval  发送结果,成功返回TXDS,失败返回MAXRT或ERROR
    7   */
    8 u8 NRF_Tx_Dat(u8 *txbuf)
    9 {
    10     u8 state;
    11 
    12     /*ce为低,进入待机模式1*/
    13 
    14     /*写数据到TX BUF 最大 32个字节*/
    15     SPI_NRF_WriteBuf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
    16 
    17     /*CE为高,txbuf非空,发送数据包 */
    18     NRF_CE_HIGH();
    19 
    20     /*等待发送完成中断 */
    21     while (NRF_Read_IRQ()!=0);
    22 
    23     /*读取状态寄存器的值 */
    24     state = SPI_NRF_ReadReg(STATUS);
    25 
    26     /*清除TX_DS或MAX_RT中断标志*/
    27     SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state);
    28 
    29     SPI_NRF_WriteReg(FLUSH_TX,NOP);    //清除TX FIFO寄存器
    30 
    31     /*判断中断类型*/
    32     if (state&MAX_RT)                    //达到最大重发次数
    33         return MAX_RT;
    34 
    35     else if (state&TX_DS)                 //发送完成
    36         return TX_DS;
    37     else
    38         return ERROR;                 //其他原因发送失败
    39 }
    40  


    14     /*写数据到TX BUF 最大 32个字节*/
    15     SPI_NRF_WriteBuf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);
    此两行代码即为写入要发送的数据。

    17     /*CE为高,txbuf非空,发送数据包 */
    18     NRF_CE_HIGH();
    拉高CE,启动发送。

    20     /*等待发送完成中断 */
    21     while (NRF_Read_IRQ()!=0);
    MCU启用查询的方式,等待中断发生。(注:例程暂时提供是查询的方式检测中断,在此,编者并不建议用查询的方式,因为这会占用CPU,使部分其他功能可能无法加入,建议用中断的方式进行。)

    23     /*读取状态寄存器的值 */
    24     state = SPI_NRF_ReadReg(STATUS);
    25 
    26     /*清除TX_DS或MAX_RT中断标志*/
    27     SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state);
    28 
    29     SPI_NRF_WriteReg(FLUSH_TX,NOP);    //清除TX FIFO寄存器
    中断产生后,读取状态寄存器的值,判断中断的类型,此处SPI_NRF_ReadReg();函数为读寄存器函数,功能与操作与上面的函数类似,就不展开了。读取后,并复位状态寄存器,清除中断,并且清除发送寄存器
    至此,NRF24L01发送完成。

    接收模式:
    对比发送模式与接收模式的代码编写流程,可以发现其实两者是差不多的,只是配置有部分不同,数据处理与CE拉高顺序部分不同,发送模式下,写入数据和地址后,拉高CE,接收模式下,先拉高CE,再读取数据。因为有多地方是相同的,所以就不再赘述,只说明不相同的地方。

    模式配置的不同:
    先看接收模式的代码:
    1 void NRF_RX_Mode(void)

    3 {
    4     NRF_CE_LOW();

    6     SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH);
    7                      //写RX节点地址

    9     SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x01);    
    10                      //使能通道0的自动应答
    11 
    12     SPI_NRF_WriteReg(NRF_WRITE_REG+EN_RXADDR,0x01);
    13                      //使能通道0的接收地址
    14 
    15     SPI_NRF_WriteReg(NRF_WRITE_REG+RF_CH,CHANAL);      
    16                      //设置RF通信频率
    17 
    18     SPI_NRF_WriteReg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    19                      //选择通道0的有效数据宽度
    20 
    21     SPI_NRF_WriteReg(NRF_WRITE_REG+RF_SETUP,0x0f); 
    22                      //设置TX发射参数,0db增益,2Mbps,
    23                      低噪声增益开启
    24 
    25     SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG, 0x0f);  
    26                      //配置基本工作模式的参数;PWR_UP,EN_CRC,
    27                      16BIT_CRC,接收模式
    28 
    29 } 



    6     SPI_NRF_WriteBuf(NRF_WRITE_REG+RX_ADDR_P0,RX_ADDRESS,RX_ADR_WIDTH);
    7                      //写RX节点地址
    此段代码在发送模式的配置亦有同样的一段,作用是写明通道0的地址,在这里,接收通道0作用是不大一样的,接收模式下,接收设备的接收通道0接收的是一个数据包,而在发送模式下,接收通道0接收的是接收设备发过来的应答信号。

    9     SPI_NRF_WriteReg(NRF_WRITE_REG+EN_AA,0x01);    
    10                      //使能通道0的自动应答
    在发送模式下,同样有此一句代码,但意义实质是不一样的,接收模式下,这句代码是使接收通道0接收到数据后,接收设备向发送设备发送应答信号。而发送模式下,此代码是使设备发送完数据后,进入接收状态,准备接收应答信号。

    18     SPI_NRF_WriteReg(NRF_WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);
    19                      //选择通道0的有效数据宽度
    此为设置接收设备接收的一包数据中有效数据的字节数,一包数据可以包含1到32个有效字节数据,在此说明,发送设备发过来的一个包数据中有限数据的字节数必须与接收数据通道0的有效数据宽度相等。

    25     SPI_NRF_WriteReg(NRF_WRITE_REG+CONFIG, 0x0f);  
    26                      //配置基本工作模式的参数;PWR_UP,EN_CRC,
    27                      16BIT_CRC,接收模式
    此段代码,接收模式向配置寄存器写入的参数和发送模式不同,此处不同就在于配置寄存器最低位置1(最低位PRIM_RX置1为接收模式、置0为发送模式),因此接收模式输入的参数比发送模式大1。

    当然,还有个差别是,接收设备不需要配置自动重发。

    接收数据函数NRF_Rx_Dat(rxbuf)分析:
    代码如下:
    1 u8 NRF_Rx_Dat(u8 *rxbuf)
    2 {
    3     u8 state;
    4     NRF_CE_HIGH();   //进入接收状态
    5     /*等待接收中断*/
    6     while (NRF_Read_IRQ()!=0);

    8     NRF_CE_LOW();    //进入待机状态
    9     /*读取status寄存器的值  */
    10     state=SPI_NRF_ReadReg(STATUS);
    11 
    12     /* 清除中断标志*/
    13     SPI_NRF_WriteReg(NRF_WRITE_REG+STATUS,state);
    14 
    15     /*判断是否接收到数据*/
    16     if (state&RX_DR) {                              //接收到数据
    17         SPI_NRF_ReadBuf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);
    18                         //读取数据
    19         SPI_NRF_WriteReg(FLUSH_RX,NOP);          //清除RX 
    20                          FIFO寄存器
    21         return RX_DR;
    22     } else
    23         return ERROR;                    //没收到任何数据
    24 } 

    可以看到,发送数据处理函数与接收处理函数基本一样,只是CE置高与数据处理顺序不同而已。
    至此,接收模式讲解完毕

    说明一下:
    状态寄存器中TX_DS、RX_DR、MAX_RT三位其对应类型中断发生时是被置1的,同时清除这些中断是向这些位写1,这就是为什么会看到,代码中,清除中断标志是先读状态寄存器的数值后,再向状态寄存器写入刚读出的数值。
    (模糊的地方,FIFO的处理)

    一个数据包可以写入1—32个字节的有效数据,也就是说发送一次数据,可以选择发送1—32个字节。

    注:有关具体寄存器、与其具体的位,请查阅中文数据手册,此处就不再列出
    展开全文
  • SPI通信原理

    2018-07-20 10:57:33
    介绍SPI通信原理,时钟图示,硬件示意图,性能特点,数据传输方法,用户逻辑及数据结构。
  • 单片机SPI通信接口

    2020-07-17 15:05:48
    UART、I2C和 SPI 是单片机系统中最常用的三种通信协议。这节课我们来学习剩下的 SPI 通信协议。
  • OLED与32单片机SPI通信

    2020-12-31 19:24:28
    OLED的SPI通信
  • FPGA_SPI通信

    2017-09-13 13:14:36
    提供 430和FPGA之间的模拟spi通信程序 根据单片机采集到的不同ad电压值控制FPGA DDS波形生成的幅值 同时该SPI通信协议实现对DDS波形频率的控制
  • codewarrior单片机SPI通信程序,便于大家理解SPI通信与应用,更好实现单片机的SPI应用功能

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,133
精华内容 2,053
关键字:

spi通信