STM32-——SPI

一、通信

1.1通信是什么;

通信是将一个设备的数据发送到另一个设备中,从而实现硬件的扩展;

1.2通信的目的是什么;

实现硬件的扩展-在STM32中集成了很多功能,例如PWM输出,AD采集,定时器等,在STM32中是通过内部硬件电路实现的,可以通过指针操作相应的寄存器,来控制硬件电路,通过读来获取电路状态,通过写来操控电路;而有一些功能是STM32内没有集成的例如蓝牙无线遥控,陀螺仪测姿态等,此时需要外挂模块,来实现这些功能,而这些功能的数据是保存在外挂模块的寄存器中的,STM32想要获取这些数据来控制外挂模块就需要与该设备进行通信,通过读写外挂模块相应的寄存器,实现对外挂模块的控制,从而达到硬件扩展的功能;

1.3设备间如何进行通信

通过在设备间连接一根或者多根通信线,实现数据的接收和数据的发送,从而达到主控模块控制外挂模块的功能;

1.4通信协议是什么;

通信协议是指通信双方规定的通信规则,双方按照协议进行数据的收发;

1.5有哪些通信协议;

主要的通信方式:串口通信(USART),I2C,SPI,CAN,USB通信;

1.6通信协议有哪些模式;

通信方式的特点主要由以下几种模式决定:双工模式,时钟模式,电平模式,设备模式;

1.7通信特性具体是什么;

1.7.1双工模式:

双工模式分为全双工,半双工,单工;

全双工:通信双方可以同时接收或者发送数据,一般有两根通信线,接收线路和发送线路互不干扰,全双工;

半双工:通信双方在指定时间,只能接收或者只能发送,一根通信线,半双工;

单工:数据只能由一个设备发送另一个设备接收,一根通信线(全双工撤去一根通信线可转换为单工);

1.7.2时钟模式

同步时钟:通信双方在时钟线的时钟脉冲驱动下,进行数据的收发;

异步时钟:通信双方没有时钟线,需要双方约定传输频率(波特率),根据传输频率来接收数据;

*波特率和比特率

波特率:单位时间内接收的码元个数,单位是码元/s,也称波特;在通信系统中,二进制的一位称为码元或者符号;波特率是指单位时间内传送二进制数据的位数,单位用bps(位/秒)表示,记作波特

比特率:单位时间内接收的比特的个数,单位是bit/s,比特率来衡量异步串行通信的数据传输速率,即单位时间内传送二进制有效数据的位数,单位用bps表示。

在二进制下波特和比特是相同的,多进制下是不同的;

1.7.3电平模式

单端信号:通信线上的电平是对GND的电平,所以通信设备需要共地;

差分信号:俩根传输线上的电位差,差分信号具有很强的抗干扰性,所以差分信号一般可以传输很远的距离;

1.7.4设备模式

点对点设备:

多设备;

多设备分为一主多从模式和多主多从模式;

一主多从模式:指的是有一个主机,多个从机,主机对总线的时钟线有绝对的控制权,从机在任何时候都只能接收,不能发送;主机在数据线空闲时候,可以调用,从机只能在接收或者发送数据的时候才可以短暂的控制;

多住多从模式

一根总线上挂载了多个设备,这些设备既可以作为从机又可以作为主机;

又分为:固定多主机模式和可变多主机模式;

固定多主机模式:主机的数量是固定的,每个主机都可以掌握总线的控制权,当多个主机同时申请总线控制权时,总线进行仲裁,失败的让出总线控制权;

可变多主机模式:每一个挂载在总线的设备都可以作为主机,当需要作为主机与其他设备进行通信时,申请总线控制权,对从机设备进行寻址即可,通信完成后,让出总线控制权,变回从机;当多个主机同时申请总线控制权时,总线进行仲裁,失败的让出总线控制权;

1.8总结:

STM32-——SPI_第1张图片

二、SPI协议

2.1SPI协议介绍

SPI是(Serial Peripheral Interface)是由Motorola公司开发的一种通用数据总线;

有多根通信线:SCK(Serial Clock串行时钟线),MOSI(Master Output Slave Input主机输出从机输入),MISO(Master Output Slave Input从机输出主机输入),SS(Slave Select片选);

不同的芯片有不同的名字规定:例如MOSI,很多芯片会写成DI,MISO写成DO;SS写成CS,具体参考数据手册;

同步全双工单端;

支持总线挂载多设备;

分析一个协议通过从硬件和软件入手,在硬件方面,电路是如何连接的,输入输出端口如何配置;

在软件方面时序是如何生成的,包括什么,数据是如何传输的,高位先行还是低位先行,完整的时序包括什么;

2.2SPI协议对硬件的规定

所有设备的MOSI连接在一起,MISO连接在一起,SCK连接在一起;每个从设备的CS单独连接在主设备上,GND连接在一起(单端信号),如果从设备没有供电,还需要连接VCC;

输出模式配置为推挽输出,输入模式配置为上拉输入;

*CS单独连接,一主多从的模式下,上电后,默认所有设备的CS都是高电平,此时MISO均为高阻态模式,当主机选中从机通信时,将相应的从机CS置低电平,此时MISO会推挽输出;目的是同一时间只能选择一个主机,防止多个输出导致电路短路;

STM32-——SPI_第2张图片

SPI硬件核心:

分析流程:内置波特率发生器,将输入的系统时钟进行分频后输入给主机的移位寄存器,在时钟脉冲的驱动下,每来一个时钟脉冲,移位寄存器在上升沿将最高位,放在MOSI线上,下降沿从机移位寄存器接收到MOSI上的数据放在最低位;同时时钟脉冲通过SCK输入给从机,从机在同步时钟脉冲的驱动下,主机移位寄存器将最高位放在MOSI同时,也将从机移位寄存器中最高位放在MISO上,在从机接收MOSI时,主机同时接收从机移位寄存器放在MISO上的数据位;这样一个时钟脉冲就实现了主机和从机一位的数据交换,重复8次后,完成一个字节的传输,通过不断以字节为单位的数据交换,完成数据流的传输;

总结:移位寄存器时钟源由主机提供,叫波特率发生器,通过SCK输出为从机提供时钟源,产生的时钟驱动主机移位寄存器向左移出(高位先行),将主机移位寄存器的值移动到从机的移位寄存器中;

过程:波特率发生器时钟的上升沿驱动主机移位寄存器将最高位移动到MOSI数据线上,波特率的下降沿(数据采样)MOSI将数据位移到从机移位寄存器的最低位,同时时钟信号上升沿通过SCK驱动从机移位寄存器将最高位向左移动到MISO上,下降沿移到主机的移位寄存器中;

实现了主机和从机的字节交换,SPI就是基于字节单元交换来实现数据通信的,当主机需要发送一个数据并接受一个数据时候就采用交换时序;

STM32-——SPI_第3张图片

2.3SPI协议对软件的规定

2.3.1时序组成:

起始条件:SS从高电平切换到低电平

STM32-——SPI_第4张图片

停止条件:SS从高电平切换到低电平

STM32-——SPI_第5张图片

交换一个字节:SPI通过配置CPHA(Clock Phase时钟相位)和CPOL(时钟极性clock polarity)的值1或0,配置四种字节传输模式,模式0,模式1,模式2,模式3;

最常用的是模式0;

过程分析:CPOL=0,CPHA=0;

规定在空闲状态时,SCK为低电平;

SCK的第一个边沿移入数据,第二个边沿移出数据;

分析:SS从高电平变为低电平产生起始条件,即选择该设备,此时SCK默认空闲状态为低电平,MOSI电平没有规定,MSIO解除高阻态模式;主机和从机的移位寄存器需要在第一个边沿变化前,起始条件后,将数据位的最高位移出在数据线上,主机和从机移位寄存器需要在下一个边沿时,将数据移入,并在新的边沿到来时将最高位移出,最后一个数据移入后,SCK恢复为空闲状态,低电平,在ss恢复为高电平,产生终止条件后,MSIO恢复为高阻态;这就是传输一个字节的时序STM32-——SPI_第6张图片

模式1

STM32-——SPI_第7张图片

模式2

STM32-——SPI_第8张图片

模式三

STM32-——SPI_第9张图片

2.3.2示波器时序分析

I2C时序是有效数据流第一个字节为寄存器地址,之后依次是读写的数据;

与I2C的时序不同,SPI时序通常是指令集加读写的数据;

SPI通过使用起始条件->指令集(执行什么功能,例如发送执行0x60,具体手册中有介绍);

发送一个指令的时序:发送完成后,此时主机也是获取了一个数据0xFF,但是这个0XFF没有意义;

STM32-——SPI_第10张图片

指定地址写 向SS指定的设备,发送写指令(0x02),   随后在指定地址(Address[23:0])下,写入指定数据(Data)

过程:SS使能后,从高电平变为低电平,下降沿,产生起始条件,同时驱动MOSI移出发送从机的指令集第一位0(对MOSI和MISO初始电平没有规定,同时因为从机没有数据要输入给主机,所以从机移出不用管),第一个边沿变化上升沿,从机采集数据0;直到八个数据采集完毕后,用0x02换取了0xff;

表示写数据指令,最后一个下降沿时刻,吧下一个字节的第一个数据位放在MOSI上,之后重复上述八次,执行三个字节写入要写入寄存器的地址24位地址,之后确定了地址,写入数据即可;

STM32-——SPI_第11张图片

指定地址读 向SS指定的设备,发送读指令(0x03),      随后在指定地址(Address[23:0])下,读取从机数据(Data)STM32-——SPI_第12张图片

完整的时序是起始条件+指令集+地址+停止条件;

三、STM32中的SPI外设

3.1SPI外设的介绍

SPI外设是STM32内部集成的SPI硬件电路,可以自动执行时钟的生成,数据的收发功能减轻了CPU的负担;

可配置为8位/16位数据帧;高位先行/低位先行;

时钟频率:Fpclk/ (2, 4, 8, 16, 32, 64, 128, 256);

支持一主多从模式,主模式或者从模式;

可以精简为:半双工,单工模式;

支持DMA;

兼容I2S协议;(I2S是数字音频传输协议与I2C没关系)

3.2SPI外设的结构图

STM32-——SPI_第13张图片

分析:写入一个数据时,数据从数据总线发送到发送缓冲区TDR中,当移位寄存器没有值时,TDR的值会立刻放入移位寄存器中,并置标志位TXE为1,表示发送缓冲区空,此时可以写入新的数据等待移位寄存器发送完毕后,立刻写入新的数据;移位寄存器在时钟脉冲驱动下遵循低位先行将最低为移出放在MOSI线上,依次重复八次,完成一个数据的发送;

接收数据时,数据从MISO上依次输入,到移位寄存器中,待移位寄存器接收到了一个字节的数据后,会整体将数据转移到RXD接收缓冲区中,并置标志位RXNE为1,表示接受缓冲区非空,此时用户可以读出数据;

通过缓冲区和移位寄存器的配合双重缓冲,不断发送接收数据,就可以实现连续的数据流;

STM32-——SPI_第14张图片

波特率发生器:本质是一个预分频器;在控制寄存器中BR[2:0]控制预分频系数作为时钟源提高时钟脉冲指导数据发送和接收;

STM32-——SPI_第15张图片

主控电路:

通过配置寄存器的位,来实现控制;

LSBFIRST控制低位先行还是高位先行;

SPE是SPI使能;

BR2,BR1,BR0控制预分频系数;

MSTR控制主从模式,主模式是1,从模式是0;

CPOL控制时钟极性,CPHA控制时钟相位,二者决定交换一个字节的模式;

STM32-——SPI_第16张图片

SR状态寄存器

TXE为1发送缓冲区空,RXNE为接受缓冲区非空;判断各个电路状态;

CR2使能位;

STM32-——SPI_第17张图片

NSS从模式选择,通过配置CR,经过数据选择器选择从模式,低电平有效;(实现多主机模型);

STM32-——SPI_第18张图片

总结:写入一个数据时,数据从数据总线到发送缓存区TDR,读取DR时候从RDR读出到数据总线,数据寄存器和移位寄存器配合就可以实现连续的数据流;

3.3分析SPI外设实现过程

数据控制器控制寄存器移位,控制数据的收发,通过MOSI和MISO和从机实现数据交换从而实现数据收发;

波特率发送器提高时钟源,从SCK输出作为从机的时钟源;

最后使能CMD,开启外设;

实现过程:

  1. RCC开启GPIO时钟和SPI时钟;
  2. 配置GPIO为推挽输出模式和上拉输入/浮空输入模式;
  3. 配置波特率发生器,初始化GPIO;
  4. 配置数据控制器;
  5. 使能CMD;
  6. GPIO模拟SS;

STM32-——SPI_第19张图片

3.4时序图;

连续传输:封装复杂,但是性能高,传输速率高;

非连续传输:容易封装,传输速率不高;

分析:

   过程:首先SS置低电平,产生起始条件,开始时序,此时TXE为1表示发送寄存器为空,软件写入0xF1到发送缓存器DR中,也就是发送数据寄存器中,即发送要写入的第一个数据,写入后TDR编程0XF1,同时TXE变成0,表示发送寄存器有值,此时移位寄存器没有数据,所以TDR中数据会立刻转入移位寄存器中,并置TXE为1,表示发生寄存器空,移位寄存器有数据后,时序开始产生,此时软件等待TXE为1时,即转入移位寄存器后,TDR是空,提前把下个数据0XF2写入TDR准备转入移位寄存器,此时TXE置0;直到第一个数据发送完成,第二数据进入移位寄存器中,数据寄存器再次为空,TXE置1,依次重复,直到发送到最后一个数据进入移位寄存器,TXE从此后保存1,并且需要等待一段时间,即移位寄存器将数据转运出去后,结束;等波形全部发送完成后,BSY清0表示发送完成;

读取过程:SPI是全双工,发送过程还有接收过程,第一个字节发送完成,第一个字节的接收也完成,此时移位寄存器的值整体转入接收缓存器,RDR中存放0XA1,并置RXNE接收寄存器非空为1,当移位寄存器中的值集齐后,会自动转入RDR中覆盖原有的值,读取RDR的值要及时;RXNE置0,当移位寄存器集齐下个八位数据时,再次转入接收缓存区中,软件清除RXNE再次置0,重复直到最后一次,数据整体进入RDR中,置RXNE为1,这个过程中;

这个过程对软件配合要求高,每个数据要在每个标志位后将数据读走,及时处理,配合的好时钟可以连续不断的产生,每个字节间没有间隔,传输效率最高;

STM32-——SPI_第20张图片

配置:模式3,SCK默认高电平;

过程:写入数据检测到TXE为1,发送缓冲区为空,写入数据TXE自动置0,移位寄存器为空,此时写入的数据会立刻转入到移位寄存器,(区别:在连续传输中,一旦TXE置1就会立刻把下个数据放入发送缓冲区,为了连续传输,数据更紧密)在这个模式下,TXE置1不会立刻写入第二个数据,而是等待第一个数据发送完成后,并且接收完成后,RXNE置1后,先把第一个数据读出,在写入第二个数据,之后写入第二个数据,等待TXE置1,然后等待RXNE置1,读出第二个数据,依次重复直到结束;

即第一步等待TXE为1;

第二写入数据到TDR中;

第三步等待RXNE为1;

第四步读出RDR数据;

依次重复;

缺点:就是数据和数据间存在间隙,降低字节传输速率;

STM32-——SPI_第21张图片

四、API实现

4.1API软件模拟SPI读写W25Q64(见STM32_W24Q64介绍)

4.1.1程序规划:

首先明确想实现的功能-实现软件控制GPIO口模拟引脚变化,组成时序,实现对W25Q64的读写;

4.1.1.1建立SPI通信层模块(底层):

1.主要对通信引脚的封装,初始化(GPIO初始化,引脚电平变化封装);

2.以及SPI的三个时序组成部分:起始,终止,交换字节;

4.1.1.2硬件驱动层(上层)

基于SPI通信层模块建立W25Q64模块,在这个模块里调用底层的拼图,组成完整的时序(写使能,擦除,页编程,读数据等)

4.1.1.3应用层

mian函数里调用驱动层函数,实现功能;

4.1.2模块封装

首先建立第一个模块,MYSPI模块对应.c,.h文件,并且包含在文件中,完成基础配置(参考STM32_程序建立)

STM32-——SPI_第22张图片STM32-——SPI_第23张图片

2.初始化SPI,初始化通信引脚(使用的是PA4.5.6.7四个引脚);

功能:初始化GPIO;

参数:无;

返回值:无;

初始化GPIO,配置GPIO模式为推挽输出和上拉输入(方法见STM32GPIO输入输出);

配置PA6为从机的上拉输入,其他为主机的推挽输出;(一般第一步是RCC开启时钟,编译器必须将定义放在最前面才能正确编译;)

STM32-——SPI_第24张图片

3.把配置引脚高低电平的操作,封装成函数,即三个输入引脚(MOSI,CS,SCK),一个输出引脚(MISO);

4.输出引脚,输出一个参数,形参为BitValue,输入引脚读取一个值,返回值为uint8_t,没有参数;调用GPIO读写GPIO引脚的函数;

功能:控制GPIO实现引脚电平变化,实现模拟SPI时序;

参数:电平高低1/0;

返回值:读取的电平高低;

STM32-——SPI_第25张图片

之后需要配置初始时引脚的默认电平;

使用模式0,即CPHA,CPOL都为0,此时SCL空闲状态为低电平,SS默认为高电平不选中任何从机;

STM32-——SPI_第26张图片

5.最后封装SPI三个默认时序单元(根据上面分析的时序);

功能:产生起始条件;

参数:无;

返回值:无;

起始条件;STM32-——SPI_第27张图片

功能:产生终止条件;

参数:无;

返回值:无;

终止条件;STM32-——SPI_第28张图片

交换字节;uint8_t MYSPI_SwapByte(uint8_t ByteSend),参数是我们要传出去的字节,返回值是交换得到的字节,传递给调用函数的地方;

功能:实现交换一个字节数据;

参数:发送的数据;

返回值:交换得到的数据;

在硬件上,根据时序图,SS出现下降沿的同时,出现数据移出,但是软件模拟时,程序是一天天执行的,所以要有先后顺序,即SS先出现下降沿,之后数据移出;

思路:定义一个字节ByteReceive接收值;

当起始条件后,主机移出一位到MOSI上,将我们发送的字节最高位移出(使用按位与的操作加移位(用来屏蔽其他无用的位,或者挑出某些位,叫掩码),与任何数与0为0,与1不变,即发送的数0xXX与上0x80,例如发送1111 1010想要最高位1111 1010&

1000 0000->1000 000;前提是这个数是非0即1,否则要先把移位到需要的位置;),之后时钟上升沿的时候接受数据,读取MyISO上的数据(移出的是最高位)(读取GPIO口的数据通过按位或,任何数与1为1,与0不变;读取数据,例如读取数据1001 1001 | 1000 000->1001 1001,),

STM32-——SPI_第29张图片

第二种方法

分析:第一次输出通过掩码的方式读取最高位后,将数据位左移一位,此时数据位最低位空出,并且下次掩码读取最高位时,最高位是目前的最高位,即1101 1101 -> 1011 1010,所以每次循环输出都是最高位,第一次输入此时ByteSend已经移出了最高位最低位为0|0x01,便可把MISO上的数据保存在内部;

STM32-——SPI_第30张图片

此时通信层模块编辑完成,放在头文件声明;

STM32-——SPI_第31张图片

下面实现第二个模块硬件驱动层,硬件驱动层在SPI通信层基础上实现,创建.C.H文件然后包含SPI通信层的头文件;

STM32-——SPI_第32张图片

1.初始化

STM32-——SPI_第33张图片

2.拼接完整的时序

根据指令集实现,例如获取ID号,时序就是先发送指令F9,然后连续交换接收三个字节,然后结束(第一个是ID厂商,后俩个是设备ID,高八位是存储器类型,低八位表示容量);

由于设备有俩个返回值,所以通过指针实现多返回值(函数的传参方法——复制传参(形参的变化不会影响到实参),指针传参(形参改变会影响到实参)->(不懂可参考C语言基础——指针部分);

首先起始条件,然后发送0x9F读取ID号指令,不需要接收交换的数据,之后从机执行连续发送三个字节,下次三次交换就是三个ID,主机接收,从机任意交换即可;最后停止条件;

STM32-——SPI_第34张图片

但是在程序中,总是以数字表示,意义不太明显,可读性不高,所以使用宏定义的方法;

由于宏定义较多,定义一个.h文件存放;

STM32-——SPI_第35张图片

修改:

STM32-——SPI_第36张图片

测试显示;STM32-——SPI_第37张图片

STM32-——SPI_第38张图片STM32-——SPI_第39张图片

写使能指令:

功能:使能指写;

参数:无;

返回值:无;

起始条件,传入指令,停止条件;

STM32-——SPI_第40张图片

读状态寄存器函数

功能:用途判断芯片是不是忙状态;读取最低位BUSY(1为忙状态,0为空闲);

参数:无;

返回值:无;

读取后,要设计一个等待BUSY为0的函数;

STM32-——SPI_第41张图片

 结构图:CS起始条件后,先接收指令,然后读取状态;如果时序不停,那么芯片将会一直发送新的状态;(即可以连续读出,方便执行等待);

等待Busy为0;

起始条件,写入指令,读取当前状态寄存器,使用掩码的方式&0x01取出最低位;通过whilie进行死循环等待,如果最低为BUSY一直为1,则一直等待,直到为0时,结束;

这个过程可能会出现,错误卡死程序;

设置一个TIMEOUT,每循环一次自减一次,直到为0时候,退出或者跳转到自定义的错误处理函数;

STM32-——SPI_第42张图片

页编程函数

功能:对一页数据进行写入;

参数:操作24位地址(C语言无24位,使用32位即可),发送的数据(一个个数据发送太麻烦,定义一个数组,数组通过指针传递,直接完成多数据传输),数据的个数(定义为16位,因为一页最大是256字节,如果定义为8位要写入256时就会出错)

返回值:无;

首先进行写使能,起始条件,发送页编程指令,然后发送三个字节地址,最后发送数据,停止条件,等待芯片忙结束;(写操作前需要进行使能,写入完毕后会自动失能,所以每次写入前进行写使能,写完芯片会自动失能,并且结束后,进行芯片忙判断,芯片忙时不能进行新的操作;)

先发送指令,然后连续发送三个字节24位地址,然后发送数据(先发送字节1,然后2,最大是256,超过就会覆盖首位);

STM32-——SPI_第43张图片

 参数是地址

STM32-——SPI_第44张图片

 扇区擦除函数:

功能:擦除整个扇区;

参数:操作24位地址(C语言无24位,使用32位即可),;

返回值:无;

首先写使能,然后起始条件,发送指令0x20,然后发送地址,停止条件,最后等待忙;

STM32-——SPI_第45张图片

 读操作函数:

功能:擦除整个扇区;

参数:操作24位地址(C语言无24位,使用32位即可),读取的数据(通过数组输出),读取次数;

返回值:无;

在读操作前,DO一直是高阻态形式,发送完三个字节地址后,DO开启输出,主机就可以接收DO的波形了,接收时DI的波形是XXXXX,表示数据无所谓,随意即可只用作交换;

读取没有页的限制,可以一直读取,所以参数次数(设置uint32_t);

STM32-——SPI_第46张图片

STM32-——SPI_第47张图片

STM32-——SPI_第48张图片

整个驱动模块完成;在应用层main测试:

定义俩个数组,一个是要写入的数组,一个是要读出的数组;

初始化后,OLED显示数据;

先擦除扇区,然后写入数据,然后读出数据

STM32-——SPI_第49张图片

STM32-——SPI_第50张图片

验证掉电不丢失:注释掉擦除和写入,断电,上电;

STM32-——SPI_第51张图片

验证FLASH擦除后变为FF的特性;

STM32-——SPI_第52张图片

STM32-——SPI_第53张图片

验证只能1写0,不能0写1;

STM32-——SPI_第54张图片

STM32-——SPI_第55张图片

STM32-——SPI_第56张图片

STM32-——SPI_第57张图片

如果不擦除的得出的数据=原始数据&写入数据;

验证写入数据不能跨页:从一页的页末开始写,读取也从页末开始,判断是否能跨页,写入是不能跨页的所以,直接转到页首覆盖,而读取是可以跨页的,所以读取的FF是下页的数据;

STM32-——SPI_第58张图片

STM32-——SPI_第59张图片STM32-——SPI_第60张图片

如果确实有很大的数据要写(超过页),那么只能在软件上分批次写入,先计算数组跨多少页,然后擦除,一页一些,封装成函数;

这就是软件实现模拟SPI;

4.2AP2硬件实现读写WW5Q64

将软件改成硬件实现,只需要更改底层通信层代码的操作,驱动层不需要修改,因为他们是调用底层通信函数来实现功能的,这就是代码隔离封装的好处;

保留GPIO模拟CS,起始条件,停止条件,其他的删除;

第一部分,写入初始化部分,第二部分写入SPI外设操作时序,完成一个字节交换;

思路:第一步开启GPIO和SPI时钟;

第二步:初始化GPIO,SCK和MOSI输出配置为推挽输出,输入配置成上拉输入,SS引脚配置成通用推挽输出;

第三步配置SPI外设;

第四步使能CMD;

第五步参考非连续的时序图,实现交换一个字节的时序;

STM32-——SPI_第61张图片

查看库函数

STM32-——SPI_第62张图片

第一步RCC开启SPI和GPIO时钟(定义须在时钟前,编译器限制);

第二步初始化GPIO,使用软件模拟SS,配置PA4为推挽输出,MOIS和SCK配置成外设输出的复用推挽输出,配置MISO为上拉输入;

STM32-——SPI_第63张图片

第三步初始化SPI外设,选择SPI模式为主机,选择是双工模式,选择数据帧大小,高位先行低位先行,选择波特率发生器的系数,选择模式0,选择CRC校验位(不是重点),选择NSS的软硬件模式(不是重点,通过软件模拟);

STM32-——SPI_第64张图片

第四步使能SPI,同时将SS配置为高电平不选择;

第五步根据时序图,实现发送一个字节的时序,实现非连续发送一个字节

主要步骤:第一步检验标志位TXE是否为1,如果为1代表发送缓冲区为空,通过DR寄存器写入数据,然后等待自动检验移位寄存器,转移,发送,再发送过程中,主机同时接受数据到移位寄存器,发送一个字节同时,接受到从机一个字节,并移入接受缓冲区,置标志位RXNE为1,接受缓冲区非空,检测标志位,如果为1,读取DR寄存器的值;

STM32-——SPI_第65张图片

STM32-——SPI_第66张图片

五、实际应用

在项目中添加数据存储模块:

数据存储模块设计

设计目的:小车在正常运行过程中需要对小车的位置信息、调试配置参数及状态信息等进行定时的存储,主要包括了  运行出错报警记录和 定位参数的配置等,使其数据掉电不易丢失。

如若采用随机存储器(RAM)进行 数据的保存,一旦主控芯片掉电,数据必然会丢失的,只有将 数据存储在 ROM 或者 FLASH 中才能确保数据得以存储。 系统存储数据的方案有两种:其一是存储到单片机的片内 FLASH 里;其二是存储在片外 ROM 里。但 STM32F103 单片机片内可编程 FLASH 在进行擦除操作和写入操作时有一定的限制且 系统又需要保存大量运行状态数据及配置参数,所以在选择存储器时要考虑到其容量及可擦除次数等因素。因此增添外部 flash 存储,外部 flash 所选用的芯片是 W25Q128;

后续会添加实际项目!

源码:Q2990696125;

你可能感兴趣的:(stm32,网络,嵌入式硬件)