Урок 47
Часть 1
Подключаем гироскоп LSM6DS3
Сегодня мы продолжим работать ещё с одним датчиком, который в себе объединяет сразу два функционала – акселерометр и гироскоп – LSM6DS3. Выполнен он также с использованием технологии MEMS. Установлен на плате расширения STEVAL-MKI160V1, которая в свою очередь вставляется в плату расширения X-NUCLEO-IKS01A1, предназначенной для работы с отладочной платой Nucleo. Мы будем подключать данную оценочную плату к плате Nucleo STM32F401RE.
Данный акселерометр-гироскоп также наряду с интерфейсом I2C может подключиться и с использованием интерфейса SPI. Но мы будем использовать подключение именно по I2C, так как именно такое подключение имеет место в оценочной плате X-NUCLEO-IKS01A.
Также использовать в рамках данного занятия мы данный датчик будем только как гироскоп, так как в качестве акселерометра мы его уже подключали.
Данный гироскоп в данном датчике в сравнении с предыдущим рассмотренным имеет следующие технические характеристики:
Диапазон показаний ±125/±245/±500/±2000 dps (появился ещё один наименьший предел);
Чувствительность 4.375 – 70 mdps/LSb (соответственно по меньшему пределу стала лучше);
Отклонение от нуля ±10 dps при установке диапазона 2000 dps (что втрое лучше, чем у рассмотренного ранее датчика).
Частота измерений 14,9 – 952 Гц.
С некоторыми остальными показателями, регистрами, значениями и другими тонкостями гироскопа мы познакомимся в ходе его программирования.
Проект мы создадим из готового проекта, в котором мы работали с акселерометром данного датчика – из проекта Accel_LSM6DS3, только назовём мы данный проект теперь соответственно Gyro_LSM6DS3.
Запустим проект Cube MX. Изменим мы здесь только скорость USART.
Сгенерируем проект, откроем его. Настроим программатор на авторезет. Добавим файл lsm6ds3.c. Скомпилируем проект.
В бесконечном цикле пока закомментируем код вызова функции считывания данных и отправки их в USART
/* USER CODE BEGIN 3 */
//Accel_ReadAcc();
}
Для универсальности проекта, так как, возможно, позже мы объединим работу с акселерометром и гироскопом в один проект, переименуем функцию Accel_Ini в файле lsm6ds0.c на Accel_Gyro_Ini. То же самое проделаем с прототипом и с вызовом данной функции в main().
Закомментируем в функции Accel_Gyro_Ini вот эту строку
LD2_OFF;
// AccInit(ctrl);
LD2_ON;
Добавим функцию инициализации гироскопа по подобию функции инициализации акселерометра
//———————————————
void GyroInit(uint16_t InitStruct)
{
uint8_t value = 0;
}
//———————————————
Вызовем её в функции общей инициализации
// AccInit(ctrl);
GyroInit(ctrl);
LD2_ON;
В файле lsm6ds0.h заранее добавим несколько макросов, необходимых для работы с гироскопом. Код данного файла после всех изменений примет следующий вид:
#ifndef LSM6DS3_H_
#define LSM6DS3_H_
#include «stm32f4xx_hal.h»
#include <string.h>
//————————————————
#define ABS(x) (x < 0) ? (-x) : x
//————————————————
#define LD2_Pin GPIO_PIN_5
#define LD2_GPIO_Port GPIOA
#define LD2_ON HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET) //GREEN
#define LD2_OFF HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET)
//————————————————
#define LSM6DS3_ACC_GYRO_CTRL1_XL 0X10
#define LSM6DS3_ACC_GYRO_CTRL2_G 0X11
#define LSM6DS3_ACC_GYRO_CTRL3_C 0X12
#define LSM6DS3_ACC_GYRO_FIFO_CTRL5 0X0A
#define LSM6DS3_ACC_GYRO_CTRL9_XL 0X18
#define LSM6DS3_ACC_GYRO_CTRL10_C 0X19
//————————————————
#define LSM6DS3_ACC_GYRO_IF_INC_DISABLED 0x00
#define LSM6DS3_ACC_GYRO_IF_INC_ENABLED 0x04
#define LSM6DS3_ACC_GYRO_IF_INC_MASK 0x04
//————————————————
#define LSM6DS3_ACC_GYRO_BDU_CONTINUOS 0x00
#define LSM6DS3_ACC_GYRO_BDU_BLOCK_UPDATE 0x40
#define LSM6DS3_ACC_GYRO_BDU_MASK 0x40
//————————————————
#define LSM6DS3_ACC_GYRO_FIFO_MODE_BYPASS 0x00
#define LSM6DS3_ACC_GYRO_FIFO_MODE_FIFO 0x01
#define LSM6DS3_ACC_GYRO_FIFO_MODE_STREAM 0x02
#define LSM6DS3_ACC_GYRO_FIFO_MODE_STF 0x03
#define LSM6DS3_ACC_GYRO_FIFO_MODE_BTS 0x04
#define LSM6DS3_ACC_GYRO_FIFO_MODE_DYN_STREAM 0x05
#define LSM6DS3_ACC_GYRO_FIFO_MODE_DYN_STREAM_2 0x06
#define LSM6DS3_ACC_GYRO_FIFO_MODE_BTF 0x07
#define LSM6DS3_ACC_GYRO_FIFO_MODE_MASK 0x07
//————————————————
#define LSM6DS3_ACC_GYRO_ODR_XL_POWER_DOWN 0x00
#define LSM6DS3_ACC_GYRO_ODR_XL_13Hz 0x10
#define LSM6DS3_ACC_GYRO_ODR_XL_26Hz 0x20
#define LSM6DS3_ACC_GYRO_ODR_XL_52Hz 0x30
#define LSM6DS3_ACC_GYRO_ODR_XL_104Hz 0x40
#define LSM6DS3_ACC_GYRO_ODR_XL_208Hz 0x50
#define LSM6DS3_ACC_GYRO_ODR_XL_416Hz 0x60
#define LSM6DS3_ACC_GYRO_ODR_XL_833Hz 0x70
#define LSM6DS3_ACC_GYRO_ODR_XL_1660Hz 0x80
#define LSM6DS3_ACC_GYRO_ODR_XL_3330Hz 0x90
#define LSM6DS3_ACC_GYRO_ODR_XL_6660Hz 0xA0
#define LSM6DS3_ACC_GYRO_ODR_XL_13330Hz 0xB0
#define LSM6DS3_ACC_GYRO_ODR_XL_MASK 0xF0
//————————————————
#define LSM6DS3_ACC_GYRO_ODR_G_POWER_DOWN 0x00
#define LSM6DS3_ACC_GYRO_ODR_G_13Hz 0x10
#define LSM6DS3_ACC_GYRO_ODR_G_26Hz 0x20
#define LSM6DS3_ACC_GYRO_ODR_G_52Hz 0x30
#define LSM6DS3_ACC_GYRO_ODR_G_104Hz 0x40
#define LSM6DS3_ACC_GYRO_ODR_G_208Hz 0x50
#define LSM6DS3_ACC_GYRO_ODR_G_416Hz 0x60
#define LSM6DS3_ACC_GYRO_ODR_G_833Hz 0x70
#define LSM6DS3_ACC_GYRO_ODR_G_1660Hz 0x80
#define LSM6DS3_ACC_GYRO_ODR_G_MASK 0xF0
//————————————————
#define LSM6DS3_ACC_GYRO_FS_XL_2g 0x00
#define LSM6DS3_ACC_GYRO_FS_XL_16g 0x04
#define LSM6DS3_ACC_GYRO_FS_XL_4g 0x08
#define LSM6DS3_ACC_GYRO_FS_XL_8g 0x0C
#define LSM6DS3_ACC_GYRO_FS_XL_MASK 0x0C
//————————————————
#define LSM6DS3_ACC_GYRO_FS_G_245dps 0x00
#define LSM6DS3_ACC_GYRO_FS_G_500dps 0x04
#define LSM6DS3_ACC_GYRO_FS_G_1000dps 0x08
#define LSM6DS3_ACC_GYRO_FS_G_2000dps 0x0C
#define LSM6DS3_ACC_GYRO_FS_G_MASK 0x0C
//————————————————
#define LSM6DS3_ACC_GYRO_XEN_XL_MASK 0x08
#define LSM6DS3_ACC_GYRO_YEN_XL_MASK 0x10
#define LSM6DS3_ACC_GYRO_ZEN_XL_MASK 0x20
#define LSM6DS3_ACC_GYRO_XEN_XL_ENABLED 0x08
#define LSM6DS3_ACC_GYRO_YEN_XL_ENABLED 0x10
#define LSM6DS3_ACC_GYRO_ZEN_XL_ENABLED 0x20
//————————————————
#define LSM6DS3_ACC_GYRO_XEN_G_DISABLED 0x00
#define LSM6DS3_ACC_GYRO_XEN_G_ENABLED 0x08
#define LSM6DS3_ACC_GYRO_YEN_G_DISABLED 0x00
#define LSM6DS3_ACC_GYRO_YEN_G_ENABLED 0x10
#define LSM6DS3_ACC_GYRO_ZEN_G_DISABLED 0x00
#define LSM6DS3_ACC_GYRO_ZEN_G_ENABLED 0x20
#define LSM6DS3_ACC_GYRO_XEN_G_MASK 0x08
#define LSM6DS3_ACC_GYRO_YEN_G_MASK 0x10
#define LSM6DS3_ACC_GYRO_ZEN_G_MASK 0x20
//————————————————
#define LSM6DS3_ACC_GYRO_OUTX_L_XL 0X28
#define LSM6DS3_ACC_GYRO_OUTX_H_XL 0X29
#define LSM6DS3_ACC_GYRO_OUTY_L_XL 0X2A
#define LSM6DS3_ACC_GYRO_OUTY_H_XL 0X2B
#define LSM6DS3_ACC_GYRO_OUTZ_L_XL 0X2C
#define LSM6DS3_ACC_GYRO_OUTZ_H_XL 0X2D
//————————————————
#define LSM6DS3_ACC_GYRO_OUTX_L_G 0X22
#define LSM6DS3_ACC_GYRO_OUTX_H_G 0X23
#define LSM6DS3_ACC_GYRO_OUTY_L_G 0X24
#define LSM6DS3_ACC_GYRO_OUTY_H_G 0X25
#define LSM6DS3_ACC_GYRO_OUTZ_L_G 0X26
#define LSM6DS3_ACC_GYRO_OUTZ_H_G 0X27
//————————————————
void Accel_Gyro_Ini(void);
void AccelGyro_Read(void);
//————————————————
#endif /* LSM6DS3_H_ */
Скопировав из другой функции, добавим в функцию GyroInit следующий код (так как здесь ничего не меняется):
uint8_t value = 0;
//автоувеличение адреса регистра
value = Accel_IO_Read(0xD4,LSM6DS3_ACC_GYRO_CTRL3_C);
value&=~LSM6DS3_ACC_GYRO_IF_INC_MASK;
value|=LSM6DS3_ACC_GYRO_IF_INC_ENABLED;
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_CTRL3_C,value);
//установим бит BDU
value = Accel_IO_Read(0xD4,LSM6DS3_ACC_GYRO_CTRL3_C);
value &= ~LSM6DS3_ACC_GYRO_BDU_MASK;
value|=LSM6DS3_ACC_GYRO_BDU_BLOCK_UPDATE;
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_CTRL3_C,value);
//выбор режима FIFO
value = Accel_IO_Read(0xD4,LSM6DS3_ACC_GYRO_FIFO_CTRL5);
value&=~LSM6DS3_ACC_GYRO_FIFO_MODE_MASK;
value|=LSM6DS3_ACC_GYRO_FIFO_MODE_BYPASS;
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_FIFO_CTRL5,value);
Так как в коде ничего не изменилось, объяснение не требуется.
Теперь добавим следующий код сюда же:
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_FIFO_CTRL5,value);
//пока выключим датчик (ODR_XL = 0000)
value = Accel_IO_Read(0xD4,LSM6DS3_ACC_GYRO_CTRL2_G);
value&=~LSM6DS3_ACC_GYRO_ODR_G_MASK;
value|=LSM6DS3_ACC_GYRO_ODR_G_POWER_DOWN;
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_CTRL2_G,value);
В данном коде мы работаем с регистром CTRL2_G (адрес 0X11), который предназначен только для работы только с гироскопом, с его битами, отвечающим за частоту снятия данных именно с гироскопа
Пока мы здесь отключаем датчик (все биты выставляем в 0).
Дальше добавим следующий код
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_CTRL2_G,value);
//Full scale selection 500 dps
value = Accel_IO_Read(0xD4,LSM6DS3_ACC_GYRO_CTRL2_G);
value&=~LSM6DS3_ACC_GYRO_FS_G_MASK;
value|=LSM6DS3_ACC_GYRO_FS_G_500dps;
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_CTRL2_G,value);
Дальше мы работаем с тем же регистром, только с другими битами, отвечающими за максимально измеряемую датчиком угловую скорость относительно оси. Думаю, нам достаточно 500 градусов в секунду, быстрее мы не разгонимся.
Пишем код дальше
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_CTRL2_G,value);
//Включим оси
value = Accel_IO_Read(0xD4,LSM6DS3_ACC_GYRO_CTRL10_C);
value&=~(LSM6DS3_ACC_GYRO_XEN_G_ENABLED|\
LSM6DS3_ACC_GYRO_YEN_G_ENABLED|\
LSM6DS3_ACC_GYRO_ZEN_G_ENABLED);
value|=(LSM6DS3_ACC_GYRO_XEN_G_MASK|\
LSM6DS3_ACC_GYRO_YEN_G_MASK|\
LSM6DS3_ACC_GYRO_ZEN_G_MASK);
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_CTRL10_C,value);
Как и указано в комментарии, здесь мы включаем оси гироскопа. Включим мы все 3 оси
Продолжаем писать исходный код
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_CTRL10_C,value);
//Включим Data Rate 833 Гц
value = Accel_IO_Read(0xD4,LSM6DS3_ACC_GYRO_CTRL2_G);
value&=~LSM6DS3_ACC_GYRO_ODR_G_MASK;
value|=LSM6DS3_ACC_GYRO_ODR_G_833Hz;
Accel_IO_Write(0xD4,LSM6DS3_ACC_GYRO_CTRL2_G,value);
Здесь мы включили частоту снятия показаний 833 Гц. Также работаем мы с вышеупомянутым 2 регистром.
Фильтры сегодня не используем, т.к. в данном датчике и так организована неплохая фильтрация
На этом Инициализацию можно считать завершенной.
Соберем код, прошьем контроллер и убедимся, что зеленый светодиод у нас светится.
В следующей части урока мы напишем все функции по сбору данных и отправке их в порт USART и проверим данный функционал на практике.
Предыдущий урок Программирование МК STM32 Следующая часть
Техническая документация на датчик
Техническая документация на плату расширения
Отладочную плату можно приобрести здесь Nucleo STM32F401RE
Оценочную плату X-NUCLEO-IKS01A1 можно приобрести здесь STM32 X-NUCLEO-IKS01A1
Оценочную плату STEVAL-MKI160V1 можно приобрести здесь STEVAL-MKI160V1
Смотреть ВИДЕОУРОК
Добавить комментарий