这篇内容有点长,如果有人想透过我的博客学习STM8的SPI,那是我的荣幸

首先我要先说大纲,这样大家心里比较有底,可以把精力都用在SPI理解上

【SPI初步介绍】:介绍SPI如何接线、名称解释、通讯注意事项

【SPI引脚 - 初始化(上)】:相对于STM8,SPI的引脚位置说明,还有引脚的设置,另外还有初始化的部分代码

【SPI寄存器 - 初始化(下)】:使用寄存器做一些设定,例如波特率、SPI开启或关闭、SPI中断、传输方式。。。太多了,要看寄存器手册,我有整理图片出来,另外还包括完整的初始化代码

【SPI通讯】:SPI发送数据、SPI轮询方式接收数据、SPI中断方式接收数据

【SPI初步介绍】

下图是SPI的通讯方式

M:Master(主)

S:Slave(从)

I:Input(输入)

O:Output(输出)

MISO:主设备(M)接收(I)数据,从设备(S)输出(O)数据

MOSI:主设备(M)输出(O)数据,从设备(S)接收(I)数据

SCK:时钟讯号

GPIO:普通I/O口

NSS:或叫SS,由外部的高低电平决定自己是主机还是从机,在STM8里,可以由软件决定,从而省下一个引脚去做别的事情,其他的芯片,就要去看datasheet才知道了

CS:片选(不一定会有),从机决定接收数据的依据,应用在SPI一主多从,就像广播一样,『一年二班小朋友起立!』,但一年一班的小朋友也听到了,不过你不要起立啊,当然,一主一从也有可能用到的

上面解释了各引脚功能,下面解释SPI的通讯方式:

MOSI:主机发送线路。额外说明,主机想收到从机数据,主机要提供SCK,但是产生SCK的唯一条件,就是主机要发数据出去,哪怕是无意义的数据(伪字节),不管主机想发还是收,都不能省略这条线

MISO:如果不打算接收从机数据,就不要接了,如果想收,作为配套的,SCK这条线就必然要接上了

SCK:可接可不接,不接的情况下,是从机已经规定好接收格式,主机必须按照这个格式发送

NSS:可接可不接,上面解释过了

CS:可接可不接,上面也解释过了

最后一点,主机和从机的GND要连上,原理我不知道,这经验是从串口(UART)学来的,任何通讯方式都要共地

【SPI引脚 - 初始化(上)】

因为我是用STM8S开发板来研究的,所以内容就局限在这里,链接是我的另一篇博客,介绍开发板和一些工具https://www.cnblogs.com/PureHeart/p/10824556.html

下面是引脚图

这就是SPI相关的引脚,文章一开始也说了,某些情况下,可以省略几个引脚

然后要说设置的部分了

MISO要设置成『弱上拉输入模式』

MOSI、SCK要设置成『推挽输出模式』

为什么设置成这样,原理我不懂,但是能实现就好了不是吗?

在现今社会里,没有成功就代表什么都不是,可以纠结原理,但不是必要?

扯远了,回来说正题,这两种模式,需要看寄存器手册,我知道有人是用『库』来开发

但我自学的时候就学寄存器了

下面这张图,是GPIO的设定

MISO对应的引脚是PC7,设定为『弱上拉输入模式』,所以DDR=0,CR1=1,CR2=0

MOSI对应的引脚是PC6,设定为『推挽输出模式』,所以DDR=1,CR1=1,CR2=0

SCK对应的引脚是PC5,设定为『推挽输出模式』,所以DDR=1,CR1=1,CR2=0

NSS我不想外部控制,想用软件的方式选择是主机还是从机,在后续文章关于SPI寄存器会有说明

有了这份数据,可以写代码了,不过先上一张Px_DDR寄存器的图,关于GPIO的寄存器,我觉得看上面的表格应该就够了,上图只是说明对应位置

PC_DDR = 0x60; // 0110 0000
PC_CR1 = 0xe0; // 1110 0000
PC_CR2 = 0x60; // 0110 0000 /* ==================== 分割线 ====================== 上方是寄存器控制,相对来说比较简洁的写法 */
/* ==================== 分割线 ====================== 下方是比较针对的写法,直接控制寄存器内的某一位,两种写法选一个即可 */ PC_DDR_DDR5 = 1; // 配置PC5(SCK)端口为输出模式
PC_CR1_C15 = 1; // 配置PC5(SCK)端口为推挽输出模式
PC_CR2_C25 = 1; // 配置PC5(SCK)端口为高速率输出 PC_DDR_DDR6 = 1; // 配置PC6(MOSI)端口为输出模式
PC_CR1_C16 = 1; // 配置PC6(MOSI)端口为推挽输出模式
PC_CR2_C26 = 1; // 配置PC6(MOSI)端口为高速率输出 PC_DDR_DDR7 = 0; // 配置PC7(MISO)端口为输入模式
PC_CR1_C17 = 1; // 配置PC7(MISO)端口为弱上拉输入模式
PC_CR2_C27 = 0; // 禁止PC7(MISO)端口外部中断

关于『寄存器』和『寄存器的某一位』,直接用一个例子来解释比较快

【所有一年级的学生去操场】【一年一班的同学去操场】

『寄存器』就相当于一年级

『寄存器的某一位』就相当于一年级的某一班

上面也说了,分割线的上方和下方,选择一个来用即可

上面代码的变量,全部都定义在『iostm8s103F3.h』里面了,当然,这是官方的头文件里面的内容,不是我自己命名这些变量的

貌似官方没有SPI范例,但是有Timer、UART之类的范例,随便拿一个来添加SPI代码即可

这是官方全部范例的链接,提取码是gszh,需要请自取https://pan.baidu.com/s/1La0LdFQxKl2_AyZXkBkv3w

【SPI寄存器 - 初始化(下)】

虽然图片有点多,但是代码没几行的

下面我直接贴上我测试时的代码,具体情况可能大家都不同,寄存器的几个位修改一下就好了,我直接配合『初始化-上』的代码一起贴出来

其实整个初始化的思路如下

1.打开SPI时钟

2.引脚配置

3.开启SPI中断(如果不需要则不用开)

4.设置SPI_CR1(SPI控制寄存器1)

5.设置SPI_CR2(SPI控制寄存器2)

6.开启SPI

void Init_SPI(void)
{
CLK_PCKENR1 |= 0x02; //打开SPI时钟
/*PC6、PC5设置为输出,最大10MHz*/
//PC_DDR = 0x60; // 0110 0000
//PC_CR1 = 0xe0; // 1110 0000
//PC_CR2 = 0x60; // 0110 0000 PC_DDR_DDR5 = 1; // 配置PC5(SCK)端口为输出模式
PC_CR1_C15 = 1; // 配置PC5(SCK)端口为推挽输出模式
PC_CR2_C25 = 1; // 配置PC5(SCK)端口为高速率输出 PC_DDR_DDR6 = 1; // 配置PC6(MOSI)端口为输出模式
PC_CR1_C16 = 1; // 配置PC6(MOSI)端口为推挽输出模式
PC_CR2_C26 = 1; // 配置PC6(MOSI)端口为高速率输出 PC_DDR_DDR7 = 0; // 配置PC7(MISO)端口为输入模式
PC_CR1_C17 = 1; // 配置PC7(MISO)端口为弱上拉输入模式
PC_CR2_C27 = 0; // 禁止PC7(MISO)端口外部中断 SPI_ICR_RXIE = 1; // 开启SPI中断接收(下方备注) // [7]先发MSB
// [6]禁止SPI
// [5][4][3]f_Master / 2
// [2]主设备
// [1]空闲时SCK保持低电平
// [0]数据采样从第一个时钟沿开始
SPI_CR1 = 0x04; /*MSB、1MHz、主设备、CPOL空闲为低、CPHA第一个时钟开始*/ // [7]双线单向模式
// [6]输入使能(只接收模式)
// [5]CRC计算禁止
// [4]下个发送数据来自Tx缓冲
// [3]保留
// [2]全双工(同时收发)
// [1]使能软件从设备管理(不需要判断硬件CS位,节省一个引脚)
// [0]主模式
SPI_CR2 = 0x03; /*双线单向视距传输、CRC计算禁止、软件NSS、主模式*/ SPI_CR1_SPE = 1; // 打开SPI
}

备注:关于中断的部分,如果想要使用,还必须加上一行代码『asm("rim");』,通常加在main函数里面的while(1)之前

      这个代码就像电源的总闸一样,你房间的电闸打开了,但总闸没开,结果还是没有电

      当然有一个相对应的,就是关闭总闸『asm("sim");』

【SPI通讯】

终于到最后的环节了,关于发送和接收,接收又分两种,轮询和中断

直接上代码吧,也没几行

/* SPI发送 */
void SPI_sendchar(unsigned char c)
{
while(!(SPI_SR & 0x02)); // 等待发送缓冲区『为』空
SPI_DR = c; // 将发送的数据写到数据寄存器
//while(!(SPI_SR & 0x01)); // 轮询的方式,等待接收缓冲区『非』空
//UART1_sendchar(SPI_DR); // 备注
} /* SPI中断 */
#pragma vector=SPI_RXNE_vector
__interrupt void SPI_RXNE_IRQHandler(void)
{
//RxBuf[cnt++]=SPI_DR;
while(!(SPI_SR & 0x01)); // 轮询
UART1_sendchar(SPI_DR); // 备注
}

备注:我用很迂回的方式来显示结果,逻辑分析仪抓SPI还没研究成功,所以我借用了UART(串口)

       轮询或中断接收到数据,透过串口把数据发送给『USB转TTL小板』,在电脑上用串口调试助手显示出来

终于写完了,谢谢你的观看,希望对你有帮助

【STM8】SPI通讯的更多相关文章

  1. SPI的学习和ESP8266的SPI通讯测试

    SPI简介: SPI是串行外设接口(Serial Peripheral Interface)的缩写.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时 ...

  2. [Andorid] 通过JNI实现kernel与app进行spi通讯

    CPU:RK3399 系统:Android 7.1 人脸识别的要求越来越高,因此主板增加了 SE 加密芯片,加密芯片通过 spi 接口与 CPU 通讯. 对于 kernel 层的代码,Linux 原始 ...

  3. Linux学习 :SPI通讯协议

    SPI接口的全称是"Serial Peripheral Interface",意为串行外围接口,是Motorola首先在其MC68HCXX系列处理器上定义的.SPI接口主要应用在E ...

  4. LPC1768的SPI通讯

    SPI是一种全双工串行接口,可处理多个连接到指定总线上的主机和从机.在数据传输过程中总线上只能有一个主机和一个从机通信.在数据传输中,主机总是会向从机发送一帧8到16个位的数据,而从机也总会向主机发送 ...

  5. SPI通讯协议

    一.SPI概述 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线, ...

  6. SPI通讯(Serial Peripheral interface)

    1. SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线:SCLK,MISO,MOSI,CS 2. SPI结构简图: 可以看出,SPI主从设备两端都有一个位移寄存器,数据在位 ...

  7. 【STM8】外挂存储器W25Q16

    好像有几张图片被强制缩小了?看到这篇博客的人先对你们说声抱歉,我不知道怎么设置 文字就可以很长(文章宽度的全部),图片就只有文章宽度的2/3宽度 开新分页应该就是原始尺寸了,这点还是和大家说抱歉... ...

  8. MFRCC522 SPI无法通讯【worldsing笔记】

    用单片机于MRFC522与单片接时,加上485通讯后出现很诡异的像: 只要485芯片上有收到外部发送的信号时RC522就死掉,经过仿真卡在了SPI的收发部分(等待回复) u8 MFRC522Write ...

  9. STM32学习笔记——SPI串行通讯(向原子哥学习)

    一.SPI  简介 SPI是 Serial Peripheral interface 的缩写,就是串行外围设备接口.SPI 接口主要应用在  EEPROM, FLASH,实时时钟,AD 转换器,还有数 ...

随机推荐

  1. docker使用redis过程出现的问题记录

    第一次使用docker搭建成功了单机版redis,但在使用过程中,还是遇到了不少问题,故而先把这些问题记录下来,以防后面再出现会忘记. 目前,只是在docker中搭建了三个单机版的容器,打算先捣鼓一周 ...

  2. 力扣 - 剑指 Offer 67. 把字符串转换成整数

    题目 剑指 Offer 67. 把字符串转换成整数 思路1 根据题意,要解决这题,首先要判断的条件有: 不包括首位空格 第一位必须为:+.-.数字三者其一,否则不合法 数字必须连续的,如果遇到非数字, ...

  3. Treevalue(0x02)——函数树化详细解析(上篇)

    本文将对 func_treelize 这一treevalue库中的核心功能进行详细的原理解析. 关于treevalue的概述,可以参考之前的文章:Treevalue(0x01)--功能概述 树化函数基 ...

  4. ubuntu图标

    linux桌面图标跟windows系统一样,只是个快捷方式,在/usr/share/applications/目录下面有应用程序的启动图标,可以直接复制到桌面,如果这个文件夹下没有的话,可以自己新建一 ...

  5. 【JAVA】编程(4)---摇色子

    作业要求: 利用" Math.random ( )  "生成随机数的方法来模拟同时摇三个色子获得的点数:点数的多少不同,也会导致不同的输出结果:可适当对程序增添一些更有趣的功能: ...

  6. 暑假算法练习Day4

    已经坚持第四天啦,Fighting!!! 1008 数组元素循环右移问题 (20 分) 一个数组\(A\)中存有\(N\)\((>0)\)个整数,在不允许使用另外数组的前提下,将每个整数循环向右 ...

  7. js中修改this指向的方法(call,apply,bind)

    前言:call.apply和bind都是为了改变某个函数运行时的this指向的,对于前端人员来说,关于this的掌握程度,直接决定了前端水平的高低.下面我们就来简单浅显易懂的来看一下es5中常用的三种 ...

  8. linux安装python3.6.1

    Linux下安装Python3.6和第三方库   如果本机安装了python2,尽量不要管他,使用python3运行python脚本就好,因为可能有程序依赖目前的python2环境, 比如yum!!! ...

  9. [loj3032]馕

    (直接贪心会导致分子和分母过大) 令$S_{i}=\sum_{j=1}^{L}V_{i,j}$(即其独吞整个馕的快乐度),对第$i$个人求出$n$个位置$x_{1},x_{2},...,x_{n-1} ...

  10. 使用国内的镜像源搭建 kubernetes(k8s)集群

    1. 概述 老话说的好:努力学习,提高自己,让自己知道的比别人多,了解的别人多. 言归正传,之前我们聊了 Docker,随着业务的不断扩大,Docker 容器不断增多,物理机也不断增多,此时我们会发现 ...