Ничего не найдено :(
    В гостях у Самоделкина! » Темы » Советы » Автономный контроллер для датчика влажности почвы. Детали

    Автономный контроллер для датчика влажности почвы. Детали



    Так как предыдущая моя публикация вызвала некоторый интерес, и параллельно возникли вопросы по реализации контроллера, я решил описать более подробно некоторые детали.

    Принцип работы кода

    Со времени публикации код претерпел некоторые изменения в лучшую сторону. По совету ino53 я добавил контроль расхода батарейки CR2032 с помощью измерения микроконтроллером напряжения питания. Также VICTOR_ZH совершенно справедливо указал на то, что опорное напряжение нужно установить внутреннее 1,1V вместо напряжения питания. Также здесь я более подробно опишу принцип измерения напряжения с датчика с помощью АЦП и принцип мигания светодиодом.
    В начале кода добавились дополнительные константы:
    #define SLEEP_PERIOD WDTO_8S
    #define SKIP_WDT_WAKEUPS 4
    #define SKIP_READVCC_WAKEUPS 4
    #define THRESHOLD_VCC 2300


    Первая (SLEEP_PERIOD WDTO_8S) - это, так называемая, built in (встроенная) константа для того, чтобы задать 8-секундный период срабатывания сторожевого таймера (watchdog). К сожалению у нас нет иной альтернативы для реализации функция засыпания/просыпания на сравнительно длительный период, потому что существуют или еще более мелкие интервалы сторожевого таймера (WDTO_4S, WDTO_2S, WDTO_1S, WDTO_500MS и т.д.) или просыпание по внешнему прерыванию. Внешнее прерывание может быть реализовано по нажатию кнопки или по срабатыванию какого-то датчика. Ни тем, ни другим мы не располагаем, а наш датчик измеряет непрерывно, поэтому он тоже не подходит. Поэтому используем 8-секундный таймер.

    SKIP_WDT_WAKEUPS задает количество 8-секудных периодов засыпания, через которое контроллер опрашивает датчик на предмет его текущей емкости. Сейчас мы имеем период 4x8 = 32 секунды. Точно такой же период SKIP_READVCC_WAKEUPS задает количество 8-секудных периодов засыпания, через которое контроллер измеряет напряжение питания (VCC).

    THRESHOLD_VCC задает пороговое значение напряжения питания VCC (мВ), при котором микроконтроллер attiny85 начинает мигать светодиодом сигнал SOS на морзянке, сигнализирующий о необходимости замены батарейки. Величина 2300 мВ была выбрана опытным путем - если еще сильнее снижать напряжение, то светодиод начинает светить слишком слабо, хотя микроконтроллер attiny85 продолжал работать и при 2100 мВ.

    Проверка точности работы АЦП осуществлялась с помощью прецизионного источника питания ZK-J3X, подключенного к разъемам батарейки с помощью "крокодилов". ZK-J3X представляет собой понижающий преобразователь, на вход которого можно подключить источник питания от 5 до 27 В. Я использовал блок питания 12 В 1,5 А. В домашних условиях очень удобно использовать подобные преобразователи вместо громоздких блоков питания для проверки низковольтной электроники.



    Далее мы задаем два счетчика для SKIP_WDT_WAKEUPS и SKIP_READVCC_WAKEUPS, которые мы будем изменять внутри вектора прерывания, срабатывающего по ватчдогу.
    volatile uint8_t wakeup_counter_adc = 0;
    volatile uint8_t wakeup_counter_readvcc = 0;


    // Вектор прерывания таймера WDT
    ISR(WDT_vect)
    {
      wakeup_counter_adc++;
      wakeup_counter_readvcc++;
    }


    Порядок работы кода внутри цикла while(1) такой:
    1. Засыпаем с помощью функции goToSleep() на 8 секунд и просыпаемся
    2. В векторе ISR(WDT_vect) прибавляем единицу к счетчикам
    3. Проверяем условия wakeup_counter_adc > SKIP_WDT_WAKEUPS и wakeup_counter_readvcc > SKIP_READVCC_WAKEUPS
    4. Если прошло 32 секунды, то микроконтроллер совершает опрос датчика, мигает светодиодом 10 раз подряд раз в полсекунды/секунду или нет в зависимости от полученной емкости (значения АЦП)
    5. Если прошло 32 секунды, то микроконтроллер выполняет функцию readVcc(), измеряя напряжение питания и, в зависимости от полученного значения питания в милливольтах, подает светодиодом сигнал SOS или не подает


    Функция goToSleep(), в принципе, подробно прокомментирована, остановлюсь только на одном моменте.
    void goToSleep()
    {
      ADCSRA &= ~_BV(ADEN); // отключить ADC; уменьшает энергопотребление
      wdt_enable(SLEEP_PERIOD); // установить таймер
      WDTCR |= _BV(WDIE); // включить прерывания от таймера; фикс для ATtiny85
      set_sleep_mode(SLEEP_MODE_PWR_DOWN); // установить режим сна Power-down
      sleep_enable(); // разрешить режим сна
      sei(); // включить прерывания; иначе таймер не будет работать
      sleep_cpu(); // заснуть
      sleep_disable(); // запретить режим сна
      ADCSRA |= _BV(ADEN); // включить ADC
      wdt_disable(); // Выключить ватчдог
    }


    В прошлой реализации я забыл в конце выключить ватчдог (wdt_disable();), поэтому светодиод начинал моргать, но прекращал это делать ровно через 8 секунд.

    Разберем функцию readVCC:

    Для измерения напряжения питания приходится менять режим работы АЦП. В регистре ADMUX мы временно делаем опорным напряжение питания и переводим АЦП на измерение внутреннего напряжения 1,1V (микроконтроллер как бы производит сравнение). Для корректного измерения необходимо подождать более 1 секунды (так написано в мануале), произвести измерение и полученное значение АЦП конвертировать в милливольты с помощью формулы. В конце мы возвращаем опорное напряжение на внутреннее 1,1V и переводим измерение АЦП на ADC3.

    Далее разберем процесс измерения с помощью АЦП:
    Автономный контроллер для датчика влажности почвы. Детали

    В функции ADC_Read() мы проводим единственное измерение. Включаем его, ждем пока оно закончится и забираем значения из двух регистров ADCL и ADCH, складывая их побайтно. А функция ADC_Read_Avg(uint8_t nsamples) просто предоставляет интерфейс для произвольного количества последовательных измерений, значения которых суммируются и делятся на количество измерений. Делается это для увеличения точности.

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

    for(int i = 0; i < 10; i++)
    {
      SET_HIGH(PORTB, PB4);
      _delay_ms(1000);
      SET_LOW(PORTB, PB4);
      _delay_ms(1000);
    }


    Здесь мы просто в цикле последовательно зажигаем и гасим светодиод, подавая напряжение на вывод PB4.

    Настройки avrdudej-0.1

    Как я уже упоминал ранее, для заливки кода в attiny85 я использую свободную программу avrdudej-0.1. Как это ни странно, она имеет минимальный необходимый набор функций и является кроссплатформенной - я использую ее и под Windows, и под Linux. Для обеспечения ее работоспособности достаточно:

    • установить JRE или OpenJDK
    • (под Linux в свойствах файла отметить галочку "является выполняемым")
    • прописать пути к arduino IDE, avrdude и avrdude.conf в "Edit -> Preferences". На скриншоте видно, что avrdude в arduino IDE находится в скрытой папке ".arduino15".




    Размер кода

    Лично для меня оказалось очень странным, когда я выяснил, что размера кода, загружаемый в микроконтроллер, сильно отличается от размера формируемого файла .hex. Существует мнемоническое правило: фактический размер загружаемого кода в три раза меньше, чем размер файла. Фактический размер кода можно посмотреть в avrdudej-0.1 непосредственно при заливке или с помощью утилиты avr-size, которая поставляется вместе с компилятором. На скриншоте линуксового терминала видно, что размер soil-avr.hexz, загружаемый во flash-память микроконтроллера, составляет 784 байта. Размер файла на накопителе компьютера около 2,2 кБ.



    Мигрируем на attiny13a

    В данном случае мы выяснили, что объем кода для attiny85 оказался меньше 1кБ, а значит можно использовать микроконтроллер с гораздо меньшей памятью и гораздо более дешевый. Например, attiny25, attiny202 или даже attiny13a. На последнем остановимся подробнее. Дело в том, что attiny13a является очень дешевым микроконтроллером, производство клонов которого давно наладили китайцы. В принципе, нам ничего особо не мешает внести минимальные изменения в печатную плату и код, и использовать attiny13a.





    В плату мы вносим два минимальных изменения: немного отодвигаем разъем для крепления приставки, учитывая опыт предыдущей конструкции, а также меняем широкое посадочное место для attiny85 (SOIC8W) на обычный SOIC8 (150mil) - в этом корпусе поставляются attiny202, attiny204 и attiny13a.

    Какие изменения нужно внести в код? Прежде всего это настройки АЦП:



    Регистры attiny13a отличаются от attiny85, поэтому настройки будут немного отличаться. Более подробно можно посмотреть в разделе 14.12 Register Description.

    Основной проблемой является отсутствие в attiny13a прерываний по ватчдогу ISR(WDT_vect), поэтому придется пойти обходным путем. Например, как это реализовано здесь.



    Отличия в Code::Blocks для Windows и для Linux

    В предыдущей статье я писал, что для программирования микроконтроллеров AVR я использую свободную IDE Code::Blocks. В ходе работы я столкнулся с небольшой проблемой при переносе кода с Windows на Linux и обратно. Выяснилось, что код проекта идентичен для двух платформ за исключением шагов, которые выполняются на этапе компиляции - создаются разные файлы. Например, под Windows есть команда, создающая файл .lss. Но под Linux нет команды cmd, поэтому компиляция останавливается.

    
    cmd /c "avr-objdump -h -S $(TARGET_OUTPUT_FILE) > $(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).lss"
    


    Поэтому, чтобы проект заработал в иной экосистеме, нужно просто заменить команды в Build options... pre/post build steps на правильные.
    Файл с командами для Windows и Linux лежит в расшаренной папке. Там же лежит проект платы для attiny13a и исправленные проекты Code:Blocks для attiny85 для Windows и Linux. Проекту под Windows требуется пересборка. Актуальный hex лежит в Linux/soil_avr/bin/Release. Проекта Code:Blocks для attiny13a пока нет, но он обязательно будет.

    Ссылка на проекты

    В одной из следующих статей я опишу как работать с новыми микроконтроллерами attiny202, attiny402, attiny424 и как сделать простой UPDI-программатор для них. В условиях новых цен на микроконтроллеры это очень актуально.
    Сложность статьи достаточно высокая, поэтому вопрос
    Нужны здесь подобные статьи?
    Всего проголосовало: 7
    Подборки: attiny85 attiny13

    Бензиновый снегоуборщик – отличный помощник в хозяйстве. Советы по эксплуатации, причины поломок, ремонт своими руками

    Стеклодувная пушка. Доводка, запуск, настройка для работы на парах бензина

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

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

       Сложная статья? Скорее наоборот, все очень подробно и тщательно раз.яснено и показано - побольше бы таких статей - больше бы появилось поклонников такого интересного и популярного ныне дела, как программирование микроконтроллеров! Успехов Вам в этом нелёгком деле... :)))




    Привет, Гость!


    Зарегистрируйтесь

    Или войдите на сайт, если уже зарегистрированы...

    Войти

    Добавьте самоделку

    Добавьте тему

    Онлайн чат

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

    Все комментарии