嵌入式单片机基础篇(三十五)之SPI通信以及51单片机程序
嵌入式单片机基础篇(三十五)之SPI通信以及51单片机程序
SPI通信以及51单片机程序
SPI通信协议:
1、简而言之:
(1)利用时钟脉冲得上升沿和下降沿来实现数据传输。
(2)数据传输方式为字节高位在前,低位在后传输。
(3)标准SPI协议为4线制传输数据,4条信号线分别为:
MISO 主设备数据输入,从设备数据输出。
MOSI 主设备数据输出,从设备数据输入。
SCLK 时钟信号,由主设备产生。
CS 从设备片选信号,由主设备控制(一般低电平有效)。
(4)SPI内部结构简明图如下:
(5)由上图可以看出,SPI接口传输数据的方式是主机发送一字节数据的最高位的同时也会接收到从机的一字节数据的最高位并放在自己的最低位,从机亦然。
(6)如果主机在时钟信号的上升沿接收数据,那么主机在时钟信号的下降沿就会发送数据。
(7)标准的SPI协议为高速、全双工、同步的串行通信协议。
(8)四线制的SPI为标准的SPI接口,同时收发数据;三线制或二线制的SPI为非标准的SPI接口,一般使用SCL时钟信号线、片选线CS、和数据信号线DIO或片选信号线直接接地,只有SCL时钟信号线和数据线DIO。
(9)物理拓扑图:
2、传输模式:
(1)CPOL(Clock Polarity,时钟极性)表示SCK在空闲时为高电平还是低电平。当CPOL=0,SCK空闲时为低电平,当CPOL=1,SCK空闲时为高电平。
(2)CPHA(Clock Phase,时钟相位)表示SCK在第几个时钟边缘采样数据。当CPHA=0,在SCK第一个边沿采样数据,当CPHA=1,在SCK第二个边沿采样数据。(所谓的采样数据也就是接收数据)
(3)根据时钟的极性与相位的不同,SPI的传输模式可以分为4种模式,如下表:
(4)SPI的传输模式一般由从机决定。
3、51单片机模拟SPI读写单字节数据程序:
unsigned char SPI_WriteReadByte(unsigned char dat)
{
unsigned char i = 0;
unsigned char temp = 0;
unsigned char read_data = 0x00;
// SCK=0;
for(i=0;i<8;i++) {SCK=0;temp=((dat&0x80)==0x80)?1:0;dat= dat<<1; SI=temp;SCK=1;read_data <<=1;read_data|=(unsigned char)SO; }
// SCK=1;
return read_data;
}
4、51单片机模拟SPI通信协议控制25AA040读写数据完整程序:
#include <reg51.h> //包含单片机寄存器的头文件
#include <intrins.h> //包含_nop_()函数定义的头文件
sbit SCK=P3^4; //将SCK位定义为P3.4引脚
sbit SI=P3^5; //将SI位定义为P3.5引脚
sbit SO=P3^6; //将SO位定义为P3.6引脚
sbit CS=P3^7; //将CS定义为P3.7引脚#define WREN 0x06 //写使能锁存器允许
#define WRDI 0x04 //写使能锁存器禁止
#define READ 0x03 //读出
#define WRITE 0x02 //写入
void delay1ms()
{unsigned char i,j; for(i=0;i<10;i++)for(j=0;j<33;j++); }void delaynms(unsigned char n){unsigned char i;for(i=0;i<n;i++)delay1ms();}
unsigned char SPI_WriteReadByte(unsigned char dat)
{
unsigned char i = 0;
unsigned char temp = 0;
unsigned char read_data = 0x00;
// SCK=0;
for(i=0;i<8;i++) {SCK=0;temp=((dat&0x80)==0x80)?1:0;dat= dat<<1; SI=temp;SCK=1;read_data <<=1;read_data|=(unsigned char)SO; }
// SCK=1;
return read_data;
}
unsigned char WriteSet(unsigned char dat,unsigned char addr)
{unsigned char readdat;SCK=0; //将SCK置于已知状态CS=0; //拉低CS,选中X5045SPI_WriteReadByte(WREN); //写使能锁存器允许CS=1; //拉高CSCS=0; //重新拉低CS,否则下面的写入指令将被丢弃SPI_WriteReadByte(WRITE); //写入指令SPI_WriteReadByte(addr); //写入指定地址SPI_WriteReadByte(dat); //写入数据CS=1; //拉高CSSCK=0; //将SCK置于已知状态return readdat;
}unsigned char ReadSet(unsigned char addr)
{unsigned char dat;SCK=0; //将SCK置于已知状态CS=0; //拉低CS,选中X5045SPI_WriteReadByte(READ); //开始读SPI_WriteReadByte(addr); //写入指定地址dat=SPI_WriteReadByte(addr); //读出数据CS=1; //拉高CSSCK=0; //将SCK置于已知状态return dat; //返回读出的数据}void main(void)
{ while(1){WriteSet(0xaa,0x10); //将数据“0xaa”写入第一个X5045的指定地址“0x10”delaynms(10); //X5045的写入周期为约10msP1=ReadSet(0x10); //将数据从第一个X5045中的指定地址读出来}
}
5、51单片机模拟SPI通信协议控制25AA040电路图:
6、25AA040手册:
25AA040手册