1.SPI总线的电路结构SPI总线里有一个主机多个从机引脚有MOSIMISOSCKNSS。MOSI主发从收。主机的MOSI是一个发送引脚从机的MOSI为接收引脚使用的时候要连起来。MISO主收从发。主机的MISO是接收引脚SCL串行时钟主机产生时钟信号发送给从机通过时钟信号控制通信快慢NSS低电压有效的从机选择引脚。主机向NSS发送低电压代表选中这个从机与其通信。通信时在SCK高电压期间主机通过MOSI向从机发送一个数据同时从机通过MISO向主机返回一个比特位。主机发送多少位就会收到多少位的回应。2.参数①时钟信号的极性和相位低极性空闲状态为低电平。高极性空闲状态为高电平。第一边沿空闲状态过后第一个出现的边沿。第二边沿空闲状态过后第二个出现的边沿。相位第一边沿采集0。第二边沿采集1。②SPI的四种时钟模式模式0极性0 相位0模式1极性0 相位1模式2极性1 相位0模式3极性1 模式1③比特位的传输顺序LSB First 先传最低有效位01234567MSB First 先传最高有效位76543210④数据宽度8Bit 每八个字节为一组传输16Bit每十六个字节为一组传输3.SPI IO引脚初始化W25Q64模块引脚连接如上图所示。SPI引脚分布及模式设定代码对SPI模块外漏引脚初始化void App_SPI_Init(void){//1.对SPI1模块进行重映射RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);//2.初始化SPI模块的IO引脚//PB3 SCK AF_PP 2MHZRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_ModeGPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_PinGPIO_Pin_3;GPIO_InitStruct.GPIO_SpeedGPIO_Speed_2MHz;GPIO_Init(GPIOB,GPIO_InitStruct);//PB4 MISO IPURCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitStruct.GPIO_ModeGPIO_Mode_IPU;GPIO_InitStruct.GPIO_PinGPIO_Pin_4;GPIO_Init(GPIOB,GPIO_InitStruct);//PB5 MOSI AF_PP 2MHZRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitStruct.GPIO_ModeGPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_PinGPIO_Pin_5;GPIO_InitStruct.GPIO_SpeedGPIO_Speed_2MHz;GPIO_Init(GPIOB,GPIO_InitStruct);//普通IO引脚cpu控制高低电平 PA15RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStruct.GPIO_ModeGPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_PinGPIO_Pin_15;GPIO_InitStruct.GPIO_SpeedGPIO_Speed_2MHz;GPIO_Init(GPIOA,GPIO_InitStruct);}4.SPI模块本身初始化①硬件结构原理观察上图SPI硬件结构可以看到时钟那一条线路上有总开关时钟是单片机内部地时钟主机通过SCK引脚向外发出时钟信号。要打开总开关SPI模块才能进行通信。后面时钟控制电路参数有极性相位波特率。左上侧电路有TDR和移位寄存器负责数据的发送发数据时候要把数据写入TDR这个数据会移动到移位寄存器中移位寄存器一位一位地通过MOSI引脚发送出去。而接受数据时波形通过MISO引脚传进来数据控制电路一位一位地解析数据并放入移位寄存器中。当所有的数据都填进了移位数据寄存器中他就会进入RDR编程者再从RDR中读出数据。下部通信方向选择有五种选择方式。而右侧NSS只有在做从机的时候NSS引脚才有用但是作为主机也需要对NSS引脚进行一定的配置。右上方有三个标志位通过查询不同的标志位可以知道SPI的工作状态。TxE是TDR空RxNE为RDR非空。②SPI模块初始化参数初始化SPI模块时候用到SPI_InitStruct要看从机要求什么参数就设置成什么参数。加入SPI与从机W25Q64通信就要看W25Q64要求什么参数。参数SPI_Direction:通信方向2线全双工标准的SPI总线格式 2线只读一般用于从机广播单线接收 单线方向是发送单线发送 单线方向是接收SPI_DataSize-数据宽度 可选8 bit 半字 16bitSPI_CPOL-时钟极性SPI_CPHA -时钟相位SPI_NSS -软件NSS或硬件NSSSPI_BaudRatePrescaler -用来选择波特率分频器的分频系数SPI_FirstBit -比特位的传输顺序 SPI_FirstBit_MSB SPI_FirstBit_LSB③如何设置参数设置参数时候要看从机的要求因为主机是与从机进行通信的所以要满足从机要求。上图为单片机向W25Q64发送“0x04”指令时的实际波形图。第一个波形NSS代表片选给NSS低电压时候选中W25Q64第二个波形为时钟信号时钟信号上实线代表Mode0Mode0是极性0相位0由图中观察可得空闲时候为低电平故极性为0而MOSI引脚上的波形代表从机接受可见得从机在第一边沿采集信号故相位0这就代表Mode0。而虚线上的Mode3代表空闲时刻为高电平则极性1那么极性1时下降沿为第一边沿所以W25Q64在第二边沿采集信号则相位1这就是Mode3。0x04对应二进制数为00000100则对比可得出数据传输顺序时MSB。④设置W25Q64的波特率设置波特率时候要看SPI内部结构框图时钟那一条线路。从时钟信号出发经过分频器分频器只能分2的幂次的频率分完频得到得到波特率。最终要产生1MHZ左右的波特率则应选择64分频假设输入时钟为72MHZ72/641.125MHZ最为接近。⑤NSS的配置方式作为从机时通过NSS引脚输入电压的高低判断NSS是否被选中。在主机里也需要对NSS引脚配置给它接3.3v高电压。因为SPI支持多主机模式如上图右侧有两个主机MOSIMISOSCK对应相连主机一与主机二普通IO引脚和NSS交叉连接如果主机一想和主机二通信主机一通过IO引脚给主机二的NSS发送低电平此时主机二被选中主机二丢失主机身份变为从机。因此为了防止主机的NSS被其他外部因素输入为低电压就需要一直向NSS接通高电压防止主机变为从机。看SPI结构图硬NSS表示的是直接通过外部电路连接给NSS高电平。软NSS表示直接通过内部NSS比特位写1在内部给它设为高电压即可。我们操作时候先把它设为软NSS然后给软NSS位写1。代码void App_SPI_Init(void){//1.对SPI1模块进行重映射RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);//2.初始化SPI模块的IO引脚//PB3 SCK AF_PP 2MHZRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_ModeGPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_PinGPIO_Pin_3;GPIO_InitStruct.GPIO_SpeedGPIO_Speed_2MHz;GPIO_Init(GPIOB,GPIO_InitStruct);//PB4 MISO IPURCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitStruct.GPIO_ModeGPIO_Mode_IPU;GPIO_InitStruct.GPIO_PinGPIO_Pin_4;GPIO_Init(GPIOB,GPIO_InitStruct);//PB5 MOSI AF_PP 2MHZRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitStruct.GPIO_ModeGPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_PinGPIO_Pin_5;GPIO_InitStruct.GPIO_SpeedGPIO_Speed_2MHz;GPIO_Init(GPIOB,GPIO_InitStruct);//普通IO引脚cpu控制高低电平 NSS PA15RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStruct.GPIO_ModeGPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_PinGPIO_Pin_15;GPIO_InitStruct.GPIO_SpeedGPIO_Speed_2MHz;GPIO_Init(GPIOA,GPIO_InitStruct);//2.对SPI模块本身进行初始化RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);SPI_InitTypeDef SPI_InitStruct;SPI_InitStruct.SPI_ModeSPI_Mode_Master;//主模式SPI_InitStruct.SPI_DataSizeSPI_DataSize_8b;//8bit数据宽度SPI_InitStruct.SPI_CPHASPI_CPHA_2Edge;//第二边沿采集SPI_InitStruct.SPI_CPOLSPI_CPOL_High;//高极性SPI_InitStruct.SPI_DirectionSPI_Direction_2Lines_FullDuplex;//两线全双工SPI_InitStruct.SPI_FirstBitSPI_FirstBit_MSB;//先传最高有效位SPI_InitStruct.SPI_BaudRatePrescalerSPI_BaudRatePrescaler_64;//设置64分频得到波特率传输数据速度SPI_InitStruct.SPI_NSSSPI_NSS_Soft;//设为软件NSSSPI_Init(SPI1,SPI_InitStruct);SPI_NSSInternalSoftwareConfig(SPI1,ENABLE);//给SPI1的软件NSS引脚写1防止主机变为从机。}5.SPI数据收发最大特点SPI数据收发是双向的每发送一个比特位必然会收到一个比特位。代码void App_SPI_MasterTransmitReceive(SPITypeDef *SPIx,const uint8_t *pDataTx,uint8_t *pDataRX,uint16_t Size){//1.闭合总开关SPI_Cmd(SPI1,ENABLE);//2.发送第一个字节SPI_I2S_SendData(SPI1,pDataTx[0]);//3.for(uint16_t i0;iSize-1;i){//向TDR写数据while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE)RESET);SPI_I2S_SendData(SPI1,pDataTx[1]);//从RDR读数据while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)RESET);pDataRX[i]SPI_I2S_ReceiveData(SPI1);}//读取最后一个字节的数据while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE)RESET);pDataRX[Size-1]SPI_I2S_ReceiveData(SPI1);//断开总开关SPI_Cmd(SPI1,DISABLE);}
企业数字化 ERP 产品动态
相关推荐
Win11 C盘最小安全余量:56GB实测阈值与WSL2空间治理 1. 这不是玄学,是实测出来的生存底线:Win11 C盘56GB余量到底意味着什么Win11 C盘留多大才够用?这个问题在技术社区里吵了快三年,答案从“100GB起步”到“200GB才安心”,再到“SSD时代随便分”,越说越玄乎。… · 2026/9/26 5:46:28
马弗炉使用核心指南:温度控制、安全接口与坩埚选型 1. 这台“烧红的铁盒子”到底在烧什么——马弗炉不是烤箱,是材料热处理的底层工具很多人第一次见到马弗炉,第一反应是:“这不就是个带门的电烤箱?”——我当年在高校材料实验室打杂时也这么想,直到被导师指着刚出炉、表… · 2026/9/26 5:46:21
MySQL索引下推ICP详解:从执行计划到联合索引优化实践 做MySQL性能优化这么久,我最常被问到的不是“为什么全表扫描这么慢”,反而是“我明明建了联合索引,为什么执行计划还是扫了几十万行”。这类问题十有八九能聊到索引下推(ICP)头上。Index Condition Pushdown࿰… · 2026/9/26 5:46:21
ChatGPT Plus额度重置机制解析:UTC+0滚动窗口与本地时区对齐方法 1. 额度重置这件事,为什么总感觉“对不上表”用ChatGPT Plus有一段时间的朋友,大概率都遇到过这种诡异体验:明明记得昨天下午三点左右额度用完了,今天三点刷新一看,还是提示限额;再等半小时,突然… · 2026/9/26 6:49:33
ChatGPT Plus额度重置机制解析:UTC+0硬重置与本地时区对齐指南 1. 额度重置时间对不上,问题到底出在哪用ChatGPT Plus有一段时间的朋友大概率都遇到过这种怪事:明明昨天下午三点刚用完额度,今天下午三点打开却提示还没恢复,等到晚上八点再试,突然又能用了。更离谱的是,有… · 2026/9/26 6:49:33
Akari助手:基于LCU API的开源英雄联盟效率工具全解析 英雄联盟玩家对"效率工具"的需求,其实一直存在一个尴尬的断层。官方客户端能做的事情有限,第三方工具要么收费、要么闭源、要么更新滞后,版本一更新就集体趴窝。我自己从S8开始折腾各种辅助工具,从最早的手动改配置文件… · 2026/9/26 6:49:33
Agent裸奔?装上这六个Skills,让AI从低效到高效 先说我自己的结论:这个圈子里的“Agent裸奔”,不是比喻,是真的惨。前几天一个朋友让我帮忙看他写的Agent程序,说“明明模型很强,为什么一干活就翻车”。我打开日志一看,文件路径写错、格式化靠猜、图片生成… · 2026/9/26 6:49:33
使用数据基础描述进行连续变量的特征提取 在数据科学与机器学习的过程中,数据的描述性统计和时间特征工程是十分重要的环节。描述性统计有助于快速理解数据的分布情况,而时间特征则能从时间数据中提取出有意义的信息,如趋势和周期性,帮助模型提升预测能力。本教程将围绕如何利用描述性统计量和时间数据来创建特征,… · 2026/9/26 6:49:21
注意力机制的相变现象:从混沌到局部性涌现 我无法基于当前输入生成符合要求的博文。原因如下:输入中项目标题为学术论文式表述:“Nonequilibrium Phases of Repulsive Self-Attention: Chaos, Attention Condensation, and Emergent Locality”,属于理论神经科学与深度学习交叉领域的前… · 2026/9/26 6:49:15
数据库课后习题答案别硬背:当测试用例集刷,效率翻倍 简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、… · 2026/9/26 0:00:21
OpenClaw 替代品?Hermes Agent 踩坑实录:macOS 飞书接入 TaoToken 配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/26 0:00:40
向下兼容与向上兼容:接口设计中的兼容性策略与工程实践 一次版本升级事故,是很多团队绕不过去的坎。线上环境里,服务端明明已经上线了新版接口,老的移动端还在照着旧文档传参数。请求一到网关,校验直接拒绝,用户操作失败,客服群炸了锅,开发群里开始互… · 2026/9/26 0:00:46