STM32F1笔记(十三)SPI

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

SPI接口一般使用4条线通信:

MISO主设备数据输入,从设备数据输出。

MOSI主设备数据输出,从设备数据输入。

SCLK时钟信号,由主设备产生。

从图中可以看出,主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。寄存器通过MOSI信号线将字节传送给从机,从机也将自己的移位寄存器中的内容通过MISO信号线返回给主机。这样,两个移位寄存器中的内容就被交换。外设的写操作和读操作是同步完成的。如果只进行写操作,主机只需忽略接收到的字节;反之,若主机要读取从机的一个字节,就必须发送一个空字节来引发从机的传输,这个空字节通常称为dummy_byte。

SPI总线四种工作方式是为了和不同外设进行数据交换,其输出串行同步时钟极性和相位可以进行配置。

时钟极性CPOL=0,串行同步时钟的空闲状态为低电平;如果CPOL=1,串行同步时钟的空闲状态为高电平。

时钟相位CPHA=0,在串行同步时钟的第一个跳变沿(上升或下降)数据被采样;如果CPHA=1,在串行同步时钟的第二个跳变沿(上升或下降)数据被采样。

SPI主从设备的时钟相位和极性应该一致。

 

STM32F1的SPI时钟最多可以到18Mhz。可用DMA。

SPI配置示例

void SPI2_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB, GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2, &SPI_InitStructure);SPI_Cmd (SPI2, ENABLE);SPI2_ReadWriteByte(0xff); 
}  

SPI_Direction:选择半双工、全双工。

SPI_Mode:选择主机模式、从机模式。

SPI_DataSize:选择8位还是16位帧格式传输。

SPI_CPOL:设置时钟极性为高电平还是低电平。

SPI_CPHA:设置时钟相位,选择在时钟的第几个跳变沿数据被采样。

SPI_NSS:设置NSS信号由硬件(NSS管脚)还是软件控制。

SPI_BaudRatePrescaler:设置SPI波特率预分频值。示例选择256即本次SPI传输速度=36M/256=140.625KHz。

SPI_FirstBit:设置数据传输顺序是MSB位在前还是LSB位在前。大部分应用是MSB在前。

SPI_CRCPolynomial:设置CRC校验多项式,提高通信可靠性,大于1即可。

 

标准库里SPI发送一个字节函数为

SPI_I2S_SendData(SPI2, data);

接受一个字节函数为

data = SPI_I2S_ReceiveData(SPI2);

因此需要我们再封装几个函数,SPI写任意字节,读任意字节,读写任意字节。

 

SPI最常见的应用场景是读写FLASH。

正点原子战舰板子上的FLASH为W25Q128。该款FLASH的容量为128Mb也就是16M字节。将16M的容量分为256个块(Block),每个块大小为64K字节,每个块又分为16个扇区(Sector),每个扇区4K字节。W25Q128最小擦除单位为一个扇区,也就是每次必须擦除4K字节。这样就需要开辟一个至少4K的缓存区,即单片机需要有4K以上的SRAM才能很好操作。W25Q128最大SPI时钟能达80Mhz。

 

FLASH拿到手通常先测试能否到它的ID

从W25QXX datasheet  里看到,主机给它发0x90,0x00,0x00,0x00,即可读取16位ID

u16 W25QXX_ReadID(void)
{u16 Temp = 0;W25QXX_CS = 0;SPI2_ReadWriteByte(0x90);SPI2_ReadWriteByte(0x00);SPI2_ReadWriteByte(0x00);SPI2_ReadWriteByte(0x00);Temp |= SPI2_ReadWriteByte(0xFF) << 8;Temp |= SPI2_ReadWriteByte(0xFF);W25QXX_CS = 1;return Temp;
} 

这里要注意读ID时MOSI发送的是0xFF,这个就是DUMMY_BYTE,大多DUMMY_BYTE是0xFF,少部分设备会有特殊要求

FLASH读取数据,先发0x03和读取数据的地址起点,然后即可读取。

代码如下

void W25QXX_Read(u8* pBuffer, u32 ReadAddr, u16 NumByteToRead)   
{ u16 i;   			W25QXX_CS = 0;SPI2_ReadWriteByte(0x03);SPI2_ReadWriteByte((u8) ((ReadAddr) >> 16));SPI2_ReadWriteByte((u8) ((ReadAddr) >> 8)); SPI2_ReadWriteByte((u8) ReadAddr);for(i = 0; i < NumByteToRead; i++){ pBuffer[i] = SPI2_ReadWriteByte(0XFF);}W25QXX_CS = 1;  				    	      
} 

 

W25Q128写使能,要给flash写数据,必须先写使能。

从W25QXX datasheet  里看到,只要发0x06即可写使能。

void W25QXX_Write_Enable(void)   
{W25QXX_CS=0;SPI2_ReadWriteByte(0x06);W25QXX_CS=1;  	      
} 

 

写使能后还不能立即往FLASH里面写数据,需要将写入数据的FLASH地址擦除。

void W25QXX_Erase_Sector(u32 Dst_Addr)   
{  	  Dst_Addr *= 4096;W25QXX_Write_Enable();W25QXX_Wait_Busy();W25QXX_CS = 0;SPI2_ReadWriteByte(0x20);SPI2_ReadWriteByte((u8) ((Dst_Addr) >> 16)); SPI2_ReadWriteByte((u8) ((Dst_Addr) >> 8));   SPI2_ReadWriteByte((u8) Dst_Addr);W25QXX_CS = 1;W25QXX_Wait_Busy();
} 

 

FLASH写数据需要考虑跨扇区写入的问题,因为FLASH只提供了往一个页page写数据的命令0x02。

void W25QXX_Write_Page(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)
{u16 i;W25QXX_Write_Enable();W25QXX_CS = 0;SPI2_ReadWriteByte(0x02);SPI2_ReadWriteByte((u8) ((WriteAddr) >> 16));SPI2_ReadWriteByte((u8) ((WriteAddr) >> 8));SPI2_ReadWriteByte((u8) WriteAddr);for(i = 0; i < NumByteToWrite; i++){SPI2_ReadWriteByte(pBuffer[i]);}W25QXX_CS = 1;W25QXX_Wait_Busy();
} void W25QXX_Write_NoCheck(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)   
{ 			 		 u16 pageremain;pageremain = 256 - WriteAddr % 256;if(NumByteToWrite <= pageremain){pageremain = NumByteToWrite;}while(1){W25QXX_Write_Page(pBuffer , WriteAddr, pageremain);if(NumByteToWrite == pageremain){    break;}else{pBuffer += pageremain;WriteAddr += pageremain;	NumByteToWrite -= pageremain;if(NumByteToWrite > 256){pageremain = 256;}else{pageremain = NumByteToWrite;}}};	    
} u8 W25QXX_BUFFER[4096];void W25QXX_Write(u8* pBuffer, u32 WriteAddr, u16 NumByteToWrite)   
{u32 secpos;u16 secoff;u16 secremain;u16 i;u8 * W25QXX_BUF;W25QXX_BUF = W25QXX_BUFFER;	     secpos = WriteAddr / 4096;  secoff = WriteAddr % 4096;secremain = 4096 - secoff;  if(NumByteToWrite <= secremain){secremain = NumByteToWrite;}while(1) {	W25QXX_Read(W25QXX_BUF, secpos * 4096, 4096);for(i = 0; i < secremain; i++){if(W25QXX_BUF[secoff + i] != 0XFF){break;}}if(i < secremain){W25QXX_Erase_Sector(secpos);for(i = 0; i < secremain; i++){W25QXX_BUF[i + secoff] = pBuffer[i];	  }W25QXX_Write_NoCheck(W25QXX_BUF, secpos * 4096, 4096);}else{W25QXX_Write_NoCheck(pBuffer, WriteAddr, secremain);}if(NumByteToWrite == secremain){break;}else{secpos++;secoff = 0;pBuffer += secremain;WriteAddr += secremain;NumByteToWrite -= secremain;if(NumByteToWrite > 4096){secremain = 4096;}else{secremain = NumByteToWrite;}}	 }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374366.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

红帽Openshift:入门–云中的Java EE6

现在有一段时间&#xff0c;我正在研究“云”。 研究它的功能&#xff0c;它可以做什么&#xff0c;为什么我们应该切换到“云”&#xff0c;进行讨论&#xff0c;与RealDolmen的云专家maartenballiauw等人交谈。 我已经在Google App Engine&#xff08;用于Java&#xff09;上…

python自定义函数参数_python自定义函数的参数之四种表现形式

&#xff08;1&#xff09;def a(x,y):print x,y 这是最常见的定义方式&#xff0c;调用该函数&#xff0c;a(1,2)则x取1&#xff0c;y取2&#xff0c;形参与实参相对应&#xff0c;如果a(1)或者a(1,2,3)则会报错 &#xff08;2&#xff09;def a(x,y3):print x,y 提供了默认值…

osg添加纹理示例

转自http://www.cnblogs.com/ylwn817/articles/1976851.html #include <osgDB/ReadFile>#include <osgViewer/Viewer> #include <osg/Node>#include <osg/Geode>#include <osg/Geometry>#include <osg/Group>#include <osg/Texture2D&g…

2.运算符

Swift 支持大部分标准 C 语言的运算符&#xff0c;分为一元、二元和三元运算符。 一元运算符对单一操作对象操作&#xff08;如 -a&#xff09;。一元运算符分前置运算符和后置运算符&#xff0c;前置运算符需紧跟在操作对象之前&#xff08;如 !b&#xff09;&#xff0c;后置…

C语言开发笔记(二)volatile

volatile常用于多线程共享资源和嵌入式软件的中断。 &#xff08;一&#xff09;嵌入式软件中断中volatile的应用 volatile unsigned short g_timer3_count 0;void TIM3_IRQHandler(void) {if (TIM_GetITStatus(TIM3, TIM_IT_Update) ! RESET){TIM_ClearITPendingBit(TIM3, T…

在WebLogic 12c上运行RichFaces 4.1.0.Final

您可能已经注意到&#xff0c;我只是喜欢JSF。 不仅是Mojarra的规范和参考实现&#xff0c;而且是市场上最具创意的组件套件。 这是我一直以来最喜欢的PrimeFaces &#xff0c;当然还有RichFaces 。 这就是为什么在这里找到“在xxx上运行xxx”帖子的原因:)今天是我的RichFaces和…

maven 私服的setting.xml配置

1 <?xml version"1.0" encoding"UTF-8"?>2 <settings xmlns"http://maven.apache.org/SETTINGS/1.0.0" 3 xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation"http://m…

python中的运算符_Python 中的神秘运算符

今天我们来讲讲 Python 里一个不为众人所知的运算符。你可能会觉得疑惑&#xff1a;还有我不知道的运算符&#xff1f;别急着下结论&#xff0c;先往下看看再说。 在 Python3.5 中通过 PEP465https://www.python.org/dev/peps/pep-0465 加入了 运算符&#xff0c;也就是矩阵相乘…

input type:text输入框点击输入,文字消失

<input name"Header1$txbsearch" type"text" value"18912345678" id"Header1_txbsearch" class"txbindex" οnfοcus"if (value 18912345678){value }" οnblur"if (value ){value18912345678}" sty…

C语言开发笔记(一)自动转换和强制转换

整型数据和实行数据之间可以进行运算&#xff0c;而且字符型数据可以和整型数据通用&#xff0c;所以整型、实型、字符型数据之间也是可以进行运算的&#xff0c;但在运算处理之前&#xff0c;不同类型的数据要事先转换成同一种数据类型。转换方法有两种&#xff1a;自动转换和…

Apache Shiro:简化应用程序安全性

考虑到JAVA已有10多年的历史了&#xff0c;对于需要在其应用程序中内置身份验证和授权的应用程序开发人员来说&#xff0c;选择的数量非常少。 在JAVA和J2EE中&#xff0c;JAAS规范是一种尝试解决安全性的问题。 尽管JAAS用于身份验证&#xff0c;但授权部分却过于繁琐而无法使…

Maven 导出依赖Jar,生成source.jar,javadoc.jar

下载最新版的Maven http://maven.apache.org/download.cgi 解压到本地文件夹新建环境变量 MAVEN_HOME maven解压目录在path加入 %MAVEN_HOME%/bin;需要确保已经有Java环境变量 &#xff08;打开cmd java -version,javac -version两个命令看正常不&#xff09;一、导出到默认目…

python提取包含特定字符串的行_python语言----txt中搜索特定字符串所在行

打开IDLE(python)&#xff0c;并新创建一个py文件&#xff0c;编辑内容为&#xff1a; 本示例演示如何在一个txt文件中搜索特定的字符串&#xff0c;并将其行显示# 1. 打开文件# 2. 读取行信息# 3. 判断是否包含关键词# 4. 不包含则循环操作&#xff0c;包含的话将行显示并退出…

asp.net 分布式应用开发

Net Framework推出的许多新技术为上述任务的实现提供了相对简单的解决方案。其中&#xff0c;基于SOAP的Web Service在处理分布式应用时具有比传统的DCOM/CORBA明显的优点&#xff0c;结合基于Web的ASP.NET页面开发技术和SQL Server数据存储技术&#xff08;或Xml文档&#xff…

Spring Data JPA的持久层

1.概述 本文将重点介绍Spring 3.1&#xff0c;JPA和Spring Data的持久层的配置和实现。 有关使用基于Java的配置和项目的基本Maven pom设置Spring上下文的分步介绍&#xff0c;请参阅本文 。 持久性与春天 系列 &#xff1a; 第1部分 – 具有Spring 3.1和Hibernate的持久层 …

C语言开发笔记(三)自加和自减

看到一段代码&#xff0c;被坑了。 #include <stdio.h>int main(void) {int a 7;printf("%d\n", a);printf("%d\n", a--);printf("%d\n", -a);printf("%d\n", -a--);printf("%d\n", a);return 0; } 结果为 -a的逻辑…

求解数独回溯算法

实现的java代码如下&#xff08;该算法只是将结果打印输出&#xff0c;并没有对原数组实现更改&#xff09;&#xff1a; //判断a[i][j]取值val是否有效public boolean isValid(int[][] a, int i, int j, int val){//判断是否跟同行冲突for(int j10;j1<9;j1){if(a[i][j1]val…

python语言属于哪一种语言_Python与Java:你应该学习哪种语言,他们有什么区别?...

在企业招聘中&#xff0c; Python和Java经常是需求最大的编程语言。这两种编程功能强大&#xff0c;灵活且面向对象的语言&#xff0c;通常在组织中和各种其他设置中使用。这可能会导致我们提出一个不可避免的问题&#xff1a;哪个更好&#xff1f; 这是一个复杂的问题&#xf…

关于手机端CSS Sprite图标定位的一些领悟

今天在某个群里面闲逛&#xff0c;看见一个童鞋分享了一个携程的移动端的页面。地址这里我也分享下吧&#xff1a;http://m.ctrip.com/html5/在手机端我都很少用雪碧图合并定位图标&#xff0c;用的比较多就是用字体图标来代替&#xff0c;有些图标不多的时候就自己单个的切出来…

将Java向前推进? 一个定义。 一年回顾。

这篇文章是许多其他“年终”博客文章和评论之一。 但这并不是这样。 我正在尝试总结我在2011年所学到的有关Oracle和Java的知识&#xff0c;还试图解释“将Java向前推进”对我的意义以及我认为应该更好或更简单地改变的东西。 感谢您全年关注我的博客&#xff0c;也感谢您在Twi…