ATMEGA的SPI总线 - 第2部分
参考:
1.https://www.yiboard.com/thread-783-1-1.html
2.https://mansfield-devine.com/speculatrix/2018/01/avr-basics-spi-on-the-atmega-part-2/
3.https://blog.csdn.net/woshi_ziyu/article/details/79451095
在第1部分中,我们在AVR ATMEGA328P微控制器上已经设置好SPI总线。现在我们就可以开始使用SPI了。
<ignore_js_op>
设置相关引脚
在开始之前,我们需要在AVR上设置SPI总线的引脚(在主机模式下使用)。我在这里使用的是ATMEGA328P,所以需要定义一些宏来使代码变得更清晰。如果您使用不同的微控制器,则可以根据您的需要进行调整。
- #define SPI_SS_GPIO PB2
- #define SPI_SS_PORT PORTB
- #define SPI_SS_DDR DDRB
- #define SPI_MOSI_GPIO PB3
- #define SPI_MOSI_PORT PORTB
- #define SPI_MOSI_DDR DDRB
- #define SPI_MISO_GPIO PB4
- #define SPI_MISO_PORT PORTB
- #define SPI_MISO_DDR DDRB
- #define SPI_SCK_GPIO PB5
- #define SPI_SCK_PORT PORTB
- #define SPI_SCK_DDR DDRB
复制代码
现在让我们用这些宏来设置引脚。
- SPI_MOSI_DDR |= (1 << SPI_MOSI_GPIO); // MOSI as output
- SPI_SS_DDR |= (1 << SPI_SS_GPIO); // SS as output
- SPI_SCK_DDR |= (1 << SPI_SCK_GPIO); // SCK as output
- // MISO should be configured automatically as input as that's default state
- // on GPIOs, but if you want to be emphatic
- SPI_MISO_DDR &= ~(1 << SPI_MISO_GPIO); // MISO as input
- SPI_SS_PORT |= (1 << SPI_SS_GPIO); // take SS high to deselect slave
- SPI_MISO_PORT |= (1 << SPI_MISO_GPIO); // set pullup on MISO
复制代码
为了稍后简化事宜,我们可能还想设置一些宏来控制SS线。
- #define SPI_SLAVE_SELECTED SPI_SS_PORT &= ~(1 << SPI_SS_GPIO)
- #define SPI_SLAVE_DESELECTED SPI_SS_PORT |= (1 << SPI_SS_GPIO)
复制代码
现在我们已经设置完成,让我们看看实现这些艰苦工作的寄存器。
SPDR - SPI数据寄存器
这是关键的SPI寄存器的第三个,它像魔术一样工作。只需在该寄存器中写入一个字节,AVR就会启动SPI,并将数据的整个字节发送到电缆上,而无需您进一步操作。由于第1部分提到的移位寄存器之间的传输,当这样做时,SPDR包含传入的数据。所以主从机之间的数据交换由主机完成:
● 将SS线拉低以启用从机设备。
● 写一个字节到SPDR。
● 等待交换完成。
● 再次把SS线拉高。
● 读取SPDR中的内容。
就是这样。我们如何知道交换是否完成?很简单 - SPSR寄存器中的SPIF位被置位。所以你所需要做的就是等待。在下面的例子中,我们只是在一个while循环中停留。这是阻塞的,如果你的微控制器很难控制,你可能会发现浪费时钟周期。如果是这样,您将需要考虑启用SPI中断,SPIF被设置时会触发。在SPI数据交换发生时,您可以继续其他事情。
所以这里有一些代码可以通过SPI发送一个字节的数据,然后返回一个字节。
- uint8_t value = 0xFA; // randomly chosen value for demo purposes
- SPI_SLAVE_SELECTED;
- SPDR = value; // initiates transfer
- while( !(SPSR & (1 << SPIF))); // wait for SPIF bit to be set
- SPI_SLAVE_DESELECTED;
复制代码
而就是这样! SPDR现在包含从机发回的任何内容 - 很可能没有任何兴趣。
正是SPI的这一点可以让你头疼。主机刚刚发送给从机的字节可能是某种类型的命令。为了得到从机的响应,只需发送另一个任意值的字节,从机就会发送它的响应。
实际上,您可能必须发送和接收多个字节。下面是如何写一个值到该芯片的内存位置的方法:
1. 将SS线拉低。
2. 发送写入命令(0x02)。忽略从芯片回来的数据。
3. 发送16位内存地址的高字节。忽略从芯片回来的数据。
4. 发送16位内存地址的低字节。忽略从芯片回来的数据。
5. 发送一个字节的需要存储在该位置的值。忽略从芯片回来的数据。
6. 将SS线置位。
所以在这种情况下,所有的流量都是单向的,所有从芯片返回的数据(实际上只是零)都被丢弃了。现在让我们从内存位置读取一个值。方法是:
1. 将SS线拉低。
2. 发送读命令(0x03)。忽略从芯片回来的数据。
3. 发送16位内存地址的高字节。忽略从芯片回来的数据。
4. 发送16位内存地址的低字节。忽略从芯片回来的数据。
5. 发送您喜欢的任何单字节值,芯片将忽略这些值。然而,通过上述操作,芯片将已经存储在其移位寄存器中的存储位置的值发送回去。
6. 将SS线置位。
内存位置的值现在在SPDR中。
在示波器上显示如下:
<ignore_js_op>
从内存中获取一个字节的数据似乎有很多工作要做。但是23LCV512是这些SPI器件的典型特征,一旦完成初始连接,不断地触发,它将返回更多的信息。
所以,举例来说,如果你想得到32个字节的数据,你可以使用与上面描述的相同的过程,只是发送起始地址,但是在步骤5中,为了促使从机返回数据,而不是发送一个字节的垃圾数据 - 你会发送32个。但这还不够。在每个字节之后,您需要检查SPDR中设置的内容并将其存储在某处,因为在发送下一个垃圾字节后,该值将会被覆盖。
这就是基本的SPI使用方法。
ATMEGA的SPI总线 - 第2部分的更多相关文章
- ATMEGA的SPI总线 - 第1部分
转自: 1. https://www.yiboard.com/thread-782-1-1.html 2.https://mansfield-devine.com/speculatrix/2018/0 ...
- SPI总线
一.概述. SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控 ...
- MSP430单片机的两种SPI总线实现方式
MSP430单片机上的SPI总线的实现方式分为两种:硬件实现和软件实现. 二者的抽象层次不同,硬件实现方式下程序员只需要完成总线协议的寄存器层,即一字节(char,8位二进制)数据,而软件实现方式下程 ...
- SPI总线协议及SPI时序图详解
SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚 ...
- SPI总线(同步)
一.SPI总线简介 串行外围设备接口SPI(serial peripheral interface)总线技术是Motorola公司推出的一种同步串行接口.SPI 用 于CPU与各种外围器件进行全双工. ...
- STM32学习笔记(八) SPI总线(操作外部flash)
1. SPI总线简介 SPI全称串行外设接口,是一种高速,全双工,同步的外设总线:它工作在主从方式,常规需要至少4根线才能够正常工作.SPI作为基本的外设接口,在FLASH,EPPROM和一些数字通讯 ...
- SPI总线的特点、工作方式及常见错误解答
1.SPI总线简介 SPI(serial peripheral interface,串行外围设备接口)总线技术是Motorola公司推出的一种同步串行接口.它用于CPU与各种外围器件进行全双工.同步串 ...
- SPI总线通信电路设计
数据带宽=(总线频率×数据位宽)÷8 B表示带宽,F表示存储器时钟频率,D表示存储器数据总线位数,则带宽为: B(峰值带宽)=F(时钟频率MHz)×D(总线位数bit)/8 例如,PC-100的SDR ...
- linux内核SPI总线驱动分析(一)(转)
linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析 (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...
随机推荐
- Android开发禁止首次进入activity弹出软键盘,限制屏幕只能竖屏或者横屏展示
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 只需在在Manifest.xml中设定activity的属性为: android:windowSoft ...
- 自定义吐司以及Toast的各种用法,详解。教你学会使用各种各样的Toast
package com.david_Custoast; import com.david_Custoast.R; import android.app.Activity; import android ...
- LinuxIP配置方法
一.双网卡双IP. eth0为电信,eth1为联通. # cd /etc/sysconfig/network-scripts/ # vi ifcfg-eth0 DEVICE=eth0 HWADDR=0 ...
- IOS 打包相关
Unity 导出的Xcode工程 http://gad.qq.com/article/detail/29330 [Unity3D]Unity 生成的XCode工程结构 http://blog.163. ...
- Mono生命周期小实验
今天在写代码的时候,遇到一个初始化顺序问题,于是做了一个实验,下面记录结果: 情景: 1.在 脚本A中实例化 一个预制体,该预制体挂有脚本B 2.在 脚本A中,获取实例化物体 身上的 脚本B,并且设置 ...
- springboot x.x.x RELEASE pom 第一行报错解决办法
springboot x.x.x RELEASE pom 第一行报错解决办法 在pom.xml 文件的properties中加入maven jar插件的版本号 <properties> & ...
- Spring的循环依赖,学就完事了【附源码】
目录 啥是循环依赖? Spring可以解决循环依赖的条件 Spring如何去解决循环依赖 SpringBean的创建流程 Spring维护的三级缓存 getSingleton getSingleton ...
- 图解选择排序及算法优化(Java实现)
选择排序 前言 原理:每次循环对比找出最小/大值,将最值的元素交换至左侧 思想:直接选择排序(Straight Select Sort)算法思想:第一趟从n个元素的数据序列中选出关键字最小/大的元素并 ...
- webstorm中emmet展开a标签和行内元素不换行的解决办法
大家好我是木瓜太香,大家在使用 webstorm 编写 html 的时候可能会遇到展开部分标签挨在一起的情况,相信很多小伙伴都想解决这个问题,接下来我们就开始吧! 先来看看我们输入如下 emmet 代 ...
- oracle之二数据字典表和动态性能视图
数据字典表和动态性能视图 Oracle提供了大量的内部表,它们记录了数据库对象的更改和修正.可以将这些内部表划分为两种主要类型:静态的数据字典表和动态的性能表.这些内部表是由oracle维护的,可以说 ...