Датчик угла поворота 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