飞思卡尔16位单片机(十三)—— SPI模块测试

一、SPI模块介绍

         串行外围器件接口(SPI)模块提供单片机和外围器件间的全双工、同步和串行通信。这些外围器件可以包括其他微控制器、模数移位器、移位寄存器、传感器和存储器等。SPI运行在主模式中最高可运行在总线时钟除以2的波特率上,在辅模式中最高可运行在总线时钟除以4的波特率上。

        SPI的中心元件是SPI移位寄存器。数据写入双缓冲发射器(写入SPIDR),然后转移到位于数据传输起点的SPI移位寄存器。在数据字节中转换后,数据被传输到双缓冲接收器,在这里数据可以被读取(从SPIDR读取)。管脚复用逻辑控制着单片机管脚和SPI模块间的连接。SPI的功能框图如下图所示。

        当SPI配置为主SPI时,时钟输出被路由到SCK管脚,移位器输出被路由到MOSI,移位器输入从MISO管脚路由出来。当SPI 配置为从SPI时,SCK管脚为时钟输出。MOSI为移位输出,MISO管脚为移位器输入。

       在外部SPI系统,只需将所有SCK管脚彼此连接,所有MISO管脚连接起来,所有MOSI管脚连接起来就可以来。外围器件通常为这些管脚使用略有不同的名称。

       AT25040N为存储容量为4K的EEPROM存储器,在这个实验中使用SPI接口进行数据的读和写。硬件电路的原理图如下图所示。

        SPI接口由4个管脚组成,分别为SCK,MOSI,MISO,CS。

SCK — SPI串行时钟

当SPI作为从SPI 被使能时,该管脚是串行时钟输入。当SPI作为主SPI被使能时,该管脚是串行时钟输出。

MOSI — Master Data Out, Slave Data In

当SPI作为主SPI被使能时,该管脚是串行数据输出。当SPI作为从SPI被使能时,该管脚为串行数据输入。选择单线双向模式并选择了主模式,该管脚就成为双向数据I/O 管脚(MOMI)。

MISO — Master Data In, Slave Data Out

当SPI作为主SPI被使能时,该管脚是串行数据输入。当SPI作为从SPI被使能时,该管脚是串行数据输出。如果选择单线双向模式并选择了辅模式,该管脚变成双向数据I/O管脚(SISO)。

CS — 从选择

在SPI传输过程中,数据在一个SCK边沿从MOSI管脚上进行采样(读取)和转移,半个SCK周期后改变MOSI管脚上的位值。在8个SCK周期后,主SPI的移位寄存器中的数据已经从MOSI管脚转移到从SPI,同时MISO管脚里的8位数据被转移到主SPI的移位寄存器中。传输结束时,收到的数据字节从移位器转移到接收数据缓冲器,并设置SPRF,显示数据可以通过读取SPIDR进行读取。如果传输结束时发送缓冲器中有另外一个数据字节在等待,它就被移到移位器,设置SPTEF,启动新传输。

         这里我们再介绍一下AT25040N通信的模式,其模式如下:

单片机向AT25040N写入数据之前,首先要向AT25040N写入“Write Enable”命令,此命令格式如下:

        单片机向AT25040N写入数据的格式如下,写入数据至少由3个字节的命令组成,第一个字节为“op-code”命令,该字节的“A”位为AT25040N地址中的A8位,因为AT25040N为存储空间为4Kb的EEPROM,可存储512字节的数据,每个字节对应一个地址,需要用9位地址来表示,分别为“A8—A0”,“op-code”之后是“A7—A0”,之后是要传输的数据。

单片机由AT25040N读取数据的格式如下。首先是“op-code”命令,之后是读取数据地址的低8位,之后是要读取的数据。

  

二、例程测试

        在这个实验中,我们采用SPI向AT25040芯片中写入一个字节的数据,并将数据读出再验证。SPI的初始化代码如下所示。

void INIT_SPI(void) 
{
  HOLD_dir = 1;
  CS_dir = 1;

  SPI0CR1 = 0b01010000;   //使能SPI,禁止中断,时钟高有效,相位为0;
  SPI0CR2 = 0x00;         //SS管脚为普通I/O,双向模式;
  SPI0BR = 0x70;          //设置SPI时钟频率为2MHz;
  CS = 1;
}

初始化代码将SPI设置为与AT25040芯片模式一致的模式,并设置CS引脚为普通引脚,通过程序控制,最后设置了通讯频率。

下面是SPI发送的代码。

void SPI_send(unsigned char data) 
{
  while(!SPI0SR_SPTEF);
  SPI0DRL = data; 
}

代码比较简单,显示判断缓冲器是否为空,等待为空时写入需要发送的数据。

下面是SPI接收的代码。

unsigned char SPI_receive(void) 
{
  unsigned char temp,data;
  while(!SPI0SR_SPIF);
  temp = SPI0SR;
  data = SPI0DRL;
  return(data);
} 

接收代码也比较简单,等待标志位置1,然后通过读取标志寄存器的方式清除标志位,最后读取数据并返回数据。

下面是主函数的代码。

void main(void) 
{
  DisableInterrupts; 
  INIT_PLL();
  LEDCPU_dir = 1;
  INIT_SPI();
  INIT_FM25040A();
  EnableInterrupts; 
  LEDCPU = 1;

  CS = 0;
  SPI_send(0x06);
  delay();
  CS = 1;
 
  delay();
  CS = 0;
  SPI_send(0x02);
  SPI_send(0x00);
  SPI_send('E');       //存储一个字节的数据
  delay();
  CS = 1;

  longdelay();
  CS = 0;
  SPI_send(0x03);
  SPI_send(0x00);
  delay();

  SPI_send(0x00);
  delay();

  temp_SPI = SPI_receive();  //读取数据,以便shift register中的数据存入到SPI0DRL
  
  data_receive = SPI_receive();  //读取数据

  CS = 1;
  if(data_receive == 'E')        //判断数据是否正确
    LEDCPU = 0;
  
  for(;;);
}

在主函数中,程序向AT25040发送一个字节的数据,并读取出数据,然后判断数据是否正确,正确则点亮LED灯。

大家可以对照上面的AT25040的通信协议对代码进行分析。

        将程序下载到单片机中,并运行,LED灯点亮。

发布了78 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/bhniunan/article/details/104238988