当前位置: 首页 > news >正文

美妆网站建设太原seo外包公司

美妆网站建设,太原seo外包公司,用摄像头直播网站怎么做,上市公司查询网站开胃简介 根据上一节对STM32的SPI介绍!本节将进行硬件SPI的实现,片选用软件实现!跟着Whappy走起!W25Q64的驱动层,我们不需要更改,仅仅需要更改一下SPI的协议,即:由软件实现改成硬件…

开胃简介

根据上一节对STM32的SPI介绍!本节将进行硬件SPI的实现,片选用软件实现!跟着Whappy走起!W25Q64的驱动层,我们不需要更改,仅仅需要更改一下SPI的协议,即:由软件实现改成硬件实现。跟着Whappy同志步伐学起来!

SPI硬件整体框架如下图,代码配置也是根据这个SPI的基本结构进行实现的,如下五步实现过程。

STM32的SPI相关库函数的介绍如下:

初始化和配置函数

 
函数名功能参数介绍使用方法
SPI_I2S_DeInit将 SPI/I2S 外设寄存器重置为默认值SPIx: SPI 外设地址在重新配置 SPI 前调用,清除所有之前的配置
SPI_Init根据指定配置初始化 SPISPIx: SPI 外设地址<br>SPI_InitStruct: SPI 配置结构体配置 SPI 通信参数,如时钟极性、数据大小等
I2S_Init根据指定配置初始化 I2SSPIx: SPI 外设地址<br>I2S_InitStruct: I2S 配置结构体配置 I2S 通信参数,如标准、数据长度等
SPI_StructInit填充 SPI 初始化结构体默认值SPI_InitStruct: SPI 配置结构体指针在手动配置 SPI 前,快速获取默认配置
SPI_I2S_StructInit填充 I2S 初始化结构体默认值I2S_InitStruct: I2S 配置结构体指针在手动配置 I2S 前,快速获取默认配置

控制和命令函数

 
函数名功能参数介绍使用方法
SPI_Cmd使能或禁用 SPISPIx: SPI 外设地址<br>NewState: 使能/禁用状态开启或关闭 SPI 外设
I2S_Cmd使能或禁用 I2SSPIx: SPI 外设地址<br>NewState: 使能/禁用状态开启或关闭 I2S 外设
SPI_I2S_ITConfig配置 SPI/I2S 中断SPIx: SPI 外设地址<br>SPI_I2S_IT: 中断类型<br>NewState: 使能/禁用状态配置中断,如发送完成、接收完成等
SPI_I2S_DMACmd配置 SPI/I2S DMA 请求SPIx: SPI 外设地址<br>SPI_I2S_DMAReq: DMA 请求类型<br>NewState: 使能/禁用状态启用或禁用 DMA 传输

数据传输函数

 
函数名功能参数介绍使用方法
SPI_I2S_SendData通过 SPI/I2S 发送数据SPIx: SPI 外设地址<br>Data: 待发送的 16 位数据发送单个数据字
SPI_I2S_ReceiveData从 SPI/I2S 接收数据SPIx: SPI 外设地址读取接收缓冲区的 16 位数据

高级配置函数

 
函数名功能参数介绍使用方法
SPI_NSSInternalSoftwareConfig配置内部片选信号SPIx: SPI 外设地址<br>SPI_NSSInternalSoft: NSS 信号配置软件控制从设备片选
SPI_SSOutputCmd配置 SS 输出SPIx: SPI 外设地址<br>NewState: 使能/禁用状态控制从设备片选输出
SPI_DataSizeConfig配置数据大小SPIx: SPI 外设地址<br>SPI_DataSize: 数据大小设置每次传输的数据位数
SPI_BiDirectionalLineConfig配置双向线路方向SPIx: SPI 外设地址<br>SPI_Direction: 传输方向设置单工或半双工模式下的传输方向

CRC 校验函数

 
函数名功能参数介绍使用方法
SPI_TransmitCRC发送 CRCSPIx: SPI 外设地址手动发送 CRC 值
SPI_CalculateCRC使能/禁用 CRC 计算SPIx: SPI 外设地址<br>NewState: 使能/禁用状态开启或关闭 CRC 硬件计算
SPI_GetCRC获取 CRC 值SPIx: SPI 外设地址<br>SPI_CRC: CRC 类型读取发送或接收 CRC 值
SPI_GetCRCPolynomial获取 CRC 多项式SPIx: SPI 外设地址读取当前使用的 CRC 多项式

状态和标志函数

 
函数名功能参数介绍使用方法
SPI_I2S_GetFlagStatus获取状态标志SPIx: SPI 外设地址<br>SPI_I2S_FLAG: 标志类型检查传输、错误等各种状态
SPI_I2S_ClearFlag清除状态标志SPIx: SPI 外设地址<br>SPI_I2S_FLAG: 标志类型手动清除特定状态标志
SPI_I2S_GetITStatus获取中断状态SPIx: SPI 外设地址<br>SPI_I2S_IT: 中断类型检查中断是否触发
SPI_I2S_ClearITPendingBit清除中断挂起位SPIx: SPI 外设地址<br>SPI_I2S_IT: 中断类型手动清除中断挂起状态

代码实现SPI步骤--五步实现(采用非连续传输发送)

GPIO 模式十六进制值模式说明典型应用场景
GPIO_Mode_AIN0x0模拟输入模式用于模拟信号输入,如传感器、ADC采样
GPIO_Mode_IN_FLOATING0x04浮空输入模式外部悬空输入,无上拉/下拉电阻
GPIO_Mode_IPD0x28下拉输入模式输入引脚默认为低电平
GPIO_Mode_IPU0x48上拉输入模式输入引脚默认为高电平
GPIO_Mode_Out_OD0x14开漏输出模式需要外部上拉电阻,常用于 I2C 通信
GPIO_Mode_Out_PP0x10推挽输出模式通用数字输出模式,驱动能力强
GPIO_Mode_AF_OD0x1C开漏复用功能复用功能的开漏输出,如 I2C
GPIO_Mode_AF_PP0x18推挽复用功能复用功能的推挽输出,如 USART、SPI

第一步:开启时钟,开启SPI和GPIO的时钟;

第二步:初始化GPIO,其中SCK和MOSI是由硬件外设控制的输出信号,配置称复用推挽输出,MISO是硬件外设的输入信号,配置上拉输入。SN片选引脚,是由软件控制的输出信号,配置成通用推挽输出。

第三步:配置SPI外设,这一步,我们使用一个结构体进行配置(STM32的库函数)

第四步:使能SPI。

void MySPI_Init(void)
{// 开启GPIOA时钟/* 开启GPIOA的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);    // 开启GPIOA的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);     // 开启SPI1的时钟/* GPIO的配置 */// 配置SCK和MOSI引脚GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         // 设置为复用推挽输出模式 (Alternate Function Push-Pull)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;  // 选择引脚5 (SCK) 和 引脚7 (MOSI)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       // 设置引脚速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);                   // 初始化GPIOA的这两个引脚// 配置MISO引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;           // 设置为上拉输入模式 (Input with Pull-Up)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;               // 选择引脚6 (MISO)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       // 设置引脚速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);                   // 初始化GPIOA的MISO引脚// 配置NSS引脚 (片选)GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        // 设置为推挽输出模式 (Push-Pull Output)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;               // 选择引脚4 (NSS)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       // 设置引脚速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);                   // 初始化GPIOA的NSS引脚/* SPI的配置 */SPI_InitTypeDef SPI_InitStructure;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; // 设置SPI波特率预分频器为128,确定SPI通信速度SPI_InitStructure.SPI_CRCPolynomial = 7;                      // 设置CRC多项式为7,用于数据完整性检测SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;             // 设置数据位宽为8位SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 设置SPI为全双工模式(即同时发送和接收数据)SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;            // 设置数据传输顺序为先发送最高有效位(MSB)SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                 // 设置SPI为主模式SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                     // 设置为软件控制的片选(NSS)SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                  // 设置时钟相位 (CPHA) 为第一沿变化SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                    // 设置时钟极性 (CPOL) 为低电平SPI_Init(SPI1, &SPI_InitStructure);                            // 初始化SPI1外设// 使能SPISPI_Cmd(SPI1, ENABLE);  // 启动SPI1外设,开始进行SPI通信
}

详细解释:

  1. 时钟使能

    • RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE):启用GPIOA外设时钟,以便能够配置和使用GPIOA引脚。
    • RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE):启用SPI1外设时钟,确保SPI外设可以正常工作。
  2. GPIO配置

    • SCK (Serial Clock)MOSI (Master Out Slave In) 引脚配置为复用推挽输出模式(GPIO_Mode_AF_PP),通过这些引脚来传输数据。
    • MISO (Master In Slave Out) 引脚配置为上拉输入模式(GPIO_Mode_IPU),用于接收从外设发送来的数据。
    • NSS (Chip Select) 引脚配置为推挽输出模式(GPIO_Mode_Out_PP),用于控制SPI外设的选通。
  3. SPI配置

    • 波特率预分频器:设置为128,这会影响SPI的时钟频率,确保SPI通信速度适合与外设交互。
    • CRC多项式:设置为7,SPI传输过程中可以使用CRC校验以提高数据的完整性。
    • 数据位宽:设置为8位,即每次传输一个字节的数据。
    • SPI方向:设置为全双工模式,意味着数据可以在同一时间同时进行接收和发送。
    • 数据位顺序:设置为MSB先传输(SPI_FirstBit_MSB),即先发送最高有效位(MSB)。
    • SPI模式:设置为主模式(SPI_Mode_Master),意味着此外设将控制通信。
    • 片选控制:选择软件控制片选模式(SPI_NSS_Soft),即通过软件控制NSS信号的状态。
    • 时钟极性和相位SPI_CPOL_Low 表示时钟的空闲状态为低电平,SPI_CPHA_1Edge 表示数据将在时钟的第一沿变化时采样。
  4. 使能SPI

    • SPI_Cmd(SPI1, ENABLE):使能SPI1外设,开始SPI通信,允许SPI发送和接收数据。

这段代码配置了STM32的SPI1外设,使其能够与其他SPI外设进行通信(例如传感器、外部存储设备等)。

第五步:最后,参考一下非连续传输,进行一个字节的交换!如下图

uint8_t MySPI_SwapByte(uint8_t Byte)
{// 等待SPI1的发送数据寄存器空,确保可以发送数据while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);// 发送数据SPI_I2S_SendData(SPI1, Byte);  // 通过SPI发送一个字节的数据// 等待SPI1的接收数据寄存器非空,确保数据已接收while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);// 读取接收到的数据并返回return SPI_I2S_ReceiveData(SPI1);  // 返回接收到的字节数据
}

详细解释:

  1. 等待发送寄存器空

    • SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE):检查SPI1的数据发送寄存器(TXE标志)是否为空。如果为“空”(即可以发送数据),则返回SET,否则继续等待。
    • 这是通过循环检查,确保数据寄存器准备好可以发送数据,避免数据溢出或丢失。
  2. 发送数据

    • SPI_I2S_SendData(SPI1, Byte):将参数 Byte 中的数据通过SPI总线发送出去。SPI的发送操作是同步的,当数据发送寄存器可用时,数据将被传送到外部设备。
  3. 等待接收寄存器非空

    • SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE):检查SPI1的接收数据寄存器(RXNE标志)是否非空。若接收寄存器有数据(即数据已经接收到),则返回SET,否则继续等待。
    • 这确保了只有在数据完全接收后,才进行下一步操作。
  4. 读取接收数据

    • SPI_I2S_ReceiveData(SPI1):从SPI1接收数据寄存器中读取接收到的字节并返回。
    • 在交换字节数据时,发送和接收操作是并行进行的。因此,读取接收到的数据通常就是发送数据时外设返回的数据。

总结:

该函数实现了SPI的数据发送与接收。它通过等待SPI硬件标志位来确保发送和接收过程的同步,确保数据的完整传输。在使用时,传入一个字节,发送后等待接收另一个字节并返回。这个函数可以用于SPI设备之间的字节交换操作。

源码

把上一节软件部分改一下即可

#include "stm32f10x.h"                  // Device header//片选
void MySPI_W_CS(uint8_t BitValue)
{GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)BitValue);
}void MySPI_Init(void)
{// 开启GPIOA时钟/* 开启GPIOA的时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);    // 开启GPIOA的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);     // 开启SPI1的时钟/* GPIO的配置 */// 配置SCK和MOSI引脚GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         // 设置为复用推挽输出模式 (Alternate Function Push-Pull)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;  // 选择引脚5 (SCK) 和 引脚7 (MOSI)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       // 设置引脚速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);                   // 初始化GPIOA的这两个引脚// 配置MISO引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;           // 设置为上拉输入模式 (Input with Pull-Up)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;               // 选择引脚6 (MISO)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       // 设置引脚速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);                   // 初始化GPIOA的MISO引脚// 配置NSS引脚 (片选)GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        // 设置为推挽输出模式 (Push-Pull Output)GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;               // 选择引脚4 (NSS)GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       // 设置引脚速率为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);                   // 初始化GPIOA的NSS引脚/* SPI的配置 */SPI_InitTypeDef SPI_InitStructure;SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; // 设置SPI波特率预分频器为128,确定SPI通信速度SPI_InitStructure.SPI_CRCPolynomial = 7;                      // 设置CRC多项式为7,用于数据完整性检测SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;             // 设置数据位宽为8位SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 设置SPI为全双工模式(即同时发送和接收数据)SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;            // 设置数据传输顺序为先发送最高有效位(MSB)SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                 // 设置SPI为主模式SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                     // 设置为软件控制的片选(NSS)SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;                  // 设置时钟相位 (CPHA) 为第一沿变化SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;                    // 设置时钟极性 (CPOL) 为低电平SPI_Init(SPI1, &SPI_InitStructure);                            // 初始化SPI1外设// 使能SPISPI_Cmd(SPI1, ENABLE);  // 启动SPI1外设,开始进行SPI通信
}//SPI模式0
/*** @brief 开始SPI通信,拉低片选信号* @note 通常在发送数据前调用,选中从设备*/
void MySPI_Start(void)
{MySPI_W_CS(0);  // 拉低CS(片选)信号,选中从设备
}/*** @brief 结束SPI通信,拉高片选信号* @note 通常在数据传输完成后调用,取消从设备选择*/
void MySPI_Stop(void)
{MySPI_W_CS(1);  // 拉高CS(片选)信号,取消从设备选择
}uint8_t MySPI_SwapByte(uint8_t Byte)
{// 等待SPI1的发送数据寄存器空,确保可以发送数据while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != SET);// 发送数据SPI_I2S_SendData(SPI1, Byte);  // 通过SPI发送一个字节的数据// 等待SPI1的接收数据寄存器非空,确保数据已接收while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);// 读取接收到的数据并返回return SPI_I2S_ReceiveData(SPI1);  // 返回接收到的字节数据
}

知识普及:

SPI 的四种模式详细解析:

模式定义

SPI 模式由两个参数决定:

  • CPOL (Clock Polarity):时钟极性
  • CPHA (Clock Phase):时钟相位

详细模式说明

  1. 模式0 (CPOL=0, CPHA=0)
  • 时钟空闲态为低电平
  • 在上升沿采样数据
  • 在下降沿发送数据
  • 最常用的模式
  1. 模式1 (CPOL=0, CPHA=1)
  • 时钟空闲态为低电平
  • 在下降沿采样数据
  • 在上升沿发送数据
  1. 模式2 (CPOL=1, CPHA=0)
  • 时钟空闲态为高电平
  • 在下降沿采样数据
  • 在上升沿发送数据
  1. 模式3 (CPOL=1, CPHA=1)
  • 时钟空闲态为高电平
  • 在上升沿采样数据
  • 在下降沿发送数据

时序图解释

SPI Timing Diagram

Click to open code

选择建议

  • 确保主从设备的模式一致
  • 根据从设备的具体通信要求选择
  • 模式0最为通用
  • 特定外设可能有特定模式要求

配置示例(STM32)

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;   // 时钟极性
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 时钟相位

SPI的学习到此就圆满结束了!相较于I2C,尽管SPI需要多几条物理线路,但它的实现要简单得多。I2C在多设备通信时的复杂性和时序管理常常让人感到头疼,而SPI通过其清晰、简洁的同步时序,极大简化了实现过程。与此不同,USART通信尽管也能够由软件模拟,但相较于SPI和I2C,它的实现要复杂得多。原因在于,USART是一种异步通信协议,没有统一的时钟信号,数据传输完全依赖于发送和接收设备之间的同步,时序完全靠软件来控制和测量,带来了更高的实现难度和出错的风险。

在实际应用中,许多设备的基础通信都使用USART,这也是因为USART协议在很多情况下是最为通用且具备足够灵活性的标准。尽管它实现较为复杂,但其异步特性在一些特定场合(如无需时钟信号、长距离通信等)下仍具有不可替代的优势。因此,虽然USART的时序和同步管理比SPI和I2C复杂,但它仍在很多嵌入式应用中占有一席之地。

进军下一章节!!!!! 时间2024.12.26  20:51 地点:苏州

http://www.dinnco.com/news/13495.html

相关文章:

  • 上传产品网站怎么做的长沙seo培训班
  • 一个服务器可以备案几个网站广告营销平台
  • 海南靠谱网站建设定制深圳网站做优化哪家公司好
  • 做网站时字幕怎么做百度竞价排名软件
  • 简述网站推广方式广州seo公司排名
  • 苏州h5网站建设价钱网站页面关键词优化
  • 公司制作网站怎么做的企业培训有哪些方面
  • 企业网站建设应该计入哪个科目淘宝关键词排名怎么查
  • 推广网站怎样做浙江百度查关键词排名
  • 怎样在手机上做自己的网站类似火脉的推广平台
  • 尼高网站设计公司seo测试工具
  • 做网站在哪里做比较好搜索引擎优化有哪些要点
  • 网站做系统叫什么名字吗seo网站优化系统
  • 网站底部固定广告代码seo推广专员
  • 校园网建设网站特色网络营销的优化和推广方式
  • 网站建设公司(深圳信科)在哪里找软件开发公司
  • 门户网站的注意要素东莞做网络推广的公司
  • 青海网站开发公司百度实时热点排行榜
  • 网站栏目一般有哪些南昌网站设计
  • 国外获奖flash网站2021百度新算法优化
  • 做网站域名网站推广怎样做
  • 网页动态设计怎么做网站优化排名资源
  • 阳江做网站详细解读qq空间刷赞推广网站
  • 有发展的小企业网站建设今日国内新闻最新消息10条新闻
  • 网站关键词几个字百度推广登录地址
  • 专门做爬虫的网站武汉全网推广
  • ideo设计公司上海太原seo软件
  • 大气扁平网站网络优化包括
  • wordpress客户端建站网络营销推广策划的步骤
  • 学互联网做网站是什么seo内容优化是什么意思