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 总线在物理上是通过接在外围设备微控 ...
随机推荐
- PDCurses 笔记(一)
之前没有接触过curse和ncurse,平时用的也都是windows系统,所以对PDCurses也挺感兴趣的.网上关于PDCurses的内容也不是很多,但是感觉上它的函数应该都是和其他操作系统里函数都 ...
- Corosync 配置描述
NAME corosync.conf - corosync executive configuration file SYNOPSIS /etc/corosync/corosync.conf DESC ...
- 【cocos2d-js官方文档】三、Bake功能使用说明
设计意图 在游戏开发的过程中,经常会遇到作为UI或者不怎么修改的背景的层(Layer), 这些层内容并不怎么变动. 而在游戏的渲染过程中,这些层往往又会消耗大量的渲染时间,特别是比较复杂的UI界面,比 ...
- codeforces734E
题目连接:http://codeforces.com/contest/734/problem/E E. Anton and Tree time limit per test 3 seconds mem ...
- JavaScript处理异步请求的几种方式(取异步函数返回值)
JavaScript处理异步的几种方式 Javascript语言的执行环境是"单线程"(single thread,就是指一次只能完成一件任务.如果有多个任务,就必须排队,前面一个 ...
- RabbitMQ生产部署指南
像RabbitMQ这样的数据服务通常有许多可调参数.一些配置对开发有很大的意义,但并不适合生产,本指南旨在为此提供帮助 虚拟主机 例如,在单租户环境中,当您的RabbitMQ集群专门为生产中的单个系统 ...
- 【线段树】bzoj3922 Karin的弹幕
设置一个值K. d<=K:建立多组线段树:d>K:暴力. 最优时间复杂度的伪计算: O(n*K*logn(建树)+m*logn(询问类型1)+m*n/K(询问类型2)+m*K*logn(修 ...
- 【点分治】bzoj1316 树上的询问
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; #defin ...
- 开发板无法ping通虚拟机的问题解决一例
先描述一下遇到的问题: 使用的开发板是Tq2440,我将虚拟机和开发板都设在在了同一个网段,并且虚拟机使用的是桥接的方式,我用nfs的方式挂载根文件系统是失败,系统无法起来,后来我进入uboot命令模 ...
- iOS开发学习 阶段过程简述
下面就简单介绍一下我iOS开发的感受,也是学习iOS开发的一个体系架构. 1 iOS开发环境 1.1 开发环境 标准的配置是Mac OS X + Xcode. MacOSX的话首选用苹果电脑,macm ...