硬件探索——STM32F4通过SPI总线读取GMR(磁编码器)

发布时间:2026/9/16 10:50:26
硬件探索——STM32F4通过SPI总线读取GMR(磁编码器) 使用STM32F407VET6通过SPI串行总线读取GMR磁编码器的相关数据速度、角度绝对值等使用了PC10(SCK)、PC11(MISO)、PC12(MOSI)、PA15(CS)四个GPIO将其与编码器对应连接程序中使用了延时函数需要包含系统滴答定时器延时函数使用的头文件delay.h头文件spi.h#ifndef __SPI_H__ #define __SPI_H__ #include sys.h #define SPI3_PORT GPIOC #define SPI3_PIN (GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12) #define SPI3_PORT_RCC RCC_AHB1Periph_GPIOC void SPI3_Init(void); //初始化SPI3 uint16_t SPI3_ReadWriteByte(uint16_t TxData); //SPI3总线读写一个字节 #endif源文件spi.c#include spi.h void SPI3_Init() { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; RCC_AHB1PeriphClockCmd(SPI3_PORT_RCC, ENABLE); //使能GPIO时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);//使能SPI3外设时钟SPI3挂载于内部低速总线APB1最高84MHz //GPIO初始化设置 GPIO_InitStructure.GPIO_Pin SPI3_PIN; //PC10~12使用复用功能输出 GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; //复用功能 GPIO_InitStructure.GPIO_OType GPIO_OType_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed GPIO_Speed_100MHz; //100MHz GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_UP; //上拉 GPIO_Init(SPI3_PORT, GPIO_InitStructure); //初始化 //GPIO复用功能设置 GPIO_PinAFConfig(SPI3_PORT, GPIO_PinSource10, GPIO_AF_SPI3); //PC10复用为 SPI3_SCK GPIO_PinAFConfig(SPI3_PORT, GPIO_PinSource11, GPIO_AF_SPI3); //PC11复用为 SPI3_MISO GPIO_PinAFConfig(SPI3_PORT, GPIO_PinSource12, GPIO_AF_SPI3); //PC12复用为 SPI3_MOSI RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, ENABLE); //复位SPI3 RCC_APB1PeriphResetCmd(RCC_APB1Periph_SPI3, DISABLE);//停止复位SPI3 //SPI相关参数设置 SPI_InitStructure.SPI_Direction SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:双线双向全双工 SPI_InitStructure.SPI_Mode SPI_Mode_Master; //设置SPI工作模式:设置为SPI主机 SPI_InitStructure.SPI_DataSize SPI_DataSize_16b; //设置SPI的数据大小:SPI发送接收16位帧结构 SPI_InitStructure.SPI_CPOL SPI_CPOL_Low; //串行同步时钟的空闲状态:低电平 SPI_InitStructure.SPI_CPHA SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿上升或下降数据被采样 SPI_InitStructure.SPI_NSS SPI_NSS_Soft; //NSS信号由软件使用SSI位管理内部NSS信号由SSI位控制 SPI_InitStructure.SPI_BaudRatePrescaler SPI_BaudRatePrescaler_256; //定义波特率预分频的值为256 SPI_InitStructure.SPI_FirstBit SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始 SPI_InitStructure.SPI_CRCPolynomial 7; //CRC值计算若有的多项式 SPI_Init(SPI3, SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPI3寄存器 SPI_Cmd(SPI3, ENABLE); //使能SPI3外设 SPI3_ReadWriteByte(0xffff);//发送全1启动传输 } //SPI3读写数据 //TxData:要写入的数据 //返回值:读取到的数据 uint16_t SPI3_ReadWriteByte(uint16_t TxData) { while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) RESET) {} //等待发送区空 SPI_I2S_SendData(SPI3, TxData); //通过外设SPI3发送一个16bit数据 while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_RXNE) RESET) {}//等待16bit数据接收完成 return SPI_I2S_ReceiveData(SPI3); //返回通过SPI3最近接收的数据 }头文件gmr.h#ifndef __GMR_H__ #define __GMR_H__ #include sys.h #define CS_PORT GPIOA #define CS_PIN (GPIO_Pin_15) #define CS_PORT_RCC RCC_AHB1Periph_GPIOA #define SPI3_CS PAout(15) /* SPI command for TLE5012 */ #define READ_STATUS 0x8001 //8000 #define READ_ANGLE_VALUE 0x8021 //8020 #define READ_SPEED_VALUE 0x8031 //8030 #define WRITE_MOD1_VALUE 0x5060 //0_1010_0_000110_0001 #define MOD1_VALUE 0x0001 #define WRITE_MOD2_VALUE 0x5080 //0_1010_0_001000_0001 #define MOD2_VALUE 0x0801 #define WRITE_MOD3_VALUE 0x5091 //0_1010_0_001001_0001 #define MOD3_VALUE 0x0000 #define WRITE_MOD4_VALUE 0x50E0 //0_1010_0_001110_0001 #define MOD4_VALUE 0x0098 //9bit 512 #define WRITE_IFAB_VALUE 0x50B1 #define IFAB_VALUE 0x000D /* Functionality mode */ #define REFERESH_ANGLE 0 void GMR_Init(void); uint16_t ReadAngle1(void); float Conversion_Speed1(void); short ReadSpeed1(void); uint16_t ReadValue1(uint16_t u16RegValue); #endif源文件gmr.c#include gmr.h #include spi.h GPIO_InitTypeDef GPIO_InitStructure_SPI; void GMR_Init() { GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量 RCC_AHB1PeriphClockCmd(CS_PORT_RCC, ENABLE); GPIO_InitStructure.GPIO_Pin CS_PIN; //要设置的IO口 GPIO_InitStructure.GPIO_Mode GPIO_Mode_OUT; //普通输出模式 GPIO_InitStructure.GPIO_OType GPIO_OType_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed GPIO_Speed_100MHz; //100MHz GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_UP; //上拉 GPIO_Init(CS_PORT, GPIO_InitStructure); /* 初始化GPIO */ GPIO_SetBits(CS_PORT, CS_PIN); //将片选端口拉高 /* 以下代码初始化SPI接口的读写 */ GPIO_InitStructure_SPI.GPIO_Pin GPIO_Pin_12; //PC12复用功能输出 GPIO_InitStructure_SPI.GPIO_Mode GPIO_Mode_AF; //使用复用功能 GPIO_InitStructure_SPI.GPIO_Speed GPIO_Speed_100MHz;//100MHz GPIO_InitStructure_SPI.GPIO_PuPd GPIO_PuPd_UP; //上拉 } uint16_t ReadValue1(uint16_t u16RegValue) { uint16_t u16Data; SPI3_CS 0; SPI3_ReadWriteByte(u16RegValue); //SPI_TX_OFF;将主设备数据输出从设备数据输入MOSI配置成开漏--输入模式 GPIO_InitStructure_SPI.GPIO_OType GPIO_OType_OD;//开漏输出 GPIO_Init(SPI3_PORT, GPIO_InitStructure_SPI);//初始化 //发送 0xFFFF 是无用的可能是为了有时钟 u16Data (SPI3_ReadWriteByte(0xffff) 0x7FFF);//0x12/0xff*100k SPI3_CS 1; //SPI_TX_ON;将主设备数据输出从设备数据输入MOSI配置成推挽--输出模式 GPIO_InitStructure_SPI.GPIO_OType GPIO_OType_PP;//推挽输出 GPIO_Init(SPI3_PORT, GPIO_InitStructure_SPI);//初始化 return(u16Data); } short ReadSpeed1() { short Data; Data (short)(ReadValue1(READ_SPEED_VALUE) 1) 1; return Data; } float Conversion_Speed1() { float Speed; Speed ((float)(ReadSpeed1() * 360) / 65535) / (2 * 0.0000213); //单位°/s; return (Speed / (float)360.0); //返回每秒的转数 } uint16_t ReadAngle1() { return ((ReadValue1(READ_ANGLE_VALUE) 1) * 360 / 0x10000); }使用实例如下#include sys.h #include delay.h #include usart.h #include spi.h #include gmr.h int main(void) { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2 delay_init(168); //初始化延时函数 uart_init(115200); //初始化串口波特率为115200 GMR_Init(); SPI3_Init(); while (1) { delay_ms(5); printf(speed:%d\r\n, ReadSpeed1()); printf(angle:%d\r\n, ReadAngle1()); } }效果如下

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询