STM32硬件SPI通信详解-------附代码

SPI外设简介

1.STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成数据收发等功能,减轻CPU的负担
2.可配置8位/16位数据帧高位先行/低位先行
3.时钟频率: fPCLK / (2, 4, 8, 16, 32, 64, 128, 256)
4.支持多主机模型主或从操作
5.可精简为半双工/单工通信
6.支持DMA
7.兼容I2S协议

STM32F103C8T6 硬件SPI资源SPI1(APB2外设,72MHZ)、SPI2(APB1外设,32MHZ)

SPI框图

在这里插入图片描述LSBFIRST控制位:配置低位或者高位先行
接收缓冲区:RDR -----发送缓冲区:TDR {二者配合实现无延迟传输}
BR[2:0]:时钟分频
TXE:发送寄存器空
RXNE:接收寄存器非空
NSS:实现多主机

SPI基本结构

在这里插入图片描述

主模式全双工连续传输

在这里插入图片描述

非连续传输

在这里插入图片描述

软件/硬件波形对比

在这里插入图片描述
在这里插入图片描述

STM32硬件SPI代码

STM32外设SPI库函数详解

void SPI_I2S_DeInit(SPI_TypeDef* SPIx);
//恢复缺省配置
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
//SPI初始化
void I2S_Init(SPI_TypeDef* SPIx, I2S_InitTypeDef* I2S_InitStruct);
//I2S初始化
void SPI_StructInit(SPI_InitTypeDef* SPI_InitStruct);
//SPI结构体变量初始化
void I2S_StructInit(I2S_InitTypeDef* I2S_InitStruct);
//I2S结构体变量初始化
void SPI_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
//SPI外设Cmd使能
void I2S_Cmd(SPI_TypeDef* SPIx, FunctionalState NewState);
//I2SCmd外设使能
void SPI_I2S_ITConfig(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT, FunctionalState NewState);
//中断使能
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);
//使能或者失能SPIx/I2Sx的DMA接口
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
//写DR数据寄存器,发送字节
/*注释:数据的发送和接收可以是8位或者16位的。为保证正确的操作,需要在启用SPI之前就确定好数据帧格式*/
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx);
//读DR数据寄存器,接收字节
/*注释:数据的发送和接收可以是8位或者16位的。为保证正确的操作,需要在启用SPI之前就确定好数据帧格式*/
void SPI_NSSInternalSoftwareConfig(SPI_TypeDef* SPIx, uint16_t SPI_NSSInternalSoft);
//通过软件内部配置选定SPI的NSS引脚
void SPI_SSOutputCmd(SPI_TypeDef* SPIx, FunctionalState NewState);
//使能或者失能SS输出
void SPI_DataSizeConfig(SPI_TypeDef* SPIx, uint16_t SPI_DataSize);
//为所选SPI配置数据帧大小,8/16位数据帧配置
void SPI_TransmitCRC(SPI_TypeDef* SPIx);
//发送SPIx的CRC校验值
void SPI_CalculateCRC(SPI_TypeDef* SPIx, FunctionalState NewState);
//使能或失能硬件CRC校验
/*只有在禁止SPI时(SPE=0),才能写该位,否则出错;该位只能在全双工模式下使用;I2S模式下不使用*/
uint16_t SPI_GetCRC(SPI_TypeDef* SPIx, uint8_t SPI_CRC);
//返回指定SPI的发送或接收CRC寄存器值
/*当BSY标志为’1’时读该寄存器,将可能读到不正确的数值; 在I2S模式下不使用*/
uint16_t SPI_GetCRCPolynomial(SPI_TypeDef* SPIx);
//返回指定SPI的CRC多项式寄存器值
/*该寄存器包含了CRC计算时用到的多项式;在I2S模式下不使用*/
void SPI_BiDirectionalLineConfig(SPI_TypeDef* SPIx, uint16_t SPI_Direction);
//为指定的SPI选择双向模式下的数据传输方向
/*双向模式下的输出使能,决定在“单线双向”模式下数据的输出方向,这个“单线”数据线在主设备端为MOSI引脚,在从设备端为MISO引脚,在I2S模式下不使用*/
FlagStatus SPI_I2S_GetFlagStatus(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
//检查指定的SPI/I2S标志是否设置
void SPI_I2S_ClearFlag(SPI_TypeDef* SPIx, uint16_t SPI_I2S_FLAG);
//清除指定标志位
ITStatus SPI_I2S_GetITStatus(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
//检查指定的SPI/I2S中断是否发生
void SPI_I2S_ClearITPendingBit(SPI_TypeDef* SPIx, uint8_t SPI_I2S_IT);
//清除中断标志位

STM32硬件SPI.c配置

#include "stm32f10x.h"                  // Device header

/**
  * 函    数:SPI写SS引脚电平,SS仍由软件模拟
  * 参    数:BitValue 协议层传入的当前需要写入SS的电平,范围0~1
  * 返 回 值:无
  * 注意事项:此函数需要用户实现内容,当BitValue为0时,需要置SS为低电平,当BitValue为1时,需要置SS为高电平
  */
void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_12, (BitAction)BitValue);		//根据BitValue,设置SS引脚的电平
}

/**
  * 函    数:SPI2初始化
  * 参    数:无
  * 返 回 值:无
  */
void MySPI_Init(void)
{
	/*************开启时钟********************/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	//开启GPIOA的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);	//开启SPI1的时钟
	
	/************GPIO初始化*******************/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);					//将PB12引脚初始化为推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);					//将PB13和PB15引脚初始化为复用推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);					//将PB14引脚初始化为上拉输入
	
	/***************SPI初始化*****************/
	SPI_InitTypeDef SPI_InitStructure;						//定义结构体变量
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;			//模式,选择为SPI主模式
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;	//方向,选择2线全双工
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//数据宽度,选择为8位
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;		//先行位,选择高位先行
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;	//波特率分频,选择128分频
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;				//SPI极性,选择低极性
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;			//SPI相位,选择第一个时钟边沿采样,极性和相位决定选择SPI模式0
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;				//NSS,选择由软件控制
	SPI_InitStructure.SPI_CRCPolynomial = 7;				//CRC多项式,暂时用不到,给默认值7
	SPI_Init(SPI2, &SPI_InitStructure);						//将结构体变量交给SPI_Init,配置SPI2
	
	/***************SPI使能*******************/
	SPI_Cmd(SPI2, ENABLE);									//使能SPI2,开始运行
	
	/*设置默认高电平-----不选中从机*/
	MySPI_W_SS(1);											//SS默认高电平
}

/**
  * 函    数:SPI起始
  * 参    数:无
  * 返 回 值:无
  */
void MySPI_Start(void)
{
	MySPI_W_SS(0);				//拉低SS,开始时序
}

/**
  * 函    数:SPI终止
  * 参    数:无
  * 返 回 值:无
  */
void MySPI_Stop(void)
{
	MySPI_W_SS(1);				//拉高SS,终止时序
}

/**
  * 函    数:SPI交换传输一个字节,使用SPI模式0
  * 参    数:ByteSend 要发送的一个字节
  * 返 回 值:接收的一个字节
  */
uint8_t MySPI_SwapByte(uint8_t ByteSend)
{
	while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) != SET);	//等待发送数据寄存器空
	
	SPI_I2S_SendData(SPI2, ByteSend);								//写入数据到发送数据寄存器,开始产生时序
	
	while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) != SET);	//等待接收数据寄存器非空
	
	return SPI_I2S_ReceiveData(SPI2);								//读取接收到的数据并返回
}

STM32硬件SPI.h配置

#ifndef __MYSPI_H
#define __MYSPI_H

void MySPI_Init(void);
void MySPI_Start(void);
void MySPI_Stop(void);
uint8_t MySPI_SwapByte(uint8_t ByteSend);

#endif

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
很高兴为您解答这个问题。以下是针对STM32-24位AD7799驱动手册代码详解的简要说明。 首先,AD7799是一款24位精度的模数转换器,可用于测量各种传感器的输出信号。它可通过SPI接口与微控制器(如STM32通信,以读取和写入寄存器值。 在STM32中,可以采用模拟SPI硬件SPI与AD7799通信,具体实现方式取决于使用的STM32型号和开发环境。以下是一些可能使用的代码和说明: 1. 模拟SPI方式: ```c // 初始化GPIO口 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化SPI void SPI_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOB,&GPIO_InitStructure); } void AD7799_SPI_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); SPI_InitTypeDef SPI_InitStructure; 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_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); } // SPI发送数据 uint8_t AD7799_SPI_Write(uint8_t data) { uint8_t i; for(i = 0; i < 8; i++) { if(data & 0x80) GPIO_SetBits(GPIOB, GPIO_Pin_9); else GPIO_ResetBits(GPIOB, GPIO_Pin_9); data <<= 1; GPIO_ResetBits(GPIOB, GPIO_Pin_10); GPIO_SetBits(GPIOB, GPIO_Pin_10); } return data; } // SPI接收数据 uint8_t AD7799_SPI_Read(void) { uint8_t i, data = 0; for(i = 0; i < 8; i++) { data <<= 1; GPIO_ResetBits(GPIOB, GPIO_Pin_10); if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)) data |= 0x01; GPIO_SetBits(GPIOB, GPIO_Pin_10); } return data; } ``` 2. 硬件SPI方式: ```c // 初始化SPI void AD7799_SPI_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); SPI_InitTypeDef SPI_InitStructure; 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_2; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); } // SPI发送数据 uint8_t AD7799_SPI_Write(uint8_t data) { while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET); SPI_I2S_SendData(SPI1, data); while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET); return SPI_I2S_ReceiveData(SPI1); } ``` 上述代码只是示例,具体实现方式需要根据您的应用场景进行调整。同时,还需要编写读取和写入AD7799寄存器的函数,例如: ```c // AD7799写寄存器函数 void AD7799_WriteReg(uint8_t reg, uint16_t value) { AD7799_SPI_Write(reg << 3); AD7799_SPI_Write(value >> 8); AD7799_SPI_Write(value & 0xFF); } // AD7799读寄存器函数 uint16_t AD7799_ReadReg(uint8_t reg) { uint16_t value = 0; AD7799_SPI_Write((reg << 3) | 0x04); value |= AD7799_SPI_Read() << 8; value |= AD7799_SPI_Read(); return value; } ``` 以上是一个简单的STM32-24位AD7799驱动手册代码详解。希望能帮助到您!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

领悟电子界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值