1.SPI通信简介:串行外围设备接口(Serial Peripheral Interface)是由时钟线SCK、MOSI(master output slave input)、MISO(master input slave output)、片选CS四条线组成的一种全双工通信协议。
SPI通过时钟线SCK的状态来进行不同的操作,比如当SCK从0到1(低电平到高电平)时,开始进行数据传输,即此时开始读取MOSI/MISO的状态(高低电平)。
SPI支持一主多从,从机通过片选CS进行选择,所有的从机都有自己独立的CS线,但是所有的其他线都是共享的,比如,所有的SCK线都是通过一更总线连接到MCU上。当CS位低电平0时,表示当前设备被选择。
MOSI线是主机输入数据,从机接受数据。MISO是从机输出数据,主机读取数据。因为SPI具有两根数据线,因此可以进行全双工通信,同一时刻可以进行数据发送和数据接受。
SPI的时序图如下:
2.EEPROM
电可擦除可编程只读存储器EEPROM(Elctrically Erasable Programmable Read-Only Memory)是一种掉电非易失性的存储器,通常是基于SPI通信协议与主机进行数据传输。
EEPROM的引脚定义入下:
EEPROM的指令集如下:
3.本文利用按键进行数据加减,将数据写入到EEPROM中,并且从EEPROM中读取数据,显示在数码管中。仿真电路图如下:
代码:
#include <reg52.h>
#define EEPROM_Address_W 0x02 //从指定地址开始写
#define EEPROM_Address_R 0X03 //从指定地址开始读
#define EEPROM_Address_ENABLE 0x06 //开启写使能命令
#define EEPROM_Address_DISABLE 0x04 //关闭写使能命令
#define EEPROM_Address_REGISTER 0x05 //读取寄存器的状态(状态寄存器的值)
typedef unsigned char uchar;
typedef unsigned int uint;
sbit KEY1 = P1^5; //按键
sbit KEY2 = P1^6;
sbit SCK = P3^1; //时钟线
sbit SI = P3^2; //主机输出,从机输入
sbit SO = P3^3; //主机输入,从机输出
sbit CS = P3^4; //片选线,选择使用哪一个从机
uchar num = 3;
//SPI写应该Byte函数
void SPI_WriteByte(uchar Byte)
{
uchar i;
for(i = 0;i < 8;i++)
{
//SCK从低电平到高电平(上升沿)时传输数据
SCK = 0;
if(Byte & 0x80) //取出最高为,每次只能传输一个bit的数据
{
SI = 1;
}
else
{
SI = 0;
}
Byte <<= 1;
SCK = 1;
}
SCK = 0;
}
//SPI读一个Byte函数
uchar SPI_ReadByte(void)
{
uchar i,Byte;
SCK = 0;
for(i = 0;i < 8;i++)
{
SCK = 1;
Byte <<= 1;
if(SO)
{
Byte ++;
}
SCK = 0;
}
return Byte;
}
//EEPROM开启写使能函数
void EEPROM_Write_ENABLE(void)
{
CS = 1;
CS = 0;
SPI_WriteByte(EEPROM_Address_ENABLE);
CS = 1;
}
//EEPROM关闭写使能函数
void EEPROM_Write_DISABLE(void)
{
CS = 1;
CS = 0;
SPI_WriteByte(EEPROM_Address_DISABLE);
CS = 1;
}
//从EEPROM中读取数据
uchar EEPROM_Read(uchar HW_Address,uchar SW_Address)
{
uchar date = 0;
CS = 1;
CS = 0;
SPI_WriteByte(HW_Address);
SPI_WriteByte(SW_Address);
date = SPI_ReadByte();
CS = 1;
return date;
}
//往EEPROM中写数据函数
void EEPROM_Write(uchar HW_Address,uchar SW_Address,uchar date)
{
//HW_Address:EEPROM硬件地址
//SW_Address: EEPROM的软件地址,即写出内存的地址
uchar status = 0x01;
EEPROM_Write_ENABLE(); //开启写使能
CS = 1;
CS = 0;
SPI_WriteByte(HW_Address);
SPI_WriteByte(SW_Address);
SPI_WriteByte(date);
CS = 1;
//读取EEPROM状态寄存器的最低为,当状态寄存器的最低位为1表示还未写完
while(1)
{
CS = 1;
CS = 0;
SPI_WriteByte(EEPROM_Address_REGISTER);
status = SPI_ReadByte();
if((status & 0x01) == 0)
{
break;
}
CS = 1;
}
EEPROM_Write_DISABLE(); //关闭写使能
}
//扫描按键
void get_key()
{
if(KEY1 == 0)
{
num ++;
if(num >= 9) //num只能是0~9
{
num = 9;
while(KEY1 == 0);
}
}
else if(KEY2 == 0)
{
num --;
if(num <= 0)
{
num = 0;
}
while(KEY2 == 0);
}
}
//数码管显示,只能显示0~9
void display(uchar date)
{
// P0 = date & 0x0f;
P2 = date & 0x0f;
}
//主函数
void main(void)
{
// display(num);
num = EEPROM_Read(EEPROM_Address_R,0x00);
while(1)
{
display(num);
EEPROM_Write(EEPROM_Address_W,0x00,num);
get_key();
}
}
4.运行结果:
5.总结:SPI通信时只需要四根线:SCK、MOSI、MISO、CS即可。 SPI具有通信简单、数据传输速率快的优点。但是,SPI没有应答确认机制,因此,相比较IIC通信在数据可靠性上存在不足。