51单片机 | SPI协议与应用实例
————————————————————————————————————————————
SPI总线
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
参考链接:
http://blog.csdn.net/fly__chen/article/details/52724109
http://blog.csdn.net/skyflying2012/article/details/11910173
http://blog.sina.com.cn/s/blog_9cc7125c0100yk1s.html
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
简介:
- 串行外围设备接口
- 全双工三线同步,可以同时发出和接收串行数据
- 采用主从(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相位 |
说明 |
|
0 |
0 |
0 |
第一个边沿上升沿 |
|
1 |
0 |
1 |
第二个边沿下降沿 |
|
2 |
1 |
0 |
第一个边沿下降沿 |
|
3 |
1 |
1 |
第二个边沿上升沿 |
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显示时钟实例
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
实现效果:

实现代码:
#include <reg52.h>
typedef unsigned char uchar;
typedef unsigned int uint;
//写操作控制字节,D7=1,D0=0
uchar code write_address[] =
{
//秒,分,小时,日,月,星期,年
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c
};
//读操作,D7=1,D0=1,地址同写操作
uchar code read_address[] =
{
0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d
};
uchar code table[] =
{
//0,1,2,3,4,5,6,7,8,9
0xfc, 0x60, 0xda, 0xf2, 0x66, 0xb6, 0xbe, 0xe0, 0xfe, 0xf6
};
//dat1和dat2存放读出来的时间,初始值写入12年5月9日1时1分1秒,dat1存放1234位,dat2存放567位
uchar dat1[] = {0x01, 0x01, 0x01, 0x09, 0x05, 0x02, 0x12};
uchar dat2[] = {0x01, 0x01, 0x01, 0x09, 0x05, 0x02, 0x12};
sbit rst = P3 ^ ;
sbit scl = P3 ^ ;
sbit sda = P3 ^ ;
sbit ACC7 = ACC ^ ;
void Delay(uint m)
{
while(m--);
}
/* SPI协议操作,读字节 */
uchar ReadByte()
{
uchar i;
for (i = ; i < ; ++i)
{
ACC = ACC >> ; //累加器左移1位,补上未知数x
ACC7 = sda; //从sda引脚写入ACC最高位
scl = ;
scl = ; //时钟下降沿读入
}
return ACC;
}
/* SPI协议操作,写字节 */
void WriteByte(uchar byte)
{
uchar i;
for (i = ; i < ; ++i)
{
byte >>= ; //byte左移1位存入CY
scl = ;
sda = CY; //从CY移入sda,发送给DS102
scl = ; //时钟上升沿写入
}
}
void Write1302(uchar address, uchar dat) //写地址子程序
{
rst = ;
scl = ;
rst = ; //rst上升沿开始写数据
WriteByte(address); //先写入地址控制字节
WriteByte(dat); //再写入数据字节
rst = ;
}
uchar Read1302(uchar address)
{
uchar temp;
rst = ;
scl = ;
rst = ; //读过程中保持rst高电平状态
WriteByte(address | 0x01); //写入地址并置R/W位为1(读)
temp = ReadByte(); //在单片机写入命令字节的最后一位的第一个下降沿处即读出数据
scl = ;
rst = ;
return temp;
}
void SetRST()
{
uchar i;
Write1302(0x8e, 0x00); //向10001110写保护寄存器,写入指令0x00
for (i = ; i < ; ++i)
Write1302(write_address[i], dat1[i]); //从秒到年各寄存器写入对应初始值
Write1302(0x8e, 0x80); //向写保护寄存器,写入数据0x80
}
void ReadTime()
{
uchar i, temp1, temp2, temp3;
temp3 = 0x80; //temp3存放时间寄存器地址
for (i = ; i < ; ++i) //分别读出秒分小时日月星期年
{
temp1 = Read1302(temp3);
temp2 = temp1;
dat1[i] = (temp1 >> ) & 0x0f; //读出的数据1234位存入dat1,屏蔽其他位
dat2[i] = (temp2 >> ) & 0x07; //读出的数据567位存入dat2,屏蔽其他位
temp3 = temp3 + 0x02; //下一个寄存器地址
}
}
void main()
{
rst = ;
SetRST(); //时钟建立
while()
{
ReadTime(); //读时间
P2 = 0xfe;
P1 = table[dat1[] % ];
Delay();
P2 = 0xfd;
P1 = table[dat2[] % ];
Delay();
P2 = 0xfb;
P1 = 0x02; // -
Delay();
P2 = 0xf7;
P1 = table[dat1[] % ];
Delay();
P2 = 0xef;
P1 = table[dat2[] % ];
Delay();
P2 = 0xdf;
P1 = 0x02; // -
Delay();
P2 = 0xbf;
P1 = table[dat1[] % ];
Delay();
P2 = 0x7f;
P1 = table[dat2[] % ];
Delay();
}
}

51单片机 | SPI协议与应用实例的更多相关文章
- [51单片机] SPI nRF24L01 无线简单程序 1
main.c #include <reg51.h> #include <api.h> #define uchar unsigned char /**************** ...
- 51单片机 | 1-Wire总线及应用实例
———————————————————————————————————————————— 1-Wire总线 - - - - - - - - - - - - - - - - - - - - - - - ...
- [51单片机] SPI nRF24L01无线 [可以放在2个单片机里实现通信]
main.c #include<reg51.h> #include"2401.h" #define uint unsigned int #define uchar un ...
- 51单片机I/O口直接输入输出实例(附调试及分析过程)
51单片机P0/P1/P2/P3口的区别: P0口要作为低8位地址总线和8位数据总线用,这种情况下P0口不能用作I/O,要先作为地址总线对外传送低8位的地址,然后作为数据总线对外交换数据: P1口只能 ...
- 51单片机 | I/O口直接输入输出实例
51单片机P0/P1/P2/P3口的区别: P0口要作为低8位地址总线和8位数据总线用,这种情况下P0口不能用作I/O,要先作为地址总线对外传送低8位的地址,然后作为数据总线对外交换数据: P1口只能 ...
- 51单片机 | 并行I/O口扩展实例(74LS244/74LS373/4071)
并行I/O口扩展实例 //<51单片机原理及应用(第二版)——基于Keil C与Proteus>第四章例4.4 I/O口不能完全用于输入/输出操作,当需要扩展外部存储器时,P0.P2口用作 ...
- 基于51单片机的CAN通讯协议C语言程序
//-----------------------函数声明,变量定义-------------------------------------------------------- #includ ...
- Windows 通用应用尝试开发 “51单片机汇编”总结
一.前言 终于完成windows通用应用“51单片机汇编”,半年前开始玩WindowsPhone开发的第一个真正意义上的App(还很多缺点=_=).开发从1月中旬考完试到今天,期间实习了半个月,玩了几 ...
- SPI协议及其工作原理详解
一.概述. SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控 ...
随机推荐
- 【hdoj_1051】WoodenSticks
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1051 题意可以理解为:给定若干个二元数对,要将这些数对分为不同的组,同一组中的若干个二元数对可以排列成一个 ...
- win32 右键弹出菜单
#define CW_ABOUT 100 #define CW_DOCUMENT 200 POINT t; GetCursorPos(&t); HMENU hMenu,hPopupMen ...
- 【转载】Synflood code
''' Syn flood program in python by Tequila/e credits to Silver Moon for base's of syn packets. r s s ...
- NYOJ 914 Yougth的最大化【二分/最大化平均值模板/01分数规划】
914-Yougth的最大化 内存限制:64MB 时间限制:1000ms 特判: No 通过数:3 提交数:4 难度:4 题目描述: Yougth现在有n个物品的重量和价值分别是Wi和Vi,你能帮他从 ...
- HDU 1811 Rank of Tetris 【拓扑排序 + 并查集】
自从Lele开发了Rating系统,他的Tetris事业更是如虎添翼,不久他遍把这个游戏推向了全球. 为了更好的符合那些爱好者的喜好,Lele又想了一个新点子:他将制作一个全球Tetris高手排行榜, ...
- UVALive 5097 Cross the Wall
贪心思想,$dp$,斜率优化. 首先将人按照$w$从大到小排序,如果$w$一样,按$h$从大到小排.这样一来,某位置之后,比该位置$h$小的都是不需要考虑的. 因此,形成了如下图所示的结果: 即第一个 ...
- 揭秘响应式web设计
0.引言 响应式web设计的作用主要使网页能在不同小大的显示窗口下依然优雅.当前的显示窗口有pc,ipad,iphone以及一些其他的设备.不同的显示窗口的分辨率各不相同,如何在不同的分辨率的情况下 ...
- 搭建基于Ant+Jmeter+jenkins的自动负载测试框架的若干问题记录及解决
1.关于构建时使用的默认build.xml问题 如图,如果构建脚本build.xml不在workspace根目录.或者说构建脚本不叫build.xml.那么需要在高级里设置Build File选项的 ...
- 【对询问分块】【主席树】bzoj2683 简单题
对操作序列分块,每S次暴力重建主席树. 当S=sqrt(n*log(n))时,复杂度为O(m*sqrt(n*log(n))). 在线的. #include<cstdio> #include ...
- 【分块】bzoj1858 [Scoi2010]序列操作
分块 Or 线段树 分块的登峰造极之题 每块维护8个值: 包括左端点在内的最长1段: 包括右端点在内的最长1段: 该块内的最长1段: 该块内1的个数: 包括左端点在内的最长0段://这四个是因为可能有 ...