前言:
目前各位老铁们对“delayc文件主要包含哪些函数并简要说明各函数的作用”可能比较关怀,各位老铁们都需要学习一些“delayc文件主要包含哪些函数并简要说明各函数的作用”的相关内容。那么小编同时在网上网罗了一些对于“delayc文件主要包含哪些函数并简要说明各函数的作用””的相关资讯,希望咱们能喜欢,大家快快来学习一下吧!文章目录前言一、硬件设计1.FRAM铁电存储器介绍2.SPI总线原理2.1.接口信号定义2.2.SPI的4种工作模式3.STC8A8K64S4A12系列单片机SPI介绍二、软件设计1.SPI相关寄存器汇集2.寄存器解析2.1.SPI控制寄存器SPCTL2.2.SPI状态寄存器SPSTAT2.3.中断允许寄存器IE22.4.中断优先级控制寄存器3.SPI配置步骤4.外接FRAM存储器读写单字节实验(模拟SPI)4.1.工程需要用到的c文件4.2.头文件引用和路径设置4.3.编写代码4.4.硬件连接5.外接FRAM存储器读写多字节实验(模拟SPI)5.1.编写代码5.2.硬件连接6.外接FRAM存储器读写单字节实验(硬件SPI)6.1.工程需要用到的c文件6.2.头文件引用和路径设置6.3.编写代码6.4.硬件连接7.外接FRAM存储器读写多字节实验(硬件SPI)7.1.编写代码7.2.硬件连接总结前言
今天介绍下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总线接口包括以下四种信号:
MOSI(Master Output,Slave Input):主器件数据输出,从器件数据输入。MISO(Master Input, Slave Output):主器件数据输入,从器件数据输出。SCK(Serial Clock):有时也称为SCLK,时钟信号,由主器件产生。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
模式0
CPOL=0,CPHA=0
重要
2
模式1
CPOL=0,CPHA=1
3
模式2
CPOL=1,CPHA=0
4
模式3
CPOL=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使用寄存器汇总
序号
寄存器名
读/写
功能描述
1
P_SW1
读/写
外设端口切换控制寄存器1。
2
SPCTL
读/写
SPI控制寄存器。
3
SPSTAT
读/写
SPI状态寄存器。
4
SPDAT
读/写
SPI数据寄存器。
5
IE2
读/写
中断允许寄存器2。
6
IP2
读/写
中断优先级控制寄存器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文件
序号
文件名
后缀
功能描述
1
uart
.c
包含与用户uart有关的用户自定义函数。
2
fm25cl64b
.c
SPI通信及操作FRAM有关的用户自定义函数。
3
delay
.c
包含用户自定义延时函数。
4.2.头文件引用和路径设置
■ 需要引用的头文件
#include "delay.h" #include "uart.h" #include " fm25cl64b.h"
■ 需要包含的头文件路径
本例需要包含的头文件路径如下表:
表5:头文件包含路径
序号
路径
描述
1
…\ Source
uart.h、fm25cl64b.h和delay.h头文件在该路径,所以要包含。
2
…\Use
STC8.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相关用户函数汇集
序号
函数名
功能描述
1
FramWriteByte
向FRAM指定地址存入单字节数据。
2
FramReadByte
从FRAM指定地址读取单字节数据。
3
FRAM_Read_Nbyte
从FRAM指定地址读取多字节数据。
4
FRAM_Write_Nbyte
向FRAM指定地址存入多字节数据。
5
FRAM_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文件
序号
文件名
后缀
功能描述
1
uart
.c
包含与用户uart有关的用户自定义函数
2
fm25cl64b
.c
SPI通信及操作FRAM有关的用户自定义函数。
3
delay
.c
包含用户自定义延时函数。
6.2.头文件引用和路径设置
■ 需要引用的头文件
#include "delay.h" #include "uart.h" #include " fm25cl64b.h"
■ 需要包含的头文件路径
本例需要包含的头文件路径如下表:
表8:头文件包含路径
序号
路径
描述
1
…\ Source
uart.h、fm25cl64b.h和delay.h头文件在该路径,所以要包含。
2
…\User
STC8.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相关用户函数汇集
序号
函数名
功能描述
1
FramWriteByte
向FRAM指定地址存入单字节数据。
2
FramReadByte
从FRAM指定地址读取单字节数据。
3
FRAM_Read_Nbyte
从FRAM指定地址读取多字节数据。
4
FRAM_Write_Nbyte
向FRAM指定地址存入多字节数据。
5
FRAM_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:开发板连接图
总结
以上是今天要讲的内容,希望对大家有帮助,如果有啥不明白的,欢迎讨论哦!