SPI是当前用的比较多的硬件总线,结构很简单,一共只要4根线就可以了。 其中两根是数据线,名字等会说,一根时钟线,叫SCK; 一根是片选线(CS)。4根线的连接见下面:
SPI的典型应用中,通信的双方一个是主(Master),一个是从(slave)。区别是由主设备提供通信时钟信号SCK给从设备,此外主设备还需要提供一个引脚来驱动Slave的片选信号CS。主从设备的SO和SI是交叉连接的, 主的SO是数据输出口要接在从设备的SI上,反之依然。根据这样的设计,能做SPI的设备往往是单片机, ARM芯片或者更强一些的CPU什么,而flash, 网络芯片或者声音A/D 和D/A转换芯片就扮演从设备的角色。主设备提供片选信号来选中从设备和连续时钟信号来驱动双方设备的读写过程。
由于从设备往往都是厂家设计好的, 主要的用户工作是如何在主设备上把从设备驱动起来。这是把我搞的灰头土脸的地方。以我要驱动Flash为例,根据看的文档,我直觉上知道应该把片选信号先拉低(选中flash),然后在SO上发出控制指令,最后等数据到来。结果我的程序是这样写的:
1、初始化SPI控制器,包括波特率设置
2、驱动CS为低电平选中flash
3、发送控制命令
4、接受数据
结果我收到的数据只有一个字节,内容为0. 忙了一个早上还是这个结果,搞的我极其郁闷,严重怀疑自己的RP,然后开始怀疑单片机是不是坏的,flash是不是坏的。一圈下来继续怀疑RP。最后实在郁闷,就扛来示波器测波形。因为这个玩也不熟悉,因此不敢轻易动,弄坏了把自己卖了才赔的起了(10G的哦)。结果发现430单片机的片选CS信号正常,在数据发送的时候SO口的确有波形输出,说明输出是对的。但是。。。。为什么SCK没有连续时钟信号输出 ???? 我立刻理直气壮认为 单片机烧了,告诉师兄, 结果师兄暴汗.... :SPI主设备如果不连续输出数据,就不维护时钟了。顿时觉得自己长的好白阿。 正确的做法应该在主设备上送完指令后不停的送无用数据让spi控制器继续输出时钟并且读取发回来的数据。由于SPI控制器是同步读取数据的,因此我在发送的同时也读取数据,因此我送出去一个字节的数据,所以读回来一个数据,当然这个数据是无用的。
知道问题了,午饭后我把程序改成中断模式的, 所有的数据发送和接受全部采用中断。 发送寄存器一空 430就会发一个发送就绪中断,我在中断程序中把数组中的命令字发出去,等发完之后就一直发0x00,维护时钟,直到发送出去的字节数等于期望收到的数据量。另外一方面当数据收到后430就触发接收中断得到数据。中断程序把数据读出来扔到接收数组里面。 等发送完后要检查是不是移位寄存器为空,防止还有数据没出去,等空了就拉高片选信号断开flash. 完成这些后,检查接收数组,可以看到如果发送命令为n字节,则前面n字节的数据都是废的,所以要从n+1的位置来找收到的数据。圆满大结局。(其实后面还碰到了波特率不对,结果丢数据的问题,但是很快解决了加上现在写的手酸,就略过拉)
关键字:SPI总线 硬件总线
引用地址:SPI总线初体验
SPI的典型应用中,通信的双方一个是主(Master),一个是从(slave)。区别是由主设备提供通信时钟信号SCK给从设备,此外主设备还需要提供一个引脚来驱动Slave的片选信号CS。主从设备的SO和SI是交叉连接的, 主的SO是数据输出口要接在从设备的SI上,反之依然。根据这样的设计,能做SPI的设备往往是单片机, ARM芯片或者更强一些的CPU什么,而flash, 网络芯片或者声音A/D 和D/A转换芯片就扮演从设备的角色。主设备提供片选信号来选中从设备和连续时钟信号来驱动双方设备的读写过程。
由于从设备往往都是厂家设计好的, 主要的用户工作是如何在主设备上把从设备驱动起来。这是把我搞的灰头土脸的地方。以我要驱动Flash为例,根据看的文档,我直觉上知道应该把片选信号先拉低(选中flash),然后在SO上发出控制指令,最后等数据到来。结果我的程序是这样写的:
1、初始化SPI控制器,包括波特率设置
2、驱动CS为低电平选中flash
3、发送控制命令
4、接受数据
结果我收到的数据只有一个字节,内容为0. 忙了一个早上还是这个结果,搞的我极其郁闷,严重怀疑自己的RP,然后开始怀疑单片机是不是坏的,flash是不是坏的。一圈下来继续怀疑RP。最后实在郁闷,就扛来示波器测波形。因为这个玩也不熟悉,因此不敢轻易动,弄坏了把自己卖了才赔的起了(10G的哦)。结果发现430单片机的片选CS信号正常,在数据发送的时候SO口的确有波形输出,说明输出是对的。但是。。。。为什么SCK没有连续时钟信号输出 ???? 我立刻理直气壮认为 单片机烧了,告诉师兄, 结果师兄暴汗.... :SPI主设备如果不连续输出数据,就不维护时钟了。顿时觉得自己长的好白阿。 正确的做法应该在主设备上送完指令后不停的送无用数据让spi控制器继续输出时钟并且读取发回来的数据。由于SPI控制器是同步读取数据的,因此我在发送的同时也读取数据,因此我送出去一个字节的数据,所以读回来一个数据,当然这个数据是无用的。
知道问题了,午饭后我把程序改成中断模式的, 所有的数据发送和接受全部采用中断。 发送寄存器一空 430就会发一个发送就绪中断,我在中断程序中把数组中的命令字发出去,等发完之后就一直发0x00,维护时钟,直到发送出去的字节数等于期望收到的数据量。另外一方面当数据收到后430就触发接收中断得到数据。中断程序把数据读出来扔到接收数组里面。 等发送完后要检查是不是移位寄存器为空,防止还有数据没出去,等空了就拉高片选信号断开flash. 完成这些后,检查接收数组,可以看到如果发送命令为n字节,则前面n字节的数据都是废的,所以要从n+1的位置来找收到的数据。圆满大结局。(其实后面还碰到了波特率不对,结果丢数据的问题,但是很快解决了加上现在写的手酸,就略过拉)
上一篇:RS485通信测试学习笔记
下一篇:串行通信总结
推荐阅读最新更新时间:2024-05-03 00:03
STM32:DMA方式接收SPI总线数据,并按照协议进行处理
一、前言 为满足高速数据传输的要求,采用SPI总线。MCU端(STM32F072 Cortex-M0)接收CPU发送的SPI数据(数据18个字节为一包,起始包为0xAA,最后一包为CheckSum校验),接收完成后,将校验正确的数据分配给RF发送给接收端。 二、硬件电路 如下图所示,SPI部分使用SPI2即PB12 PB13 PB14 PB15 三、程序流程 3.1 SPI初始化 SPI初始化为从模式,代码如下: pre name= code class= cpp void BSP_SPI2_Init(void) { SPI_InitTypeDef SPI_InitStructure; GPIO_In
[单片机]
51单片机SPI总线的实现
//-----------------------函数声明,变量定义------------------------------------------------------ #include reg51.h #include intrins.h sbit SCK=P1^0; // 将p1.0口模拟时钟输出 sbit MOSI=P1^1; // 将p1.1口模拟主机输出 sbit MISO=P1^2; // 将p1.1口模拟主机输入 sbit SS1=P1^3; // 将p1.1口模拟片选 #define delayNOP(); {_nop_();_nop_();_nop_();_nop_();}; //----
[单片机]
IIC和SPI总线协议的区别
现今,在低端数字通信应用领域,我们随处可见IIC (Inter-Integrated Circuit) 和 SPI (Serial Peripheral Interface)的身影。原因是这两种通信协议非常适合近距离低速芯片间通信。Philips(for IIC)和Motorola(for SPI) 出于不同背景和市场需求制定了这两种标准通信协议。 IIC 开发于1982年,当时是为了给电视机内的CPU和外围芯片提供更简易的互联方式。电视机是最早的嵌入式系统之一,而最初的嵌入系统是使用内存映射(memory-mapped I/O)的方式来互联微控制器和外围设备的。要实现内存映射,设备必须并联入微控制器的数据线和地址线,这种方式
[嵌入式]
SPI总线在XF-S4240与MCS51通信中的应用
SPI 总线技术是Motorola公司推出的一种同步串行接口。它可以使MCU与各种外围设备以串行方式进行通信以交换信息,并且硬件连接较少,编程方便。 SPI接口已经是一种标准外设接口,目前已有很多MCU及外设都带有SPI接口。MCS51虽然也有带SPI接口的单片机——AT89S8252,但价格相对较高。在开发基于RFID的自助语音导游系统中,由于RFID读卡模块带有SCI接口,XF-S4240语音合成模块带有SCI及SPI接口,如采用不带有SPI接口的AT89C51单片机,必然存在扩展接口的问题。 本文介绍的C51软件模拟实现SPI通信接口的方法,编程简单,有效降低了系统的成本。该方法已在项目开发中得到了验证。
[单片机]