简介:

  SPI,Serial Peripheral interface串行外围设备接口。

  接口应用在:EEPROM, FLASH,实时时钟,AD 转换器,还有数字信号处理器和数字信号解码器之间。

  特点:高速的、全双工、同步的通信总线、占用4根线;可以同时发生和接收串行数据;可以当做主机或从机工作;提供频率可编程时钟;发送结束中断标志;写冲突保护;总线竞争保护等。

  接口使用的4条通讯线:

  1. MISO  主设备数据输入,从设备数据输出
  2. MOSI  主设备数据输出,从设备数据输入
  3. SCLK  时钟信号,由主设备产生
  4. CS      从设备片选信号,由主设备控制

  SPI的功能很强大,SPI时钟最多可以到18Mhz,支持DMA,可以配置为SPI协议或者I2S协议。

  使用STM32的SPI的主模式,配置步骤如下:

1.配置相关引脚的复用功能,使能SPI2时钟

  第一步就要使能 SPI2 的时钟。其次要设置 SPI2 的相关引脚为复用输出,这样才会连接到SPI2上,否则这些IO口还是默认的状态,也就是标准的输入输出口。这里我们使用PB13、14、15这三个(SCK、MISO、MOSI、CS使用软件管理方式)所以设置这三个复用IO。

  1. GPIO_InitTypeDef GPIO_InitStructure;
  2. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );//PORTB 时钟使能
  3. RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE );//SPI2 时钟使能
  4. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  5. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15 复用推挽输出
  6. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  7. GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 GPIOB
2.初始化SPI2,设置SPI2工作模式

  接下来我们要初始化 SPI2,设置 SPI2 为主机模式,设置数据格式为 8 位,然设置 SCK 时钟极性及采样方式。并设置 SPI2 的时钟频率(最大 18Mhz),以及数据的格式(MSB 在前还是LSB 在前)。

  这在库函数中是通过 SPI_Init 函数来实现的。

  1. void SPI_Init(SPI_TypeDef* SPIx,SPI_InitTypeDef* SPI_InitStruct);

  第一个参数为SPI标号,这里使用的SPI2;第二个参数是定义SPI_InitTypeDef结构体指针

  1. typedef struct
  2. {
  3. uint16_t SPI_Direction;
  4. // 设置 SPI 的通信方式,可以选择为半双工,全双工,以及串行发和串行收方式
  5. uint16_t SPI_Mode;
  6. // 设置 SPI 的主从模式
  7. uint16_t SPI_DataSize;
  8. // 为 8 位还是 16 位帧格式选择项
  9. uint16_t SPI_CPOL;
  10. // 设置时钟极性
  11. uint16_t SPI_CPHA;
  12. // 设置时钟相位
  13. uint16_t SPI_NSS;
  14. //设置 NSS 信号由硬件(NSS 管脚)还是软件控制
  15. uint16_t SPI_BaudRatePrescaler;
  16. //设置 SPI 波特率预分频值
  17. uint16_t SPI_FirstBit;
  18. //设置数据传输顺序是 MSB 位在前还是 LSB 位在前
  19. uint16_t SPI_CRCPolynomial;
  20. //设置 CRC 校验多项式,提高通信可靠性,大于 1 即可
  21. }SPI_InitTypeDef;

第一个参数 SPI_Direction 是用来设置 SPI 的通信方式,可以选择为半双工,全双工,以及串行发和串行收方式,这里我们选择全双工模式 SPI_Direction_2Lines_FullDuplex。

第二个参数 SPI_Mode 用来设置 SPI 的主从模式,这里我们设置为主机模式 SPI_Mode_Master,当然有需要你也可以选择为从机模式 SPI_Mode_Slave。

第三个参数 SPI_DataSiz 为 8 位还是 16 位帧格式选择项,这里我们是 8 位传输,选择SPI_DataSize_8b。

第四个参数 SPI_CPOL 用来设置时钟极性,我们设置串行同步时钟的空闲状态为高电平所以我们选择 SPI_CPOL_High。

第五个参数 SPI_CPHA 用来设置时钟相位,也就是选择在串行同步时钟的第几个跳变沿(上升或下降)数据被采样,可以为第一个或者第二个条边沿采集,这里我们选择第二个跳变沿,所以选择 SPI_CPHA_2Edge

第六个参数 SPI_NSS 设置 NSS 信号由硬件(NSS 管脚)还是软件控制,这里我们通过软件控制 NSS 关键,而不是硬件自动控制,所以选择 SPI_NSS_Soft。

第七个参数 SPI_BaudRatePrescaler 很关键,就是设置 SPI 波特率预分频值也就是决定 SPI 的时钟的参数 , 从不分频道 256 分频 8 个可选值,初始化的时候我们选择 256 分频值SPI_BaudRatePrescaler_256,  传输速度为 36M/256=140.625KHz。

第八个参数 SPI_FirstBit 设置数据传输顺序是 MSB 位在前还是 LSB 位在前, ,这里我们选择SPI_FirstBit_MSB 高位在前。

第九个参数 SPI_CRCPolynomial 是用来设置 CRC 校验多项式,提高通信可靠性,大于 1 即可。

  设置好9个参数,初始化SPI外设,范例:

  1. SPI_InitTypeDef SPI_InitStructure;
  2. SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线双向全双工
  3. SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主 SPI
  4. SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // SPI 发送接收 8 位帧结构
  5. SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;//串行同步时钟的空闲状态为高电平
  6. SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;//第二个跳变沿数据被采样
  7. SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS 信号由软件控制
  8. SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //预分频 256
  9. SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从 MSB 位开始
  10. SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC 值计算的多项式
  11. SPI_Init(SPI2, &SPI_InitStructure); //根据指定的参数初始化外设 SPIx 寄存器
3.使能SPI2

  初始化完成之后就是使能SPI2通信,使能SPI2通信后,就可以开始SPI通讯。

  使能SPI2的方法是:

  1. SPI_Cmd(SPI2,ENABLE); //使能SPI外设
4.SPI传输数据  

固体库提供的发送数据函数原型为:

  1. void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);

  表示从SPIx数据寄存器写入数据Data从而实现发送。

固体库提供的接收数据函数原型为:

  1. uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx)

  表示从SPIx数据寄存器读出接收到的数据。

5.查看SPI传输状态

  在 SPI 传输过程中,我们经常要判断数据是否传输完成,发送区是否为空等状态,这是通过函数 SPI_I2S_GetFlagStatus 实现的,这个函数很简单就不详细讲解,判断发送是否完成的方法是:

  1. SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE);

  W25Q64是华邦公司推出的大容量SPI,FLASH产品,W25Q64的容量是64Mb,该系列还有W25Q80/16/32等。W25Q64容量为64Mb也就是8M字节。

  W25Q64将8M的容量分为128个块(Block),每个块大小为64K字节,每个块又分16个扇区(Sector),每个扇区4K个字节。

  W25Q64的最小擦除单位为一个扇区,也就是每次必须擦除4K个字节。这样我们必须给W25Q64开辟一个至少4K的缓存区,这样对SRAM要求不高,要求芯片必须有4K以上SRAM才能很好的操作。

  W25Q64的擦写周期多达10W次,具有20年的数据保存期限,支持电压为2.7到3.6V,W25Q64支持标准的SPI,还支持双输出/四输出的SPI时钟可以到80MHz(双输出时钟相当于160MHz,四输出时相当于320Mhz)

补充:

  1. 以下是SPI模块的初始化代码,配置成主机模式,访问SD Card/W25Q64/NRF24L01
  2. SPI口初始化
  3. 这里针是对SPI2的初始化
  1. void SPI2_Init(void)
  2. {
  3. GPIO_InitTypeDef GPIO_InitStructure;
  4. SPI_InitTypeDef SPI_InitStructure;
  5.  
  6. RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能
  7. RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );//SPI2时钟使能
  8.  
  9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //PB13/14/15复用推挽输出
  11. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12. GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB
  13.  
  14. GPIO_SetBits(GPIOB,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //PB13/14/15上拉
  15.  
  16. SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
  17. SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
  18. SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
  19. SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
  20. SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
  21. SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
  22. SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //定义波特率预分频的值:波特率预分频值为256
  23. SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
  24. SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
  25. SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
  26.  
  27. SPI_Cmd(SPI2, ENABLE); //使能SPI外设
  28.  
  29. SPI2_ReadWriteByte(0xff);//启动传输
  30.  
  31. }
  32.  
  33. //SPI 速度设置函数
  34. //SpeedSet:
  35. //SPI_BaudRatePrescaler_2 2分频
  36. //SPI_BaudRatePrescaler_8 8分频
  37. //SPI_BaudRatePrescaler_16 16分频
  38. //SPI_BaudRatePrescaler_256 256分频
  39.  
  40. void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
  41. {
  42. assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));
  43. SPI2->CR1&=0XFFC7;
  44. SPI2->CR1|=SPI_BaudRatePrescaler; //设置SPI2速度
  45. SPI_Cmd(SPI2,ENABLE);
  46.  
  47. }
  48.  
  49. //SPIx 读写一个字节
  50. //TxData:要写入的字节
  51. //返回值:读取到的字节
  52. u8 SPI2_ReadWriteByte(u8 TxData)
  53. {
  54. u8 retry=0;
  55. while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
  56. {
  57. retry++;
  58. if(retry>200)return 0;
  59. }
  60. SPI_I2S_SendData(SPI2, TxData); //通过外设SPIx发送一个数据
  61. retry=0;
  62.  
  63. while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) //检查指定的SPI标志位设置与否:接受缓存非空标志位
  64. {
  65. retry++;
  66. if(retry>200)return 0;
  67. }
  68. return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
  69. }

  

STM32(13)——SPI的更多相关文章

  1. STM32(12)——CAN

    简介: CAN是Controller Area Network,是 ISO 国际标准化的串行通信协议. CAN  控制器根据两根线上的电位差来判断总线电平.总线电平分为显性电平和隐性电平,二者必居其一 ...

  2. 基于MVC4+EasyUI的Web开发框架经验总结(13)--DataGrid控件实现自动适应宽带高度

    在默认情况下,EasyUI的DataGrid好像都没有具备自动宽度的适应功能,一般是指定像素宽度的,但是使用的人员计算机的屏幕分辨率可能不一样,因此导致有些地方显示太大或者太小,总是不能达到好的预期效 ...

  3. Web 在线文件管理器学习笔记与总结(13)重命名文件夹(14)复制文件夹

    (13)重命名文件夹 ① 重命名文件夹通过 rename($oldname,$newname) 实现 ② 检测文件夹名是否符合规范 ③ 检测当前目录中是否存在同名文件夹名称,如果不存在则重命名成功 i ...

  4. 在Mac OS X中使用VIM开发STM32(2)

    本文原创于http://www.cnblogs.com/humaoxiao,非法转载者请自重! 在我先前的博文⎣在Mac OS X中使用VIM开发STM32(1)⎤中,我们安装完成了MACVIM,这一 ...

  5. Android菜鸟的成长笔记(13)——异步任务(Async Task)

    原文:[置顶] Android菜鸟的成长笔记(13)——异步任务(Async Task) Android的UI线程主要负责处理用户的事件及图形显示,因此主线程UI不能阻塞,否则会弹出一个ANR(App ...

  6. Windows Phone开发(13):如何规范用户的输入行为

    原文:Windows Phone开发(13):如何规范用户的输入行为 很多时候,我们对用户的操作或输入做一定程度的限制,以避免发生不必要的异常或错误,因此,对一些特殊的类型,进行输入限制是很有必要的. ...

  7. 网站静态化处理—web前端优化—下【终篇】(13)

    网站静态化处理—web前端优化—下[终篇](13) 本篇继续web前端优化的讨论,开始我先讲个我所知道的一个故事,有家大型的企业顺应时代发展的潮流开始投身于互联网行业了,它们为此专门设立了一个事业部, ...

  8. [.net 面向对象程序设计深入](13)实战设计模式——设计模式使用场景及原则

    [.net 面向对象程序设计深入](13)实战设计模式——设计模式使用场景及原则 1,什么是设计模式? 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计 ...

  9. 51单片机学习笔记(清翔版)(13)——LED点阵、74HC595

    如图3,点阵屏分单色和彩色,点阵屏是由许多点组成的,在一个点上,只有一颗一种颜色的灯珠,这就是单色点阵屏,彩色的在一个点上有三颗灯珠,分别是RGB三原色. 图4你可能没看出来,那么大块黄色的就是点阵屏 ...

随机推荐

  1. Python学习---线程基础学习

    线程基础 什么是线程(thread) 线程是CPU调度能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流[换言之,线程就是一堆指令集合], ...

  2. IOS ASI (第三方请求)

    什么是ASI全称是ASIHTTPRequest,外号“HTTP终结者”,功能十分强大基于底层的CFNetwork框架,运行效率很高可惜作者早已停止更新,有一些潜在的BUG无人去解决很多公司的旧项目里面 ...

  3. [译] 怎样(以及为什么要)保持你的 Git 提交记录的整洁

    最近在掘金翻译了一篇文章,主要讲的是 Git 提交记录的维护,确实很有用,感兴趣的同学可以去看一下.链接如下: [译] 怎样(以及为什么要)保持你的 Git 提交记录的整洁 截图:

  4. 代码注释模板(把内容保存为xml文件,导入eclipse中即可)

    <?xml version="1.0" encoding="UTF-8" standalone="no"?><templa ...

  5. 网易mumu模拟器配置文件和修改adb port位置

    网易mumu模拟器配置文件在安装目录下 emulator\nemu\vms\myandrovm_vbox86下的myandrovm_vbox86.nemu文件中 修改port位置

  6. [19/03/30-星期六] IO技术_四大抽象类_ 字节流( 字节输入流 InputStream 、字符输出流 OutputStream )_(含字节文件缓冲流)

    一.概念及分类 InputStream(输入流)/OutputStream(输出流)是所有字节输入输出流的父类 [注]输入流和输出流的是按程序运行所在的内存的角度划分的 字节流操作的数据单元是8的字节 ...

  7. php签到

    <?php namespace Member\Controller; use Member\Controller\MController; class IndexController exten ...

  8. 1.springboot:入门项目

    简介: Springboot 来简化spring应用开发,约定大于配置,去繁从简,just run 就可以创建一个独立的,产品应用 背景: J2EE笨重开发,繁多的配置,低下的开发效率,复杂的部署流程 ...

  9. xtrabackup2.4选项参考

    该xtrabackup2.4选项参考¶ 此页面记录了xtrabackup二进制文件的所有命令行选项 . 选项 --apply-log-only 此选项仅在准备备份时执行重做阶段.这对增量备份非常重要. ...

  10. 图片验证码——base64编码的使用

    一.介绍: 1.base64编码简介: Base64就是一种编码格式.Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成 ...