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 }

  • 相关阅读:
    SP笔记:交叉实现七行并成一行
    HTML tag 学习
    操作哈希表
    Efficient bipedal robots based on passivedynamic walkers
    Pushing People Around
    ZEROMOMENT PONTTHIRTY FIVE YEARS OF ITS LIFE

    Active Learning for RealTime Motion Controllers
    Accelerometerbased User Interfaces for the Control of a Physically Simulated Character
    Dynamic Response for Motion Capture Animation
  • 原文地址:https://www.cnblogs.com/hughdong/p/7105979.html
Copyright © 2011-2022 走看看