GPIO模拟SPI通讯接口

一、SPI总述

    SPI 是一种允许一个主设备启动一个与从设备的同步通讯的协议,从而完成数据的交换。也就是说,SPI是一种规定好的通讯方式。这种通信方式的优点是占用端口较少,一般4根就够基本通讯了。同时传输速度也很高。一般来说要求主设备要有SPI控制器(但可用模拟方式),就可以与基于SPI的芯片通讯了。

    常见的SPI外围设备包括FLASHRAM、网络控制器、LCD显示驱动器、A/D转换器和MCU等。

    SPI 的通信原理很简单,它需要至少4根线,事实上3根也可以。也是所有基于SPI的设备共有的,它们是SDI(数据输入),SDO(数据输出),SCK(时 钟),CS(片选)。其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效。这就允许在同一总线上连接多个SPI设备成为可能

     接下来就负责通讯的3根线了。通讯是通过数据交换完成的,这里先要知道SPI是串行通讯协议,也就是说数据是一位一位的传输的。这就是SCK时钟线存在的原 因,由SCK提供时钟脉冲,SDISDO则基于此脉冲完成数据传输。数据输出通过SDO线,数据在时钟上沿或下沿时改变,在紧接着的下沿或上沿被读取。 完成一位数据传输,输入也使用同样原理。这样,在至少8次时钟信号的改变(上沿和下沿为一次),就可以完成8位数据的传输。

     要注意的是,SCK信号线只由主设备控制,从设备不能控制信号线。同样,在一个基于SPI的设备中,至少有一个主控设备。这就不适用于多处理器的无主控通讯。

     这样传输的特点:这样的传输方式有一个优点,与普通的串行通讯不同,普通的串行通讯一次连续传送至少8位数据,而SPI允许数据一位一位的传送,甚至允许暂停,因为SCK时钟线由主控设备控制,当没有时钟跳变时,从设备不采集或传送数据。也就是说,主设备通过对SCK时钟线的控制可以完成对通讯的控制。

     SPI还是一个数据交换协议:因为SPI的数据输入和输出线独立,所以允许同时完成数据的输入和输出。

     不同的SPI设备的实现方式不尽相同,主要是数据改变和采集的时间不同,在时钟信号上沿或下沿采集有不同定义,需要参考相关器件的文档。




二、SPI的信号线


之前说过,SPI一共有4根信号线,再回顾下作用:

  • SCLK:Serial Clock,(串行)时钟 
  • SDI(MISO):Master In Slave Out,主设备输入,从设备输出
  • SDO(MOSI):Master Out  Slave In,主设备输出,从设备输入 
  • CS:    Chip Select,选中从设备,片选

     GPIO模拟SPI总的来说是比较简单,把相应的管脚配置成GPIO功能,再按需要配置管脚的输入输出方向,然后根据SPI总线的时序设定IO口的电平。例如,要实现一块LCD的驱动,LCD与主控芯片之间使用SPI协议通信,GPIO就可以这样配置——由于主控芯片不需要从LCD读取数据,SDI可以不接;LCD需要一直被控制,CS接地,使LCD一直处于使能状态。




    三、相位和极性


    CKPOL (Clock Polarity) = CPOL = POL = Polarity = (时钟)极性

    CKPHA (Clock Phase) = CPHA = PHA = Phase = (时钟)相位


    1、CPOL  极性

    先解释下什么是SCLK时钟的空闲。SCLK空闲就是当SCLK在数发送8个bit比特数据之前和之后的状态,于此对应的,SCLK在发送数据的时候,就是正常的工作的时候,有效active的时刻了。    
    简单的说,SPI的CPOL,表示当SCLK空闲的时候,其电平的值是低电平0还是高电平。
    CPOL=0,时钟空闲idle时候的电平是低电平,所以当SCLK有效的时候,就是高电平,就是所谓的active-high 
    CPOL=1,时钟空闲idle时候的电平是高电平,所以当SCLK有效的时候,就是低电平,就是所谓的active-low


    2、CPHA  相位

    相位,对应着数据采样是在第几个边沿(edge),是第一个边沿还是第二个边沿,0对应着第一个边沿,1对应着第二个边沿。 

    CPHA=0,表示第一个边沿: 
    对于CPOL=0,idle时候的是低电平,第一个边沿就是从低变到高,所以是上升沿; 
    对于CPOL=1,idle时候的是高电平,第一个边沿就是从高变到低,所以是下降沿; 
    CPHA=1,表示第二个边沿: 
    对于CPOL=0,idle时候的是低电平,第二个边沿就是从高变到低,所以是下降沿; 
    对于CPOL=1,idle时候的是高电平,第一个边沿就是从低变到高,所以是上升沿;


    如上所述,CPOL和CPHA可构成4种组合,这就是常说的SPI四种传输模式——

    CPOL=0, CPHA=0 
    CPOL=0, CPHA=1
    CPOL=1, CPHA=0 
    CPOL=1, CPHA=1

    有图有真相:




    四、GPIO模拟SPI驱动

    概念了解清楚了,我们来上代码吧


    #define SS  252      //定义SS所对应的GPIO接口编号
    #define SCLK 253      //定义SCLK所对应的GPIO接口编号
    #define MOSI 254      //定义SCLK所对应的GPIO接口编号
    #define MISO 255      //定义MISO所对应的GPIO接口编号
    #define OUTP 1      //表示GPIO接口方向为输出
    #define INP 0       //表示GPIO接口方向为输入
    /* SPI端口初始化 */
    void spi_init()
    {
    	set_gpio_direction(SS, OUTP);
    	set_gpio_direction(SCLK, OUTP);
    	set_gpio_direction(MOSI, OUTP);
    	set_gpio_direction(MISO, INP);
    	set_gpio_value(SCLK, 0);     //CPOL=0
    	set_gpio_value(MOSI, 0);
    }
    /*
    从设备使能
    enable:为1时,使能信号有效,SS低电平
    为0时,使能信号无效,SS高电平
    */
    void ss_enable(int enable)
    {
    	if (enable)
    		set_gpio_value(SS, 0);     //SS低电平,从设备使能有效
    	else
    		set_gpio_value(SS, 1);     //SS高电平,从设备使能无效
    }
     /* SPI字节写 */
    void spi_write_byte(unsigned char b)
    {
    	int i;
    	for (i=7; i>=0; i--) {
    		set_gpio_value(SCLK, 0);
    		set_gpio_value(MOSI, b&(1<<i));   //从高位7到低位0进行串行写入
    		delay();       //延时
    		set_gpio_value(SCLK, 1);    // CPHA=1,在时钟的第一个跳变沿采样
    		delay(); 
    	}
    }
    /* SPI字节读 */
    unsigned char spi_read_byte()
    {
    	int i;
    	unsigned char r = 0;
    	for (i=0; i<8; i++) {
    		set_gpio_value(SCLK, 0);
    		delay();       //延时
    		set_gpio_value(SCLK, 1);    // CPHA=1,在时钟的第一个跳变沿采样
    		r = (r <<1) | get_gpio_value(MISO);   //从高位7到低位0进行串行读出
    		delay();
    	}
    }
    /*
     SPI写操作
     buf:写缓冲区
     len:写入字节的长度
    */
    void spi_write (unsigned char* buf, int len)
    {
    	int i;
    	spi_init();       //初始化GPIO接口
    	ss_enable(1);       //从设备使能有效,通信开始
    	delay();        //延时
    	//写入数据
    	for (i=0; i<len; i++)
    		spi_write_byte(buf[i]);
    	delay();
    	ss_enable(0);       //从设备使能无效,通信结束
    }
    /*
    SPI读操作
    buf:读缓冲区
    len:读入字节的长度
    */
    void spi_read(unsigned char* buf, int len)
    {
    	int i;
    	spi_init();       //初始化GPIO接口
    	ss_enable(1);       //从设备使能有效,通信开始
    	delay();        //延时
    	//读入数据
    	for (i=0; i<len; i++)
    		buf[i] = spi_read_byte();
    	delay();
    	ss_enable(0);       //从设备使能无效,通信结束
    }




       

  • 15
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: STM32是一种由意法半导体公司生产的高性能微控制器,它可以通过模拟SPI协议与其他设备通信。SPI是串行外设接口协议,用于在微控制器和其他设备之间传输数据。 使用STM32模拟SPI协议,需要首先了解SPI协议的工作原理。SPI协议通过一个主设备和至少一个从设备之间进行通信。通信的数据是在时钟和数据线上同步传输的。在STM32中,模拟SPI协议的实现需要通过一些特定的寄存器和GPIO口进行配置。 通常情况下,STM32作为主设备时需要产生一个时钟信号来驱动从设备传输数据。在STM32的GPIO口中,需要将Clock、Master-out-slave-in、Master-in-slave-out、Slave-select四个口与从设备相连。每个GPIO口需要进行相应的配置,包括时钟极性、相位、主从模式、时钟速率等参数。 使用STM32模拟SPI协议通信的流程如下:首先,主设备通过拉低Slave-select口来选择一个从设备;然后,主设备生成时钟信号,并在时钟上上升沿或下降沿发送数据;从设备接收到时钟信号后,通过Master-in-slave-out口传送相应的数据;在传输完成后,主设备释放Slave-select口,通信结束。 总的来说,使用STM32模拟SPI协议进行通信需要进行一系列的配置和操作,但是可以实现快速、可靠的数据传输。 ### 回答2: STM32是一款高性能微控制器,支持多种通信协议,其中包括SPI协议。SPI协议是一种基于“主从”架构的串行通信协议,可以用于外设与主控器之间的通讯。 STM32模拟SPI协议使用GPIO模拟SPI通信,具有简单、快速、灵活等特点。在模拟SPI协议时,需要将不同GPIO端口设置为SPI通信引脚,包括如下四个信号线: 1. SCLK:时钟信号,由主控器产生,控制数据传输速度。 2. MOSI:数据输出信号,由主控器向从设备输出数据。 3. MISO:数据输入信号,从设备向主控器返回数据。 4. CS:片选信号,由主控器产生,选择与其通信的从设备。 在模拟SPI协议时,先拉低CS信号,向从设备发送命令和数据,等待从设备的响应,并读取从设备返回的数据。通讯完成后释放CS信号。 模拟SPI协议需要通过软件编写SPI接口程序来实现,主控器需要控制时钟脉冲的频率和传输字节的数量等参数。可以通过编写SPI接口类库,使用STM32内部的SPI外设来实现模拟SPI协议,或者通过GPIO口位操作实现。 总之,STM32模拟SPI协议是一种简单易用、灵活、仅依赖于GPIO模拟SPI协议,可以快速实现与各种从设备的通信。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值