Bootstrap

STM32单片机控制A1333角度传感器磁编码器

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如下表:

WriteCODE
10x00
20x27
30x81
40x1F
50x77

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
;