• 【硬件通讯协议】SIP总线协议以及模拟(软件)SPI


    参考资料

    NXP 官方网站提供的 SPI 总线规范

    S12SPIV4.pdficon-default.png?t=M666https://www.nxp.com/files-static/microcontrollers/doc/ref_manual/S12SPIV4.pdfSPI 是 Motorola 提出的,被收购后是分给了恩智浦吧!

    真的很无语,就是一个规范而已,CSDN上还那么多要下载积分才能下载的搬运工!

    SPI协议需参考IIC协议,对于SPI协议介绍没有非常细致!

    【硬件通讯协议】IIC总线协议以及模拟(软件)IICII2总线的介绍,软件IIC基于C51的实现方法。提供部分代码供为参考!https://blog.csdn.net/qq_41650023/article/details/126207398?spm=1001.2014.3001.5502


    SPIBus

    SPI是4线制总线:MISO、MOSI、SCLK、CS。SPI是全双工的!

    • MISO:Master input slave output(主机输入,从机输出)数据流由从机到主机
    • MOSI:Master output slave input(主机输出,从机输入)数据流由主机到从机
    • SCLK:Serial Clock(串行时钟信号线)时钟信号由主机产生
    • CS/SS:Chip select / Slave select(片选信号)

    对于不同的公司命名方面可能有些差异,但是功能是相同的!

    SPI 和 IIC 也较为相似,具体再详细看 IIC 协议!

    SPI 一般被作用于一主多从的状态。

    SPI由于不同生产厂商,数据输入输出、时钟频率指标都会不同,要查手册!!!!

    通讯模式

    CS 信号由高变低,是 SPI 的起始信号。CS 信号由低变高,是 SPI 的停止信号。

    片选是低电平有效,最好加上拉电阻

    写数据也是没有硬性规定的,可以先写高位,也可以先写低位!

    单独接CS

    单独进行和某一个从机的通讯,CS可以用二进制解码芯片来拓展。例如3-8译码器。

    SPI通信含有移位寄存器的器件

    此时同时进行片选,但数据过多时,会从Peripheral1溢出到Peripheral2,最适合驱动数码管或者LED点阵了啊!!!这种连接方式被称为:菊花链。

    时钟相位和时钟极性

    SPI 有四种通讯模式,根据时钟极性(CPOL/SPO)、时钟相位(CPHA/SPH)所控制。

    • CPOL = 1:SCK信号线在空闲时为高电平
    • CPOL = 0:SCK信号线在空闲时为低电平
    • CPHA = 1:数据线在 SCK 的“偶数边沿”被采样
    • CPHA = 0:数据线在 SCK 的“奇数边沿”被采样

    至于是上升沿还是下降沿采样,需要结合CPOL和CPOH共同判断!

    Transfer ModeCPOLCPHA采样效果
    Mode 000第一个边沿为上升沿,奇数边沿采样(上升沿数据采样)
    Mode 101第一个边沿为上升沿,偶数边沿采样(下降沿数据采样)
    Mode 210第一个边沿为下降沿,奇数边沿采样(下降沿数据采样)
    Mode 311第一个边沿为下降沿,偶数边沿采样(上升沿数据采样)

    主机和从机在相同的模式下才可以正常进行通讯!


    SPI总线接口的软件实现-89C51

    采用和X5045进行通讯作为例子!

    SCK信号线在空闲时为低电平

    1. sbit SPI_SO = P1^1;
    2. sbit SPI_SI = P1^6;
    3. sbit SPI_SCK = P1^4;
    4. sbit SPI_CS = P1^2;

    SPIBus发送一个字节数据

    1. void SPI_WriteByte(unsigned char byte)
    2. {
    3. unsigned char i;
    4. unsigned char tmp;
    5. for(i=0; i<8; i++)
    6. {
    7. SPI_SCK = 0;
    8. tmp = byte & 0x80;
    9. if(tmp == 0x80)
    10. {
    11. SPI_SI = 1;
    12. _nop_();
    13. }
    14. else
    15. {
    16. SPI_SI = 0;
    17. _nop_();
    18. }
    19. SPI_SCK = 1;
    20. byte = byte<<1;
    21. }
    22. }

    SPIBus接收一个字节数据

    1. unsigned char SIP_ReadByte()
    2. {
    3. unsigned char i;
    4. unsigned char byte = 0;
    5. for(i=8; i>0; i--)
    6. {
    7. byte = byte<<1;
    8. SPI_SCK = 1;
    9. _nop_();
    10. _nop_();
    11. SPI_SCK = O;
    12. _nop_();
    13. _nop_();
    14. byte = byte | (unsigned char)SPI_SO;
    15. }
    16. return byte;
    17. }

    SPIBus开始/结束

    1. void SPI_Start(void)
    2. {
    3. SPI_CS = 1;
    4. _nop_();
    5. _nop_();
    6. SPI_SCK = 0;
    7. _nop_();
    8. _nop_();
    9. SPI_CS = 0;
    10. _nop_();
    11. _nop_();
    12. }
    13. void SPI_End(void)
    14. {
    15. SPI_SCK = 0;
    16. _nop_();
    17. _nop_();
    18. SPI_CS = 1;
    19. _nop_();
    20. _nop_();
    21. }

    X5045相关的程序

    1. #define WREN 0X06 // 设置写使能锁存器
    2. #define WRDI 0X04 // 复位写使用锁存器
    3. #define RSDR 0X05 // 读状态寄存器
    4. #define WRSR 0X01 // 写状态寄存器
    5. #define READ 0X03 // 读操作指令 0000 A8 011
    6. #define WRITE 0X02 // 写操作指令 0000 A8 010
    7. #define WIP 0X01 // 状态寄存器写操作是否正忙

    读取X5045状态寄存器功能

    1. unsigned char X5045_ReadStatus(void)
    2. {
    3. unsigned char tmp;
    4. SPI_Start();
    5. SPI_WriteByte(RSDR);
    6. tmp = SPI_ReadByte();
    7. return tmp;
    8. }

    写X5045状态寄存器功能

    1. void X5045_WriteStatus(unsigned char status)
    2. {
    3. unsigned char tmp;
    4. SPI_Start();
    5. SPI_WriteByte(WREN);
    6. SPI_End();
    7. SPI_Start();
    8. SPI_WriteByte(WRSR);
    9. SPI_WriteByte(status);
    10. SPI_End();
    11. d0
    12. {
    13. SPI_Start();
    14. SPI_WriteByte(RSDR);
    15. tmp = SPI_ReadByte();
    16. SPI_End();
    17. }
    18. while(tmp&WIP);
    19. }

    读X5045指定地址EEPROM中的数据

    1. unsigned char X5045_ReadAddrData(unsigned char addr)
    2. {
    3. unsigned char addr_tmp,tmp;
    4. unsigned char read_cmd;
    5. if(addr > 255)
    6. read_cmd = READ|0X08;
    7. else
    8. read_cmd = READ;
    9. addr_tmp = (unsigned char)(addr & 0xff);
    10. SPI_Start();
    11. SPI_WriteByte(read_cmd);
    12. SPI_WriteByte(addr_tmp);
    13. tmp = SPI_ReadByte();
    14. SPI_End();
    15. return tmp;
    16. }

    写X5045指定地址EEPROM中的数据

    1. void X5045_WriteAddrData(unsigned char addr, unsigned char edate)
    2. {
    3. unsigned char addr_tmp,tmp;
    4. unsigned char cmd_tmp;
    5. SPI_Start();
    6. SPI_WriteByte(WREN);
    7. SPI_End();
    8. if(addr > 255)
    9. cmd_tmp = WRITE|0X08;
    10. else
    11. cmd_tmp = WRITE;
    12. addr_tmp = (unsigned char)(addr & 0xff);
    13. SPI_Start();
    14. SPI_WriteByte(cmd_tmp);
    15. SPI_WriteByte(addr_tmp);
    16. SPI_WriteByte(edate);
    17. SPI_End();
    18. d0
    19. {
    20. SPI_Start();
    21. SPI_WriteByte(RSDR);
    22. tmp = SPI_ReadByte();
    23. SPI_End();
    24. }
    25. while(tmp&WIP);
    26. }

    喂狗

    1. void X5045_WDT(void)
    2. {
    3. SPI_CS = 0;
    4. _nop_();
    5. _nop_();
    6. SPI_CS = 1;
    7. _nop_();
    8. _nop_();
    9. }

    最后由于此芯片用到的较少,就介绍到此!


    参考:

    Serial Peripheral Interface (SPI) - learn.sparkfun.com

    主要理解SPI的传输协议,用硬件SPI不就香多了!!

    🎉 今日学习达成!

     

  • 相关阅读:
    Apifox和Eolink两个测试工具谁最实用?
    正则表达式基本知识
    揭秘GaussDB(for Redis):全面对比Codis
    UNet详细解读(一)论文技术要点归纳
    霍格沃兹~~~
    高效使用浏览器的5个小技巧,第1个技巧最实用
    设备驱动号 绑定文件描述符
    手机流量卡经营商城小程序的作用是什么
    GBase 8s ALTER FRAGMENT 语句 MODIFY子句(一)
    .NET静态代码织入——肉夹馍(Rougamo) 发布1.1.0
  • 原文地址:https://blog.csdn.net/qq_41650023/article/details/126225381