SPI是Sysnchronous Serial Peripheral Interface 的缩写。SPI是一种全双工、高速、同步的通信总线,有两种操作模式:主模式和从模式。所谓全双工是指SPI主器件在向从器件发送数据的同时,也读取(或者接收从器件)的数据,从器件接收主器件数据的同时也向主器件发送数据。STC15W系列部分单片机内部集成了SPI总线接口。SPI总线在嵌入式系统中非常重要,如多片单片机间通信,SPI flash存储芯片的数据读写等。SPI总线由4条线组成,分别为:MOSI、MISO、SCLK、SS。下面分别对这4条线做下说明。

MOSI(Master Out Slave In)主器件输出从器件输入,用于主器件到从器件的串行数据传输。当SPI器件做主器件时是信号输出线,当SPI器件做从器件时是信号输入线。在时钟的前半周期,主机将数据放在MOSI信号线上,从机在该边界处获取数据。

MISO(Master In Slave Out):主器件的输入,从器件的输出,用于实现从器件到主器件的数据传输。当SPI器件做主器件时是信号输入线,当SPI器件做从器件时是信号输出入线。SPI规范中一个主机可以连接多个从机,主机的MISO线会连接到多个从机上,当主机与其中一个从机通信时,因将其他从机MISO脚驱动置为高阻状态(将SS脚拉高)。

SCLK(SPI Clock):串行时钟信号,用于同步主器件和从器件之间在MOSI及MISO线上的数据传输。当主器件启动一次数据传输时,自动产生8个SCLK时钟周期信号给从机。在SCLK的每个跳变处(上升沿或下降沿)移处一位数据。因此,一次数据传输可以传输一个字节的数据。

SS(Slave Select):从机选择信号(线),可以说是片选(CS)信号,从机选择信号是一个输入信号,低电平有效,故STC15单片机说明书中,在SS上加了一横线。当器件的SS脚未必设置成忽略时,当SPI器件的SS脚被拉低时,该机就被设置成从器件。

STC15系列单片机SPI的功能框图如下:

STC15系列单片机的SPI相关特殊功能寄存器如下:

有了对SPI寄存器的了解,就可以来编写SPI的库函数。建两个文件分别以stcspior.h, stcspi.c存入C51 Template文件夹下Library文件夹中。完成后的头文件如下:

/*stcspi.hDesigned by Bill LiuVersion 0.0 Modified last by Bill Liu on 12/26/2021
*/#ifndef __STCSPI_H__
#define __STCSPI_H__#include "mtype.h"
#include "stc15w4k.h"
#include "stcint.h"
#include "delay.h"extern FSYSCLOCK FSCLK; //FSCLK was defined in mian.h, FSYSCLOCK was defined in mtype.h//***********************************************************
typedef enum
{SPI_PG1 = 0, //P1.2/SS,P1.3/MOSI,/P1.4/MISO,P1.5SCLKSPI_PG2,     //P2.4/SS_2,P2.3/MOSI_2,P2.2/MISO_2,P2.1/SCLK_2SPI_PG3      //5.4/SS_3,P4.0/MOSI_3,P4.1/MISO_3,P4.3/SCLK_3
}SPI_PINGROUP; //***********************************************************
typedef enum
{SPI_FCLK0 = 0, //cpu fclk/4SPI_FCLK1, //cpu fclk/8SPI_FCLK2, //cpu fclk/16SPI_FCLK3, //cpu fclk/32
}SPI_FCLK; //frequency of SPI clk/***********************************************************
Function: SPI_PinSel(SPI_PINGROUP mSel);
Return value: void
Discription: configure SPI pins
Example:SPI_PinSel(SPI_PG1); //P1.2/SS,P1.3/MOSI,/P1.4/MISO,P1.5SCLK
***********************************************************************/
void SPI_PinSel(SPI_PINGROUP mSel);/***********************************************************
Function: SPI_ClkSel(SPI_FCLK mSel);
Return value: void
Discription: configure SPI clock
Example:SPI_PinSel(SPI_FCLK0); //cpu fclk/4
***********************************************************************/
void SPI_ClkSel(SPI_FCLK mSel);/***********************************************************
Function: SPI_SSPin(BOOL mEnable);
Return value: void
Discription: configure SPI SS pin enable/disable
Example:SPI_SSPin(0); //SPI SS pin is ignored
***********************************************************************/
void SPI_SSPin(BOOL mEnable);/***********************************************************
Function: SPI_Enable(BOOL mEnable);
Return value: void
Discription: configure SPI enable/disable
Example:SPI_Enable(1); //SPI enableSPI_Enable(0); //SPI disable
***********************************************************************/
void SPI_Enable(BOOL mEnable);/***********************************************************
Function: SPI_DataOrder(BOOL fLSB);
Return value: void
Discription: configure transmit data order for SPI transmitting
Example:SPI_DataOrder(1); //begin from LSB
***********************************************************************/
void SPI_DataOrder(BOOL fLSB);/***********************************************************
Function: SPI_MasterEnable(BOOL bMaster);
Return value: void
Discription: configure SPI device master/slave
Example:SPI_MasterEnable(1); //set this device as master
***********************************************************************/
void SPI_MasterEnable(BOOL bMaster);/***********************************************************
Function: SPI_IdleClkPol(BOOL bHigh);
Return value: void
Discription: configure SPI idle clk voltage level
Example:SPI_IdleClkPol(1); //SPI idle clk voltage level: high
***********************************************************************/
void SPI_IdleClkPol(BOOL bHigh);/***********************************************************
Function: SPI_ClkPhase(BOOL bSOT); // SOT:sampling on the trailing edge
Return value: void
Discription: configure SPI  clk phase, sampling on the trailing edge/sampling on the leading edge
Example:SPI_ClkPhase(1); //sampling on the trailing edge
***********************************************************************/
void SPI_ClkPhase(BOOL bSOT);/***********************************************************
Function: SPI_Init(BOOL mSSable,SPI_PINGROUP mSel, SPI_FCLK mSelClk, BOOL bMaster);
Return value: void
Discription: configure SPI  device
Example:SPI_Init(1, SPI_PG1, SPI_FCLK0, 1);//SS pin enable, SPI pin select group 0, SPI clock, mcu clock/4, master device
***********************************************************************/
void SPI_Init(BOOL mSSable,SPI_PINGROUP mSel, SPI_FCLK mSelClk, BOOL bMaster); /***********************************************************
Function: SPI_SendChar(i8 mdata);
Return value: void
Discription: master SPI device send  char
Example:SPI_SendChar(123);
***********************************************************************/
void SPI_SendChar(i8 mdata); /***********************************************************
Function: SPI_SendStringAndEof(i8* str);
Return value: void
Discription: master SPI device transmit string and end of flag
Example:SPI_SendStringAndEof("Hello world!");
***********************************************************************/
void SPI_SendStringAndEof(i8* str); /***********************************************************
Function: SPI_RecChar(i8* mdata);
Return value: char
Discription: SPI slave device receive  char
Example:char tem;SPI_RecChar(&tem);
***********************************************************************/
char SPI_RecChar(i8* mdata); /***********************************************************
Function: SPI_SendAndRecChar(i8 mdata);
Return value: void
Discription: master SPI device transmit char and receive char
Example:char tem = SPI_SendAndRecChar(i8 mdata);
***********************************************************************/
char SPI_SendAndRecChar(i8 mdata);/***********************************************************
Function: SPI_RecStringTillEof(i8* str);
Return value: void
Discription: SPI slave device receive  string till end of flag
Example:char str[20];SPI_RecStringTillEof(str);
***********************************************************************/
void SPI_RecStringTillEof(i8* str); #endif

在写源代码时需要特别注意的是要清除SPSTAT中的SPIF及WCOL需写入1,有点类似STM32部分寄存器的操作,前面在写中断库函数时,就没注意到这点,现已修改过来。完成后的源代码如下:

/*stcspi.cDesigned by Bill LiuVersion 0.0 Modified last by Bill Liu on 12/26/2021
*/#include "stcspi.h"//***********************************************************
void SPI_PinSel(SPI_PINGROUP mSel)
{ui8 tem = P_SW1;SetBits(&tem,3,2,mSel);P_SW1 = tem;
}
//End of SPI_PinSel(SPI_PINGROUP mSel)//***********************************************************
void SPI_ClkSel(SPI_FCLK mSel)
{ui8 tem = SPCTL;SetBits(&tem,1,0,mSel);SPCTL = tem;
}
//End of SPI_ClkSel(SPI_FCLK mSel)//***********************************************************
void SPI_SSPin(BOOL mEnable)
{if(mEnable)SPCTL &= 0x7F;elseSPCTL |= 0x80;
}
//End of SPI_SSPin(BOOL mEnable)//***********************************************************
void SPI_Enable(BOOL mEnable)
{if(mEnable)SPCTL |= 0x40;elseSPCTL &= 0xBF;
}
//End of SPI_Enable(BOOL mEnable)//***********************************************************
void SPI_DataOrder(BOOL fLSB)
{if(fLSB)SPCTL |= 0x20;elseSPCTL &= 0xDF;
}
//End of SPI_DataOrder(BOOL fMSB)//***********************************************************
void SPI_MasterEnable(BOOL bMaster)
{if(bMaster)SPCTL |= 0x10;elseSPCTL &= 0xEF;
}
//End of SPI_MasterEnable(BOOL bMaster)//***********************************************************
void SPI_IdleClkPol(BOOL bHigh)
{if(bHigh)SPCTL |= 0x08;elseSPCTL &= 0xF7;
}
//End of SPI_IdleClkPol(BOOL bHigh)//***********************************************************
void SPI_ClkPhase(BOOL bSOT)
{if(bSOT) //sampling on the trailing edgeSPCTL |= 0x04;elseSPCTL &= 0xFB;
}
//End of SPI_ClkPhase(BOOL bSOT)//***********************************************************
void SPI_Init(BOOL mSSable,SPI_PINGROUP mSel, SPI_FCLK mSelClk, BOOL bMaster)
{SPI_SSPin(mSSable);SPI_PinSel(mSel);SPI_ClkSel(mSelClk);SPI_MasterEnable(bMaster);
}
//End of SPI_Init(BOOL mSSable,SPI_PINGROUP mSel, SPI_FCLK mSelClk, BOOL bMaster)//***********************************************************
void SPI_SendChar(i8 mdata)
{SPI_Enable(1);STC_ClearSPIFlag();//clear flagSPDAT = mdata;while(!(SPSTAT & 0x80));SPSTAT = 0xFF; //clear flag
}
//End of SPI_SendChar(i8 mdata)//***********************************************************
void SPI_SendStringAndEof(i8* str)
{ ui8 i = 0;while(str[i] != 0){SPI_SendChar(str[i]);Delayxus(2,FSCLK);i++;}SPI_SendChar(0xFF);
}
//End of SPI_SendStringAndEof(i8* str)//***********************************************************
char SPI_RecChar(i8* mdata)
{ SPI_Enable(1);STC_ClearSPIFlag();//clear flagwhile(!(SPSTAT & 0x80));STC_ClearSPIFlag();//clear flag*mdata = SPDAT;return *mdata;
}
//End of SPI_RecChar(i8* mdata)//***********************************************************
char SPI_SendAndRecChar(i8 mdata)
{i8 tem;SPI_Enable(1);STC_ClearSPIFlag();//clear flagSPDAT = mdata;while(!(SPSTAT & 0x80));STC_ClearSPIFlag();//clear flagtem = SPDAT;return tem;
}
//End of SPI_SendAndRecChar(i8 mdata)//***********************************************************
void SPI_RecStringTillEof(i8* str)
{ui8 i = 0;memset(str, 0, strlen(str));SPI_Enable(1);STC_ClearSPIFlag();//clear flagwhile(str[i] != 0xFF){STC_ClearSPIFlag();//clear flagwhile(!(SPSTAT & 0x80));STC_ClearSPIFlag();//clear flagstr[i] = SPDAT;i++;}str[i] = 0;
}
//SPI_RecStringTillEof(i8* str)

此处不做验证示例,以后在项目实战中再做说明。本文代码及相关库文件已打包上传到CSDN,如需离线查看,可去下载,文件名为STC15 SPI Library Source Code.rar。

51单片机实战教程(21 同步串行外围通信接口SPI)相关推荐

  1. 51单片机实战教程(一 数据类型别名定义)

    前面已经讲了C语言基础,从此以后将进行编程实战.C数据类型名较长,编程输入不太方便. 下面编写一个定义数据类型别名的程序,并定义实现后面例程常用到的位操作及字符串操作函数. 1. 打开前面教程中创建的 ...

  2. 51单片机实战教程(34 线缆摇摆测试机设计)

    本文将讲解51单片机在线缆摇摆测试机中的应用,包含单片机程序及人机界面程序设计,将以本人以前做过的一个案子为例来做讲解. 公司外购一款线缆,进料检验时,需要做摇摆测试,以判定品质是否合格.公司当时没有 ...

  3. 51单片机实战教程(32 人机界面编程9)

    人机界面(Usart HMI)屏可以轻松设计漂亮友好的人机界面,也可以通过Usart串口与机器CPU通信.但仅有这些是不够的.还需要自定义 通信协议.通信协议包含波特率设置,数据格式,编码解码,数据打 ...

  4. 51单片机实战教程(33 步进电机的驱动与控制)

    步进电机虽然同为电机的一种,但不能像直流电机或者交流电机那样按额定电压与电流给线圈通上直流或交流电机就可正常运转.它需要专用的驱动器或驱动电路供电,才可正常工作.每给驱动器一个脉冲信号,电机就转动一定 ...

  5. 51单片机实战教程(六 网线测试治具设计)

    我们日常接触的线材如USB.HDMI.VGA及网线等在生产过程中一般都需要做导通.线序测试.其中有Overmolding制程的产品还需做短路测试.其对应的连接器也需要做同样的测试.厂商的通常做法是购买 ...

  6. 51单片机实战教程(22 看门狗)

    在要求高可靠性的系统中,为防止系统在异常情况下或者受到异常干扰导致MCU/CPU程序跑飞,系统长时间异常工作, 通常的做法就是引入看门狗.如果MCU/CPU不在规定时间内按要求访问看门狗,看门狗就强迫 ...

  7. 51单片机实战教程(28 人机界面编程五)

    2本文将介绍Usart HMI常用指令 1 page指令 用于页面切换,使用格式 : page obj obj指页面名称或id, 示例: 有下面两个页面, 要从page0 切换到main 代码如下: ...

  8. 51 单片机实战教程(13 外围芯片驱动程序之CS1237芯片驱动)

    CS1237芯片是一枚国产24位A/D转换芯片,输出速率可选:10Hz.40Hz.640Hz.1.28kHz.内置时钟电路,不需外部晶振.带可编程PGA,PGA放大倍数可选:1.2.64.128.2 ...

  9. 51 单片机实战教程(14 外围芯片驱动程序之LTC1658芯片驱动)

    LTC1658是一款14bit轨到轨DAC芯片.可选用3V或5V供电,采用3线串口通信(兼容SPI与MICROWIRE),其应用场景为数字校准.工业控制.自动测试设备等.它采用SOP8封装,Pin脚定 ...

最新文章

  1. 第五章 RNA-seq分析
  2. HNUOJ 13341
  3. 数据结构与算法 --- js描述集合
  4. /opt/hbase/conf 中不能启动hbase_Hbase从入门到入坑
  5. 深入JVM系列(二)之GC机制、收集器与GC调优
  6. 微信公众帐号开发教程第13篇-图文消息全攻略
  7. 【设计模式】—— 解释器模式Interpret
  8. 马云经典语录:我不是传奇 我是平凡的人
  9. 亚像素边缘提取方法总结
  10. java后台管理项目策划书_12款适合做Java后台管理系统的项目
  11. 高校全场景智慧教室建设方案
  12. git commit --amend如何合并多个commitId
  13. Cocos Creator接入谷歌广告AdMob详细教程(原创)
  14. CSS实现图片层闪光效果
  15. linux r画图如何输出图片大小,R画图,设画布大小
  16. 产品思维训练 | 你的项目总是不能按期上线,你会如何解决?
  17. 解决webbench运行时卡住的问题
  18. 《C++ 黑客编程揭秘与防范(第2版)》—第6章6.2节详解PE文件结构
  19. unity3D 使用rigidbody.AddForce(movement)
  20. 雷地豫 (易經大意 韓長庚)

热门文章

  1. 安装程序无法自动安装Virtual Machine Communication Interface
  2. 最新广东省知识产权贯标奖励及补助政策汇总大全,包括广州、深圳等
  3. 博弈论之:动态博弈,先下手为强
  4. 安装或卸载时出现“called runscript when not marked in progress”的解决办法,亲测有效!不是通过管理员运行Explorer.exe此方法
  5. 简述微型计算机存储器的分类及各自的特点,存储器分类及各自特点有哪些
  6. MDK 5.36 can‘t add xxx to analyzer
  7. python有哪些细节描写_晨览作文|好作文都有哪些不可或缺的细节描写?
  8. git 拉远端代码强制覆盖本地代码
  9. 智能剪辑工具王者剪辑设置镜头过渡效果流程
  10. InstallShield 软件打包完整教程(含添加自定义依赖环境)