Датчик угла поворота AS5050 и STM8
В этой заметке будет рассказано о том, как использовать датчик угла поворота AS5050 с микроконтроллером STM8. Для STM8 я использую компилятор Raisonance и среду разработки Ride7. Магнитный сенсор AS5050 передаёт данные по протоколу SPI. Приведённая здесь информация может относится также и к датчику AS5055, так как он похож на AS5050. Датчик AS5050 по магнитному полю определяет своё положение относительно магнита и выдаёт угол поворота.
Обмен по SPI
По сравнению с кодом инициализации SPI, приведённым здесь, изменился лишь один параметр в функции SPI_Init(). Вместо SPI_CLOCKPHASE_2EDGE нужно поставить SPI_CLOCKPHASE_1EDGE, иначе обмен по SPI происходит неправильно. В остальном всё осталось так же.
Сама функция обмена тоже изменилась. Дело в том, что в заметке «Использование SPI с STM8» я приводил 8-битную функцию обмена, а с датчиком AS5050 используется 16-битный обмен. Поэтому функция выглядит так:
#define CS_1 WRITE_1(AS5050_PORT, AS5050_SELECT_PIN)
#define CS_0 WRITE_0(AS5050_PORT, AS5050_SELECT_PIN)
static u16 SPI_ReadWrite(u16 uPackage)
{
u16 uResult = 0;
u8 uHigh;
CS_0;
while ((SPI->SR & (u8)SPI_FLAG_TXE) == RESET) { ; }
SPI->DR = (u8)(uPackage >> 8);
while ((SPI->SR & (u8)SPI_FLAG_RXNE) == RESET) { ; }
uHigh = SPI->DR;
while ((SPI->SR & (u8)SPI_FLAG_TXE) == RESET) { ; }
SPI->DR = (u8)(uPackage & 0x00FF);
while ((SPI->SR & (u8)SPI_FLAG_RXNE) == RESET) { ; }
uResult = SPI->DR;
CS_1;
uResult |= (u16)uHigh << 8;
return uResult;
}
Суть функции в том, что регистр DR 8-битный. Обмен идёт одновременно в обе стороны. Поэтому сначала посылаем старшие биты слова, и принимаем старшие биты ответа. Затем, соотвественно, посылаем младшие биты, и принимаем младшие биты. Особенность датчика AS5050 такова, что он шлёт ответ на команду после посылки следующей команды. Это надо учитывать при обмене данными с датчиком.
Чётность
Данные, принимающие участие в обмене с датчиком, должны иметь бит чётности (это первый бит в слове). Иными словами, количество бит «1» в посылаемом слове должно быть чётным. Для проверки этого и для установки бита чётность я написал следующие функции:
#define PARITY_BIT 0x0001
// Проверка чётности
static bool CheckEvenParity(u16 uWord)
{
u8 uOnes = 0;
u8 uMask = 1;
u8 i;
for (i = 0; i < 16; i++)
{
if (uWord & (uMask << i))
uOnes++;
}
return (0 == (uOnes % 2));
}
// количество бит "1" должно быть чётным
static void SetEvenParity(u16 *uWord)
{
if (NULL == uWord)
return;
if (!CheckEvenParity(*uWord))
{
*uWord |= PARITY_BIT;
}
}
Команды и ответы
Команды для обмена с AS5050 содержат в себе адрес, бит чётности и бит, определяющий, служит ли команда для чтения или для записи. Бит чётности вычисляется для всего слова в целом. Для формирования команды я написал такую функцию:
typedef bool AS_RWTYPE;
#define AS_READ false
#define AS_WRITE true
static u16 MakeCommand(u16 uAddress, AS_RWTYPE bWrite)
{
u16 uResult;
uResult = uAddress << 1;
if (bWrite)
uResult &= ~WRITE_BIT;
else
uResult |= WRITE_BIT;
SetEvenParity(&uResult);
return uResult;
}
Адреса могут быть такими:
// Регистры AS5050 #define POWER_ON_RESET 0x3F22 /* чтение/запись */ #define SOFTWARE_RESET 0x3C00 /* запись */ #define MASTER_RESET 0x33A5 /* запись */ #define CLR_ERROR_FLAG 0x3380 /* чтение */ #define NO_OPERATION 0x0000 /* запись */ #define AUTO_GAIN_CTRL 0x3FF8 /* чтение/запись */ #define ANGULAR_DATA 0x3FFF /* чтение */ #define ERROR_STATUS 0x33A5 /* чтение */
Проверить полученный с датчика ответ можно функцией, в которой проверяется чётность и наличие бита ошибки.
static bool CheckData(u16 uData)
{
bool bResult = true;
if (!CheckEvenParity(uData))
{
#ifdef DEBUG_RS232
printf("Нарушена чётность" CRLF);
#endif
bResult = false;
}
if (uData & ERROR_BIT)
{
#ifdef DEBUG_RS232
printf("Установлен бит ошибки" CRLF);
#endif
bResult = false;
}
return bResult;
}
Ну и ещё одна функция, которая формирует дополнительный пакет данных, который можно использовать с некоторыми командами. Мне он не пригодился, но функцию я всё равно написал. Подробнее читайте PDF'ку на микросхему.
static u16 MakePackage(u16 uData)
{
u16 uResult;
uResult = uData << 2;
SetEvenParity(&uResult);
return uResult;
}
Получение угла с датчика AS5050
Используя вышеописанные функции, можно, наконец, получить угол с датчика. Для этого потребуется три команды:
- Послать ANGULAR_DATA для запроса угла.
- Послать NO_OPERATION, в качестве ответа придёт результат предыдущего запроса, то есть угол.
- Проверить результат и послать команду CLR_ERROR_FLAG в случае, если до этого возникли ошибки.
s16 GetAngle_AS5050(void)
{
s16 iAngle;
u16 uData;
SPI_ReadWrite(MakeCommand(ANGULAR_DATA, AS_READ));
uData = SPI_ReadWrite(MakeCommand(NO_OPERATION, AS_WRITE));
if (CheckData(uData))
{
iAngle = (uData >> 2) & 0x3FF;
} else
{
SPI_ReadWrite(MakeCommand(CLR_ERROR_FLAG, AS_READ));
iAngle = ANGLE_ERROR;
}
return iAngle;
}
Преобразование угла в градусы
Полученное значение угла — это 10-битное целое число. Но, допустим, требуется узнать угол поворота в градусах. Очень легко можно преобразовать это значение в градусы. Делается это так:
iResult = GetAngle_AS5050(); iResult /= 2.84444; // преобразование в градусы, 0-359°
Автор: амдф
Дата: 05.02.2012
Избранное
Остальное
Лента atom