Azotirovanie.ru

Инженерные системы и решения
25 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Простой частотомер на основе Arduino UNO (0-1МГц)

Простой частотомер на основе Arduino UNO (0-1МГц)

Приводится описание частотомера, измеряющего частоту до 1 МГц, построенного на основе платы Arduino UNO. Но, прежде всего, хочу напомнить, что Arduino UNO это небольшая печатнаяплата, на которой расположен микроконтроллер ATMEGA328, а так же вся его «обвязка», необходимая для его работы, включая USB-программатор и источник питания.

Стоимость Arduino UNO лежит в пределах от 200 до 1000 рублей, в зависимости от места продажи. Конечно, самое дешевое на радиорынке и китайском интернет-посылторге «Aliexpress». Описание платы Arduino UNO, а также программного обеспечения для неё, и подключения к персональному компьютеру приводится в Л.1, так что, если кто не в курсе, обязательно прочтите сначала статью в Л.1.

Принципиальная схема

Схема частотомера показана на рис. 1. Как видно из схемы, к цифровым портам D2-D7 платы Arduino UNO подключен модуль жидкокристаллического индикатора Н1 типа 1602А.

А входной сигнал поступает через вполне понятный усилитель-формирователь на транзисторе VT1 и микросхеме D1 на порт D8. Питается входной усилитель-формирователь и ЖК-индикатор от стабилизатора напряжения 5V, имеющегося на плате Arduino UNO.

Принципиальная схема частотомера (до 1МГц) на платформе Arduino UNO

Рис. 1. Принципиальная схема частотомера (до 1МГц) на платформе Arduino UNO.

Но, вернемся к ЖК-индикатору. Индикатор представляет собой плату, на которой установлен собственно ЖК-дисплей и схема для его обслуживания, выполненная на двух безкорпусных микросхемах. Индикатор 1602А стандартный, на основе контроллера HD44780. Обозначение 1602А фактически значит, что он на две строки по 16 символов в строке.

Индикатор был куплен на «Aliexpress», найден по запросу «HD44780» (цены от 81 рубля).

Питание +5V на ЖК-индикатор поступает через вывод 2 его платы. Общий минус на выводы 3 и 1. Поскольку в индикатор планируется только передавать информацию от контроллера, а не наоборот, вывод 5 (RW) соединен с нулем. Данные на ЖК-индикатор будут поступать через его выводы 11-14 (выводы 7-10 не используются).

Выводы 15 и 16 служат для подключения подсветки ЖК-индикатора. На них подается напряжение 5V. Для управления ЖК-индикатором решено было использовать порты с D2 по D7 платы Arduino UNO. В принципе, можно и другие порты, но я вот так, решил использовать именно эти.

ЖК-индикатор подключили. Но просто так он работать не станет. Для того чтобы он взаимодействовал с Arduino UNO нужно в программу загрузить подпрограмму для его управления.

Программа

Такие подпрограммы почему-то называются «библиотеками», и в программном комплекте для Arduino UNO есть много разных «библиотек».

Таблица 1. Исходный код программы.

частотомер на основе Arduino UNO - программный код

Для работы с ЖК-индикатором на основе HD44780 нужна библиотека LiquidCrystal. Поэтому программа для нашего частотомера (таблица 1) начинается с загрузки этой библиотеки:

Эта строка дает команду загрузить в Arduino UNO данную библиотеку. Затем, нужно назначить порты Arduino UNO, которые будут работать с ЖК-инди-катором. Как я уже сказал, я выбрал порты с D2 по D7. Эти порты назначены строкой:

LiquidCrystal led(2, 3, 4, 5, 6, 7);

После чего, программа переходит собственно к работе частотомера.

Среди набора функций языка для программирования Arduino UNO есть такая функция: pulseln , перевести это можно как «входной импульс». Эта функция измеряет в микросекундах длительность положительного либо отрицательного перепада входного импульса. Так что измерение частоты здесь будет происходить через предварительное измерение периода.

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

В программе длительность положительного полупериода обозначена Htime, длительность отрицательного полупериода — Ltime, а длительность всего периода — Ttime.

Измерение полупериодов происходит в строках:

Затем, производится вычисление полного периода в строке:

Вычисление частоты, учитывая, что значение периода выражено в микросекундах, происходит здесь:

Затем, указывается строка ЖК-индика-тора (нижняя строка, это строка 1), в которую записывается результат:

И результат записывается в ЖК-индикатор:

Далее указывается единица измерения:

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

измеренное значение (время выражено в миллисекундах, поэтому 1 сек = 1000): delay(1000);

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

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

например, так: delay(2000);

Теперь показания будут сменяться каждые две секунды. Можно выбрать любое другое значение, как меньше 1000, так и больше, но слишком увлекаться его уменьшением не стоит, — чрезмерно частая смена показаний затрудняет зрительное восприятие. На мой взгляд, оптимально -1 секунда.

Теперь о других деталях программы.

порт 8 платы ARDUINO UNO назначен как цифровой вход. На него поступают импульсы, частоту которых нужно измерить.

указано что индикатор двухстрочный, по 16 знаков в строке.

Индикатор у нас двухстрочный. Одна строка остается свободной и в неё можно записать что угодно. Здесь в верхнюю строку (верхняя строка, это строка 0) записано слово «frequency»:

К сожалению, китайский ЖК-индикатор по-русски не понимает, поэтому писать можно только латинскими буквами. Если попробовать написать кириллицей, например, слово «частота», он начинает гнусно ругаться китайскими иероглифами. Если на вход (порт D8 ARDUINO UNO) сигнал не поступает, на ЖК-индикаторе будет мигать: «infhz». Работу частотомера можно ускорить или замедлить, изменив время индикации, как это сказано выше.

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

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

подставив вместо 1000000 другое значение, или вообще изменив формулу вычисления результата, соответственно той, которая необходима для конкретного случая применения прибора. Соответственно, нужно будет изменить и единицу измерения, заменив её в строке: lcd.print(«hz»); И изменить заголовок в верхней строке ЖК-индикатора, изменив его в строке: lcd.print(«frequency»);

Читайте так же:
Счетчик трафика интернета какой лучше

Напряжение питания частотомера может быть от 7 до 12V. Питание подается на соответствующее гнездо на плате ARDUINO UNO. Напряжение может быть нестабилизированным (на плате есть собственный стабилизатор на 5V), но

обязательно хорошо отфильтрованным (пульсации должны быть минимальными). Питание возможно и от источника напряжением 5V через USB-порт, но в этом случае, напряжение должно быть не только хорошо отфильтрованным, но и стабилизированным.

Схема входного усилителя состоит из собственно входного усилителя на транзисторе VТ1 и триггера Шмитта на элементах микросхемы D1. Кстати, микросхему К561ЛЕ5 или К561ЛА7 можно заменить любой КМОП-микросхемой, в которой есть не менее трех инверторов, соответственно, изменив схему.

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

При питании от гальванической батареи, например, «Кроны» или её аналога напряжением 9V, с целью экономии источника питания можно отключить подсветку ЖК-индикатора. Для этого нужно в разрыв его вывода 15 или 16 включить выключатель, которым включать подсветку, если она нужна. Если же подсветка вообще не требуется, выводы 15 и 16 ЖК-индикатора можно вообще не подключать.

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

Набирая программу (таблица 1) совсем не обязательно набирать то, что в строках после знака « ; » (точка с запятой). Потому что это комментарии и пояснения, никак не влияющие на работу программы.

Каравкин В. РК-12-16.

1. Каравкин В. Ёлочная мигалка на Arduino как средство от боязни микроконтроллеров. РК-11-2016.

Урок 39. Реле времени: управление устройствами по таймеру

В этом уроке мы создадим четырёхканальное реле времени. К данному устройству можно подключить до 4 приборов (лампочки, светодиодные ленты, моторы, обогреватели, вентиляторы и т.д.), каждое из которых будет включаться на заданные для него промежутки времени суток и в заданные дни недели.

Каждый из четырёх каналов нашего реле времени может выдавать не только логические уровни (1/0 — вкл/выкл), но и сигналы ШИМ (включать приборы на определённую мощность).

В реле времени имеется 20 таймеров (их количество можно уменьшить или увеличить до 128, указав нужное число в строке 16 скетча). Один таймер включает только одно устройство (канал) на заданный промежуток времени, не влияя на работу остальных устройств (каналов). Каждому устройству (каналу) можно назначить несколько таймеров, следовательно, включать и выключать каждое из устройств можно несколько раз в сутки и на разную мощность. При отключении питания, таймеры реле не сбиваются, так как их настройки хранятся в энергонезависимой памяти Arduino. Текущее время также не сбивается, так как оно берётся из модуля часов реального времени, который снабжен батарейкой.

Реле времени можно использовать для включения освещения по времени в доме, квартире, на даче, на производстве и т.д. Можно использовать для включения по времени вентиляции, котлов, обогревателей, полива газонов, систем очистки дачных бассейнов и т.д. Еще одним преимуществом реле времени является создание эффекта присутствия, например, Вас нет дома, но свет утром и вечером включается, а днём и ночью выключается, утром включается радио или телевизор, а ночью включается ночник. Это может заставить задуматься нежелательных «гостей», что дом обитаем и делать там нечего.

Нам понадобится:
    х 1шт.
  • Дисплей LCD1602 I2C зелёный или синий x 1шт.
  • Trema I2C HUB прямоугольный или квадратный x 1шт. x 1шт. x 1шт. x 1шт.

Для реализации проекта нам необходимо установить библиотеки:

    для работы с символьными ЖК дисплеями. для работы с энкодерами через аппаратный таймер. для работы с модулями реального времени.
  • Библиотеки EEPROM, Wire и pgmspace используемые в скетче, входят в стандартный набор Arduino IDE.

О том как устанавливать библиотеки, Вы можете ознакомиться на странице Wiki — Установка библиотек в Arduino IDE .

Видео:

Схема подключения:

Trema модуль RTC и дисплей LCD1602 I2C подключаются к аппаратной шине I2C через Trema I2C HUB, а Trema энкодер можно подключать к любым (цифровым или аналоговым) выводам Arduino, их номера указываются в скетче (в примере использованы выводы D4, D7 и D8). Для удобства подключения используется Trema Shield.

Реле времени: включение нагрузки по времени

Приборы подключаются к каналам 1-4:
  • Маломощные приборы с питанием 5 В постоянного тока до 20 мА можно подключать напрямую к одному из каналов.
  • Приборы с питанием до 30 В постоянного тока подключаются через силовой ключ.
  • Приборы с питанием от сети 220 В переменного тока подключаются через твердотельное или электромеханическое реле.
Алгоритм работы:

Режим просмотра времени: При включении питания на индикаторе отображается текущее время, дата и день недели. Номера включённых каналов отображаются в правом верхнем углу дисплея.

Меню: Для входа в меню нужно нажать на энкодер. Далее поворачивая экодер вправо или влево можно выбрать разделы «ТАЙМЕРЫ», «ЧАСЫ», «ВЫХОД», для входа в требуемый раздел нужно опять нажать на энкодер.

Меню>часы: В данном разделе меню, поворачивая энкодер вправо или влево, можно выбрать разделы «ВРЕМЯ», «ДАТА», «ВЫХОД», для входа в требуемый раздел нужно нажать на энкодер.

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

Меню>часы>дата: Этот раздел меню предназначен для установки текущей даты и дня недели. Устанавливаемый в данный момент параметр даты (день, месяц, год, день недели) должен мигать. Выбор значения осуществляется поворотом энкодера, а переход к следующему значению, нажатием на энкодер.

Меню>таймеры: В данном разделе меню, поворачивая энкодер вправо или влево, можно выбрать один из установленных таймеров (для их редактирования) или разделы «НОВЫЙ ТАЙМЕР», «СТЕРЕТЬ ВСЕ ТАЙМЕРЫ», «ВЫХОД», для входа в требуемый раздел нужно нажать на энкодер. Установленные таймеры отображаются в виде строки из времени их старта/сброса и номера канала «00:00-00:00-0».

Меню>таймеры>новый таймер: Выбор данного раздела приведёт к созданию нового таймера, на экране отобразится надпись «НОВЫЙ ТАЙМЕР СОЗДАН» после чего Вам будет предложено ввести время старта/сброса и указать номер канала (который будет включаться данным таймером). Данный раздел меню недоступен если установлены все таймеры.

Читайте так же:
Счетчик лет между датами

Меню>таймеры>стереть все таймеры: Выбор данного раздела приведёт к удалению всех таймеров, на экране отобразится надпись «ВСЕ ТАЙМЕРЫ УДАЛЕНЫ». Данный раздел меню недоступен если нет ни одного установленного таймера.

Меню>таймеры>00:00-00:00-0: Вместо «00:00-00:00-0» будет строка из времени старта/сброса таймера и номера канала которым он управляет. Данный раздел меню предназначен для редактирования выбранного таймера, поворачивая энкодер вправо или влево, можно выбрать разделы «ВРЕМЯ И КАНАЛ», «ПОВТОРЫ», «УРОВЕНЬ СИГНАЛА», «СТЕРЕТЬ ТАЙМЕР», «ВЫХОД», для входа в требуемый раздел нужно нажать на энкодер.

Меню>таймеры>00:00-00:00-0>время и канал: Этот раздел меню предназначен для установки (редактирования) времени старта/сброса таймера и номера канала которым он управляет. Устанавливаемый в данный момент параметр (час старта, минута старта, час сброса, минута сброса, номер канала) должен мигать. Выбор значения осуществляется поворотом энкодера, а переход к следующему значению, нажатием на энкодер.

Меню>таймеры>00:00-00:00-0>повторы: Этот раздел меню предназначен для установки (редактирования) повторов таймера по дням недели, в которые он должен срабатывать. Под устанавливаемым в данный момент параметром (ПН, ВТ, СР, ЧТ, ПТ, СБ, ВС) должен мигать курсор. Поворот энкодера устанавливает или сбрасывает стрелочку под устанавливаемым параметром, если она установлена значит в этот день недели таймер будет срабатывать, иначе он срабатывать не будет. Переход к следующему дню недели осуществляется нажатием на энкодер.

Меню>таймеры>00:00-00:00-0>уровень сигнала: Этот раздел меню предназначен для установки (редактирования) уровня сигнала на выбранном канале при срабатывании таймера. Выбор уровня сигнала от 5% до 100% осуществляется поворотом энкодера с шагом 5%, а нажатие на энкодер приведёт к выходу из данного раздела.

Меню>таймеры>00:00-00:00-0>стереть таймер: Выбор данного раздела приведёт к удалению выбранного таймера, на экране отобразится надпись «ТАЙМЕР УДАЛЕН».

Примеры:
Создание таймера который по будням, между 18:00 и 20:00, будет включать 4 канал с уровнем сигнала 100%:
  • Нажмите на энкодер для входа в меню.
  • Поворачивайте энкодер пока не увидите раздел «ТАЙМЕРЫ» и войдите в него нажав на энкодер.
  • Поворачивайте энкодер пока не увидите раздел «НОВЫЙ ТАЙМЕР» и войдите в него нажав на энкодер.
  • Введите «18:00-20:00 к4». Выбор значений осуществляется поворотом энкодера, а переход к следующему — нажатием.
  • Поворачивайте энкодер пока не увидите раздел «ПОВТОРЫ» и войдите в него нажав на энкодер.
  • Установите галочки под «ПН, ВТ,СР,ЧТ,ПТ» . Установка осуществляется поворотом энкодера, а переход — нажатием.
  • Поворачивайте энкодер пока не увидите раздел «УРОВЕНЬ СИГНАЛА» и войдите в него нажав на энкодер.
  • Установите значение «100%». Выбор значения осуществляется поворотом энкодера, а установка — нажатием.
  • Поворачивайте энкодер пока не увидите раздел «ВЫХОД» и выйдите из редактирования таймера нажав на энкодер.
  • Поворачивайте энкодер пока не увидите раздел «ВЫХОД» и выйдите из раздела «ТАЙМЕРЫ» нажав на энкодер.
  • Поворачивайте энкодер пока не увидите раздел «ВЫХОД» и выйдите из «МЕНЮ» нажав на энкодер.

Теперь на экране отображается текущее время, дата и день недели, а по будням, с 18:00 до 20:00 в правом верхнем углу экрана будет отображаться цифра 4, при этом на 4 канале будет установлен уровень логической «1» (сигнал ШИМ со 100% заполнением). На остальных каналах будет уровень логического «0».

Создание таймера который между 19:00 и 21:00 каждого дня, будет включать 3 канал с уровнем сигнала 50%:
    Повторите все шаги из предыдущего примера, но:
  • Вместо «18:00-20:00 к4» введите «19:00-21:00 к3» .
  • Вместо «ПН, ВТ, СР, ЧТ, ПТ» установите галочки под всеми днями недели «ПН, ВТ, СР, ЧТ, ПТ, СБ, ВС».
  • Вместо «100%» установите уровень сигнала «50%».

После того как Вы установите два таймера (из 1 и 2 примера): По будням с 18:00 до 19:00 в правом верхнем углу экрана будет отображаться цифра 4, при этом на 4 канале будет установлен уровень логической 1 (сигнал ШИМ со 100% заполнением). По будням с 19:00 до 20:00 в правом верхнем углу экрана будет отображаться цифра 3 и 4, при этом на 3 канале будет установлен сигнал ШИМ с 50% заполнением, а на 4 канале будет установлен уровень логической «1» (сигнал ШИМ со 100% заполнением). По будням с 20:00 до 21:00 и в выходные с 19:00 до 21:00, в правом верхнем углу экрана будет отображаться цифра 3, при этом на 3 канале будет установлен сигнал ШИМ с 50% заполнением.

Примечание:

Включение и выключение устройств осуществляется по установленным таймерам только в режиме просмотра времени. Это сделано для того, чтобы устройства «случайно» не включились во время редактирования текущей даты, времени или таймера.

Код программы:

Библиотека iarduino_Encoder_tmr использует второй аппаратный таймер, НЕ ВЫВОДИТЕ СИГНАЛЫ ШИМ НА 3 ИЛИ 11 ВЫВОД!

Подключение Arduino к счетчику Меркурий 230

У трехфазного счетчика электричества Меркурий 230 ART есть шина CAN, с помощью которой можно подключить Arduino.

Для этого нужен такой преобразователь уровней MAX485 (RS-485 Module TTL to RS-485)

С помощью такого подключения можно получить различные данные, в том числе текущее напряжение и ток на всех фазах, а еще показатели день/ночь потребленной энергии (цифры, которые мы передаем в МосЭнерго).

Протокол обмена данными можно скачать на официальном сайте, в этой PDF.

На шине CAN может быть одновременно много устройств, у каждого из них есть свой ID. Сначала нужно определить ID нашего счетчика, для этого мы шлем для каждого ID от 1 до 255 запрос на тестирование канала связи, состоящий из 4 байт:

  1. ID счетчика
  2. 0 (команда «запрос на тестирование канала связи»)
  3. CRC
  4. CRC

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

Схема подключения:

Код Arduino:

#define SSerialRx 11 // Serial Receive pin RO
#define SSerialTx 8 // Serial Transmit pin DI
#define SSerialTxControl 9 // RS485 Direction control
#define SSerialRxControl 10 // RS485 Direction control

#define RS485Transmit HIGH
#define RS485Receive LOW

#define Pin13LED 13

SoftwareSerial RS485Serial(SSerialRx, SSerialTx); // Rx, Tx

int byteReceived;
int byteSend;

void setup() <
Serial.begin(9600);

pinMode(Pin13LED, OUTPUT);
pinMode(SSerialTxControl, OUTPUT);
pinMode(SSerialRxControl, OUTPUT);
digitalWrite(SSerialTxControl, RS485Receive);
digitalWrite(SSerialRxControl, RS485Receive);
RS485Serial.begin(9600);
delay(3000);
Serial.println(«start»);
send(cmd_test_con, sizeof(cmd_test_con));
send(cmd_access, sizeof(cmd_access));

Serial.println(getCounter(46, 1));
Serial.println(getCounter(46, 2));

Читайте так же:
Население марокко счетчик населения

send(cmd_0, sizeof(cmd_0));
send(cmd_1, sizeof(cmd_1));
send(cmd_2, sizeof(cmd_2));
>

void loop() <
for(int f=1; f<=3; f++) <
int v = getVoltage(46, f);
Serial.print(v);
Serial.print(» «)
>
for(int f=1; f<=3; f++) <
int v = getCurrent(46, f);
// Serial.print(» I «);
>
Serial.println();
delay(1000);
return;
byte cmd_r1[] = <46, 8, 0x11, 0x21>;
send(cmd_r1, sizeof(cmd_r1));
delay(1000);
byte cmd_r2[] = <46, 8, 0x11, 0x22>;
send(cmd_r2, sizeof(cmd_r2));
delay(1000);
byte cmd_r3[] = <46, 8, 0x11, 0x23>;
send(cmd_r3, sizeof(cmd_r3));
>

void scanDeviceIds() <
for(int i=0; i<=255; i++) <
byte cmd[] = ;
send(cmd, sizeof(cmd));
delay(1000);
>
>

void send(byte *cmd, int s) <
Serial.print(«sending. «);
unsigned int crc = crc16MODBUS(cmd, s);
unsigned int crc1 = crc & 0xFF;
unsigned int crc2 = (crc>>8) & 0xFF;
digitalWrite(SSerialTxControl, RS485Transmit); // Init Transceiver
digitalWrite(SSerialRxControl, RS485Transmit); // Init Transceiver
for(int i=0; i<s; i++) <
RS485Serial.write(cmd[i]);
Serial.print(cmd[i]);
Serial.print(» «);
>
RS485Serial.write(crc1);
RS485Serial.write(crc2);
Serial.print(«crc: «);
Serial.print(crc1);
Serial.print(» «);
Serial.print(crc2);
Serial.println();
digitalWrite(SSerialTxControl, RS485Receive); // Init Transceiver
digitalWrite(SSerialRxControl, RS485Receive); // Init Transceiver
delay(200);

if (RS485Serial.available()) <
while (RS485Serial.available()) <
byteReceived = RS485Serial.read(); // Read received byte
Serial.print(» «);
digitalWrite(Pin13LED, HIGH); // Show activity
Serial.print(byteReceived); // Show on Serial Monitor
delay(1);
digitalWrite(Pin13LED, LOW); // Show activity
>
delay(1000);
>
Serial.println();
>

void sendCmd(byte *cmd, int s, byte *response) <
unsigned int crc = crc16MODBUS(cmd, s);
unsigned int crc1 = crc & 0xFF;
unsigned int crc2 = (crc>>8) & 0xFF;
digitalWrite(SSerialTxControl, RS485Transmit); // Init Transceiver
digitalWrite(SSerialRxControl, RS485Transmit); // Init Transceiver
for(int i=0; i<s; i++) <
RS485Serial.write(cmd[i]);
//Serial.print(cmd[i]); // Show on Serial Monitor
//Serial.print(» «);
>
//Serial.print(» crc: «);
RS485Serial.write(crc1);
RS485Serial.write(crc2);
digitalWrite(SSerialTxControl, RS485Receive); // Init Transceiver
digitalWrite(SSerialRxControl, RS485Receive); // Init Transceiver
delay(200);

//Serial.print(» resp: «);
response[0] = 0;
byte i = 1;
while (RS485Serial.available()) <
byteReceived = RS485Serial.read();
response[i++] = byteReceived;
Serial.print(byteReceived); // Show on Serial Monitor
Serial.print(» «);
>
response[0] = i-1;
//Serial.println(); // Show on Serial Monitor
>

int getVoltage(int addr, byte f) <
byte cmd[] = ;
byte response[17];
sendCmd(cmd, sizeof(cmd), response);
if(response[0] < 6) return -1;
return ((int)response[3+1]*256 + response[2+1])/100;
>

long getCounter(int addr, byte f) <
byte cmd[] = ;
byte response[22];
sendCmd(cmd, sizeof(cmd), response);
if(response[0] < 6) return -1;
long r = 0;
r |= (long)response[2+1]<<24;
r |= (long)response[1+1]<<16;
r |= (long)response[4+1]<<8;
r |= (long)response[3+1];
return r;
>

int getCurrent(int addr, byte f) <
byte cmd[] = ;
byte response[17];
sendCmd(cmd, sizeof(cmd), response);
if(response[0] < 6) return -1;
return ((int)response[3+1]*256 + response[2+1]);
>

unsigned int crc16MODBUS(byte *s, int count) <
unsigned int crcTable[] = <
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
>;

unsigned int crc = 0xFFFF;

for(int i = 0; i < count; i++) <
crc = ((crc >> 8) ^ crcTable[(crc ^ s[i]) & 0xFF]);
>

Измерение уровня заряда аккумулятора на Ардуино

Измерение уровня заряда Аккумулятора на Ардуино

Отслеживание уровня заряда аккумулятора или батареи является одной из основных задач при разработке автономных устройств. Особенно она актуальна для устройств, которые работают удалённо и сообщают о своём статусе, используя, например, GSM канал*. Даже когда устройство находится рядом с вами, индикация уровня заряда аккумулятора поможет сделать его использование более удобным. В данной статье мы рассмотрим простой способ отслеживания уровня заряда аккумулятора или батареи при помощи Ардуино.

*Знакомые с GSM модулями могут возразить, что в их составе уже присутствуют средства мониторинга заряда аккумулятора, и не нужно изобретать велосипед. Справедливое замечание. Но при условии, что для GSM модуля не используется стабилизация напряжения, скажем, от 12-вольтового аккумулятора. В этом случае модуль не сможет оценить уровень заряда аккумулятора. Таким образом, не стоит преуменьшать актуальность данной темы.

Теория

Предлагаемый способ отслеживания уровня заряда основан на измерении напряжения источника питания. Возьмем, к примеру, литий-ионный аккумулятор. В процессе разрядки его напряжение изменяется от 4.2 В до 3 В. Выполняя периодические замеры напряжения и сопоставляя полученный результат с приведённым диапазоном 4.2. 3 В, мы можем оценить уровень заряда. Но не всё так однозначно. Дело в том, что напряжение аккумулятора при разряде изменяется не линейно. Это видно из графика разряда литий-ионного аккумулятора, который легко найти в google по запросу li-ion discharge graph:

График разряда аккумулятора Panasonic NCR18650B

Данный график позаимствован с сайта batteryuniversity. На нём отражён процесс разряда аккумулятора Panasonic NCR18650B 3200мАч разными токами от 0.2C до 2C. Как видите, напряжение аккумулятора изменяется более-менее линейно лишь при разряде большими токами. Здесь можно вспомнить математику и посчитать процент оставшегося заряда по линейной формуле. Но это, скорее, частный случай. Пожалуй, более актуальны случаи, когда устройство потребляет незначительные токи, поэтому ориентироваться мы будем на красную и синюю кривые.

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

Следующий момент, который я беру во внимание – это то, что высокая детализация уровня заряда (в тех же процентах, которые дают нам 100 значений) бывает нужна крайне редко. В большинстве случаев достаточно понимания: когда уровень заряда находится в «зелёной зоне», когда в «жёлтой», а когда нужно быть готовым к отключению устройства из-за разряда аккумулятора. Поэтому наиболее рациональным представляется подход, когда мы выделяем 3-4 пороговых напряжения и относительно них определяем уровень заряда. Грубо говоря, если напряжение литий-ионного аккумулятора больше 4 В, то заряд высокий; если меньше 3.2 В – аккумулятор вот-вот разрядится, а между этими двумя значениями выделяем еще несколько зон. Если необходимо выразить заряд именно в процентах – пожалуйста: выделяем 10 зон и показываем результат десятками (10%, 20% и т.д.).

Читайте так же:
Законы по водным счетчикам

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

Реализация

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

  • измерять напряжение, используя АЦП Ардуино;
  • воспользоваться датчиком напряжения, например, INA219.

Первый вариант хорош тем, что для него ничего не требуется. Разве что пара резисторов. А датчик напряжения – это уже дополнительный компонент. Зато он позволит более точно измерять напряжение. Кроме того INA219 измеряет потребляемый ток и мощность, поэтому имеет потенциал для дальнейшего развития в плане мониторинга питания (с его помощью можно построить ту же кривую разряда аккумулятора, определить его ёмкость, спрогнозировать время работы устройства), но это уже отдельная тема.

Вариант 1. Измерение напряжения при помощи Ардуино.

Все платы Ардуино имеют в своём составе АЦП. У популярных плат (UNO, NANO, MEGA2560) разрядность АЦП составляет 10 бит, у более продвинутых (Due, Zero) – 12 бит. АЦП позволяет измерять напряжение в диапазоне от 0 В до опорного напряжения Vref. Значение Vref в общем случае соответствует напряжению питания платы – 5 В или 3.3 В, но может быть привязано к внутреннему стабилизатору. Для лучшего понимания принципов использования АЦП предлагаю рассмотреть следующий скетч.

Загрузите скетч в Ардуино, соедините A0 с выводом 5V и откройте монитор порта. Вы должны увидеть следующий результат:

Arduino analogRead 1023

Этот скетч измеряет напряжение на входе A0 и выводит результат в монитор порта. Разрешение АЦП используемой мной Ардуино УНО составляет 10 бит, а значит, результатом измерений будет число от 0 до 1023 (2^10 значений). При этом значение 0 будет говорить об отсутствии напряжения, а максимальное значение – 1023 – о его равенстве (а так же превышении, что мы не будем рассматривать) опорному напряжению Vref, каким бы оно ни было. У меня в монитор порта выводится как раз число 1023. Поскольку опорным напряжением АЦП по умолчанию является напряжение питания Ардуино – 5 вольт, выдаваемые USB портом компьютера (разумеется, это не точное значение), можно утверждать, что напряжение на входе A0 тоже составляет 5 вольт.

Попробуем отсоединить A0 от вывода 5V и подсоединить к 3v3. Теперь у меня в монитор порта выводится значение 687. Зная опорное напряжение, нетрудно вычислить напряжение на A0:

(5 В / 1024) * 687 = 3.35 В

Для получения более точного результата следует измерить напряжение, выдаваемое USB портом.

Если же вывод A0 соединить с «землёй», то в монитор порта будет выводиться значение 0.

Вернёмся к нашей задаче. Питание от аккумулятора не всегда предполагает наличие стабильного напряжения, которое может использоваться как опорное для АЦП. В таких случаях в качестве Vref следует использовать напряжение от внутреннего стабилизатора Ардуино. Для большинства плат, в том числе Ардуино УНО, это напряжение составляет 1.1 В. Это означает, что измеряемое напряжение необходимо понизить при помощи делителя, чтобы оно не превышало 1.1 В. Здесь нам помогут пара резисторов номиналом в несколько десятков-сотен кОм, включенные по следующей схеме:

Делитель напряжения на резисторах

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

Сам коэффициент рассчитывается по следующей формуле:

Остаётся лишь подобрать номиналы резисторов таким образом, чтобы понизить напряжение аккумулятора до нужного нам уровня. Для измерения напряжения аккумулятора 18650 я выбрал номиналы 47k и 10k. Реальное сопротивление будет отличаться, поэтому их нужно обязательно измерить мультиметром. Выбранные мной номиналы дают коэффициент

0.175, что позволяет измерять напряжение до 1.1 В / 0.175 = 6,27 В. Ниже приведены схема, пример скетча, реализующий описанный функционал, и результат его работы. Предполагается, что Ардуино питается от аккумулятора, поэтому результаты выводятся на дисплей 1602, а не в Serial.

Определение уровня заряда аккумулятора. Делитель напряжения

Результат измерения уровня заряда 18650 lcd1602

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

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

Опорное напряжение, выдаваемое внутренним стабилизатором, не обязательно будет 1.1 В, и может отличаться от одного микроконтроллера к другому. Даташит допускает разброс от 1.0 до 1.2 В. Поэтому для получения более точных измерений можно вычислить значение Vref и использовать его в скетче при расчетах. Его легко найти путём измерения заранее известного напряжения (обозначим его как V(A0)):

Vref = V(A0) * 1024 / analogRead(A0)

Вариант 2. Использование датчика напряжения INA219.

После шаманства со всеми этими делителями и внутренними источниками опорного напряжения преимущество датчиков напряжения на базе специализированных микросхем очевидно. Они позволяют измерять напряжение (а некоторые ещё и потребляемый устройством ток) в широком диапазоне и с высокой точностью. INA219 – хороший пример такого датчика. Он потребляет не более 1мА, а в спящем режиме менее 15мкА, что весьма ценно при создании автономных устройств, в условиях энергосбережения. Подробное описание датчика и используемой далее библиотеки для работы с ним вы найдёте здесь: https://compacttool.ru/datchik-napryazheniya-i-toka-na-chipe-ina219

Для отслеживания уровня заряда аккумулятора 18650 при помощи INA219 и вывода результата на дисплей я соединил компоненты в соответствии со схемой:

Определение уровня заряда аккумулятора. INA219

В этот раз я решил выделить 10 уровней заряда, чтобы отображать его в процентах. Скетч и результат его работы ниже:

Измерение уровня заряда 18650. LCD1602

Заключение

Конечно, предложенный способ не претендует на высокую точность. Существуют специализированные микросхемы мониторинга питания, которые определяют оставшуюся ёмкость аккумулятора с учётом нагрузки и других параметров. Они находят применение в ноутбуках, телефонах и другой портативной технике. Но вряд ли вы найдёте что-то подобное в любительских проектах – не тот уровень. Таким образом, определение уровня заряда аккумулятора по напряжению – приемлемая альтернатива, не требующая серьёзных аппаратных или программных ресурсов.

Arduino uno счетчик импульсов

Еще давно, во время ремонта, я установил в квартиру многотарифный счетчик Меркурий 200.02.
Немного о счетчике: это самый дешевый многотарифный однофазный счет от Инкотекс. Стоимость на сегодняшний день — 1250 руб.
Если у кого-то еще стоит одно тарифный счетчик, то быстрее меняйте. У меня за пол года разница в рублях сопоставляет 3500 руб. Т.е. много-тарифный счетчик окупается примерно за два месяца.

Читайте так же:
Счетчик меркурий с симкой

Что бы не быть голословным — вот мои показатели:

На начало января 2013
тариф1 тириф2 тариф3 сумма
4300.18 5302.61 5906.07 15508.86

На начало июля 2013
тариф1 тириф2 тариф3 сумма
5100.60 6268.54 6935.90 18305.04

Всего с января по июль было истрачено :
тариф1 : 800 , 42кв / ч
тириф2 : 965 , 93кв / ч
тариф3 : 1029 , 83кв / ч
сумма : 2796 , 18кв / ч

При одно тарифном счетчике я бы заплатил 2796 , 18 * 4.02 = 11240 , 64 руб .
На многотарифном : 800 , 42 * 4.03 + 965 , 93 * 1 , 01 + 1029 , 83 * 3.39 = 7692 , 41 руб .

Кроме экономии, есть у Меркурия еще один плюс. Наличие шины данных. У меркурия 200 это CAN-шина, у других моделей тоже CAN или RS485. Так есть модели с IRDA и GSM. Но это уже более дорогие модели.

Производитель счетчиков, предлагает ПО для чтения показаний:
http://www.incotexcom.ru/ME_po.htm

Так же есть программа "Конфигуратор", при помощи которой можно дистанционно читать показания счетчика, смотреть текущее напряжение и расход. http://dl.dropbox.com/u/3467322/RSS/. nfigurator.zip

Но для подключения счетчика к компьютеру нужен адаптер.
Можно купить либо:

1. Преобразователь USB RS485
плюсы: стоит недорого
2. Адаптер Меркурий 221. USB — CAN и RS485
плюсы: USB, и может работать как с CAN так и с RS485
минусы: цена. 3000 руб. за такое примитивное устройство — дорого.
3. Остальные адаптеры еще дороже.

В общем на помощь как всегда пришла палочка-выручалочка arDuino Nano
Так же нам понадобиться микросхема CAN:
PCA82C250T- проверено
либо аналоги: (не проверено)
TJA1040T
TJA1050T

Все, адаптер готов. В итоге он обошелся мне в 80 руб, и 20 минут работы с паяльником. Arduino у меня уже была. Но если бы пришлось покупать, то адаптер обошелся бы в 810 руб.

Кстати, на всякий случай залил скетч:

void setup () <
pinMode ( 0 , INPUT );
pinMode ( 1 , INPUT );
>

Это скорее всего на всякий случай.

Дальше запускаем Конфигуратор.
— В поле адрес указываем 6 последних цифр серийного номера.
— выбираем RS485/CAN
— ставим галку в поле "ЭХО"
— настройки COM порта оставляем по умолчанию
— нажимаем "Соединить"

Если все правильно, то соединение установиться. Если нет, то возможны следующие причины:
1. У Вас счетчик не Меркурий 200.02 (без CAN)
2. Не правильно введен сетевой адрес. В этом случае попробуйте запустить встроенную программу подбора адресов. Запускается она сочетанием клавиш Ctr-Alt-N. Не знаю как это работает, но программа начинает подбирать адрес. Занимает это около 5-ти минут — что странно. Но попробуйте. Еще возможно Вы неправильно подключили CAN шину. В этом случае попробуйте поменять полярность на шине.

Теперь следующий шаг — написать PHP скрипт для роутера wt3020h прошитый CyberWRT. Так им образом можно будет читать показания из браузера на любом устройстве, включая телефоны на Android или iPhone.

lvovitch
Посмотреть профиль
Найти ещё сообщения от lvovitch
Sirocco
Посмотреть профиль
Найти ещё сообщения от Sirocco
каким образом вытащить данные php скриптом? И откуда вытащить? Из программы для меркурия? Тоесть всегда должен работать комп под виндовс? Или из кардуино?

Я думаю что все это хозяйство нужно конектить с роутером nexx а на роутере установить вебсервер с PHP5 и Sqlite
Ну и написать веб приложение, ко всему этому хозяйству

Не хочу даже проверять, но приведённый скетч, это ваще что?
Admin
Посмотреть профиль
Отправить личное сообщение для Admin
Найти ещё сообщения от Admin

А вот интересно по какому каналу энергослужба будет конектится к эл. счетчику. Она свой интернет подводить будет?
Вопрос интересен с точки зрения снятия показания счетчика самому, так сказать не подходя к нему физически. Для энергослужбы наверно тоже не плохо, если всех посадить на такие счетчики и обходчиков уволить

Судя по коду это скетч для использования Arduino в качестве UART-USB моста
andr128
Посмотреть профиль
Отправить личное сообщение для andr128
Найти ещё сообщения от andr128

Адаптер USB-RS485. CAN из RS485 получается переворотом букв AB — BA. На проводе в 20 см даже никакие дополнительные резисторы не нужны. Далее берется сетевой модуль за $15 отсюда с установленной OpenWrt и программкой ser2net для получения сетевого COM-порта (либо локальный uhtpd c php). В результате получается ethernet+wifi адаптер для считывания показаний счетчика. Протокол обмена и php скрипты есть в инете. С техникой все просто.

Дальше начинаются юридические проблемы. Чьей собственностью является счетчик? Если Вашей, то Вы имеете полное право подключать к интерфейсу провод и считывать с него данные, но только в режиме чтения. Но все это нужно делать официально через письменное заявление на имя начальника местных сетей или сбыта.

Но намного проще считывать данные с IrDA или оптопорта — не надо никаких формальностей и пломбы будет целы. В PLC лезть вообще не рекомендуется, Вы можете нарушить работу всей системы сбора данных (дома, района и т.п.). А это уже административная либо даже уголовная ответственность.

Система работает так: есть сервер с симкой — коробочка с экраном или без, с внешней антеной, модем PLC — коробка размером с кирпич, только чуть тоньше, имеет USB выход и питание 220В, с которых и собирает сигналы от счётчиков) или CAN преобразователь. Модем опрашивает счётчики раз в два-три часа, иногда, в многоквартирных домах, два-три раза в сутки, информация летит на сервер и хранится там, не менее пяти суток. Модем в сервере работает не через GPRSEDGE3G4G, а поднимается через голосовую связь ВХОДЯЩИМ вызовом на скорости до 9600 битсек Образуется бесплатное соединение для симки модема. Соединение (входящий вызов) на сервер с данными показаний инициируется общим сервером из диспетчерской, куда стекаются показания со всех домов. Так что по сути интернета там нет, просто образуется канал связи поверх голосового канала между двумя устройствами. Также есть счётчики с симками, на них можно "позвонить" и снять данные таким образом. Это как правило трёхфазные счётчики установленные на подстанциях.

голоса
Рейтинг статьи
Ссылка на основную публикацию
Adblock
detector