Датчик AS5047P / SPI

Для работы с SPI на ардуино предусмотрена библиотека SPI.h. На драйвере VBCore BLDC выведено два SPI интерфейса - SPI1 и SPI3. Для SPI1 подключение идет к следующим пинам:

//SPI1 :
MISO PA6
MOSI PA7
SCK PA5
NSS PA4

Для SPI3:

//SPI3:
MISO PC11
MOSI PC12
SCK PC10
NSS PA_15_ALT1 //1 cheap select
NSS2 PB4       //2 cheap select

Ознакомиться с функциями SPI, I2C и других интерфейсов мы предлагаем самостоятельно в документации.

Если вы хотите работать с датчиком AS5047, то советуем вам установить библиотеку в Arduino IDE не через менеджер библиотек, а с нашего репозитория. Это немного измененная стандартная библиотека AS5047P. А изменена она была потому, что в стандартной используется SPI1, а к нашему драйверу датчик подключается по SPI 3.

Вот рабочий пример для чтения угла по датчику AS5047:

Ниже будет подробно расписано что именно было изменено в стандартной библиотеке. В целом, если вы просто хотите читать датчик, то дальнейшее описание можно пропустить.

Если вам все же интересно что было изменено в стандартной библиотеке, то хотим обратить ваше внимание на SPIClass и его конструктор. Он имеет следующий вид:

SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk, uint8_t nss)rd

В качестве альтернативы можно использовать конструктор, принимающий три параметра, а параметр cheap select передать при запуске SPI.

SPIClass::SPIClass(uint8_t mosi, uint8_t miso, uint8_t sclk)
void SPIClass::begin(uint8_t _nss)

При чтении датчиков по SPI в некоторых библиотеках (Adafruit_BMP280 например) есть возможность напрямую указать к каким пинам подключены MISO, MOSI, SCLK. В некоторых (SimpleFOC) требуется в качестве параметра функции передать SPIClass*

Однако встречаются библиотеки, в которых нет функции для переопределения SPI интерфейса. В таком случае мы всегда можем залезть в исходные файлы, они имеют расширение .h и .cpp и обычно лежат в папке src и переписать функции инициализации SPI.

Давайте рассмотрим в качестве примера библиотеку AS5047P, которую можно установить через менеджер библиотек. Возьмем из этой библиотеки пример - BasicReadAngle.

Будьте предельно внимательны с определением пинов. Например, если вы сразу загрузите эту программу на плату, у вас выйдет вот такая ошибка:

И исправить ее можно будет только через STM32CubeProgrammer. А возникнет ошибка из-за использования 13 пина в примере не по назначению:

#define LED_PIN 13

void setup() {

  // set the pinmode of the led pin to output.
  pinMode(LED_PIN, OUTPUT);
  ...
  }

Сделаем все правильно. Во-первых подключим библиотеку VBCoreG4 и укажем корректный пин для cheap select:

#include <VBCoreG4_arduino_system.h>
#include <AS5047P.h>

#define AS5047P_CHIP_SELECT_PORT PA_15_ALT1

В VBCoreG4 пины, к которым подключены светодиоды уже определены как LED1 и LED2, выберем любой и установим его в setup на вывод:

void setup() {
  
  // set the pinmode of the led pin to output.
  pinMode(LED1, OUTPUT);
...
}

Дальше загрузим программу, ничего больше не меняя, на плату, подключим датчик к SPI3 и попробуем почитать с него углы. В Serial Port вы увидите строчку "Can't connect to the AS5047P sensor! Please check the connection...".

Все потому, что библиотека использует SPI интерфейс, в котором пины для ардуино установлены по умолчанию. Давайте их переопределять. Идем вглубь библиотеки (она лежит либо в C:\Program Files (x86)\Arduino\libraries, либо в C:\Users\username\Documents\Arduino\libraries ), заходим в папку src и открываем файлы AS5047P.h и AS5047P.cpp Находим функцию

bool initSPI();

Меняем ее на

bool initSPI(SPIClass* _spi);

В теле этой функции в файле AS5047P.cpp меняем одну строчку:

__spiInterface.init(_spi);

Сохраняем все и закрываем. Дальше заходим в папку spi, открываем файл AS5047P_SPI_Arduino.h

В class AS5047P_SPI в private добавим член класса

SPIClass* spi;

И отредактируем немного public метод:

void init(SPIClass* _spi);

Сохраняем, закрываем файл. Осталось отредактировать AS5047P_SPI_Arduino.cpp

Меняем метод init

 void AS5047P_SPI::init(SPIClass* _spi) {
        spi = _spi;
        spi->begin();
    }

И обращение к методам SPI во всех оставшихся функциях. Замените

SPI.

На

spi->

Сохраните и закройте файл. Все, библиотека подправлена - в ней добавлена возможность изменения интерфейса SPI. В будущем схожим образом можно аккуратно менять исходный код и в других библиотеках.

Исправленную под наши цели библиотеку с примерами можно найти на github. Скачайте ее себе на компьютер, распакуйте в libraries и используйте при работе с датчиками AS5047P.

Полный код программы для чтения датчика AS5047P приведен ниже

#include <VBCoreG4_arduino_system.h>

//Example corrected for VBCore_G4 board
/**
 * @file BasicReadAngle.ino
 * @author Jonas Merkle [JJM] (jonas@jjm.one)
 * @brief This is a basic example program to read the angle position from a AS5047 rotary encoder.
 *        The angle postion gets updated and printed to the serial consol once a second. 
 * @version 2.2.0
 * @date 2022-11-20
 * 
 * @copyright Copyright (c) 2021 Jonas Merkle. This project is released under the GPL-3.0 License License.
 * 
 * More Information can be found here:
 * https://github.com/jonas-merkle/AS5047P
 */

// include the library for the AS5047P sensor.
#include <AS5047P.h>


// define the chip select port.
#define AS5047P_CHIP_SELECT_PORT PA_15_ALT1
//            MOSI  MISO  SCLK
SPIClass SPI_3(PC12, PC11, PC10); 

// define the spi bus speed 
#define AS5047P_CUSTOM_SPI_BUS_SPEED 100000

// initialize a new AS5047P sensor object.
AS5047P as5047p(AS5047P_CHIP_SELECT_PORT, AS5047P_CUSTOM_SPI_BUS_SPEED);

// arduino setup routine
void setup() {
  
  // set the pinmode of the led pin to output.
  pinMode(LED1, OUTPUT);

  // initialize the serial bus for the communication with your pc.
  Serial.begin(115200);

  // initialize the AS5047P sensor and hold if sensor can't be initialized.
  while (!as5047p.initSPI(& SPI_3)) {
    Serial.println(F("Can't connect to the AS5047P sensor! Please check the connection..."));
    delay(3000);
  }

}

// arduino loop routine
void loop() {

  Serial.print("Angle: ");                        // print some text to the serial consol.
  Serial.println(as5047p.readAngleDegree());      // read the angle value from the AS5047P sensor an print it to the serial consol.
                                      // wait for 500 milli seconds.

  // wait
  digitalWrite(LED1, !digitalRead(LED1));                     // deactivate the led.
  delay(100);                                     // wait for 500 milli seconds.

}

Last updated