A1333角度传感器
美国ALLEGRO型号A1333是一款360°角度传感器IC,可基于磁性圆形垂直霍尔(CVH)技术提供无接触,低延迟,高分辨率的角位置信息。它具有系统片上(SoC)架构,包括:CVH前端,数字信号处理和电机换向(UVW)或编码器输出(A,B,I)。它还包括片上EEPROM技术,能够支持多达100个读/写周期,以便对校准参数进行灵活的终端编程。芯片图片:
结构框图:
数据手册下载
硬件安装
A1333是一款360°角度传感器IC,被测量部件可以采用永磁铁,并确保使用过程没有强磁干扰。由于测量的一般都是旋转部件,则采用圆形铷磁铁即可,此处需要注意圆形磁铁的极化方向,分为轴向和径向两种。根据芯片测量原理,我们需要采用径向铷磁铁。
采用直径10mm,厚度2.5mm圆形铷磁铁即可,磁铁轴心与芯片中心,需要尽可能在同一点上,若磁铁和芯片不在同一直线上,也会出现测量误差,示意图如下图:
装配时,铷磁铁与芯片之间的间隙,需要尽可能小,数据手册中有磁强和间隙大小以及角度误差之间的关系,为了减小误差建议间隙2mm以内。本文最终采用的铷磁铁如下:
通信接口
A1333有两种编程方式:1.使用SPI接口进行输入和输出;2.输入使用曼彻斯特协议,输出使用PWM协议。本文使用SPI接口进行通信,所以只对SPI相关参数进行介绍。A1333的SPI接口提供四线全双工模式,CPHA=1,CPOL=1,总线时钟最低支持100KHz,最高支持10MHz,兼容3.3V和5V的IO模式。经典接线图如下:
A1333有三种数据帧格式,分别是16位、17位和20位的帧格式,其中20位帧格式实际上是16位数据加4位CRC校验位扩展而来,17位帧格式只有在使用扩展E2PROM才使用。如下图:
写寄存器
写寄存器的数据帧格式由1bit的低位、1bit的R/W标志位(bit=1)、6bit的地址位和8bit的数据位组成,还可以拼接可选的4bitCRC校验位,如下图所示(注意MOSI线):
读寄存器
读寄存器的操作,由至少两次SPI交互组成,第一次交互先发送需要读取的寄存器信息,此时读取回来的数据为上一次操作的数据;第二次可以发送一个空操作(读0x00寄存器)信息,此时读取回来的数据为所需的寄存器数据,其中第二次交互发送的数据帧,还可以是读操作数据帧,这样第三次交互就可以接到第二次读操作的数据了。读寄存器的数据帧格式由1bit的低位、1bit的R/W标志位(bit=0)、6bit的地址位和8bit的0组成,同样可以拼接4bit的CRC校验位。如下图所示:
寄存器
这里主要介绍角度数据寄存器(0x32)和key寄存器(0x3c)。操作A1333的寄存器前,需要操作key寄存器进行解锁。
数据寄存器(0x32)
读取出来的是15位数据,角度转换公式:ANGLE_15 × (360/32768)
key寄存器(0x3c)
在寄存器操作前,需要先操作key寄存器进行解锁,解锁方法为向key寄存器写入5组KEYCODE,解锁成功后才可以进行其他寄存器操作,KEYCODE如下表:
Write | CODE |
---|---|
1 | 0x00 |
2 | 0x27 |
3 | 0x81 |
4 | 0x1F |
5 | 0x77 |
STM32控制部分
电路原理图
程序
a1333.c
#include "a1333.h"
const uint16_t WRITE = 0x40;
const uint16_t READ = 0x00;
const uint16_t COMMAND_MASK = 0xC0;
const uint16_t ADDRESS_MASK = 0x3F;
#define CS_H() GPIO_SetBits(GPIOB,GPIO_Pin_12)
#define CS_L() GPIO_ResetBits(GPIOB,GPIO_Pin_12)
static uint16_t spi2_rw(uint16_t cmd,uint16_t *value)
{
u8 retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
{
retry++;
if(retry>200)return 0;
}
SPI_I2S_SendData(SPI2, cmd);
retry=0;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET)
{
retry++;
if(retry>200)return 0;
}
if(value){
*value = SPI_I2S_ReceiveData(SPI2);
}else{
SPI_I2S_ReceiveData(SPI2);
}
return 1;
}
static uint16_t PrimaryWrite(uint16_t address, uint16_t value)
{
u8 s=0;
uint16_t command = ((address & ADDRESS_MASK) | WRITE) << 8;
CS_L();
Delay_1us(1);
s = spi2_rw(command | ((value >> 8) & 0x0FF),0);
CS_H();
if(s == 0){
return 0;
}
command = (((address + 1) & ADDRESS_MASK) | WRITE) << 8;
CS_L();
Delay_1us(1);
s = spi2_rw(command | (value & 0x0FF),0);
CS_H();
if(s == 0){
return 0;
}
return 1;
}
static uint16_t PrimaryRead(uint16_t address, uint16_t *value)
{
u8 s=1;
uint16_t command = ((address & ADDRESS_MASK) | READ) << 8;
CS_L();
Delay_1us(1);
s = spi2_rw(command,0);
CS_H();
if(s)
{
CS_L();
s = spi2_rw(command,value);
CS_H();
if(s)
{
return 1;
}
return 0;
}else{
return 0;
}
}
void a1333_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_SPI2, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
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_256;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);
SPI_I2S_ClearFlag(SPI2, SPI_I2S_FLAG_RXNE);
{
u16 t = 0,flags;
PrimaryRead(0x00,&t);
// Unlock the device
PrimaryWrite(0x3C, 0x2700);
PrimaryWrite(0x3C, 0x8100);
PrimaryWrite(0x3C, 0x1F00);
PrimaryWrite(0x3C, 0x7700);
// Make sure the device is unlocked
t = 100;
PrimaryRead(0x3C, &flags);
while ((flags & 0x0001) != 0x0001)
{
Delay_1us(10);
t--;
if (t==0)
{
LedSet(LED1);
LedReset(LED2);
while(1){
LedReverse(LED1 | LED2);
Delay_1ms(200);
}
}
PrimaryRead(0x3C, &flags);
}
}
}
uint16_t a1333_read_angle15(void){
uint16_t read_angle = 0;
PrimaryRead(0x32, &read_angle);
read_angle = read_angle & 0x7fff;
return read_angle;
}
uint16_t a1333_read_angle15_smooth(uint8_t sm){
uint8_t i;
uint32_t total = 0;
for(i=0;i<sm;i++){
total += a1333_read_angle15();
}
return total / sm;
}
a1333.h
#ifndef __A1333_H__
#define __A1333_H__
#include "stm32f10x.h"
void a1333_init(void);
uint16_t a1333_read_angle15(void);
uint16_t a1333_read_angle15_smooth(uint8_t sm);
#endif