1.简介
SPI( Serial Peripheral Interface)是 Motorola公司于1979年推出的一种高速全双工同步串行通信协议,它由一个主设备 Maste)和一个或多个从设备(Save)组成,其中主设备启动与从设备的同步通信,从而完成数据的交换。
其有4根引脚:MOSI、MISO、CS、CLOCK
MOSI:主机输出从机输入
MISO:主机输入从机输出
CS:片选,主机需要启动哪个从机,那就拉低该从机的片选引脚。
CLOCK:时钟线。
2.时序
说到时序,就不得不说SPI协议的时钟信号。主设备根据交换的数据来产生相应的时钟脉冲,时钟脉冲又组成了时钟信号。时钟信号通过时钟极性与时钟相位来控制主机与从机之间的数据什么时候被采样,什么时候发生交换。
时钟极性:
为0时,总线空闲时为低电平;为1时,总线空闲时为高电平。
时钟相位:
与时钟极性相同时,数据在下降沿被采样,数据在上升沿发生交换。
与时钟极性不同时,数据在上升沿被采样,数据在下降沿发生交换。
源码 以51单片机控制ds1302为例
ds1302.c
#include"ds1302.h"
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
uchar code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
uchar code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};//7位 + 位读写位
//---DS1302时钟初始化2016年5月7日星期六12点00分00秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
uchar TIME[7] = {0, 0, 0x12, 0x07, 0x05, 0x10, 0x22};
/*从ds1302发送1字节数据*/
void ds1302_write(uchar addr, uchar dat)
{
uchar n;
RST = 0;//先将SCLK置低电平。
_nop_();
SCLK = 0;//先将SCLK置低电平。
_nop_();
RST = 1; //然后将RST(CE)置高电平。
_nop_();
for (n=0; n<8; n++)//开始传送八位地址命令
{
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
for (n=0; n<8; n++)//写入8位数据
{
DSIO = dat & 0x01;
dat >>= 1;
SCLK = 1;//数据在上升沿时,DS1302读取数据
_nop_();
SCLK = 0;
_nop_();
}
RST = 0;//传送数据结束
_nop_();
}
/*从ds1302读取1字节数据*/
u8 ds1302_read_byte(u8 addr)
{
u8 n = 0;
u8 datas = 0,datas1 = 0;
RST = 0;
_nop_();
SCLK = 0;
_nop_();
RST = 1;
_nop_();
for(n=0;n<8;n++)//LSB
{
DSIO = addr & 0x01;//数据从低位开始传送
addr >>= 1;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
_nop_();
for(n=0;n<8;n++)//LSB
{
datas1 = DSIO;
datas |= datas1<<n;
SCLK = 1;
_nop_();
SCLK = 0;
_nop_();
}
_nop_();
RST = 0;
_nop_();
//以下为DS1302复位的稳定时间,必须的。
SCLK = 1;
_nop_();
DSIO = 0;
_nop_();
DSIO = 1;
_nop_();
return datas;
}
/*初始化DS1302,设置初始时间,要先关闭写时保护,再写入对应地址的时间值,再开启写时保护*/
void ds1302_set_time()
{
uchar n;
ds1302_write(0x8E,0X00); //禁止写保护,就是关闭写保护功能
for (n=0; n<7; n++)//写入7个字节的时钟信号:分秒时日月周年
{
ds1302_write(WRITE_RTC_ADDR[n],TIME[n]);
}
ds1302_write(0x8E,0x80); //打开写保护功能
}
/*读取时钟信息*/
void ds1302_read_time()
{
uchar n;
for (n=0; n<7; n++)//读取7个字节的时钟信号:分秒时日月周年
{
TIME[n] = ds1302_read_byte(READ_RTC_ADDR[n]);
}
}
备注