历史上的今天
返回首页

历史上的今天

今天是:2026年03月24日(星期二)

正在发生

2023年03月24日 | 51单片机 | SPI协议与应用实例

2023-03-24 来源:zhihu

简介:

  • 串行外围设备接口

  • 全双工三线同步,可以同时发出和接收串行数据

  • 采用主从(Master Slave)架构,支持多Slave模式应用,一般仅支持单Slave

  • 时钟由Master控制,在时钟移位脉冲下,数据按位传输,高位在前,低位在后

  • 目前应用中可以达到几Mbps的水平

  • 优点:与普通的串行设备相比,可以按位传输,甚至可以暂停。当没有时钟跳变时,从设备不采集和传送数据。不需要寻址操作。全双工通信。

  • 缺点:没有应答机制确认。

特点:

  • 提供频率可编程时钟

  • 发送结束、中断标志;写冲突保护

  • 总线竞争保护

  • SPI总线工作的4种工作方式中,使用最广泛的是SPI0和SPI3方式

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

信号线情况:



  • SCLK提供时钟脉冲,SDI/SDO基于此脉冲按位传输。当处于上升沿模式时,输出:通过SDO线在时钟上升沿时输出,在紧接着的下降沿被读取。输入同理。

  • SS/CS是片选信号线,只有片选信号为使能信号时,对芯片的操作才有效,所以可以在同一总线上连接多个SPI设备

  • SDI:slave → master,从机要发送给主机的数据

  • SDO:master → slave,主机要发送给从机的数据

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

连接方式:

  • 级联方式:此时所有设备的CS端都连在一起,只要选中一个设备,则全选。可以作为一个设备进行处理。



  • 独立连接方式:设备独立操作,为被选通的从设备均处于高阻隔离状态。



- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

工作模式:


SPI模式CPOL极性CPHA相位说明
000第一个边沿上升沿
101第二个边沿下降沿
210第一个边沿下降沿
311第二个边沿上升沿


CPOL=0:SCLK有效时为高电平(active-high)

CPOL=1:SCLK有效时为低电平(active-low)

CPHA=0:表示第一个边沿

CPHA=1:表示第二个边沿

Toggling edge为切换边沿,输出信号

Sampling edge为采样边沿,输入信号



时序图:





- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

SPI协议举例

  • 主机8位寄存器存放的是1010 1010,从机存放的是0101 0101,将主从机数据交换

  • SDI:slave → master

  • SDO:master → slave

  • 上升沿发送、下降沿接收

初始化就绪状态:

  • 主机SBUFF = 1010 1010

  • 从机SBUFF = 0101 0101

操作过程:如图所示,经过8个脉冲后,master和slave数据交换



SPI的8个时钟周期的数据:



————————————————————————————————————————————

基于SPI协议,DS1302显示时钟实例

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

实现效果:


动图封面


实现代码:

   1 #include

  2 typedef unsigned char uchar;

  3 typedef unsigned int uint;

  4 //写操作控制字节,D7=1,D0=0

  5 uchar code write_address[] =

  6 {

  7     //秒,分,小时,日,月,星期,年

  8     0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c

  9 };

 10 //读操作,D7=1,D0=1,地址同写操作

 11 uchar code read_address[] =

 12 {

 13     0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d

 14 };

 15 uchar code table[] =

 16 {

 17     //0,1,2,3,4,5,6,7,8,9

 18     0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0, 0xfe, 0xf6

 19 };

 20 //dat1和dat2存放读出来的时间,初始值写入12年5月9日1时1分1秒,dat1存放1234位,dat2存放567位

 21 uchar dat1[] = {0x01, 0x01, 0x01, 0x09, 0x05, 0x02, 0x12};

 22 uchar dat2[] = {0x01, 0x01, 0x01, 0x09, 0x05, 0x02, 0x12};

 23 sbit rst = P3 ^ 0;

 24 sbit scl = P3 ^ 1;

 25 sbit sda = P3 ^ 2;

 26 sbit ACC7 = ACC ^ 7;

 27 void Delay(uint m)

 28 {

 29     while(m--);

 30 }

 31 /* SPI协议操作,读字节 */

 32 uchar ReadByte()

 33 {

 34     uchar i;

 35     for (i = 0; i < 8; ++i)

 36     {

 37         ACC = ACC >> 1; //累加器左移1位,补上未知数x

 38         ACC7 = sda; //从sda引脚写入ACC最高位

 39         scl = 1;

 40         scl = 0; //时钟下降沿读入

 41     }

 42     return ACC;

 43 }

 44 /* SPI协议操作,写字节 */

 45 void WriteByte(uchar byte)

 46 {

 47     uchar i;

 48     for (i = 0; i < 8; ++i)

 49     {

 50         byte >>= 1; //byte左移1位存入CY

 51         scl = 0;

 52         sda = CY; //从CY移入sda,发送给DS102

 53         scl = 1; //时钟上升沿写入

 54     }

 55 }

 56 void Write1302(uchar address, uchar dat) //写地址子程序

 57 {

 58     rst = 0;

 59     scl = 0;

 60     rst = 1; //rst上升沿开始写数据

 61     WriteByte(address); //先写入地址控制字节

 62     WriteByte(dat); //再写入数据字节

 63     rst = 0;

 64 }

 65 uchar Read1302(uchar address)

 66 {

 67     uchar temp;

 68     rst = 0;

 69     scl = 0;

 70     rst = 1; //读过程中保持rst高电平状态

 71     WriteByte(address | 0x01); //写入地址并置R/W位为1(读)

 72     temp = ReadByte(); //在单片机写入命令字节的最后一位的第一个下降沿处即读出数据

 73     scl = 1; 

 74     rst = 0;

 75     return temp;

 76 }

 77 void SetRST()

 78 {

 79     uchar i;

 80     Write1302(0x8e, 0x00); //向10001110写保护寄存器,写入指令0x00

 81     for (i = 0; i < 7; ++i)

 82         Write1302(write_address[i], dat1[i]); //从秒到年各寄存器写入对应初始值

 83     Write1302(0x8e, 0x80); //向写保护寄存器,写入数据0x80

 84 }

 85 void ReadTime()

 86 {

 87     uchar i, temp1, temp2, temp3;

 88     temp3 = 0x80; //temp3存放时间寄存器地址

 89     for (i = 0; i < 7; ++i) //分别读出秒分小时日月星期年

 90     {

 91         temp1 = Read1302(temp3);

 92         temp2 = temp1;

 93         dat1[i] = (temp1 >> 1) & 0x0f; //读出的数据1234位存入dat1,屏蔽其他位

 94         dat2[i] = (temp2 >> 5) & 0x07; //读出的数据567位存入dat2,屏蔽其他位

 95         temp3 = temp3 + 0x02; //下一个寄存器地址

 96     }

 97 }

 98 void main()

 99 {

100     rst = 0;

101     SetRST(); //时钟建立

102     while(1)

103     {

104         ReadTime(); //读时间

105         P2 = 0xfe;

106         P1 = table[dat1[0] % 10];

107         Delay(500);

108         P2 = 0xfd;

109         P1 = table[dat2[0] % 10];

110         Delay(500);

111         P2 = 0xfb;

112         P1 = 0x02; // -

113         Delay(500);

114         P2 = 0xf7;

115         P1 = table[dat1[1] % 10];

116         Delay(500);

117         P2 = 0xef;

118         P1 = table[dat2[1] % 10];

119         Delay(500);

120         P2 = 0xdf;

121         P1 = 0x02; // -

122         Delay(500);

123         P2 = 0xbf;

124         P1 = table[dat1[2] % 10];

125         Delay(500);

126         P2 = 0x7f;

127         P1 = table[dat2[2] % 10];

128         Delay(500);

129     }

130 }


推荐阅读

史海拾趣

ELM Technology Corporation公司的发展小趣事

ELM Technology Corporation自创立之初,就致力于电子技术的研发与创新。公司聚集了一批顶尖的科研人才,不断探索新的电子技术和解决方案。在某一关键时期,ELM推出了一款具有革命性的电子产品,该产品在市场上引起了巨大反响,不仅极大地提升了用户体验,还推动了整个电子行业的发展。通过不断的技术创新,ELM逐渐在电子行业中树立了领先地位。

B+B SmartWorx公司的发展小趣事

B+B SmartWorx在成立初期便注重全球市场布局,特别是在美国和欧洲市场。通过多年的深耕细作,公司在这些地区建立了广泛的销售渠道和优秀的团队。其产品在美洲市场占据了58%的份额,欧洲市场占28%,其余地区占14%。这种全球布局不仅提升了公司的品牌知名度,也为其后续发展奠定了坚实的基础。

Coleman Cable Inc公司的发展小趣事

在发展过程中,Coleman Cable积极寻求与行业内外的合作伙伴建立稳固的合作关系。通过与知名电子制造商建立供应链合作关系,Coleman Cable的电缆产品得以广泛应用于各种电子设备中。同时,公司还与科研机构、高校等建立产学研合作关系,共同研发新技术、新产品,推动公司技术的不断创新和升级。

Dialog Semiconductor(戴乐格半导体)公司的发展小趣事

为了进一步增强市场影响力,Dialog Semiconductor通过一系列的收购策略来扩大其业务范围。例如,在2020年,公司收购了Adesto Technologies,这是一家专注于非易失性存储器(NVM)解决方案的公司。此次收购为Dialog Semiconductor带来了近5,000家新客户,并补充了其在无线连接产品之外的有线连接解决方案。同年,Dialog Semiconductor还收购了另一家公司,获得了强大的核心IC产品组合和经验丰富的工程师团队,进一步巩固了其在IoT市场的地位。

CYMBET公司的发展小趣事

CYMBET公司成立于2000年,专注于微电子系统固态储能解决方案的研发与生产。在早期,公司就凭借其创新技术——可充电固态电池芯片(EnerChip)在行业中崭露头角。这种电池芯片使用标准半导体集成电路工艺和独特的构造技术,提供了环保、生物相容的嵌入式电源功能。EnerChip的推出不仅打破了传统电池的局限,还为医疗、传感器、RFID、工业控制等领域带来了革命性的变化。

General Dynamics SATCOM Technologies公司的发展小趣事

在电子行业中,技术的更新换代速度极快。为了保持竞争力,CYMBET公司始终将创新作为核心驱动力。公司不断投入研发资金,引进先进设备和技术人才,对EnerChip技术进行持续的优化和升级。例如,公司成功研发出了更高能量密度、更长寿命的EnerChip电池芯片,进一步提升了产品的性能和市场竞争力。同时,CYMBET还积极探索新的应用领域,将EnerChip技术应用于可穿戴设备、物联网等新兴领域,为公司带来了新的增长点。

问答坊 | AI 解惑

闭路电视监控系统防雷简介

一、 闭路电视监控系统简介:   CCTV系统结构:   电视监控系统(Closed Circuit Television,简称CCTV),一般由以下三部分组成:   前端部分:   主要由黑白(彩色)摄像机、镜头、云台、防护罩、支架等组成。   传输部分:    ...…

查看全部问答>

功率集成电路中自举元件的选择

设计指南 功率驱动集成电路中自举元件的选择 1. 自举电路工作原理 Vbs(驱动电路Vb 和Vs 管脚之间的电压差)给集成电路高端驱动电路提供电源。该电源电压必须在10-20V之间,以确保驱动集成电路能够完全地驱动MOS栅极器件(MGT)。IR公司的部分驱动集 ...…

查看全部问答>

破解密码

谁能介绍一种破解无线路由器密码的软件啊 还有它的使用方法 我搞了好久都没弄明白 …

查看全部问答>

请教:DMA中断

我在写一个S3C2440的SPI驱动时需要用到DMA中断,但发现该中断号unsigned int irq已经被其他设备占用,请问有什么办法可以解决么。 我能想到的暂时就是修改内核代码,允许中断共享,或者干脆不要先前的设备。但请问有什么更好的方法吗,谢谢! …

查看全部问答>

ADS AXD调试不能进入main函数

如题,按F5运行之后,直接就全速运行了,根本就没有进入main函数,并且编译器在main函数处还有一个断点的嘛,不知道怎么处理??…

查看全部问答>

求助:关于OPA842替代原件的问题

最近再做一个宽带放大器,其中有一个运放选用的是opa842,但在市场上找不到现货。请高手们指教一下有没有其替代原件?谢!…

查看全部问答>

wince5.0进度条问题

wince5.0中的开机进度条该如何去掉,以节省启动时间。 我菜鸟,各位高手最好详细点。…

查看全部问答>

初学MSP430 LaunchPad

收到MSP launchPad几个星期之后,在落上灰尘之前终于腾出时间来试试看了。先是看了一些帖子和博客,看得差不多了,该动手了。先是安装CCS,按照安装指示,很顺利就装上了。第一个程序是闪烁LED,几乎没有什么周折就能够通过改变C语言程序来变换闪烁 ...…

查看全部问答>

stm32迷你套件

                                 今天收到ST--有关stm32迷你套件的邮件,感觉被愚弄,我申请的名次肯定在1500名以内,如果是根据芯片预计用量来判断 ...…

查看全部问答>

温馨提示:McuIsp软件更新

今天本人观察源代码时,发现McuIsp StmIsp存在一个问题:如果你的代码长度刚好为64的整数倍加1,则最后一个字节不会下载。McuIspV0.975已经改正该问题,请及时下载。STM32手持下载机不存在该Bug。…

查看全部问答>