使用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());
}
}
效果如下:
|