avatar_UriBas

Моргалка на Arduino. Этюды для начинающих.

Автор UriBas, 08 Март 2017 в 16:08

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

UstAlexei

На крайний случай простой транзисторный усилитель, и ток в h21 больше входного.

Dunkel

Цитата: Alex_N от 16 Дек. 2017 в 13:07
Странно, для моргалок это самое важное.  40 ма - это очень мало. Чуть перегрузил и привет. Я так штук пять процессоров сжег. Вернее они работают, а порты битые.

А что подключали?
Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

Кass

Цитата: mr.Dream от 15 Дек. 2017 в 03:41У avr после сброса каждая нога порта переходит в высокоомное состояние без подтяжки. А в современных камнях нету разницы нагружать верхний или  нижний ключ выхода порта. Они комплементарные. И контроллер не будет греться, на выходные ключи идёт отдельная шина, как по минуса так и по плюсу. Это ранние версии имели болезнь. За последнее десятилетие много чего изменилось. В даташитах это обычно указано.  Например на тини13 есть сравнительная таблица. Индекс а позволяет нагружать по 40мА как по верхнему так и по нижнему ключу. Хотя более ранние версии имели асимметрию 10\40 мА из за проблем с технологией p-канальных фетов. А древние на биполярах вообще имели резистор подтягивающий и один npn транзистор. Все меняется)))

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

Цитата: Alex_N от 16 Дек. 2017 в 13:07Странно, для моргалок это самое важное.  40 ма - это очень мало. Чуть перегрузил и привет. Я так штук пять процессоров сжег. Вернее они работают, а порты битые.

Возьмите за привычку подключать что то к портам МК через токоограничивающие резисторы. Взяли оптом упаковку по 270 Ом и пихайте их на любой выход.
АРМ стенда онлайн: http://scada.kontar.ru Пользователь: Электротранспорт, Пароль: 111111

Гербалайф от всех болезней, Кашпировский лучший врач,  Орифлейм самая лучшая косметика, а МММ самый лучший способ вложения денег. Кто бы спорил. ;)

SanSanich

Цитата: Кass от 16 Дек. 2017 в 15:22Возьмите за привычку подключать что то к портам МК через токоограничивающие резисторы. Взяли оптом упаковку по 270 Ом и пихайте их на любой выход.
Ну может на любой и не надо! Если там уже есть свой делитель, на ЖК (хотя и можно, но у меня прецедентов не было).
ЗУК "ЖУЖА" Самодельный измеритель Rвн https://electrotransport.ru/index.php?msg=1280851

Alex_N

"А что подключали?"

Транзисторы. На работе табло делал. Куча мощных св. диодов. На базу выход с проца. Пока операционники не повесил - пару портов нет. Короче надо делать сразу нормально. А когда торопят, или сам решил "по быстрому что то слепить", то бывает не обращаешь внимание на такие мелочи как ток базы и т. д.
Токоогр. резисторы - так всё это знаем, но не всегда получается.

ИС-Х

Цитата: Alex_N от 16 Дек. 2017 в 18:26На базу выход с проца.
Непосредственно, напрямую?
Моя первая моргалка: https://electrotransport.ru/index.php?msg=588520
Вторая моргалка: https://electrotransport.ru/index.php?topic=31184.0
Третья моргалка: https://electrotransport.ru/index.php?msg=1130718
Еще в багажнике валяется BL1204 на всякий пожарный...

11vetal

Применяя МК нужно всегда смотреть на электрические характеристики портов. Допустим у Atmel-ов это очень хорошо описано и перечислены порты на которые можно нагружать 20мА и на которые не более 10мА и еще нужно смотреть, чтобы не превысить общую нагрузку, иначе беда с выгоревшими портами неминуема.
А так, да без ограничительных резисторов ни куда и на базу биполярного транзистора без резистора никак нельзя .
Тебя оскорбили - забудь... Тебя унизили - прости... Тебя ударили - вспомни ... б**дь, всё ВСПОМНИ и накажи!!!

Кass

Цитата: Alex_N от 16 Дек. 2017 в 18:26Транзисторы. На работе табло делал. Куча мощных св. диодов. На базу выход с проца.

Если без резистора, то понятно, что это жесть. На затвор еще ладно, хотя и там крайне рекомендуется на всякий случай поставить резюк. Если есть резюк, то хоть сколько светодиодов цепляй, с какого то количества им просто тока не хватит, но порту ничего не будет.
АРМ стенда онлайн: http://scada.kontar.ru Пользователь: Электротранспорт, Пароль: 111111

Гербалайф от всех болезней, Кашпировский лучший врач,  Орифлейм самая лучшая косметика, а МММ самый лучший способ вложения денег. Кто бы спорил. ;)

Alex_N

Да понятно, что с резисторами. Но порты всё равно горят. Нежные они очень.
Св. диоды очень мощные, и их очень много было. В результате МК, резюк, операционник, резистор, транзистор, св-диоды.
Сперва в этой цепочке не было операционника. Порты горят. Не сразу. Поработают немного и привет.

Кass

[user]Alex_N[/user], вы не о том пишите. Если вы порт подключаете через 270 ом, то плевать сколько там светодиодов, хоть накоротко на землю посадите. Ничего не будет МК.
АРМ стенда онлайн: http://scada.kontar.ru Пользователь: Электротранспорт, Пароль: 111111

Гербалайф от всех болезней, Кашпировский лучший врач,  Орифлейм самая лучшая косметика, а МММ самый лучший способ вложения денег. Кто бы спорил. ;)

SanSanich

Цитата: Кass от 17 Дек. 2017 в 21:00Если вы порт подключаете через 270 ом, то плевать сколько там светодиодов, хоть накоротко на землю посадите. Ничего не будет МК.
В подтверждение, I=U/R=5/270=0,0185185185185185 A. А это 18мА, они не спалят порт.
ЗУК "ЖУЖА" Самодельный измеритель Rвн https://electrotransport.ru/index.php?msg=1280851

geometr

Приветствую участников форума. Не так давно озаботился созданием "умной" зарядки для АКБ. Простая уже была, переделанная из компьютерного БП со стабилизацией тока и напряжения, но захотелось большего. Наткнулся на этот форум и почерпнул для себя много полезной информации. После чего для начала решил соорудить моргалку на Ардуино. С Ардуино знаком давно, делал несколько проектов, но программист из меня - так себе, поэтому конструктивная критика принимается. Итак, в программе реализовано:
1 Моргалка с устанавливаемым временем заряда/паузы, установкой частоты и заполнением несущей.
2 В режиме "добивки" при достижении заданного напряжения происходит уменьшение заполнения ШИМ вплоть до устанавливаемого значения, по достижении которого зарядка считается оконченной. Таким образом реализуется адаптивный заряд.
3 Отображение на двухстрочном дисплее (1602) текущего напряжения на АКБ (В), среднего зарядного тока (А), залитого в АКБ количества электричества (А*ч) и времени заряда (чч:мм). По достижению режима "добивки" показания напряжения на АКБ начинаю мигать. По окончании заряда мигает надпись "Charging is over" и отображается залитое в АКБ количество электричества и время зарядки.

ШИМ реализован на библиотеке PWM.h. Измерение тока и напряжения - с помощью прерываний и библиотеки MsTimer2.
Схему можно использовать из первого поста. У меня уже была похожая распаянная схема от другого проекта, поэтому путем некоторой доработки использовал ее. Там реализация не совсем правильная (хотя все работает), поэтому ее не привожу. Могу только сказать что использовал 2 мосфета NTD4860N от старой видюхи и простой драйвер - эмиттерный повторитель на двух транзисторах. При токе в импульсе 15А и 50% заполнении мосфеты без радиаторов нагревались где-то до 55 градусов.
Испытывал схему на АКБ 72Ач DETA Senator3 со своей "кастрюли". Ему уже больше 5 лет, поэтому начинает потихоньку сдавать. Пока не было времени довести зарядку до конца, машина постоянно нужна, но аккумулятор после зарядки "моргалкой" заметно повеселел и даже показал давно уже не появлявшийся зеленый глазок)))

Спойлер

// Моргалка для заряда АКБ
// Arduino UNO и иже с ними

#include <MsTimer2.h>
#include <avr/wdt.h>
#include <PWM.h>
#include <LiquidCrystal.h>

#define Ver "0.2"   // версия программы

#define CUTOFF_U 14.4       // напряжение окончания заряда (В)
#define FREQUENCY 35        // частота ШИМ (Гц)
#define DUTY 50.            // коэффициент заполнения ШИМ ( % )
#define CHARGE_PERIOD 22    // время заряда (сек)
#define IDLE_PERIOD 8       // время паузы (сек)
#define MIN_DUTY 10         // минимальное заполнение при котором заканчивается "добивка" (8-битное значение)

// выводы
#define OUT_PWM_PIN 9           // вывод ШИМ
#define OUT_LED_PIN 13          // вывод моргалки на светодиод
#define IN_MEASURE_U_PIN 14     // вывод измерения напряжения
#define IN_MEASURE_I_PIN 15     // вывод измерения тока

// Для измерения тока и напряжение используется опорное напряжение Ардуино Uref = 1,1 В.

#define koeffU1 0.015441      // масштабный коэффициент напряжения (Umax = 15.81 В)
// koeffU1 = Uref / R1 * (R1 + R2) / 1024 = 1.1/990*(990 + 13240)/1024 = 0.015217 В/ед. АЦП
#define koeffI  0.042969     // массштабный коэффициент тока для Imax = 44 А
// koeffI =  Uref / R3 / 1024 = 1.1 / 0,025 / 1024 = 0.042421875 А/ед. АЦП

#define MEASURE_PERIOD 50   // время периода измерения (* 1 мс)

LiquidCrystal disp(3, 2, 7, 6, 5, 4); // создаем объект дисплей (RS, E, D4, D5, D6, D7)

uint8_t interruptCount = 0;            // счетчик циклов прерываний
uint8_t chargeMode = 1;                // режим заряда: 1 - заряд до установленного напряжения (основной), 2 - "добивка",
// 3 - окончание зарядки
uint16_t sumU, sumI;                // переменные для суммирования кодов АЦП
uint16_t averageU, averageI;        // средние значения кодов АЦП
float measureU, measureI;           // измеренное напряжение и ток, В, А
float sumCap = 0;                   // накопленное значение отданного количества электричества, А*ч
boolean flagReady;                  // признак готовности данных измерения
boolean flagEnableCharge = true;    // признак разрешения заряда
boolean pwmON = true;               // признак разрешения работы ШИМ
boolean noDispPar = false;          // признак вывода параметров на экран
boolean pause = false;              // признак паузы при "добивке"
uint32_t time, timePrev;            // переменные для отработки millis()
uint8_t cycle50mcCount;             // счетчик циклов 50 мс
uint8_t duty;                       // коэффициент заполнения ШИМ от 0 до 255
uint16_t chargePeriod, idlePeriod;  // период заряда и паузы, мс
char *chargeTime, *chargeTimeEnd;   // строка с временем зарядки

void setup() {

  Serial.begin(9600);              // инициализируем порт, скорость 9600 бод
  analogReference(INTERNAL);       // опорное напряжение 1,1 В
  MsTimer2::set(1, timerInterupt); // прерывания по таймеру с периодом 1 мс
  MsTimer2::start();               // разрешение прерывания
  wdt_enable(WDTO_15MS);           // разрешение работы сторожевого таймера, тайм-аут 15 мс

  disp.begin(16, 2);            // инициализация дисплея
  disp.setCursor(2, 0);         // устанавливаем позицию курсора
  disp.print("BlinkCharger");   // заставка
  disp.setCursor(4, 1);
  disp.print("ver ");           // отображение версии ПО
  disp.print(Ver);
  delay(500);                   // длительность отображения заставки

  InitTimersSafe();                         // инициализация таймера для ШИМ
  SetPinFrequency(OUT_PWM_PIN, FREQUENCY);  //устанавка частоты ШИМ

  duty = (uint8_t)(DUTY / 100 * 256);       // перевод заполнения ШИМ в соответствии с разрядностью

  chargePeriod = 1000 * CHARGE_PERIOD;      // период заряда, мс
  idlePeriod = 1000 * IDLE_PERIOD;          // период паузы, мс

  pinMode(OUT_LED_PIN, OUTPUT);             // установка вывода для светодиода
}

void loop() {

  //------------------------------- ВЫПОЛНЕНИЕ ОПЕРАЦИЙ В ЦИКЛЕ 50 МС -----------------------------------------
  if (flagReady == true) {
    flagReady = false;

    //------------------------------- вычисление измеренных параметров -----------------------------------------

    // вычисление напряжения
    measureU = (float)(averageU / MEASURE_PERIOD) * koeffU1;
    if (measureU < 0) measureU = 0;
    // вычисление тока
    measureI = (float)(averageI / MEASURE_PERIOD) * koeffI;
    if (measureI < 0) measureI = 0;
    // вычисление переданного батарее тока, А/ч
    sumCap = sumCap + 1.3888889E-5 * measureI; // 1.38E-5 - коэффициент пересчета отданного количества электричества за 50 мс в А*ч

    noDispPar = false; // отображать параметры на дисплее

    //--------------------------- управление зарядом/паузой ---------------------------------------------------

    if (measureU >= CUTOFF_U && chargeMode != 3) {
      chargeMode = 2;                    // установка режима "добивки" при превышении заданного напряжения на АКБ
      flagEnableCharge = false;          // запрет зарядки
      pause = false;
      pwmON = false;
      duty = duty - 1;                   // уменьшение заполнения при превышении установленного напряжения при "добивке"
      if (duty <= MIN_DUTY) {            // ограничение минимального заполнения, признак окончания "добивки"
        duty = 0;
        chargeMode = 3;                  // установка признака окончания зарядки
        chargeTimeEnd = TimeToString(millis() / 1000);  // фиксация продолжительности зарядки
      }
    }
    if (measureU < CUTOFF_U && !pause) { // запуск паузы в режиме "добивки" при снижении напряжения на АКБ меньше установленного
      timePrev = millis();
      pause = true;
    }
    if (pause) {                        // отсчет времени паузы в режиме "добивки"
      if ((millis() - timePrev) > 1000 * IDLE_PERIOD) {
        flagEnableCharge = true;
        pause = false;
      }
    }
    if (flagEnableCharge) {             // запуск заряда с установленным временем заряда и паузы
      if ((millis() - time) > (pwmON ? chargePeriod : idlePeriod)) {
        pwmON = !pwmON;
        time = millis();
      }
    }
    if (chargeMode != 3 && pwmON) {
      pwmWrite(OUT_PWM_PIN, duty);      // запуск ШИМ
      digitalWrite(OUT_LED_PIN, HIGH);
    } else {
      pwmWrite(OUT_PWM_PIN, 0);         // остановка ШИМ
      digitalWrite(OUT_LED_PIN, LOW);
    }

    //-------------------------- Распределенные вычисления в цикле 500 мс ---------------
    cycle50mcCount++;   // счетчик циклов 50 мс

    if (cycle50mcCount >= 10) {
      cycle50mcCount = 0; // время цикла 500 мс
    }
    if (cycle50mcCount == 8 ) {
      // вывод измеренных значений в порт
      Serial.print(measureU, 2);
      Serial.print(", ");
      Serial.print(measureI, 2);
      Serial.print(", ");
      Serial.println(duty);
    }

    if (cycle50mcCount == 9) {
      if (chargeMode !=3) chargeTime = TimeToString(millis() / 1000); // вычисление времени зарядки
      if (noDispPar == false) {
        dispParameters(); // отображение параметров на дисплее раз в 0.5 с
      }
    }
  }
}
//------------------------------ индикация параметров -------------------
void dispParameters() {
  static uint8_t i;
  char str1[8], str2[8], str3[8];      // строковые массивы для форматирования вывода
  disp.clear();                        // очистка дисплея
  if (chargeMode != 3) {
    dtostrf(measureU, 5, 2, str1);     // преобразование float в форматированную строку
    if (chargeMode == 2) {             // реализация мигания значения напряжения на АКБ в режиме "добивки"
      i++;
      if (i == 1) {
        disp.print(str1);              // напряжение на АКБ, В
        disp.print(" V");
      }
      if (i >= 2) i = 0;
    } else {
      disp.print(str1);                // напряжение на АКБ, В
      disp.print(" V");
    }
    disp.setCursor(9, 0);
    dtostrf(measureI, 5, 2, str2);     // преобразование float в форматированную строку
    disp.print(str2);                  // средний зарядный ток, А
    disp.print(" A");
    disp.setCursor(0, 1);
    dtostrf(sumCap, 6, 2, str3);       // преобразование float в форматированную строку
    disp.print(str3);                  // отданное батарее количество электричества, А*ч
    disp.print(" Ah");
    disp.setCursor(11, 1);
    disp.print(chargeTime);            // время с начала зарядки, чч:мм
  } else {
    i++;                               // реализация мигания надписи
    if (i == 1) disp.print("Charging is over");
    if (i >= 2) i = 0;
    disp.setCursor(0, 1);
    dtostrf(sumCap, 6, 2, str3);       // преобразование float в форматированную строку
    disp.print(str3);                  // отданное батарее количество электричества, А*ч
    disp.print(" Ah");
    disp.setCursor(11, 1);
    disp.print(chargeTimeEnd);         // продолжительность зарядки, чч:мм
  }
}
//------------------------------ обработка прерывания по таймеру 1 мс
void  timerInterupt() {
  wdt_reset();                           // сброс сторожевого таймера
  interruptCount++;                      // счетчик циклов прерываний

  // измерение напряжения и тока

  sumU += analogRead(IN_MEASURE_U_PIN);  // измерение мгновенного значения напряжения и суммирование выборок АЦП
  sumI += analogRead(IN_MEASURE_I_PIN);  // измерение мгновенного значения тока и суммирование выборок АЦП

  if ( interruptCount >= MEASURE_PERIOD ) {  // проверка числа выборок усреднения
    interruptCount = 0;
    averageU = sumU;                     // перегрузка среднего значения
    averageI = sumI;                     // перегрузка среднего значения
    sumU = 0;
    sumI = 0;
    flagReady = true;                    // признак готовности результата измерений
  }
}
//---------------------------------- Функция для отображения времени ----------------------------------
char *TimeToString(unsigned long t) {
  static char str[8];
  int h = t / 3600; // часы
  t = t % 3600;
  int m = t / 60; // минуты
  int s = t % 60; // секунды
  if (chargeMode !=3){
  if (s%2 == 0) sprintf(str, "%02d:%02d", h, m);
  else sprintf(str, "%02d %02d", h, m);
  } else sprintf(str, "%02d:%02d", h, m);
  return str;
}
Конечно же это только начало и в планах реализация полноценной зарядки "с БлэкДжэком и шлюхами", а пока так :-)

Alex_N

Цитата: Кass от 17 Дек. 2017 в 21:00
[user]Alex_N[/user], вы не о том пишите. Если вы порт подключаете через 270 ом, то плевать сколько там светодиодов, хоть накоротко на землю посадите. Ничего не будет МК.
2*2=4. Элементарщина. А мощные транзисторы при этом откроете ?

Alex_N

Я бы хотел подытожить своё "видение" моргалки.
1. 5В кренка для питания МК.
2. 12В кренка для питания драйвера.
3 . Выход с МК (ШИМ, или просто blink) через резистор ( по просьбам трудящихся ) на вход драйвера.
4. Драйвер ( можно с опторазвязкой ) желательно с двумя выходами, один из которых инверсный, для управления двумя igbt транзисторами.
Ну вот собственно и всё. Можно подключать не только к МК, но и к какой нибудь схеме генерации импульсов.

Dunkel

Цитата: Alex_N от 18 Дек. 2017 в 08:052. 12В кренка для питания драйвера.

А нужна ли эта кренка? По ДШ и драйвер, и мосфеты терпят до 20В. А больше и не надо.
Многофункциональная облачная моргалка/логгер:
https://morgalka78.wordpress.com/

Alex_N

А если понадобится 30 ? А вообще каждый сам решает. Кому то и одного транзистора за глаза. Я описал универсальный вариант.

UriBas

#646
Цитата: geometr от 18 Дек. 2017 в 01:06
1 Моргалка с устанавливаемым временем заряда/паузы, установкой частоты и заполнением несущей.
2 В режиме "добивки" при достижении заданного напряжения происходит уменьшение заполнения ШИМ вплоть до устанавливаемого значения, по достижении которого зарядка считается оконченной. Таким образом реализуется адаптивный заряд.  .. 
Судя по коду, заряд до 14,4В идет без пауз, т.е. постоянным током? Ток задаете вручную на БП (блоке питания)?  Пауза в добивке не меняется, длит импульса тоже, регулировка только ШИМом.. конец заряда (добивки) происходит,  когда коэф заполнения достигнет минимального значения..      Адаптивным зарядом это называть рановато, поскольку адаптивный предполагает подбор ПОРЦИИ ЗАРЯДА  - т.е.  таких параметров как ток заряда или его среднего значения, а также паузы, длит импульса и пр.,  на всех этапах.
Восточная мудрость - "Шакал воет - караван идет"  Эл.вел. 350Вт.   Верую в Иисуса Христа, НЛО.  тема "продвинутой моргалки" https://electrotransport.ru/index.php?msg=1669651

geometr

Цитата: UriBas от 18 Дек. 2017 в 19:04Судя по коду, заряд до 14,4В идет без пауз, т.е. постоянным током?
Нет. И в режиме заряда до 14,4 В пауза есть.  И ШИМ тоже. Вы, наверное, не совсем разобрались с кодом.
Цитата: UriBas от 18 Дек. 2017 в 19:04Ток задаете вручную на БП (блоке питания)?
Да, ток устанавливается на БП. Средний ток устанавливаю 0,1С, соответственно ток в импульсе при 50% заполнении ШИМ будет в 2 раза больше.
Цитата: UriBas от 18 Дек. 2017 в 19:04Адаптивным зарядом это называть рановато, поскольку адаптивный предполагает подбор ПОРЦИИ ЗАРЯДА  - т.е.  таких параметров как ток заряда или его среднего значения, а также паузы, длит импульса и пр.,  на всех этапах.
Да, конечно, это не совсем адаптивный заряд но некоторая обратная связь есть. Я не претендую на оригинальность, но уменьшение заполнения ШИМ в режиме "добивки" вроде бы никто еще не реализовывал. Как показали мои испытания, этот вариант очень даже хорошо отрабатывает. АКБ вполне адекватно реагирует на уменьшение скважности даже на единицу, принимая ток в таком состоянии достаточно долго до следующего превышения порога в 14,4В.
Да, время периода заряда и паузы выбрано практически основываясь на опыте этого форума, а кто скажет какое оно должно быть и по какому закону меняться? Ведь, насколько я смог понять, читая форум, знают его только несколько избранных :kidding: