Top.Mail.Ru

Модуль датчика вибрации KY-002. Схема подключения к STM32.

Всем привет и рад познакомиться ) Добрался я, наконец-то, до написания статей, а точнее до первых попыток. Опыта в этом нет, так что, если что пишите пожелания и замечания в комментарии. Как мы и условились с Aveal, я буду делать обзоры на разнообразные датчики из такого вот набора – ссылка. А начну с одного из самых первых, KY-002 (KY-001 уже был описан ранее), просто потому что он первый из оставшихся по номенклатуре. И модуль KY-002 это небольшая платка с установленным на ней датчиком вибрации.

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

Модуль KY-002

Модуль содержит всего лишь три элемента:

  • датчик вибрации
  • резистор на 10 КОм
  • штыревой разъем с шагом 2.54 мм на 3 контакта

Нарисовал принципиальную схему KY-002:

Схема модуля датчика вибрации KY-002

Сам же датчик состоит из цилиндрического металлического корпуса, внутри которого расположена металлическая пружина, а в центре пружины – стержень:

Устройство датчика вибрации.

Два контакта датчика соединены с пружиной и с этим стержнем. При ударе, вибрации или другом механическом воздействии пружина физически контактирует со стержнем, что приводит к замыканию контактов датчика.

Возвращаемся к схеме. Здесь на выходе Output по умолчанию будет напряжение питания, потому что выход Output подтянут резистором к Power. А при замыкании пружины со стержнем Output окажется замкнут с землей (Ground). То есть датчик вибрации практически идентичен кнопке, которая нажимается при механическом ударе и т. п. Как я уже говорил, схема максимально проста )

Давайте подытожим, что будет на выходе Output модуля KY-002:

  • Без воздействия на датчик – высокий уровень, то есть напряжение, подаваемое на вывод Power.
  • При воздействии на датчик будет импульс или импульсы низкого уровня (зависит от степени и типа воздействия).

Я подключил датчик, стал стучать по нему и сохранил осциллограмму:

Сигнал на выходе.

Наверно больше и нечего про этот датчик вибрации рассказать, разве что основные характеристики:

  • при разомкнутых пружине и стержне сопротивление датчика более 10 МОм (МегаОм)
  • при замкнутых – менее 30 мОм (миллиОм)
  • количество срабатываний, которое датчик может пережить - более 100000
  • максимальное напряжение – 12 В, превышать не рекомендую )

Теперь перейдем к программной части. Я сделал два проекта – самый базовый, который может помочь проверить работоспособность датчика, и чуть посложнее, чтобы было поинтереснее.

Проект 1. Базовое подключение датчика вибрации к STM32.

Использую STM32CubeIDE – потому что она бесплатная и плюс нравится мне. Стараюсь всегда обновлять до последней версии, но это не сильно повлияет, если у вас не самая актуальная версия. Плата у меня будет такая:

Отладочная плата с STM32F401.

Контроллер STM32F401CCU6, вроде как плата называется Black Pill, короче обычный Aliexpress-девайс. Подключаю так:

Схема подключения датчика вибрации KY-002.

Из возможностей STM32 понадобится самый минимум – один порт на вход (для считывания сигнала с датчика - PB0) и один порт на выход (для управления светодиодом). На этой плате светодиод подключен к PC13. Настраиваю в STM32CubeMX:

Настройка GPIO в STM32CubeMx.

После генерации кода получаем готовый проект для CubeIDE. Хотя работа с датчиком очень проста, я оформил работу с ним в отдельных файлах, просто я так привык. За основу взял шаблон из примера про ПИД-регулятор. Структура проекта такая:

Структура проекта.

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

В файле vibration_sensor.c у меня три переменные:

static GPIO_TypeDef* port;
static uint32_t pin;
static uint8_t isInitialized = 0;

Первые две для того, чтобы в них сохранить порт и пин, к которым подключен выход с модуля. И третья переменная на всякий случай, чтобы не забыть поставить в первые две переменные правильные значения. Для этого используется функция  VIBRO_Init():

void VIBRO_Init(GPIO_TypeDef* gpioPort, uint32_t gpioPin)
{
  port = gpioPort;
  pin = gpioPin;
  isInitialized = 1;
}

Кроме нее в файле еще только одна функция:

int8_t VIBRO_Read()
{
  if (isInitialized == 1)
  {
    return HAL_GPIO_ReadPin(port, pin);
  }
  else
  {
    return -1;
  }
}

Она нужна для считывания сигнала с датчика. В main() добавляем инициализацию:

/* USER CODE BEGIN 2 */
VIBRO_Init(GPIOB, GPIO_PIN_0);

/* USER CODE END 2 */

Это позволит менять порт только в одном месте при подключении датчика к другой ножке микроконтроллера. Я так делаю всегда, это мне кажется наиболее удобным. В while(1) добавил опрос датчика и включение светодиода:

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    int8_t vibrationData = VIBRO_Read();

    if (vibrationData >= 0)
    {
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, vibrationData);
    }
}
/* USER CODE END 3 */

В момент механического воздействия на датчик светодиод будет загораться, что очень удобно для визуального наблюдения. Если забыли вызвать VIBRO_Init(), то функция VIBRO_Read() вернет значение -1, можно добавить на этот случай какие-то действия, показывающие, что возникла ошибка. Здесь я этого не делал, потому что в проекте всего две лишь функции, все очень просто.

Если прошить STM32 и постучать по датчику, то можно увидеть мигающий диод, так и было задумано. Теперь займемся вторым проектом, он сложнее, но не сильно.

Проект 2. Оценка степени воздействия на датчик вибрации.

Этот проект я назвал KY002_Timer, и для теста воздействий я придумал такую штуку… Берем любой таймер и настраиваем так, чтобы генерировалось прерывание каждые 100 мкс (можно взять и другое значение). Далее в течение более длительного времени (у меня 1 секунда = 100 мкс * 10000) опрашиваем датчик каждые 100 мкс, если датчик замкнут (то есть на него есть воздействие), то инкрементируется переменная. После одной секунды проверяем значение этой переменной. Чем больше значение – тем больше на датчик было воздействий.

Все подключено и настроено точно также как и в первом примере. Только добавлен таймер, я взял TIM9:

Настройка Timer в STM32CubeMx.

При таком предделителе получаем частоту таймера 1 МГц (частота шины 84 МГц, деленная на (83 + 1)), значит один отсчет таймера – 1 мкс. Нужен период в 100 мкс, поэтому в Counter Period я поставил 100.

В функции main() оставляю только инициализацию и запуск таймера:

/* USER CODE BEGIN 2 */
VIBRO_Init(GPIOB, GPIO_PIN_0);
HAL_TIM_Base_Start_IT(&htim9);

/* USER CODE END 2 */

Также здесь объявлены несколько вспомогательных переменных:

/* USER CODE BEGIN PD */
#define VIBRO_MEASURE_PERIOD                                         (10000)

/* USER CODE END PD */

/* USER CODE BEGIN PV */
static float vibroRatio = 0;
static uint16_t vibroCounter = 0;
static uint16_t timerCounter = 0;

/* USER CODE END PV */

Значение VIBRO_MEASURE_PERIOD задает период таймера (у меня 1 секунда). Прерывание таймера вызывается каждые 100 мкс, тогда за 1 секунду оно будет вызвано 10000 раз. Это число здесь и задается.

Добавляю в main.c callback, который вызывается при переполнении таймера (каждые 100 мкс):

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == htim9.Instance)
  {
    timerCounter++;

    int8_t vibrationData = VIBRO_Read();
    if (vibrationData == 0)
    {
      vibroCounter++;
    }

    if (timerCounter == VIBRO_MEASURE_PERIOD)
    {
      vibroRatio = (float)vibroCounter / (float)timerCounter * 100;

      timerCounter = 0;
      vibroCounter = 0;
    }
  }
}

/* USER CODE END 4 */

В callback я написал то, что описано выше. Посмотрим по строкам, сначала проверяем, что прерывание вызвано нужным таймером:

if (htim->Instance == htim9.Instance)

Следующей строкой увеличиваю переменную-счетчик timerCounter:

timerCounter++;

Эта переменная будет считать, сколько раз сработало прерывание таймера. Если ее значение станет равным VIBRO_MEASURE_PERIOD, значит прошла 1 секунда, можно проверить значения с датчика. После инкрементирования timerCounter проверяю сигнал с датчика. И если на выходе датчика низкий уровень (значит пружина замкнута со стержнем), то увеличиваю другую переменную (vibroCounter):

int8_t vibrationData = VIBRO_Read();
if (vibrationData == 0)
{
  vibroCounter++;
}

Далее проверка, прошла ли 1 секунда:

if (timerCounter == VIBRO_MEASURE_PERIOD)
{
  vibroRatio = (float)vibroCounter / (float)timerCounter * 100;

  timerCounter = 0;
  vibroCounter = 0;
}

Получается, что vibroRatio показывает степень воздействия на датчик в процентах. timerCounter увеличивается каждый раз при попадании в прерывание, а vibroCounter только при воздействии на датчик. Если разделить второе на первое, узнаем, какую долю времени на датчик было воздействие. Умножаем на 100 и получаем значение в процентах.

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

Для разных скоростей вращения я получил такие результаты:

 

Так что все получилось правильно. На этом заканчиваю свою статью и выкладываю оба проекта: KY002_Base, KY002_Timer.

 

Подписаться
Уведомление о
guest
0 комментариев
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x