【硬件通讯协议】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信号线在空闲时为低电平

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

SPIBus发送一个字节数据

void SPI_WriteByte(unsigned char byte)
{
    unsigned char i;
    unsigned char tmp;
    for(i=0; i<8; i++)
    {
        SPI_SCK = 0;
        tmp = byte & 0x80;
        if(tmp == 0x80)
        {
            SPI_SI = 1;
            _nop_();
        }
        else
        {
            SPI_SI = 0;
            _nop_();
        }
        SPI_SCK = 1;
        byte = byte<<1;
    }
}

SPIBus接收一个字节数据

unsigned char SIP_ReadByte()
{
    unsigned char i;
    unsigned char byte = 0;
    for(i=8; i>0; i--)
    {
        byte = byte<<1;
        SPI_SCK = 1;
        _nop_();
        _nop_();
        SPI_SCK = O;
        _nop_();
        _nop_();
        byte = byte | (unsigned char)SPI_SO;
    }
    return byte;
}

SPIBus开始/结束

void SPI_Start(void)
{
    SPI_CS = 1;
    _nop_();
    _nop_();
    SPI_SCK = 0;
    _nop_();
    _nop_();
    SPI_CS = 0;
    _nop_();
    _nop_();
}

void SPI_End(void)
{
    SPI_SCK = 0;
    _nop_();
    _nop_();
    SPI_CS = 1;
    _nop_();
    _nop_();
}

X5045相关的程序

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

读取X5045状态寄存器功能

unsigned char X5045_ReadStatus(void)
{
    unsigned char tmp;
    SPI_Start();
    SPI_WriteByte(RSDR);
    tmp = SPI_ReadByte();
    return tmp;
}

写X5045状态寄存器功能

void X5045_WriteStatus(unsigned char status)
{
    unsigned char tmp;
    SPI_Start();
    SPI_WriteByte(WREN);
    SPI_End();
    SPI_Start();
    SPI_WriteByte(WRSR);
    SPI_WriteByte(status);
    SPI_End();
    d0
    {
        SPI_Start();
        SPI_WriteByte(RSDR);
        tmp = SPI_ReadByte();
        SPI_End();
    }
    while(tmp&WIP);
}

读X5045指定地址EEPROM中的数据

unsigned char X5045_ReadAddrData(unsigned char addr)
{
    unsigned char addr_tmp,tmp;
    unsigned char read_cmd;
    if(addr > 255)
        read_cmd = READ|0X08;
    else
        read_cmd = READ;
    addr_tmp = (unsigned char)(addr & 0xff);
    SPI_Start();
    SPI_WriteByte(read_cmd);
    SPI_WriteByte(addr_tmp);
    tmp = SPI_ReadByte();
    SPI_End();
    return tmp;
}

写X5045指定地址EEPROM中的数据

void X5045_WriteAddrData(unsigned char addr, unsigned char edate)
{
    unsigned char addr_tmp,tmp;
    unsigned char cmd_tmp;
    SPI_Start();
    SPI_WriteByte(WREN);
    SPI_End();
    if(addr > 255)
        cmd_tmp = WRITE|0X08;
    else
        cmd_tmp = WRITE;
    addr_tmp = (unsigned char)(addr & 0xff);
    SPI_Start();
    SPI_WriteByte(cmd_tmp);
    SPI_WriteByte(addr_tmp);
    SPI_WriteByte(edate);
    SPI_End();
    d0
    {
        SPI_Start();
        SPI_WriteByte(RSDR);
        tmp = SPI_ReadByte();
        SPI_End();
    }
    while(tmp&WIP);
}

喂狗

void X5045_WDT(void)
{
    SPI_CS = 0;
    _nop_();
    _nop_();
    SPI_CS = 1;
    _nop_();
    _nop_();
}

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


参考:

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

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

🎉 今日学习达成!

 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值