【STC8A8K64S4A12开发板】—片外存储器FRAM讲解

版权声明:本文为博主原创文章,转载请附上原文出处链接。


前言

今天介绍下STC8A8K64S4A12系列单片机FRAM铁电存储器原理和SPI总线的原理及工作模式,掌握STC8A8K64S4A12系列单片机SPI外设相关的寄存器配置及程序设计。


一、硬件设计

1.FRAM铁电存储器介绍

FRAM(全称是Ferroelectric Random Access Memory)铁电存储器,该存储器能兼容RAM的一切功能,并且和ROM技术一样,是一种非易失性的存储器。可以说铁电存储器在这两类存储类型间搭起了一座跨越沟壑的桥梁——一种非易失性的RAM。

铁电存储器的工作原理是:当在铁电晶体材料上加入电场,晶体中的中心原子会沿着电场方向运动,达到稳定状态。晶体中的每个自由浮动的中心原子只有2个稳定状态,一个记为逻辑中的0,另一个记为1。中心原子能在常温、没有电场的情况下,停留在此状态达100年以上。铁电存储器不需要定时刷新,能在断电情况下保存数据。由于整个物理过程中没有任何原子碰撞,铁电存储器有高速读写、超低功耗和无限次写入等优点。

说到FRAM铁电存储器,就必须要介绍下美国Ramtron公司,该公司成立于1984年,是一家研究和开发铁电技术用于半导体存储器的公司。2012年9月,Ramtron公司被美国著名半导体公司赛普拉斯(Cypress)并购。2020年4月,infineon英飞凌完成了总价值90亿欧元(合人民币693亿元)对Cypress赛普拉斯半导体公司的收购。

Ramtron公司的FRAM主要包括两大类:串行FRAM和并行FRAM。其中串行FRAM又分I2C总线方式的FM24xx系列和SPI总线方式的FM25xx系列。艾克姆科技FRAM选择的存储器芯片是FM25CL64B芯片(SPI总线方式)。

在这里插入图片描述

图1:外部FRAM存储器实物图

☆注:Ramtron公司的商业FRAM产品全部由美国和日本的战略代工厂所制造。

2.SPI总线原理

SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速、全双工、同步的通信总线。SPI是Motorola公司推出的一种同步串行接口技术,SPI由一个主设备和一个或多个从设备组成,在一次数据传输过程中,接口上只能有一个主机和一个从机通信。

SPI总线的优点是操作简单、数据传输速率较高、全双工,缺点是只支持单个主机、没有指定的流控制、没有应答机制确认是否接收到数据。

2.1.接口信号定义

SPI总线接口包括以下四种信号:

  1. MOSI(Master Output,Slave Input):主器件数据输出,从器件数据输入。
  2. MISO(Master Input, Slave Output):主器件数据输入,从器件数据输出。
  3. SCK(Serial Clock):有时也称为SCLK,时钟信号,由主器件产生。
  4. CS(Chip select):有时也称为SS,从器件使能信号,由主器件控制,实际使用时,经常用GPIO来代替。

SPI总线支持连接多个从机,如下图所示,SPI主机通过连接到从机的片选信号使能/禁止从机,并且同时只能使能一个从机,因此总线里面有多少个从机,就需要多少个片选信号。当SPI主机需要和总线中某个从机进行通信时,主机会拉低对应的CS信号使能该从机,之后发起通信,通信完成后,拉高CS信号,解除总线的占用。

在这里插入图片描述

图2:SPI总线结构

对于SPI总线,我们还需要深刻理解下面几个知识点。

■ 硬件片选和软件片选的区别

所谓硬件片选指的是SPI本身具有片选信号,当我们通过SPI发送数据时,SPI外设自动拉低CS信号使能从机,发送完成后自动拉高CS信号释放从机,这个过程是不需要软件操作的。而软件片选则是需要使用GPIO作为片选信号,SPI在发送数据之前,需要先通过软件设置作为片选信号的GPIO输出低电平,发送完成之后再设置该GPIO输出高电平。

■ SPI总线是回环结构

SPI是一个环形总线结构,如下图所示,主设备和从设备构成一个环形。在时钟SCK的作用下,主设备发送一个位到从设备,因为是环形结构,所以从设备必定会同时传送一个位到主设备。同样,主设备向从设备发送一个字节,从设备也必定会同时传送一个字节到主设备。理解了环形结构,就很容易理解下面几点:

  • SPI是全双工,同步的通信总线。
  • 主设备向从设备发送数据时,无论我们需不需要从设备返回数据,从设备都会返回数据。
  • 主设备从从设备读取一个字节数据时,为什么需要写一个字节数据到从设备:因为是环形结构,不写数据过去,对方的数据就不会被移位过来。

在这里插入图片描述

图3:SPI数据传输示意图

■ SPI主机和从机之间连接时信号不需要交叉

SPI主机和从机连接时,MOSI和MISO信号是不需要交叉连接的,因为MOSI本身就表示了主机输出、从机输入,MISO表示主机输入、从机输出,因此不能交叉连接。

在这里插入图片描述

图4:MOSI和MISO不能交叉连接

2.2.SPI的4种工作模式

SPI总线共有4种工作模式:模式0~模式3,这4种工作模式是由时钟相位和时钟极性确定的。

1.时钟极性CPOL(Clock polarity):SPI总线空闲时,时钟信号SCLK的电平称为时钟极性,有以下两种模式:

  • CPOL=0:SPI总线空闲时,时钟信号为低电平。
  • CPOL=1:SPI总线空闲时,时钟信号为高电平。

2.时钟相位CPHA(Clock phase):SPI在时钟信号SCLK第几个边沿开始采样数据,有以下两种模式:

  • CPHA=0:在第1个时钟边沿进行数据采样。
  • CPHA=1:在第2个时钟边沿进行数据采样。

时钟极性CPOL时钟相位CPHA各有2种模式,他们两两组合就形成了SPI的4种工作模式,如下表所示。

表1:SPI总线的4种工作模式
序号SPI工作模式描述备注
1模式0CPOL=0,CPHA=0重要
2模式1CPOL=0,CPHA=1
3模式2CPOL=1,CPHA=0
4模式3CPOL=1,CPHA=1重要

SPI的4种模式中,最常用的是模式0和模式3。正是由于SPI有4种工作模式,因此当我们使用SPI总线时,需要去查询SPI总线中主机设备(如单片机)和从机设备(如SPI 存储器)的数据手册,确定他们支持什么模式,从而选择适合的工作模式。

SPI的4种模式的时序图如下。

■ 时钟相位CPHA=0时的时序

在这里插入图片描述

图5:CPHA=0时SPI时序

■ 时钟相位CPHA=1时的时序

在这里插入图片描述

图6:CPHA=0时SPI时序

3.STC8A8K64S4A12系列单片机SPI介绍

STC8A8K64S4A12系列单片机片内有1个高速串行通信接口SPI接口(以下简称SPI),该接口支持两种操作模式:主模式和从模式。这样,STC8A8K64S4A12系列单片机SPI通信方式可分为3种:单主单从(一个主机设备连接一个从机设备)、互为主从(两个设备连接,设备可互为主机和从机)、单主多从(一个主机设备连接多个从机设备)。

在这里插入图片描述

图7:SPI通信方式分类

STC8A8K64S4A12系列单片机每一组SPI都有4个IO引脚供选择使用,如下表所示。

表2:单片机SPI外设引脚分配

在这里插入图片描述

☆注:独立GPIO表示开发板没有其他的电路使用这个GPIO,非独立GPIO说明开发板有其他电路用到了该GPIO。须知同一时刻只能使能一组IO口作为SPI使用。

STC8A8K64S4A12系列单片机SPI使用哪一组IO口由P_SW1外围设备切换控制寄存器的B2、B3位决定,如下图所示。

在这里插入图片描述

图8:外围设备切换控制寄存器P_SW1

☆注:一般P_SW1寄存器B2、B3位默认是0,即如果没有对P_SW1寄存器进行操作,则默认选择的SPI是P1.2、P1.3、P1.4、P1.5这一组。

二、软件设计

1.SPI相关寄存器汇集

STC8A8K64S4A12系列单片机使用SPI外设时会用到6个寄存器,如下表所示:

表3:STC8A8K64S4A12系列SPI使用寄存器汇总
序号寄存器名读/写功能描述
1P_SW1读/写外设端口切换控制寄存器1。
2SPCTL读/写SPI控制寄存器。
3SPSTAT读/写SPI状态寄存器。
4SPDAT读/写SPI数据寄存器。
5IE2读/写中断允许寄存器2。
6IP2读/写中断优先级控制寄存器2。

2.寄存器解析

2.1.SPI控制寄存器SPCTL

SPI控制寄存器控制SPI工作模式、时钟频率、使能选择等,详见下图。

在这里插入图片描述

图9:SPI控制寄存器SPCTL

2.2.SPI状态寄存器SPSTAT

SPI状态寄存器SPSTAT的B7位用来标志SPI传输完成,B6位则在SPI对数据寄存器SPDAT写操作时置1,详见下图。

在这里插入图片描述

图10:SPI状态寄存器SPSTAT

2.3.中断允许寄存器IE2

中断允许寄存器IE2中B1位用于对SPI中断的使能控制,参考下图。

在这里插入图片描述

图11:SPI中断允许寄存器

☆注:中断允许寄存器IE2还有对其他外设的中断使能控制位,所以操作该寄存器时要按位操作。

2.4.中断优先级控制寄存器

中断优先级控制寄存器IP2和IP2H中B1位组合起来用于对SPI中断的优先级进行配置,详见下图。

在这里插入图片描述

图12:中断优先级控制寄存器

☆注:中断优先级控制寄存器还有对其他外设的中断优先级控制位,所以操作这些寄存器时要按位操作。

3.SPI配置步骤

针对STC8A8K64S4A12系列单片机SPI,软件的配置过程如下:

在这里插入图片描述

图13:SPI中断方式和非中断方式软件配置步骤

4.外接FRAM存储器读写单字节实验(模拟SPI)

4.1.工程需要用到的c文件

本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。

表4:实验需要用到的c文件
序号文件名后缀功能描述
1uart.c包含与用户uart有关的用户自定义函数。
2fm25cl64b.cSPI通信及操作FRAM有关的用户自定义函数。
3delay.c包含用户自定义延时函数。

4.2.头文件引用和路径设置

■ 需要引用的头文件

#include "delay.h"  
#include "uart.h"  
#include " fm25cl64b.h"  

■ 需要包含的头文件路径

本例需要包含的头文件路径如下表:

表5:头文件包含路径
序号路径描述
1…\ Sourceuart.h、fm25cl64b.h和delay.h头文件在该路径,所以要包含。
2…\UseSTC8.h头文件在该路径,所以要包含。

MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。

在这里插入图片描述

图14:添加头文件包含路径

4.3.编写代码

首先,在fm25cl64b.c文件中编写模拟SPI方式的读写字节函数,这里的模拟SPI读字节函数与写字节函数是分开的,代码如下:

程序清单:模拟SPI写字节函数

/***************************************************************************** 
 * 描  述 : 模拟SPI写入一个字节 
 * 入  参 : uint8 date 
 * 返回值 : 无 
 ****************************************************************************/  
void SPI_WriteByte(uint8 date)  
{  
  uint8 temp,i;  
  temp = date;    
  
  for (i = 0; i < 8; i++)   
    {  
     SPI_SCK_0;  
         delay_us(10);  
     if((temp&0x80)==0x80)  
     { SPI_MOSI_1; }  
     else   
     { SPI_MOSI_0; }  
     SPI_SCK_1 ;  
         delay_us(10);  
     temp <<= 1;  
   }  
   SPI_MOSI_0;   
} 

程序清单:模拟SPI读字节函数

/*********************************************************************** 
 * 描  述 : 模拟SPI读取一个字节 
 * 入  参 : 无 
 * 返回值 : 读取uint8数据 
 ***********************************************************************/  
uint8 SPI_ReadByte(void)  
{  
  uint8 temp=0;  
  uint8 i;  
                    
  for(i = 0; i < 8; i++)  
    {  
    temp <<= 1;  
    SPI_SCK_0 ;          
    delay_us(10);  
        if(E_SPI_MISO)   
    {temp++; }  
    SPI_SCK_1 ;  
        delay_us(10);  
   }  
   return(temp);  
}

然后,编写对FRAM存储器的基本操作函数,如下表所示。

表6:FRAM相关用户函数汇集
序号函数名功能描述
1FramWriteByte向FRAM指定地址存入单字节数据。
2FramReadByte从FRAM指定地址读取单字节数据。
3FRAM_Read_Nbyte从FRAM指定地址读取多字节数据。
4FRAM_Write_Nbyte向FRAM指定地址存入多字节数据。
5FRAM_Erase_Nbyte在FRAM指定地址开始擦除指定长度的数据。

关于每个操作外部FRAM相关用户函数,下面给出详细代码。

程序清单:向指定地址存入单字节数据函数

/**************************************************************************** 
 * 描  述 : 向指定地址存入数据 
 * 入  参 : uint16 address写入的地址,uint8  da写入的数据 
 * 返回值 : 无 
 **************************************************************************/  
void FramWriteByte(uint16 address,uint8  da)  
{  
  uint8 temM,temL;  
  
  temM=(uint8)((address&0xff00)>>8);  
  temL=(uint8)(address&0x00ff);  
  
  SPI_CS_0;                              //使能器件    
  SPI_WriteByte(FM25CL64_WREN);          //写使能FRAM      
  SPI_CS_1;                              //取消片选   
  delay_80us();  
  
  SPI_CS_0;                              //使能器件   
  SPI_WriteByte(FM25CL64_WRITE);         //写数据到FRAM存储器命令  
  SPI_WriteByte(temM);                   //写存储器地址高8位  
  SPI_WriteByte(temL);                   //写存储器地址低8位  
  SPI_WriteByte(da);                     //写入要存入的数据  
  SPI_CS_1;                              //取消片选   
} 

程序清单:从指定地址读取单字节数据函数

/*************************************************************************** 
 * 描  述 : 向指定地址读取数据 
 * 入  参 : uint16 address要读取的地址 
 * 返回值 : 返回读取到的数据uint8 
 ***************************************************************************/  
uint8 FramReadByte(uint16 address)  
{  
  uint8  temp,temM,temL;  
  
  temM=(uint8)((address&0xff00)>>8);  
  temL=(uint8)(address&0x00ff);  
  
  SPI_CS_0;                           //使能器件             
  SPI_WriteByte(FM25CL64_READ);       //读存储器命令下发  
  SPI_WriteByte(temM);                //待读地址高位下发  
  SPI_WriteByte(temL);                //待读地址低位下发  
  temp = SPI_ReadByte();              //读存储器数据  
  SPI_CS_1;                           //取消片选     
      
  return temp;  
} 

程序清单:从指定地址读取多字节数据函数

/************************************************************************ 
功能描述:在指定地址开始读取多字节数据 
入口参数:pbuf:数据存储区  ReadAddr:读数据首地址  Len:要读取的字节数 
返回值:无  
*************************************************************************/  
void FRAM_Read_Nbyte(uint8 * pbuf,uint16 ReadAddr,uint16 Len)     
{  
    uint16 i;    
                                                     
    SPI_CS_0;                                          //使能器件     
    SPI_WriteByte(FM25CL64_READ);                      //发送读数据命令     
    SPI_WriteByte((uint8)((ReadAddr&0xE0)>>8));      //写入高8位址,最大地址13位
    SPI_WriteByte((uint8)ReadAddr);                  //写入低8位址  
    for(i=0;i<Len;i++)                                 //连续读取数据   
    {  
       *pbuf++=SPI_ReadByte();                         //读一个字节            
    }  
    SPI_CS_1;                                          //取消片选              
} 

程序清单:向指定地址存入多字节数据函数

/************************************************************************ 
功能描述:在指定地址开始写入多字节数据 
入口参数:pbuf:数据存储区  WriteAddr:写入数据首地址  Len:要写入的字节数 
返回值:无  
**************************************************************************/  
void FRAM_Write_Nbyte(uint8 * pbuf,uint16 WriteAddr,uint16 Len)  
{  
    uint16 i;  
      
    SPI_CS_0;                                           //使能器件     
    SPI_WriteByte(FM25CL64_WREN);                       //写使能FRAM      
    SPI_CS_1;                                           //取消片选  
      delay_80us();  
  
    SPI_CS_0;                                           //使能器件     
      SPI_WriteByte(FM25CL64_WRITE);                      //发送写数据命令     
    SPI_WriteByte((uint8)((WriteAddr&0xE0)>>8));      //写入高8位址,最大地址13位 
    SPI_WriteByte((uint8)WriteAddr);                  //写入低8位址  
      
    for(i=0;i<Len;i++)                                  //连续写入数据   
    {        
             SPI_WriteByte(pbuf[i]);                    //写入要存入的数据 
    }  
        SPI_CS_1;                                        //取消片选  
}  

程序清单:擦除指定长度的数据函数

/************************************************************************* 
功能描述:在指定地址开始擦除指定长度的数据 
入口参数:EraseAddr:擦除首地址  Len:要擦除的字节数 
返回值:无  
**************************************************************************/  
void FRAM_Erase_Nbyte(uint16 EraseAddr,uint16 Len)  
{  
    uint16 i;  
      
    SPI_CS_0;                                           //使能器件     
    SPI_WriteByte(FM25CL64_WREN);                       //写使能FRAM      
    SPI_CS_1;                                           //取消片选  
    delay_80us();  
  
    SPI_CS_0;                                           //使能器件     
    SPI_WriteByte(FM25CL64_WRITE);                    //发送写数据命令     
    SPI_WriteByte((uint8)((EraseAddr&0xE0)>>8));      //写入高8位址,最大地址13位 
    SPI_WriteByte((uint8)EraseAddr);                  //写入低8位址  
      
    for(i=0;i<Len;i++)                                  //连续擦除数据   
    {        
             SPI_WriteByte(0x00);                     //擦除数据即写入0x00  
    }  
        SPI_CS_1;                                           //取消片选  
} 

最后,在主函数中对串口1进行初始化,并通过串口1发送不同的命令实现对单片机片外FRAM的单字节读、写及擦除等操作。

代码清单:主函数

int main()  
{  
    uint8   Temp;  
      
    P3M1 &= 0xFE;   P3M0 &= 0xFE;                     //设置P3.0为准双向口  
    P3M1 &= 0xFD;   P3M0 |= 0x02;                     //设置P3.1为推挽输出  
      
    SPI_CS_1;                                     //SPI使能引脚初始化  
    Uart1_Init();                                 //串口1初始化    
    EA = 1;                                        //使能总中断  
   delay_ms(10);                                 //初始化后延时  
      
  while (1)  
    {  
     if(WriteFLAG)                        //写模式  
         {  
              WriteFLAG=0;                      //写标志变量清零,发送一次  
              FramWriteByte(0x0050,0x33);       //向FRAM地址0x0050中写入单字节数据0x33  
           SendDataByUart1(0x33);            //串口1发送数据0x33表示写操作完成  
         }  
         if(ReadFLAG)                         //读模式  
         {  
              ReadFLAG=0;                       //读标志变量清零,发送一次  
              Temp=FramReadByte(0x0050);        //从FRAM地址0x0050读取单字节数据并赋值给变量Temp  
           SendDataByUart1(Temp);              //串口1发送Temp变量值(即读取的单字节数据)  
         }    
         if(ClearFLAG)                        //擦除模式  
         {  
              ClearFLAG=0;                      //清除标志变量清零,发送一次  
              FRAM_Erase_Nbyte(0x0050,1);       //擦除FRAM地址0x0050的数据  
           SendDataByUart1(0x00);            //串口1发送数据0x00表示擦除完成  
         }     
    }  
} 

4.4.硬件连接

在这里插入图片描述

图15:开发板连接图

5.外接FRAM存储器读写多字节实验(模拟SPI)

5.1.编写代码

首先,在fm25cl64b.c文件中编写模拟SPI方式的读写字节函数和对FRAM存储器的基本操作函数。请参考“实验2-15-1:外接FRAM存储器读写单字节实验(模拟SPI)”部分。

然后,在主函数中对串口1进行初始化,并通过串口1发送不同的命令实现对单片机片外FRAM的多字节读、写及擦除等操作。

代码清单:主函数

int main()  
{  
    P3M1 &= 0xFE;   P3M0 &= 0xFE;                     //设置P3.0为准双向口  
    P3M1 &= 0xFD;   P3M0 |= 0x02;                     //设置P3.1为推挽输出  
      
    SPI_CS_1;                                     //SPI使能引脚初始化  
    Uart1_Init();                                 //串口1初始化    
    EA = 1;                                       //使能总中断  
  delay_ms(10);                                 //初始化后延时  
      
  while(1)  
  {            
     if(WriteFLAG)                                     //写模式  
         {                
              WriteFLAG=0;                                   //写标志变量清零,发送一次  
              FRAM_Write_Nbyte(FRAM_Test_Write,0x0000,10);   //向FRAM地址0x0000中写入FRAM_Test_Write数组中10个字节数据  
        SendDataByUart1(0x33);                         //串口1发送数据0x33表示写操作完成  
         }  
         if(ReadFLAG)                                      //读模式  
         {  
              ReadFLAG=0;                                    //读标志变量清零,发送一次  
              FRAM_Read_Nbyte(FRAM_Test_Read,0x0000,10) ;    //从FRAM地址0x0000读取10个字节数据存放数组FRAM_Test_Read中  
              SendStringByUart1_n(FRAM_Test_Read,10);        //串口1发送数组FRAM_Test_Read中的值(即读取的多字节数据)  
         }    
         if(ClearFLAG)                                     //清除模式  
         {  
              ClearFLAG=0;                                   //清除标志变量清零,发送一次  
              FRAM_Erase_Nbyte(0x0000,10);         //擦除FRAM地址0x0000开始的10个字节长度的数据  
           SendDataByUart1(0x00);                         //串口1发送数据0x00表示擦除完成  
         }     
    }  
}  

5.2.硬件连接

在这里插入图片描述

图16:开发板连接图

6.外接FRAM存储器读写单字节实验(硬件SPI)

6.1.工程需要用到的c文件

本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。

表7:实验需要用到的c文件
序号文件名后缀功能描述
1uart.c包含与用户uart有关的用户自定义函数
2fm25cl64b.cSPI通信及操作FRAM有关的用户自定义函数。
3delay.c包含用户自定义延时函数。

6.2.头文件引用和路径设置

■ 需要引用的头文件

#include "delay.h"  
#include "uart.h"  
#include " fm25cl64b.h"  

■ 需要包含的头文件路径

本例需要包含的头文件路径如下表:

表8:头文件包含路径
序号路径描述
1…\ Sourceuart.h、fm25cl64b.h和delay.h头文件在该路径,所以要包含。
2…\UserSTC8.h头文件在该路径,所以要包含。

MDK中点击魔术棒,打开工程配置窗口,按照下图所示添加头文件包含路径。

在这里插入图片描述

图17:添加头文件包含路径

6.3.编写代码

首先,在fm25cl64b.c文件中对硬件SPI进行初始化,并编写硬件SPI的读写字节函数,代码如下:

程序清单:硬件SPI初始化函数

/************************************************************************************** 
 * 描  述 : 硬件SPI初始化 
 * 入  参 : 无 
 * 返回值 : 无 
 **************************************************************************************/  
void Init_SPI(void)            
{  
     P_SW1 |=0X08;                         //将 SPI 调整到 P7.4 P7.5 P7.6  P7.7   
     P_SW1 &=0XFB;                         //将 SPI 调整到 P7.4 P7.5 P7.6  P7.7   
    SPDAT = 0;  
    SPSTAT = SPIF | WCOL;               //清除SPI状态位  
    SPCTL = SPEN | MSTR | SSIG;         //主机模式        
}  

程序清单:硬件SPI读写字节函数

/*********************************************************************** 
 * 描  述 : 硬件SPI写入一个字节,并返回一个值 
 * 入  参 : uint8 date 
 * 返回值 : 无 
 ***********************************************************************/  
uint8 SPI_SendByte(uint8 SPI_SendData)  
{  
  SPDAT = SPI_SendData;        //触发SPI发送数据  
  while (!(SPSTAT & SPIF));    //等待发送完成  
  SPSTAT = SPIF | WCOL;        //清除SPI状态位  
  return SPDAT;                //返回SPI数据  
} 

然后,编写对FRAM存储器的基本操作函数,如下表所示。

表9:FRAM相关用户函数汇集
序号函数名功能描述
1FramWriteByte向FRAM指定地址存入单字节数据。
2FramReadByte从FRAM指定地址读取单字节数据。
3FRAM_Read_Nbyte从FRAM指定地址读取多字节数据。
4FRAM_Write_Nbyte向FRAM指定地址存入多字节数据。
5FRAM_Erase_Nbyte在FRAM指定地址开始擦除指定长度的数据。

关于每个操作外部FRAM相关用户函数,下面给出详细代码。

程序清单:向指定地址存入单字节数据函数

/************************************************************************** 
 * 描  述 : 向指定地址存入数据 
 * 入  参 : uint16 address写入的地址,uint8  da写入的数据 
 * 返回值 : 无 
 **************************************************************************/  
void FramWriteByte(uint16 address,uint8  da)  
{  
  uint8 temM,temL;  
  
  temM=(uint8)((address&0xff00)>>8);  
  temL=(uint8)(address&0x00ff);  
  
  SPI_CS_0;                    //使能器件   
  SPI_SendByte(WREN);          //写使能FRAM      
  SPI_CS_1;                    //取消片选   
  delay_80us();  
  
  SPI_CS_0;                    //使能器件   
  SPI_SendByte(WRITEE);        //写数据到FRAM存储器命令  
  SPI_SendByte(temM);          //写存储器地址高8位  
  SPI_SendByte(temL);          //写存储器地址低8位  
  SPI_SendByte(da);            //写入要存入的数据  
  SPI_CS_1;                    //取消片选   
}  

程序清单:从指定地址读取单字节数据函数

/************************************************************************** 
 * 描  述 : 向指定地址读取数据 
 * 入  参 : uint16 address要读取的地址 
 * 返回值 : 返回读取到的数据uint8 
 ***************************************************************************/  
uint8 FramReadByte(uint16 address)  
{  
  uint8  temp,temM,temL;  
  
  temM=(uint8)((address&0xff00)>>8);  
  temL=(uint8)(address&0x00ff);  
  
  SPI_CS_0;                      //使能器件            
  SPI_SendByte(READD);           //读存储器命令下发  
  SPI_SendByte(temM);            //待读地址高位下发  
  SPI_SendByte(temL);            //待读地址低位下发  
  temp = SPI_SendByte(0xFF);     //读存储器数据  
  SPI_CS_1;                      //取消片选    
      
  return temp;  
}

程序清单:从指定地址读取多字节数据函数

/************************************************************************** 
功能描述:在指定地址开始读取多字节数据 
入口参数:pbuf:数据存储区  ReadAddr:读数据首地址  Len:要读取的字节数 
返回值:无  
**************************************************************************/  
void FRAM_Read_Nbyte(uint8 * pbuf,uint16 ReadAddr,uint16 Len)     
{  
    uint16 i;    
                                                     
    SPI_CS_0;                                          //使能器件     
    SPI_SendByte(FM25CL64_READ);                       //发送读数据命令     
    SPI_SendByte((uint8)((ReadAddr&0xE0)>>8));       //写入高8位址,最大地址13位
    SPI_SendByte((uint8)ReadAddr);                     //写入低8位址  
    for(i=0;i<Len;i++)                                 //连续读取数据   
    {  
       *pbuf++=SPI_SendByte(0xFF);                     //读一个字节            
    }  
    SPI_CS_1;                                          //取消片选              
} 

程序清单:向指定地址存入多字节数据函数

/************************************************************************* 
功能描述:在指定地址开始写入多字节数据 
入口参数:pbuf:数据存储区  WriteAddr:写入数据首地址  Len:要写入的字节数 
返回值:无  
**********************************************************************/  
void FRAM_Write_Nbyte(uint8 * pbuf,uint16 WriteAddr,uint16 Len)  
{  
    uint16 i;  
      
    SPI_CS_0;                                           //使能器件     
    SPI_SendByte(FM25CL64_WREN);                        //写使能FRAM      
    SPI_CS_1;                                           //取消片选  
      delay_80us();  
  
    SPI_CS_0;                                           //使能器件     
    SPI_SendByte(FM25CL64_WRITE);                       //发送写数据命令     
    SPI_SendByte((uint8)((WriteAddr&0xE0)>>8));      //写入高8位址,最大地址13位 
    SPI_SendByte((uint8)WriteAddr);                     //写入低8位址  
      
    for(i=0;i<Len;i++)                                  //连续写入数据   
    {        
             SPI_SendByte(pbuf[i]);                    //写入要存入的数据
    }  
        SPI_CS_1;                                           //取消片选  
} 

程序清单:擦除指定长度的数据函数

/************************************************************************* 
功能描述:在指定地址开始擦除指定长度的数据 
入口参数:EraseAddr:擦除首地址  Len:要擦除的字节数 
返回值:无  
****************************************************************************/  
void FRAM_Erase_Nbyte(uint16 EraseAddr,uint16 Len)  
{  
    uint16 i;  
      
    SPI_CS_0;                                           //使能器件     
    SPI_SendByte(FM25CL64_WREN);                        //写使能FRAM      
    SPI_CS_1;                                           //取消片选  
      delay_80us();  
  
    SPI_CS_0;                                           //使能器件     
      SPI_SendByte(FM25CL64_WRITE);                       //发送写数据命令     
    SPI_SendByte((uint8)((EraseAddr&0xE0)>>8));       //写入高8位址,最大地址13位
    SPI_SendByte((uint8)EraseAddr);                     //写入低8位址  
      
    for(i=0;i<Len;i++)                                  //连续擦除数据   
    {        
             SPI_SendByte(0x00);                       //擦除数据即写入0x00  
    }  
        SPI_CS_1;                                       //取消片选  
} 

最后,在主函数中对串口1和SPI进行初始化,并通过串口1发送不同的命令实现对单片机片外FRAM的单字节读、写及擦除等操作。

代码清单:主函数

int main()  
{  
    uint8   Temp;  
      
    P3M1 &= 0xFE;   P3M0 &= 0xFE;                     //设置P3.0为准双向口  
    P3M1 &= 0xFD;   P3M0 |= 0x02;                     //设置P3.1为推挽输出  
      
    SPI_CS_1;                                     //SPI使能引脚初始化  
    Init_SPI();                                     //初始化SPI  
    Uart1_Init();                                 //串口1初始化    
    EA = 1;                                       //使能总中断  
  delay_ms(10);                                 //初始化后延时  
      
  while (1)  
    {  
     if(WriteFLAG)                        //写模式  
         {  
              WriteFLAG=0;                      //写标志变量清零,发送一次  
              FramWriteByte(0x0050,0x33);       //向FRAM地址0x0050中写入单字节数据0x33  
        SendDataByUart1(0x33);            //串口1发送数据0x33表示写操作完成  
         }  
         if(ReadFLAG)                         //读模式  
         {  
              ReadFLAG=0;                       //读标志变量清零,发送一次  
              Temp=FramReadByte(0x0050);        //从FRAM地址0x0050读取单字节数据并赋值给变量Temp  
        SendDataByUart1(Temp);            //串口1发送Temp变量值(即读取的单字节数据)  
         }    
         if(ClearFLAG)                        //擦除模式  
         {  
              ClearFLAG=0;                      //清除标志变量清零,发送一次  
              FRAM_Erase_Nbyte(0x0050,1);       //擦除FRAM地址0x0050的数据  
        SendDataByUart1(0x00);            //串口1发送数据0x00表示擦除完成  
         }     
    }  
}  

6.4.硬件连接

在这里插入图片描述

图18:开发板连接图

7.外接FRAM存储器读写多字节实验(硬件SPI)

7.1.编写代码

首先,在fm25cl64b.c文件中编写硬件SPI方式的读写字节函数和对FRAM存储器的基本操作函数。请参考“实验2-15-3:外接FRAM存储器读写单字节实验(硬件SPI)”部分。

然后,在主函数中对串口1和SPI进行初始化,并通过串口1发送不同的命令实现对单片机片外FRAM的多字节读、写及擦除等操作。

代码清单:主函数

int main()  
{  
    P3M1 &= 0xFE;   P3M0 &= 0xFE;                     //设置P3.0为准双向口  
    P3M1 &= 0xFD;   P3M0 |= 0x02;                     //设置P3.1为推挽输出  
      
    SPI_CS_1;                                     //SPI使能引脚初始化  
    Init_SPI();                                     //初始化SPI  
    Uart1_Init();                                 //串口1初始化    
    EA = 1;                                       //使能总中断  
   delay_ms(10);                                 //初始化后延时  
      
  while(1)  
  {            
     if(WriteFLAG)                                     //写模式  
         {                
              WriteFLAG=0;                                   //写标志变量清零,发送一次  
              FRAM_Write_Nbyte(FRAM_Test_Write,0x0000,10);   //向FRAM地址0x0000中写入FRAM_Test_Write数组中10个字节数据  
        SendDataByUart1(0x33);                         //串口1发送数据0x33表示写操作完成  
         }  
         if(ReadFLAG)                                      //读模式  
         {  
              ReadFLAG=0;                                    //读标志变量清零,发送一次  
              FRAM_Read_Nbyte(FRAM_Test_Read,0x0000,10) ;    //从FRAM地址0x0000读取10个字节数据存放数组FRAM_Test_Read中  
              SendStringByUart1_n(FRAM_Test_Read,10);        //串口1发送数组FRAM_Test_Read中的值(即读取的多字节数据)  
         }    
         if(ClearFLAG)                                     //清除模式  
         {  
              ClearFLAG=0;                                   //清除标志变量清零,发送一次  
              FRAM_Erase_Nbyte(0x0000,10);              //擦除FRAM地址0x0000开始的10个字节长度的数据  
           SendDataByUart1(0x00);                         //串口1发送数据0x00表示擦除完成  
         }     
    }  
}

7.2.硬件连接

在这里插入图片描述

图19:开发板连接图

总结

以上是今天要讲的内容,希望对大家有帮助,如果有啥不明白的,欢迎讨论哦!

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

电子友人张

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值