Использование датчика AS5050 с STM8

Датчик угла поворота 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 в случае, если до этого возникли ошибки.
Сразу после включения ошибки действительно ненадолго могут возникать, но дальше датчик входит в нормальный режим работы и посылает угол без ошибок. Ну а до этого команда 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


При копировании материалов хорошим тоном будет указание авторства и ссылка на сайт.