zoukankan      html  css  js  c++  java
  • 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=0SCLK有效时为高电平(active-high

    CPOL=1SCLK有效时为低电平(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 <reg52.h>
      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 }

  • 相关阅读:
    VM环境安装Linux系统
    设置ShowDialog
    sqlserver同步表的脚本
    C#winform设置DateTimePicker的时间格式
    C#winform解析marc显示在datagridview中以及marc卡片显示
    C#实现图书馆程序导入ISO-2709格式(MARC)功能
    时间格式转换+固定字段加空格
    sqlserver 保留小数方法
    winform的datagridview单元格输入限制和右键单击datagridview单元格焦点跟着改变
    怎么查看那个端口被占用
  • 原文地址:https://www.cnblogs.com/hughdong/p/7105979.html
Copyright © 2011-2022 走看看