понедельник, 23 июня 2014 г.

Квадрокоптер. Часть 2. Подключение акселерометра к микроконтроллеру

Всем привет. В прошлый раз мы рассказали о подключении платы stm32f3discovery к комьютеру и даже написали программу.

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




поэтому об этом рассказывать не буду.
Поэтому расскажу про подключение  акселерометра.


Заказанные детали пришли. Небольшой прокол случился с двигателями - они пришли не все, вернее, не только лишь все, мало какие пришли: я по невнимательности заказал только один. Что ж, придется ждать еще около месяца до первого полета (на самом деле - больше, учитывая характер и манеру работы команды разработчиков и конструкторов).

Подключение акселерометра


LSM303DLHC - это микросхема, содержащая трехосевой цифровой акселерометр и магнитометр. С МК связывается по I2C через выводы PB6 и PB7. Даташит на микросхемку здесь.

На официальном сайте лежат примеры работы с периферией, в том числе, и конфигурация и настройка акселерометра и гироскопа. Настройка I2C -  это просто сущий ад для начинающего разработчика, поэтому мы решили использовать библиотеки из примера.



Библиотеки лежат в  ./utilities/stm32f3discovery, main.h - в ./project/demonstration

Создаем новый проект. Подключаем библиотеки GPIO, RCC, I2C  (остальные нужные подключатся автоматически).

Из примера добавляем библиотеку stm32f3_discovery_lsm303dlhc, которая находится в папке stm32f3discovery_fw\STM32F3-Discovery_FW_V1.1.0\Utilities\STM32F3_Discovery



Необходимо скопировать заголовочный файл в папку $PROJECT/cmsis_lib/include, а С-файл - в папку $PROJECT/cmsis_lib/source.
  

Так же добавляем эти файлы в проводник проекта простым перетаскиванием в область Project-manager'а CoIDE, в правильную папку разумеется - include и source.

Прописываем include во всех заголовочных файлах
#include "stm32f30x.h"
#include "stm32f30x_gpio.h"
#include "stm32f30x_rcc.h"
#include "stm32f30x_i2c.h"
#include "stm32f3_discovery_lsm303dlhc.h"


В main.c инициализируем акселерометр, включаем фильтрацию. Мне не хочется приводить здесь разбор огромного листинга кода инициализации (я его сам не до конца понял), а хочется остановиться на том, как все же получить значения ускорений.

Получение данных с датчика производится с помощью функции Demo_CompassReadAcc(data), где data - указатель на массив float[3]. Пихаем в нее какой-нибудь массив, после обработки получаем значения ускорений по оси x, y, z (нулевой, первый и второй элементы соответственно).

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

#include "stm32f30x.h"
#include "stm32f30x_gpio.h"
#include "stm32f30x_rcc.h"
#include "stm32f30x_i2c.h"
#include "stm32f3_discovery_lsm303dlhc.h"

#define LSM_Acc_Sensitivity_2g     (float)     1.0f            /*!< accelerometer sensitivity with 2 g full scale [LSB/mg] */
#define LSM_Acc_Sensitivity_4g     (float)     0.5f            /*!< accelerometer sensitivity with 4 g full scale [LSB/mg] */
#define LSM_Acc_Sensitivity_8g     (float)     0.25f           /*!< accelerometer sensitivity with 8 g full scale [LSB/mg] */
#define LSM_Acc_Sensitivity_16g    (float)     0.0834f         /*!< accelerometer sensitivity with 12 g full scale [LSB/mg] */

float AccBuffer[3] = {0.0f};
/* 
Функции инициализации акселерометра и светодиодов.
Акселерометр возвращает значение ускорения, увеличенное в 100 раз.
Поэтому делим его на 100 и, в зависимости от наклона платки, зажигаем диодик.
*/
void Demo_CompassConfig(void);
void Demo_LEDConfig(void);
int main(void) {
 DemoCompassConfig();
 DemoLEDConfig();
     
    while(1) {
     STM_EVAL_LEDOff(LED3);
     STM_EVAL_LEDOff(LED6);
     STM_EVAL_LEDOff(LED7);
     STM_EVAL_LEDOff(LED4);
     STM_EVAL_LEDOff(LED10);
     STM_EVAL_LEDOff(LED8);
     STM_EVAL_LEDOff(LED9);
     STM_EVAL_LEDOff(LED5);
     Demo_CompassReadAcc(AccBuffer);
     for(i=0;i<3;i++) {
           AccBuffer[i] /= 100.0f;   
     }
     if (AccBuffer[0] > 0) STM_EVAL_LEDOn(LED10);
     if (AccBuffer[0] < 0) STM_EVAL_LEDOn(LED3);
     if (AccBuffer[1] > 0) STM_EVAL_LEDOn(LED6);
     if (AccBuffer[1] < 0) STM_EVAL_LEDOn(LED7);
    }
}

void Demo_CompassConfig(void)
{
  LSM303DLHCMag_InitTypeDef LSM303DLHC_InitStructure;
  LSM303DLHCAcc_InitTypeDef LSM303DLHCAcc_InitStructure;
  LSM303DLHCAcc_FilterConfigTypeDef LSM303DLHCFilter_InitStructure;

   /* Fill the accelerometer structure */
  LSM303DLHCAcc_InitStructure.Power_Mode = LSM303DLHC_NORMAL_MODE;
  LSM303DLHCAcc_InitStructure.AccOutput_DataRate = LSM303DLHC_ODR_50_HZ;
  LSM303DLHCAcc_InitStructure.Axes_Enable= LSM303DLHC_AXES_ENABLE;
  LSM303DLHCAcc_InitStructure.AccFull_Scale = LSM303DLHC_FULLSCALE_2G;
  LSM303DLHCAcc_InitStructure.BlockData_Update = LSM303DLHC_BlockUpdate_Continous;
  LSM303DLHCAcc_InitStructure.Endianness=LSM303DLHC_BLE_LSB;
  LSM303DLHCAcc_InitStructure.High_Resolution=LSM303DLHC_HR_ENABLE;
  /* Configure the accelerometer main parameters */
  LSM303DLHC_AccInit(&LSM303DLHCAcc_InitStructure);

  /* Fill the accelerometer LPF structure */
  LSM303DLHCFilter_InitStructure.HighPassFilter_Mode_Selection =LSM303DLHC_HPM_NORMAL_MODE;
  LSM303DLHCFilter_InitStructure.HighPassFilter_CutOff_Frequency = LSM303DLHC_HPFCF_16;
  LSM303DLHCFilter_InitStructure.HighPassFilter_AOI1 = LSM303DLHC_HPF_AOI1_DISABLE;
  LSM303DLHCFilter_InitStructure.HighPassFilter_AOI2 = LSM303DLHC_HPF_AOI2_DISABLE;

  /* Configure the accelerometer LPF main parameters */
  LSM303DLHC_AccFilterConfig(&LSM303DLHCFilter_InitStructure);
}

void Demo_LEDConfig(void) {
 STM_EVAL_LEDInit(LED3);
 STM_EVAL_LEDInit(LED4);
 STM_EVAL_LEDInit(LED5);
 STM_EVAL_LEDInit(LED6);
 STM_EVAL_LEDInit(LED7);
 STM_EVAL_LEDInit(LED8);
 STM_EVAL_LEDInit(LED9);
 STM_EVAL_LEDInit(LED10); 
}

  Весь проект можно скачать на github.

Гироскоп

На плате установлен гироскоп L3G20D. Подключен по SPI к выводам PE0-PE3 и PA5-PA7 (интерфейс SPI).
Но гироскоп измеряет только мгновенную угловую скорость. Чтобы получить угол, значение угловой сокрости необходимо проинтегрировать. В нашем печальном случае мы вызываем прерывание, скажем, каждые 20 мс, замеряем значение угловой скорости, умножаем его на 0.02 и прибавляем к предыдущему значению угла.
Реализовать измерение угла средствами демонстрационной библиотеки НЕ УДАЛОСЬ.
Разобраться с подключением нам помогла эта замечательная статья.
Необходимо добавить измерение второго угла.
И реализовать все-таки с помощью демо-библиотеки.
Но об этом - позже.

В следующей части - настройка таймеров, захват ШИМ.

P.S. Что за хрень вставляет blogger в html страницы?

1 комментарий:

  1. Не получилось подключить библиотеки - при сборке появляется куча ошибок о неизвестных именах в тех файлах, что подключал, например:
    [cc] D:\Education\ARM\Trening_f3\cmsis_lib\source\stm32f3_discovery.c:238:23: error: request for member 'EXTI_Line' in something not a structure or union
    [cc] EXTI_InitStructure.EXTI_Line = BUTTON_EXTI_LINE[Button];
    [cc] ^
    [cc] D:\Education\ARM\Trening_f3\cmsis_lib\source\stm32f3_discovery.c:239:23: error: request for member 'EXTI_Mode' in something not a structure or union
    [cc] EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    [cc] ^
    [cc] D:\Education\ARM\Trening_f3\cmsis_lib\source\stm32f3_discovery.c:239:36: error: 'EXTI_Mode_Interrupt' undeclared (first use in this function)

    ОтветитьУдалить