1.AS5040介绍
2.硬件电路
硬件上使用SSI通信方式连接。
3.配置硬件SPI
查看手册,AS5040时序
可以看到在空闲阶段不发生数据传输的时候时钟(CLK)和数据(DO)都保持高电位(tCLKFE阶段),在第一个脉冲的下降沿触发编码器载入发送数据,然后每一个时钟脉冲的上升沿编码器送出数据,数据的高位在前,低位在后,共发送10个数据(对应其分辨率10BIT),后面是6BIT校验数据;当传送完所有的位数以后时钟回到高电平,数据也对应回到高电平,直到下一个传输周期到达。
谢谢此文章作者的分享
stm32使用SPI获取磁性单圈绝对值编码器数据 - 知乎
代码操作:
/*
*********************************************************************************************************
*
* 模块名称 : BSP_AS5040.C
* 文件名称 : 编码器驱动模块
* 版 本 : V0.1
* 说 明 :在空闲阶段不发生数据传输的时候时钟(CLK)和数据(DO)都保持高电位(tCLKFE阶段),
在第一个脉冲的下降沿触发编码器载入发送数据
然后每一个时钟脉冲的上升沿编码器送出数据,数据的高位在前,低位在后,共发送10个数据(对应其分辨率10BIT)
当传送完所有的位数以后时钟回到高电平,数据也对应回到高电平,直到下一个传输周期到达。对比四种模式,只有当CPOL配置成“0”和CPHA配置成“1”的时候 才符合每一个时钟脉冲的上升沿编码器送出数据的情况。使用SPI获取AS5040磁性单圈绝对值编码器数据。 10bit+6bit
*********************************************************************************************************
*/
#include "bsp.h"/* GPIO口对应配置 *///绝对值编码器 CSN引脚 A4 黄色 29 --SPI1_NSS
#define ABSCSN_PORT GPIOA
#define ABSCSN_RCC RCC_APB2Periph_GPIOA
#define ABSCSN_PIN GPIO_Pin_4//绝对值编码器 CLK引脚 A5 绿色 30 ---SPI1_SCK
#define ABSCLK_PORT GPIOA
#define ABSCLK_RCC RCC_APB2Periph_GPIOA
#define ABSCLK_PIN GPIO_Pin_5//绝对值编码器 DO引脚 A6 蓝色 31 ---SPI1_MISO
#define ABSDO_PORT GPIOA
#define ABSDO_RCC RCC_APB2Periph_GPIOA
#define ABSDO_PIN GPIO_Pin_6//时钟线高低电平
#define ABSCLK_H GPIO_SetBits(ABSCLK_PORT,ABSCLK_PIN)
#define ABSCLK_L GPIO_ResetBits(ABSCLK_PORT,ABSCLK_PIN)//片选高低电平
#define ABSCSN_H GPIO_SetBits(ABSCSN_PORT,ABSCSN_PIN)
#define ABSCSN_L GPIO_ResetBits(ABSCSN_PORT,ABSCSN_PIN)//数据线读
#define READABS_DO GPIO_ReadInputDataBit(ABSDO_PORT,ABSDO_PIN)//函数声明
uint16_t SPI1_ReadWriteByte(uint8_t TxData);void AbsEncoder_Init(void)
{/*GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(ABSCLK_RCC| ABSCSN_RCC | ABSDO_RCC|RCC_APB2Periph_AFIO,ENABLE);//GPIO_DeInit(GPIOA); //时钟线 初始化 推挽输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = ABSCLK_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(ABSCLK_PORT,&GPIO_InitStructure);//片选线 初始化 推挽输出GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = ABSCSN_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(ABSCSN_PORT,&GPIO_InitStructure);//数据线 初始化 上拉输入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin = ABSDO_PIN;GPIO_Init(ABSDO_PORT,&GPIO_InitStructure);//先把时钟和片选拉高ABSCLK_H;ABSCSN_H;*/GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;/* 使能GPIO 时钟 */RCC_APB2PeriphClockCmd(ABSCSN_RCC, ENABLE);/* 配置片选口线为推挽输出模式 */ABSCSN_H; /* 片选置高,不选中 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = ABSCSN_PIN;GPIO_Init(ABSCSN_PORT, &GPIO_InitStructure);/*SPI配置*/RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE ); //GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);//GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6);//SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPISPI_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信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128; //定义波特率预分频的值:波特率预分频值为256SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式//SPI_Init(SPI1, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器SPI_Cmd(SPI1, ENABLE); //使能SPI外设//SPI1_ReadWriteByte(0xff);//启动传输 /**/
}
//SPIx 读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
uint16_t SPI1_ReadWriteByte(uint8_t TxData)
{ u8 retry=0; while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位{retry++;if(retry>200)return 0;} SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据retry=0;while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位{retry++;if(retry>200)return 0;} return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据
}
/*
*********************************************************************************************************
* 函 数 名:
* 功能说明:
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/uint16_t SPIDataBuff; //储存SPI采集绝对编码器的数据void Torque_Read(void)
{ABSCSN_L;SPIDataBuff = SPI1_ReadWriteByte(0x00); //SPI采集绝对值,数据只有10位SPIDataBuff = SPIDataBuff >> 6; //将采到的值移6位,对应10BitABSCSN_H;
}
/*
*********************************************************************************************************
* 模块名称 :
* 文件名称 : bsp_encoder.h
* 版 本 : V1.0
* 说 明 :
* 修改记录 :
* 版本号 日期 作者 说明
*********************************************************************************************************
*/
#ifndef _BSP_ENCODER_H
#define _BSP_ENCODER_H//声明
extern uint16_t SPIDataBuff; void Torque_Read(void);
uint16_t SPI1_ReadWriteByte(uint8_t TxData);
void AbsEncoder_Init(void);#endif
主函数读取
int main()
{SYS_Configuration();RCC_config();bsp_Init();/**/AbsEncoder_Init(); /* AS5040磁编码器 *//**/bsp_StartAutoTimer(1, 300); /* 定时器1周期 300毫秒 *///while (1){bsp_Idle(); /* 空闲时执行的函数,比如喂狗. 在bsp.c中 */if (bsp_CheckTimer(1)) /* 定时到 */{Torque_Read(); }}
}
抓取时序: