失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 【51单片机快速入门指南】5:软件SPI

【51单片机快速入门指南】5:软件SPI

时间:2019-09-15 15:39:56

相关推荐

【51单片机快速入门指南】5:软件SPI

目录

硬知识SPI协议简介SPI接口介绍SPI接口连接图SPI数据传输方向SPI传输模式软件SPI程序源码Soft_SPI.cSoft_SPI.h

普中51-单核-A2

STC89C52

Keil uVision V5.29.0.0

PK51 Prof.Developers Kit Version:9.60.0.0

上位机:Vofa+ 1.3.10


源于软件模拟SPI接口程序代码(4种模式)—— 内陆的咸水鱼,有改动。

硬知识

SPI协议简介

SPI的通信原理很简单,一般主从方式工作,这种模式通常有一个主设备和一个或多个从设备,通常采用的是4根线,它们是MISO(数据输入,针对主机来说)、MOSI(数据输出,针对主机来说)、SCLK(时钟,主机产生)、CS/SS(片选,一般由主机发送或者直接使能,通常为低电平有效

SPI接口介绍

SCK:时钟信号,由主设备产生,所以主设备SCK信号为输出模式,从设备的SCK信号为输入模式。

CS:片选信号,由主设备控制从设备,,所以主设备CS信号为输出模式,从设备的CS信号为输入模式。

MOSI:主设备数据输出,从设备数据输入,所以主设备MOSI信号为输出模式,从设备的MOSI信号为输入模式。

MISO:主设备数据输入,从设备数据输出,所以主设备MISO信号为输入模式,从设备的MISO信号为输出模式。

SPI接口连接图

注意:MOSI和MISO不能交叉连接(可以把主从机理解为一个整体系统,MOSI为系统主机发送从机接收的数据线,MISO为主机接收从机发送的数据线)

SPI数据传输方向

SPI作为全双工的的串行通信协议,数据传输时高位在前,低位在后。主机和从机公用由主机产生的SCK信号,所以在每个时钟周期内主机和从机有1bit的数据交换(因为MOSI和MISO数据线上的数据都是在时钟的边沿处被采样)。如下图:

SPI协议规定数据采样是在SCK的上升沿或下降沿时刻(由SPI模式决定,下面会说到),观察上图,在SCK的边沿处(上升沿或下降沿),主机会在MISO数据线上采样(接收来从机的数据),从机会在MOSI数据线上采样(接收来自主机的数据),所以每个时钟周期中会有一bit的数据交换。

SPI传输模式

SPI总线传输一共有4种模式,这4种模式分别由时钟极性(CPOL)和时钟相位(CPHA)来定义。

CPOL:规定了SCK时钟信号空闲状态的电平

CPHA:规定了数据是在SCK时钟的上升沿还是下降沿被采样

模式0:CPOL=0,CPHA =0 SCK空闲为低电平,数据在SCK的上升沿被采样(提取数据)

模式1:CPOL=0,CPHA =1 SCK空闲为低电平,数据在SCK的下降沿被采样(提取数据)

模式2:CPOL=1,CPHA =0 SCK空闲为高电平,数据在SCK的下降沿被采样(提取数据)

模式3:CPOL=1,CPHA =1 SCK空闲为高电平,数据在SCK的上升沿被采样(提取数据)

以模式0为例:SCK空闲为低电平,数据在SCK的上升沿被采样(提取数据),在SCK的下降沿切换数据线的数据。

◐在时钟的第1个上升沿(游标1处)(采样点)

MOSI上数据为1,则在此边沿从机采样(提取)数据为1,采样点在MOSI数据线的中间。

MISO上数据为0,则在此边沿主机采样(提取)数据为0,采样点在MISO数据线的中间。

◐在时钟的第1个下降沿(游标2处)(切换点)

MOSI上数据由1切换为0,,数据在时钟下降沿时切换数据。

MISO上数据由0切换为1,,数据在时钟下降沿时切换数据。

◐在时钟的第2~8个上升沿(采样点),主机在MISO上采样数据,从机在MOSI上采样数据。

◐在时钟的第2~8个下降沿(切换点),主机在MISO上切换数据,从机在MOSI上切换数据

以下内容摘自SPI总线协议及SPI时序图详解 —— Ady Lee

这里主要详解模式0(CPOL=0,CPHA=0)的时序:

我们来关注SCK的第一个时钟周期,在时钟的前沿采样数据(上升沿,第一个时钟沿),在时钟的后沿输出数据(下降沿,第二个时钟沿)。

首先来看主器件,主器件的输出口(MOSI)输出的数据bit1,在时钟的前沿被从器件采样,那主器件是在何时刻输出bit1的呢?bit1的输出时刻实际上在SCK信号有效以前,比 SCK的上升沿还要早半个时钟周期。bit1的输出时刻与SSEL信号没有关系

再来看从器件,主器件的输入口MISO同样是在时钟的前沿采样从器件输出的bit1的,那从器件又是在何时刻输出bit1的呢?从器件是在SSEL信号有效后,立即输出bit1,尽管此时SCK信号还没有起效

关于上面的主器件和从器件输出bit1位的时刻,可以从以下两图中得到验证。

注意上图中,CS信号有效后(低电平有效,注意CS下降沿后发生的情况),故意用延时程序延时了一段时间,之后再向数据寄存器写入了要发送的数据,来观察主器件输出bit1的情况(MOSI)。

可以看出,bit1(值为1)是在SCK信号有效之前的半个时钟周期的时刻开始输出的(与CS信号无关),到了SCK的第一个时钟周期的上升沿正好被从器件采样。

上图中,注意看CS和MISO信号。我们可以看出,CS信号有效后,从器件立刻输出了bit1(值为1)。

通常我们进行的spi操作都是16位的。下图记录了第一个字节和第二个字节间的相互衔接的过程。

第一个字节的最后一位在SCK的上升沿被采样,随后的SCK下降沿,从器件就输出了第二个字节的第一位。

软件SPI程序源码

Soft_SPI.c

#include "Soft_SPI.h"void SPI_Delay()//每步的间隔 用于等待电平稳定和控制通讯速率{}//MOSI拉高 移植时需修改void MOSI_H(){SOFT_SPI_MOSI = 1;}//MOSI拉低 移植时需修改void MOSI_L(){SOFT_SPI_MOSI = 0;}//MISO拉高 移植时需修改void MISO_H(){SOFT_SPI_MISO = 1;}//MISO拉低 移植时需修改void MISO_L(){SOFT_SPI_MISO = 0;}//SCK拉高 移植时需修改void SPI_SCK_H(){SOFT_SPI_SCK = 1;}//SCK拉低 移植时需修改void SPI_SCK_L(){SOFT_SPI_SCK = 0;}//读取MISO电平 移植时需修改uint8_t MISO_Read(){SOFT_SPI_MISO = 1;SPI_Delay();return SOFT_SPI_MISO;}//空闲时时钟极性(CPOL)0为低电平 1为高电平//数据有效时钟缘相位(CPHA)0为奇数缘 1为偶数缘/* CPOL = 0, CPHA = 0, MSB first */uint8_t SOFT_SPI_RW_MODE0(uint8_t write_dat){uint8_t i, read_dat = 0;SPI_SCK_L();for( i = 0; i < 8; i++ ){read_dat <<= 1; read_dat |= MISO_Read();if(write_dat & 0x80)MOSI_H(); elseMOSI_L(); write_dat <<= 1;SPI_Delay();SPI_SCK_H(); SPI_Delay();SPI_SCK_L(); }return read_dat;}/* CPOL=0,CPHA=1, MSB first */uint8_t SOFT_SPI_RW_MODE1(uint8_t write_dat) {uint8_t i, read_dat = 0;SPI_SCK_L();for(i = 0; i < 8; i++)//循环8次{if(write_dat & 0x80)MOSI_H();//若最到位为高,则输出高elseMOSI_L();//若最到位为低,则输出低write_dat <<= 1;//低一位移位到最高位SPI_Delay();SPI_SCK_H();//拉高时钟SPI_Delay();read_dat <<= 1;//数据左移read_dat |= MISO_Read();SPI_SCK_L();//拉低时钟}return read_dat;//返回数据}/* CPOL=1,CPHA=0, MSB first */uint8_t SOFT_SPI_RW_MODE2(uint8_t write_dat) {uint8_t i, read_dat = 0;SPI_SCK_H();for(i = 0; i < 8; i++)// 循环8次{read_dat <<= 1;//数据左移read_dat |= MISO_Read(); if(write_dat & 0x80)MOSI_H();//若最到位为高,则输出高elseMOSI_L();//若最到位为低,则输出低write_dat <<= 1;//低一位移位到最高位SPI_Delay();SPI_SCK_L();//拉低时钟SPI_Delay();SPI_SCK_H();//拉高时钟}return read_dat;//返回数据}/* CPOL = 1, CPHA = 1, MSB first */uint8_t SOFT_SPI_RW_MODE3(uint8_t write_dat){uint8_t i, read_dat = 0;SPI_SCK_H();for( i = 0; i < 8; i++ ){if(write_dat & 0x80)MOSI_H(); elseMOSI_L(); write_dat <<= 1;SPI_Delay();SPI_SCK_L(); SPI_Delay();read_dat <<= 1; read_dat |= MISO_Read(); SPI_SCK_H(); }return read_dat;}

Soft_SPI.h

#ifndef SOFT_SPI_H_#define SOFT_SPI_H_#include <STC89C5xRC.H>#include "stdint.h"sbit SOFT_SPI_SCK= P3^2;sbit SOFT_SPI_MOSI= P1^0;sbit SOFT_SPI_MISO= P1^0;//MOSI拉高 移植时需修改void MOSI_H();//MOSI拉低 移植时需修改void MOSI_L();//MISO拉高 移植时需修改void MISO_H();//MISO拉低 移植时需修改void MISO_L();//SCK拉高 移植时需修改void SPI_SCK_H();//SCK拉低 移植时需修改void SPI_SCK_L();//读取MISO电平 移植时需修改uint8_t MISO_Read();void SPI_Delay();//每步的间隔 用于等待电平稳定和控制通讯速率uint8_t SOFT_SPI_RW_MODE0(uint8_t write_dat);uint8_t SOFT_SPI_RW_MODE1(uint8_t write_dat);uint8_t SOFT_SPI_RW_MODE2(uint8_t write_dat);uint8_t SOFT_SPI_RW_MODE3(uint8_t write_dat);#endif

如果觉得《【51单片机快速入门指南】5:软件SPI》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。