STM Урок 51. Подключаем магнитометр LIS3MDL. Часть 3



Урок 51.

 

Часть 3

 

Магнитометр LIS3MDL

 

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

Начнём теперь вносить изменения в функцию Mag_Read. Для этого будем использовать фрагменты кода из файла lsm303dlhc.c из проекта с занятия по другому магнитометру (lsm303dlhc).

 

void Mag_Read(void)

{

        int16_t buffer[3] = {0};

        static int16_t val[3], tmp16;

        Mag_GetXYZ(buffer);

Исправим дальнейший код

        val[0]=buffer[0];

        val[1]=buffer[1];

        val[2]=buffer[2];

 

Раскомментируем строки кода, отвечающие за вывод считанной с осей информации в текстовый вид, а в графический закомментируем, заодно исправим переменные показаний осей

 

        val[2]=buffer[2];

        sprintf(str1,»X:%06d Y:%06d Z:%06drn», val[0], val[1], val[2]);

        HAL_UART_Transmit_DMA(&huart2, (uint8_t*)str1,strlen(str1));

//        buf2[0]=0x11;

//        buf2[1]=0x55;

//        buf2[2]=(uint8_t)(val[0]>>8);

//        buf2[3]=(uint8_t)val[0];

//        buf2[4]=(uint8_t)(val[1]>>8);

//        buf2[5]=(uint8_t)val[1];

//        buf2[6]=(uint8_t)(val[2]>>8);

//        buf2[7]=(uint8_t)val[2];

        HAL_UART_Transmit_DMA(&huart2,buf2,8);

 

Изменим код дальше

 

        HAL_UART_Transmit_DMA(&huart2,buf2,8);

        if(val[0]>500)

 

Чтобы нам посмотреть пока работу датчика в программе HyperTerminal, мы добавим-таки вызов функции mag_ini() в бесконечный цикл, а в обработчике прерывания пока закомментируем

 

  /* USER CODE BEGIN 3 */

                        Mag_Read();

  }

        {

                //Mag_Read();

                HAL_UART_Receive_IT(&huart2, (uint8_t*) str, 8);

 

Скомпилируем код, прошьём контроллер и проверим работу датчика в программе HyperTerminal

 

image25

 

Из данной картины, а также используя таблицу из технической документации, в которой находится чувствительность (дискретность одного гаусса, при диапазоне 4 гаусса она равна 6842) мы с вами видим, что показания по X у нас в районе 0,07 гаусс, по Y – около 0,3, по Z – около 0,33, что в принципе нормально.

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

 

//        sprintf(str1,»X:%06d Y:%06d Z:%06drn», val[0], val[1], val[2]);

//        HAL_UART_Transmit_DMA(&huart2, (uint8_t*)str1,strlen(str1));

        buf2[0]=0x11;

        buf2[1]=0x55;

        buf2[2]=(uint8_t)(val[0]>>8);

        buf2[3]=(uint8_t)val[0];

        buf2[4]=(uint8_t)(val[1]>>8);

        buf2[5]=(uint8_t)val[1];

        buf2[6]=(uint8_t)(val[2]>>8);

        buf2[7]=(uint8_t)val[2];

        HAL_UART_Transmit_DMA(&huart2,buf2,8);

 

 

Перед тем как запустить программу визуализации, обратно раскомментируем вызов функции в обработчике и закомментируем в бесконечном цикле. Также  уберём задержку из функции считывания

 

  /* USER CODE BEGIN 3 */

                        //Mag_Read();

  }

                        Mag_Read();

                        HAL_UART_Receive_IT(&huart2, (uint8_t*) str, 8);

                }

                LD2_OFF;

        }

        //HAL_Delay(20);

}

 

Запустим программу визуализации (кстати я её маленько усовершенствовал опять и включил в нее переключатель диапазонов ну и также добавил отправку 8 байтов для запуска функции чтения с осей магнитометра в контроллере) и посмотрим на графики осей

 

image26

 

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

 

char str1[30]={0};

//буферы для скользящего среднего

volatile int16_t xbuf_avg[8]={0},ybuf_avg[8]={0},zbuf_avg[8]={0};

//счётчик наполнения буферов скользящего среднего

volatile int8_t avg_cnt;

//сумма для среднего арифметического

volatile int64_t tmp64[3];

//———————————————

//———————————————

void MovingAverage(int16_t* dt)

{

        if(avg_cnt<8)

        {

                xbuf_avg[avg_cnt]=dt[0];

                ybuf_avg[avg_cnt]=dt[1];

                zbuf_avg[avg_cnt]=dt[2];

                if(avg_cnt==7)

                {

                        tmp64[0]=xbuf_avg[7]+xbuf_avg[6]+xbuf_avg[5]+xbuf_avg[4]+xbuf_avg[3]+xbuf_avg[2]+xbuf_avg[1]+xbuf_avg[0];

                        tmp64[1]=ybuf_avg[7]+ybuf_avg[6]+ybuf_avg[5]+ybuf_avg[4]+ybuf_avg[3]+ybuf_avg[2]+ybuf_avg[1]+ybuf_avg[0];

                        tmp64[2]=zbuf_avg[7]+zbuf_avg[6]+zbuf_avg[5]+zbuf_avg[4]+zbuf_avg[3]+zbuf_avg[2]+zbuf_avg[1]+zbuf_avg[0];

                        dt[0]=tmp64[0]/8;

                        dt[1]=tmp64[1]/8;

                        dt[2]=tmp64[2]/8;

                }

                avg_cnt++;

        }

        else

        {

                //вычтем из общих сумм последние элементы

                tmp64[0]-=xbuf_avg[0];

                tmp64[1]-=ybuf_avg[0];

                tmp64[2]-=zbuf_avg[0];

                //сдвинем буферы на 1 элемент

                memcpy((void*)xbuf_avg,(void*)(xbuf_avg+1),sizeof(int16_t)*7);

                memcpy((void*)ybuf_avg,(void*)(ybuf_avg+1),sizeof(int16_t)*7);

                memcpy((void*)zbuf_avg,(void*)(zbuf_avg+1),sizeof(int16_t)*7);

                //заменим на 7 элементы на новые

                xbuf_avg[7]=dt[0];

                ybuf_avg[7]=dt[1];

                zbuf_avg[7]=dt[2];

                //прибавим новые элементы

                tmp64[0]+=dt[0];

                tmp64[1]+=dt[1];

                tmp64[2]+=dt[2];

                //обновим средние значения

                dt[0]=tmp64[0]/8;

                dt[1]=tmp64[1]/8;

                dt[2]=tmp64[2]/8;                

        }

}

//———————————————

 

 

Вызовем данную функцию в функции чтения данных

 

        val[2]=buffer[2];

        //Применим фильтр скользящего среднего

                MovingAverage(val);

 

Также не забываем про инициализацию

 

void Mag_Ini(void)

{

        uint16_t ctrl = 0x0000;

        //инициализируем счетчик заполнения скользящего среднего

        avg_cnt=0;

        HAL_Delay(1000);

 

Соберем код и прошьём контроллер.

Совсем другое дело

 

image00

 

Давайте теперь попробуем добавить возможность пользователю включать и отключать фильтр, так как у нас все равно не используется синяя кнопка USER_BUTTON. Как мы можем наблюдать из схемы, подключена она к лапке порта PC13

 

image01

 

Настроим данную ножку порта в Cube MX

 

 image02

 

Заново сгенерируем проект, скомпилируем его.

Добавим проверку статуса кнопки

 

        val[2]=buffer[2];

        tmp16 = HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13);

        //Если кнопка не нажата

        //Применим фильтр скользящего среднего

        if(tmp16!=0) MovingAverage(val);

 

Теперь при нажатой кнопке фильтр будет отключаться. Проверим это, скомпилировав код и прошив контроллер

 

image03

 

Теперь мы можем наблюдать в реальном времени, как работает алгоритм чтения данных с магнитометра с фильтром и без фильтра.

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

Пока выставим при старте программы вот такие значения

 

image04

 

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

 

image05

 

Прочитаем в программе показания по осям и скорректируем их в программе МК с обратным знаком. Возможно впоследствии я внесу возможность корректировки значений в программу визуализации. А пока так

 

        val[0]=buffer[0]-745;

        val[1]=buffer[1]+3500;

        val[2]=buffer[2]-2309;

 

Скомпилируем код и прошьём контроллер. Затем запустим программу с теми же установками делителя. Шарик хотя и укатывается, но уже очень медленно

 

image06

 

Можно подобрать делитель так, что шарик вообще остановится. У меня получилось 1024.

Теперь можно поиграться магнитом возле датчика и понаблюдать за шариком.

 

 

Предыдущая часть Программирование МК STM32 Следующий урок

 

Исходный код

 

Техническая документация на датчик

Программа Hyper Terminal

Программа NS Port Monitor

Программа NS Mag Visual

 

 

Отладочную плату можно приобрести здесь Nucleo STM32F401RE

Оценочную плату можно приобрести здесь STM32 X-NUCLEO-IKS01A1

 

 

Смотреть ВИДЕОУРОК

 

STM32 Подключаем магнитометр LIS3MDL

2 комментария на “STM Урок 51. Подключаем магнитометр LIS3MDL. Часть 3
  1. Владислав:

    Доброго времени суток! Ссылка на скачивание NS Port Monitor выдает код 404, исправьте, пожалуйста.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*