概述

时钟相性与极性

CPOL(Clock Polarity)控制空闲状态时SCK的值:CPOL=0,空闲时SCK=0;CPOL=1,空闲时SCK=1。

CPHA(Clock Phase)控制何时捕获数据,CPHA=0,第一个跳变沿;CPHA=1,第二个跳变沿。详细见下图:

从选(NSS,也就是CS)管理管脚管理

  • SSM = 1,软件管理NSS片选。两种方案:一个是把NSS设为普通IO口,使用GPIO的方法置高拉低;另一个是配置成复用口,使用SPI的寄存器CR1中的SSI位来控制NSS高低。
  • SSM = 0, 硬件管理方法,推荐使用,有两种模式(SSOE在 SPI_CR2 里):
  1. NSS 输出使能,SSM=0,SSOE=1.  适合单个master通信使用,占据NSS片选线。
  2. NSS 输出禁止,SSM=0,SSOE=0. 释放NSS片选线,从而该总线的其他master设备可以进行通信。

举个例子:

目的:使用硬件的方法实现,主从通信,双向收发。

简述:master 向 slave 发生数据a 同时获取slave发送的数据b,数据a、b无误即实验成功。

操作:连线参照Figure 238. 即所有线一一对应相连,包括NSS(即CS)。

初始化及实验代码:

void init_spis(void)
{ GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
static uint16_t tmp; /* configure master */
// SPI2_NSS PB12
// SPI2_SCK PB13
// SPI2_MISO PB14
// SPI2_MOSI PB15
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTA 时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure); RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );//SPIx时钟使能
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 其他设置与 slave 相同
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Hard; // 硬件管理
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
SPI_InitStructure.SPI_CRCPolynomial = ;
SPI_Init(SPI2, &SPI_InitStructure);
SPI2->CR2 |= SPI_CR2_SSOE; // 使用硬件NSS,需要把SSOE(SS Output enable)使能 /* configure slave */
// SPI1_NSS PA4
// SPI1_SCK PA5
// SPI1_MISO PA6
// SPI1_MOSI PA7
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );//PORTA 时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure); RCC_APB2PeriphClockCmd( RCC_APB2Periph_SPI1, ENABLE );//SPIx时钟使能
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; // 其他设置与 master 相同
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
SPI_I2S_SendData(SPI1, 0x52); // slave 要发生的数据 SPI_Cmd(SPI2, ENABLE); // 使能SPI外设,此时CS会自动拉低,但是没有CLK信号。
SPI_I2S_SendData(SPI2, 0x51); // 产生 CLK信号,启动传输
while((SPI2->SR & SPI_SR_TXE) == ); // 等待发送完毕 /* 结束通信 */
SPI_Cmd(SPI2, DISABLE); // 传输结束,释放总线【注】,CLK进入IDLE状态(我设置的高)
// 注:释放总线,即开漏的控制方式,不是强制拉高,只是相当于断开与CS(NSS)的连接。
// 当然,slave设备的CS一般是有上拉的,所有放开后在没有其他master控制时,就是高。 tmp = SPI_I2S_ReceiveData(SPI2); // 查看 master 收到的数据
tmp = SPI_I2S_ReceiveData(SPI1); // 查看 slave 收到的数据 }

实验结果

SPI 及初始化例子的更多相关文章

  1. Java SPI详细的例子

    先翻一个来自于Baeldung的介绍: 为了更通俗易懂我就没有直译,如果有不严谨的地方请大神指教. JavaSPI的定义 Java SPI defines four main components S ...

  2. SPI 方式初始化 SD 卡总流程图(V2.0)

  3. [SPI]SPI协议详解

    转自:https://my.oschina.net/freeblues/blog/67400 1.SPI协议简介 1.1.SPI协议概括 SPI,是英语Serial Peripheral interf ...

  4. linux spi驱动开发学习-----spidev.c和spi test app

    一.spidev.c文件 看一个设备驱动的方法: module_init标识的入口初始化函数spidev_init,(module_exit标识的出口函数) 设备与设备驱动匹配时候调用的probe方法 ...

  5. SPI、I2C、UART三种串行总线协议的区别

    第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART(Universal Asynchronous R ...

  6. SPI、I2C、UART三种串行总线协议的区别和SPI接口介绍(转)

    SPI.I2C.UART三种串行总线协议的区别 第一个区别当然是名字: SPI(Serial Peripheral Interface:串行外设接口); I2C(INTER IC BUS) UART( ...

  7. 第24章 SPI—读写串行FLASH—零死角玩转STM32-F429系列

    第24章     SPI—读写串行FLASH 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/ ...

  8. 30-ESP8266 SDK开发基础入门篇--SPI

    这节只是做记录, 整个的教程呢,重新整理下 教程有点乱,需要再细分一下 这节只是做一下我使用其SPI的记录 还是老样子,看人家LUA源码里面怎么使用的 注意哈,对于8266 SDK的学习我还是建议大家 ...

  9. RT Thread的SPI设备驱动框架的使用以及内部机制分析

    注释:这是19年初的博客,写得很一般,理解不到位也不全面.19年末得空时又重新看了RTThread的SPI和GPIO,这次理解得比较深刻.有时间时再整理上传. -------------------- ...

随机推荐

  1. Java中遍历数组的三种方式复习

    1 for循环遍历 通常遍历数组都是使用for循环来实现.遍历一维数组很简单,遍历二维数组需要使用双层for循环,通过数组的length属性可获得数组的长度. 程序示例: package captai ...

  2. luoguP1290 欧几里德的游戏 [博弈论]

    题目描述 欧几里德的两个后代Stan和Ollie正在玩一种数字游戏,这个游戏是他们的祖先欧几里德发明的.给定两个正整数M和N,从Stan开始,从其中较大的一个数,减去较小的数的正整数倍,当然,得到的数 ...

  3. ueditor不能上传mp4格式的视频--解决方案

    1.ueditor.all.js 去掉所有的 type="application/x-shockwave-flash" 2.ueditor.all.min.js 去掉所有的 typ ...

  4. delphi 文件操作(信息获取)

    delphi获取Exe文件版本信息的函数 Type TFileVersionInfo = Record FixedInfo:TVSFixedFileInfo; {版本信息} CompanyName:S ...

  5. centos 安装 ImageMagick

    ImageMagick很好用,shell下可以批量对图片做处理,很赞!~ 编译安装 wget http://www.imagemagick.org/download/ImageMagick.tar.g ...

  6. Linux下使用java获取cpu、内存使用率

    原文地址:http://www.voidcn.com/article/p-yehrvmep-uo.html 思路如下:Linux系统中可以用top命令查看进程使用CPU和内存情况,通过Runtime类 ...

  7. 牛客 判断t1树中是否含有与t2树拓扑结构完全相同的子树

    题目链接:https://www.nowcoder.com/practice/5a41ce17e8194e1688aa83a73137f7ee?tpId=101&tqId=33239& ...

  8. C++ 操作json文件

    一.环境搭建: 参考文章:https://blog.csdn.net/fakine/article/details/79272090 二.创建实例: #include <stdio.h> ...

  9. Java缓冲区读写

    缓冲区读 有两种方法从缓冲区读取数据: 绝对位置 相对位置 使用四个版本重载的get()方法用于从缓冲区读取数据. get(int index)返回给定索引处的数据. get()从缓冲区中的当前位置返 ...

  10. 深入浅出JS:Two

    JS中的Promise: MDN上面对promise的描述:Promise 对象用于表示一个异步操作的最终状态(完成或失败),以及其返回的值. 可以直接对字面上理解:Promise:承诺,一诺千金,只 ...