avatar_Паяка

Универсальный модуль разрядной моргалки для Ардуино и не только

Автор Паяка, 17 Сен. 2018 в 15:11

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

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

Паяка

#252
[user]SapienzSPB[/user], протокол нешифрованный, описан даже на странице товара на Али. Хорошим решением видится модуль логгера и беспроводного интерфейса на ESP8266. Чтобы ESP8266 записывал и хранил логи, а загружать их можно было на телефон или ПК, и управлять с них же. Так получаем и автономную работу с сохранением данных, и гальваноразвязку, и отсутствие надобности дёргать SD-карту.

Получается, берём 3 недорогих модуля: показометр, ESP8266, SD шилд, соединяем проводками и получаем хоть эксплуатационный мониторинг АКБ, хоть контроллер разрядного устройства или даже многофункциональное ЗУ, с экраном!

Добавлено 20 Мар 2019 в 22:20

[user]serggio[/user], варианты разные могут быть. Если показометр может и управлять нагрузкой с гистерезисом, почему бы им не воспользоваться? Удобство управления одной кнопкой сомнительно, но есть интерфейс для управления и логов. А предположения по отдалённым перспективам пока просто для вдохновения.

Вольтметр, амперметр, калькулятор производных величин с энергонезависимой памятью, с экраном, кнопкой, логическим выходом, вещанием показаний и управлением по последовательному интерфейсу, и всё это в крохотном недорогом модуле, - разве плохо для практики?

Версию на Ардуино я доделаю и разовью. На неё просто не было времени. А показометр можно взять уже сейчас, добавить мосфет или дарлингтон на радиаторе и ОУ, получить разрядное устройство, да не с 7-сегментным 3-4-разрядным индикатором, а экраном, отображающим много параметров.

При желании, можно даже шунт показометра задействовать в ОС разрядной нагрузки, если у неё всего один канал.
GT TF1 60V 20Ah Chilwee DZF

serggio

Цитата: Паяка от 20 Март 2019 в 22:17Вольтметр, амперметр, калькулятор производных величин с энергонезависимой памятью, с экраном, кнопкой, логическим выходом, вещанием показаний и управлением по последовательному интерфейсу, и всё это в крохотном недорогом модуле, - разве плохо для практики?
Это слова из рекламы телемагазина для кухарок? Типо самая лучшая лапшерезка?
Какой еще вольметр, какой амперметр?
Вы обратите внимание на нагрузку схему которой я давал много страниц выше.
Там для вольт-амперных дел используется даже не МК, там внешние АЦП.
А в этих свистелках просто показометры.
Цитата: Паяка от 20 Март 2019 в 22:17А показометр можно взять уже сейчас, добавить мосфет или дарлингтон на радиаторе и ОУ, получить разрядное устройство, да не с 7-сегментным 3-4-разрядным индикатором, а экраном, отображающим много параметров.
Не понимаю тягу к «собрать на коленке из подручных средств» когда за те же 25-30 USD есть достойные законченные варианты китайских электронных нагрузок.


UriBas

Цитата: serggio от 20 Март 2019 в 22:49.. Не понимаю тягу к «собрать на коленке из подручных средств» когда за те же 25-30 USD есть достойные законченные варианты китайских электронных нагрузок.
Не беру их по одной причине, что в них изменить ничего нельзя.. То нет измерения Rвн, то пределы не те, мощность, напряжение и ток, то способ регулировки или индикации.. и т.д.  Даже самую захудалую самоделку можно подстроить под свои нужды, изменить программу и т.д.   Да, есть более менее подходящие, но от сотни и выше долларов..

Но в принципе, можно использовать  уже готовые (с Али) модули или даже сами эл.нагрузки для переделки.. может так было бы проще и быстрее сделать, пусть и немного переплатив. Новичку это трудно, а подсказки и методы переделки с минимальными усилиями от профи, здорово бы помогли! Это да. 

К примеру, за основу можно было бы взять такой вот наборчик https://mysku.ru/blog/taobao/64458.html на "муське" стоит не дорого - около 7-8 долл.  а потом его доработать под Ардуино.  Купить дополнительно модули  изм тока и напр, (2 долл) дисплей (2-6долл) + сам МК Ардуино (2долл) = Получаем пусть при 20 долларах полноценное разрядное устройство (при небольшом дополнении  зарядно- разрядное) мощностью от 150-300Вт и выше (от транзисторов зависит)!    По функционалу не сравнимо выше с готовыми стоимостью выше 100 долл.
Восточная мудрость - "Шакал воет - караван идет"  Эл.вел. 350Вт.   Верую в Иисуса Христа, НЛО.  тема "продвинутой моргалки" https://electrotransport.ru/index.php?msg=1669651

Паяка

Вот что ответил продавец на вопрос о логике, оконная или гистерезис.

Hello!
The upper and lower limits of our instrument are as follows:
First:
Voltage, upper and lower limits. After setting up.
When the measured voltage is above the upper limit. Or below the lower limit.
At this point, an output voltage can be obtained on the PCB.
You can use this voltage to control your circuit to achieve action.
But please note that the instrument itself will not be turned off. You need to amplify the signal outside to control the continuation.
Second:
Electric current. The control method is the same as the voltage.
Third:
Voltage and current are controlled through the same port.
Fourth:
Control optional function: locking.
When the lock-in is selected, as long as the control occurs, even if the condition is not established, the control high voltage output will be maintained. This function is turned off by default.
Fifth:
I suggest you buy an experiment.


Получается, логика оконная, с опциональным защёлкиванием. Т.е. останавливать разряд по достижении порога будет, но возобновлять для выкачки ёмкости - нет.
GT TF1 60V 20Ah Chilwee DZF

Иван77

Всем добра. А нет ли у кого нибудь проги готовой для воплощения зарядно-разрядного устройства на ардуино.  Повторил ЗУ от Dkin, но хочется два в одном, с устанавливаемыми порогами. И по-проще). Ну или хотя бы подсказку для написания проги, как переключать режимы. Уверен, это интересно не только мне. Спасибо.
Ездю и ездю.

Паяка

#257

Случай, когда пригодилась троичная логика. С помощью такой схемы, можно переключать 3 разряда индикатора одной ножкой, а четвёртый ОУ пригодится для усилителя сигнала шунта. Узел предназначается простому программируемому показометру, могущему измерять напряжение, ток, а также считать ампер-часы. Нарисован для индикатора с общим катодом. На случай общего анода, нужно поменять местами инвертирующие и неинвертирующие выводы компараторов и развернуть диоды.
Если нужно освободить ещё один ОУ, например, для ИТУН, можно заменить правый компаратор на DTL элемент И-НЕ, как в разрядном мини-устройстве.
А так можно считать 3 состояния с ножки, имеющей только цифровой вход, зато с программно включаемой WPU (слабой подтяжкой к Vdd).
GT TF1 60V 20Ah Chilwee DZF

S_Kov

Цитата: Паяка от 09 Май 2019 в 11:33А так можно считать 3 состояния с ножки, имеющей только цифровой вход, зато с программно включаемой WPU (слабой подтяжкой к Vdd).
Не очень толковый вариант.
На самом деле не нужны никакие подтяжки, ни встроенные, ни внешние.
Можно использовать известный факт, что (по крайней мере) PIC-контроллеры имеют встроенные ограничители тока выхода и совершенно имунны к любым закорачиванием
своих выходов между собой или на питание-землю. Ограничивающим фактором является ограничение на общий ток через все выводы. Так что коротить на землю одновременно больше 5-8 выводов надо уже посмотрев предварительно в даташите максимальный суммарный ток ;)
Я так делаю опрос кнопок и это один из самых надежный и устойчивых
к помехам способов опроса кнопок, известных мне.
Кнопка просто закорачивает выход на землю.
Вы настраиваете порт на вывод, выдаете в него единицу, а потом, не переводя порт в режим ввода,
читаете значение его выхода. Если там ноль - кнопка нажата. Если единица- отжата.
Аналогично можно подвесить кнопку на питание и выдавать тестовый ноль.
Для реализации опроса вашего внешнего источника с тремя состояниями
надо просто совместить два этих метода.

Паяка

[user]S_Kov[/user], в данной задаче все выходы заняты, свободна только ножка MCLR/Vpp, у которой есть WPU.
GT TF1 60V 20Ah Chilwee DZF

S_Kov

Цитата: Паяка от 09 Май 2019 в 13:43в данной задаче все выходы заняты,
Понятно. Надеюсь, что помеховая ситуация идеальна, т.к. перекрыть ваши микроамперы любой маломощной помехой нетрудно. Вообще, я стараюсь избегать ситуаций, когда не остается свободных ног у МК.
Как показывает опыт это оказывается дешевле ;)

Паяка

Цитата: S_Kov от 09 Май 2019 в 13:35известный факт, что (по крайней мере) PIC-контроллеры имеют встроенные ограничители тока выхода и совершенно имунны к любым закорачиванием
своих выходов между собой или на питание-землю.
Откуда этот факт? Мне такое неизвестно. Более того, используемые мной PIC не имеют таких ограничителей, в отличие от ОУ. Если же ограничить общий ток питания, будет происходить просадка и сброс.
GT TF1 60V 20Ah Chilwee DZF

S_Kov

Цитата: Паяка от 09 Май 2019 в 14:32Откуда этот факт? Мне такое неизвестно. Более того, используемые мной PIC не имеют таких ограничителей, в отличие от ОУ. Если же ограничить общий ток питания, будет происходить просадка и сброс.
Ну, я начинал с практических опытов ;) 
Кажется, еще на 84-м PIC-е, потом это все неоднократно повторял на более старших МК.
Режим короткого замыкания на землю дает примерно 25-30mA, замыкание на VDD при 5-ти вольтах дает порядка 35-40мА, что несколько выше допустимой величины , поэтому я редко использую этот режим.
Как обычно, после опытов, начинаешь читать даташит ;))
В даташите есть несколько упоминаний о предельных нагрузках на порт.
Можно начать с
• High current sink/source for direct LED drive
На светодиоде может падать 1.6V а иногда и меньше (зависит от цвета).
Вообще, мне встречался в литературе специальный термин "перегрузка порта", с которым связаны некоторые интересные вещи. Это когда порт выдает логическую единицу (например), а внешняя нагрузка подсаживает выход до величины менее логической входной единицы. Тут возникают некоторые тонкие моменты в программировании PIC-а, т.к. в режиме перегрузки при работе с соседним битом порта вы рискуете сбросить в ноль выход перегруженного порта..
Далее, есть такая полезная табличка в даташите:
Total power dissipation(1) ...800 mW
Maximum current out of VSS pin ...300 mA
Maximum current into VDD pin ...250 mA
Maximum output current sunk by any I/O pin...25 mA
Maximum output current sourced by any I/O pin .......................................................................................25 mA
Maximum current sunk by PORTA and PORTB (Combined)............................................................................200 mA
Maximum current sourced by PORTA and PORTB (Combined).......................................................................200 mA

Эта табличка позволяет прикинуть, сколько выводов порта можно одновременно коротнуть на землю ;)

Паяка

#263
Исходный код ПО версии 3 для разрядной мини-нагрузки
include 16f628a
pragma target clock 4_000_000
pragma target OSC      XT -- кварц 4 МГц
pragma target WDT      DISABLED
pragma target BROWNOUT ENABLED
pragma target LVP      DISABLED
pragma target CP       DISABLED
pragma target CPD      DISABLED
pragma target PWRTE    ENABLED
pragma target MCLR     INTERNAL

pragma EEDATA 0x7C, 0x15 -- 5500 мА
--pragma EEDATA 0xB0, 0x04 -- 1200 мА по умолчанию
--pragma EEDATA 0x28, 0x05 -- 1320 мА прототип


-- разряды индикатора пронумерованы слева направо
alias digit1_on is   pin_A0 -- o вкл. 1 разряд
alias cmp_in    is   pin_A1 -- i
alias vrefout   is   pin_A2 -- i
alias dscg_on   is   pin_A3 -- o вкл. разрядный ток
alias digit2_on is   pin_A4 -- i вкл. 2 разряд
alias btn_plus  is   pin_A5 -- i кнопка плюс
alias clkout    is   pin_A6 -- i
alias clkin     is   pin_A7 -- i

alias btn_minus is   pin_A4 -- кнопка минус
var bit minus_dir at TRISA:4
alias dp_on     is   pin_B2 -- вкл. десятичная точка

const byte segments [20] = { -- кодировка сегментов
--  -A-
-- F   B
--  -G-
-- E   C
--  -D-
--FADECpGB -- согласно соединениям на плате
0b11111001, -- 0  ABCDEF
0b00001001, -- 1  BC
0b01110011, -- 2  ABDEG
0b01101011, -- 3  ABCDG
0b10001011, -- 4  BCFG
0b11101010, -- 5  ACDFG
0b11111010, -- 6  ACDEFG
0b01001001, -- 7  ABC
0b11111011, -- 8  ABCDEFG
0b11101011, -- 9  ABCDFG
0b01111010, -- 10 ACDEG
0b10011001, -- 11 BCFE
0b01110000, -- 12 ADE
0b01111000, -- 13 ACDE
0b00011010, -- 14 - n CEG
0b11010010, -- 15 - f AEFG
0b00000000, -- 16 - пусто
0b11010000, -- 17 - r AEF
0b00111011, -- 18 - d BCDEG
0b10101011  -- 19 - y BCDFG
--FADECpGB
}
const letter_o = 0
const letter_n = 14
const letter_f = 15
const space    = 16
const letter_r = 17
const letter_d = 18
const letter_y = 19

var volatile byte sec_100 = 0 -- сотни секунд
var volatile byte sec_10  = 0 -- десятки
var volatile byte sec_1   = 0 -- единицы
var volatile byte ah_1    = 0 -- единицы А*ч
var volatile byte ah_10   = 0 -- десятые доли
var volatile byte ah_100  = 0 -- сотые доли

var volatile byte ind1 --
var volatile byte ind2 --- вывод на индикатор
var volatile byte ind3 --
var volatile word current -- ток разряда в мА
var byte current_byte[2] at current
var volatile word current_old -- старая константа
var volatile word mas = 0 -- счётчик мА*с
var volatile byte scaler = 0 -- делитель 250Гц на 125
var volatile byte idle = 0    -- счётчик простоя
var volatile byte minus_count = 0 -- удержание кнопки
var volatile byte threshold = 0 -- Порог отключения
var volatile byte ind_off_count = 0 -- Секунды до откл. индикатора
var bit ind_off_count_64 at ind_off_count:6 -- 64 секунды

var volatile byte flags = 0 -- флаги конечного автомата
var bit digit1_next   at flags:0 -- Передача индикации
var bit digit2_next   at flags:1 -- следующему разряду
var bit dp_1          at flags:2 -- Позиция десятичной
var bit dp_2          at flags:3 -- точки
var bit second        at flags:4 -- Прошла секунда
var bit minus_pressed at flags:5 -- Нажата кнопка "-"
var bit plus_pressed  at flags:6 -- Нажата кнопка "+"
var bit clock         at flags:7 -- Режим секундомера

var volatile byte flags1 = 0
var bit dscg_enable   at flags1:0 -- Разрешение разряда
var bit calibr_mode   at flags1:1 -- Режим калибровки
var bit minus_detect  at flags1:2 -- Антидребезг "-"
var bit plus_detect   at flags1:3 -- Антидребезг "+"
var bit even          at flags1:4 -- Делитель 2Гц на 2
var bit minus_hold    at flags1:5 -- Минус удерживался
var bit threshold_set at flags1:6 -- Переключение порогов
var bit dscg_finished at flags1:7 -- Разряд завершён

var volatile byte flags2 = 0
var bit ind_off       at flags2:0 -- Индикатор выключен
var bit cmp_rdy       at flags2:1 -- Компаратор сработал

alias cmp_out is CMCON_C2OUT

procedure interrupt is
pragma interrupt
if PIR1_TMR2IF then -- динамическая индикация
  PIR1_TMR2IF = off
  if !(dscg_enable|clock|calibr_mode|threshold_set)then
   ind1 = letter_o  -- Если не выбран ни разряд,
   if cmp_out then  -- ни секундомер, ни калибровка,
    ind2 = letter_f -- ни переключение порогов,
    ind3 = letter_f -- показываем состояние компаратора
   else
    ind2 = letter_n
    ind3 = space
   end if
   dp_1 = off
   dp_2 = off
  end if
  if ind_off then
   portb =  0
   dp_on = off
  elsif digit1_next then    -- включаем 1 разряд
   digit1_next = off
   digit2_next = on
   portb = segments[ind1]
   dp_on = dp_1
   digit1_on = on
   digit2_on = off
  elsif digit2_next then -- включаем 2 разряд
   digit1_next = off
   digit2_next = off
   portb = segments[ind2]
   dp_on = dp_2
   minus_dir = 1
   digit2_on = on
   digit1_on = off
  else                   -- включаем 3 разряд
   if !btn_minus then
    minus_detect = on
   else
    if (minus_count > 3) then
     minus_hold = on
    end if
    minus_count = 0
   end if
   digit1_next = on
   digit2_next = off
   portb = segments[ind3]
   dp_on = !(dp_2|dp_1)
   digit1_on = off
   minus_dir = 0
   digit2_on = off
  end if
end if
if !btn_plus then
  plus_detect = on
end if
scaler = scaler + 1
if (scaler >= 125) then -- прошло 1/2 секунды
  scaler = 0
  if plus_detect then
   plus_detect = off
   plus_pressed = on
  end if
  if minus_detect then
   minus_detect = off
   minus_pressed = on
   minus_count = minus_count + 1
  end if
  even = !even
  if !even then --прошла секунда
   second = on
  end if
end if
end procedure

TRISB    =   0b00000000
TRISA    =   0b11110110
PORTB    =   0b00000000
PORTA    =   0b00000000
CMCON    =   0b00000101 -- 1 независимый компаратор
const vrcon_105  = 0b11100111
const vrcon_12   = 0b11101000 -- 1,6(6)В при 5В Vdd
const vrcon_1125 = 0b11000010
VRCON    =   vrcon_105
-- Частота кварца 4 МГц, команд 1 МГц.
-- Тактировать конечный автомат удобно частотой 250 Гц.
-- Это оптимально и для динамической индикации,
-- и для подсчёта времени.
-- Для этого настроим предделитель TMR2 на 16,
-- получим 62500 Гц. Период 250, получим 250 Гц.
-- По прерыванию с TMR2 будем обновлять индикатор
-- и прибавлять счётчики антидребезга и секунд

PIE1     =   0b00000010 -- только от TIMER2
PIR1     =   0b00000000 -- регистр флагов прерываний
T2CON    =   0b00000110 -- предделитель 16, постделитель 1
PR2      =   250
INTCON   =   0b11000000

procedure ah_indicate is
if (ah_1 < 14) then    -- 0.00 - 13.99
  ind1 = ah_1
  ind2 = ah_10
  ind3 = ah_100
  dp_1 = on
  dp_2 = off
elsif (ah_1 < 99) then -- 14.0 - 99.9
  ind1 = ah_1 / 10
  ind2 = ah_1 % 10
  ind3 = ah_10
  dp_1 = off
  dp_2 = on
else                   -- 100 - 255
  ind1 = ah_1 / 100
  ind2 = (ah_1 % 100) / 10
  ind3 = ah_1 % 10
  dp_1 = off
  dp_2 = off
end if
end procedure

procedure dscg_count is
-- 1 А*ч = 3600 А*с (кулон)
-- 0.01 А*ч = 36 А*с = 36000 мА*с
mas = mas + current
if (mas >= 36000) then
  mas = mas - 36000
  ah_100 = ah_100 + 1
  if (ah_100 > 9) then
   ah_100 = 0
   ah_10 = ah_10 + 1
   if (ah_10 > 9) then
    ah_10 = 0
    ah_1 = ah_1 + 1
   end if
  end if
end if
end procedure

procedure clock_count is
sec_1 = sec_1 + 1
if (sec_1 > 9) then
  sec_1 = 0
  sec_10 = sec_10 + 1
  if (sec_10 > 9) then
   sec_10 = 0
   sec_100 = sec_100 + 1
   if (sec_100 > 13) then
    sec_100 = 0
   end if
  end if
end if
ind1 = sec_100
ind2 = sec_10
ind3 = sec_1
dp_1 = off
dp_2 = off
end procedure

procedure main_cycle is
forever loop
  if second then -- если прошла секунда
   second = off
   if dscg_finished then -- если разряд завершён
    ind_off_count = ind_off_count + 1 -- считаем секунды
    if ind_off_count_64 then -- если прошло 64
     ind_off = on            -- отключаем индикацию
    end if
   end if
   if cmp_rdy then
    if cmp_out then -- если напряжение ниже порога,
     dscg_on = off   -- отключаем ток
     dscg_finished = on
    end if
   end if
   cmp_rdy = cmp_out
   if dscg_enable then
    if dscg_on then -- если ток идёт,
     dscg_count -- подсчитываем ёмкость
    end if
    ah_indicate -- индицируем ёмкость
   elsif clock then
    clock_count -- считаем секунды
   end if
  end if
  if plus_pressed then -- вкл/выкл разряд
   plus_pressed = off
   if ind_off then -- если индикация выключена,
    ind_off = off  -- только включаем её
    ind_off_count = 0
   else -- иначе обрабатываем нажатие
    threshold_set = off
    clock = off
    dscg_enable = !dscg_enable
    if dscg_enable then
     dscg_on = !cmp_out
     if dscg_on then
      dscg_finished = off
     end if
    else
     dscg_on = off
    end if
   end if
  end if
  if minus_pressed then
   if ind_off then -- если индикация выключена,
    minus_pressed = off -- только включаем её
    ind_off = off
    ind_off_count = 0
   else -- иначе обрабатываем нажатие
    dscg_enable = off
    dscg_on = off
    if minus_hold  then -- длинное нажатие
     minus_pressed = off
     minus_hold = off  -- переводит в режим
     threshold_set = off  -- секундомера
     sec_100 = 0
     sec_10 = 0
     sec_1 = 0
     clock = on
    elsif (minus_count < 2) then -- короткое нажатие переключает пороги
     minus_pressed = off
     threshold_set = on
     dp_1 = off
     dp_2 = on
     if threshold > 1 then -- с верхнего на нижний
      VRCON = vrcon_105
      threshold = 0
      ind1 = 1
      ind2 = 0
      ind3 = 5
     elsif threshold > 0 then -- со среднего на верхний
      VRCON = vrcon_12
      threshold = 2
      ind1 = 1
      ind2 = 2
      ind3 = 0
     else                      -- с нижнего на средний
      VRCON = vrcon_1125
      threshold = 1
      ind1 = 11
      ind2 = 2
      ind3 = 5
      dp_1 = on
      dp_2 = off
     end if
    end if
   end if
  end if
end loop
end procedure

procedure ma_indicate_1 is
-- индикация калибровки до 1399 мА
  ind1 = current / 100
  ind2 = (current % 100) / 10
  ind3 = current % 10
  dp_1 = off
  dp_2 = off
end procedure

procedure ma_indicate_5 is
-- индикация калибровки от 0.00 до 9.99 А
  ind1 = current / 1000
  ind2 = (current % 1000) / 100
  ind3 = (current % 100) / 10
  dp_1 = on
  dp_2 = off
end procedure

alias ma_indicate is ma_indicate_5

procedure calibrate is
calibr_mode = on
current_old = current
ma_indicate
while !btn_plus loop
end loop -- ждём отпускания кнопки +
plus_pressed = off
second = off
while !second loop
end loop
second = off
while !second loop
end loop
second = off
while !(plus_pressed|minus_pressed) loop
end loop -- ждём нажатия любой кнопки
plus_pressed = off
minus_pressed = off
while (idle < 11) loop
  if second then -- если прошла секунда
   second = off
   idle = idle + 1
  end if
  if plus_pressed then
   plus_pressed = off
   idle = 0
--   if (current < 1398) then
   if (current < 6000) then
    current = current + 1
   else
--    current = 400
    current = 4000
   end if
   ma_indicate
  end if
  if minus_pressed then
   minus_pressed = off
   idle = 0
--   if (current > 401) then
   if (current > 4001) then
    current = current - 1
   else
--    current = 1399
    current = 5999
   end if
   ma_indicate
  end if
end loop
if (current_old != current) then
  INTCON_GIE = 0
  EEADR = 0
  EEDATA = current_byte[0]
  EECON1_WREN = 1
  EECON2 = 0x55
  EECON2 = 0xAA
  EECON1_WR = 1
  while EECON1_WR loop
  end loop
  EEADR = 1
  EEDATA = current_byte[1]
  EECON2 = 0x55
  EECON2 = 0xAA
  EECON1_WR = 1
  while EECON1_WR loop
  end loop
  EECON1_WREN = 0
  INTCON_GIE = 1
end if
ind1 = letter_r -- вывод "rdy"
ind2 = letter_d
ind3 = letter_y
dp_1 = off
dp_2 = off
forever loop
end loop
end procedure

EEADR = 0  --   загрузим калибровочную константу
EECON1_RD = 1
current_byte[0] = EEDATA
EEADR = 1
EECON1_RD = 1
current_byte[1] = EEDATA

if btn_plus then -- если при включении не нажат +
main_cycle
else -- если нажат, запускаем в режиме калибровки
calibrate
end if
Теперь индикатор гаснет через минуту после завершения разряда. Чтобы зажечь его снова на минуту, нужно нажать любую кнопку.

Версия 4
GT TF1 60V 20Ah Chilwee DZF

dvlad666

Цитата: Паяка от 04 Июль 2019 в 02:15
Теперь индикатор гаснет через минуту после завершения разряда. Чтобы зажечь его снова на минуту, нужно нажать любую кнопку.

Ой чудо-то какое!  :wow: А я могу себе это залить?

Паяка

[user]dvlad666[/user], можете, если есть программатор с панелькой. Только сначала проверю новую прошивку на своём экземпляре, который сегодня-завтра доделаю. И посмотрите, какая у Вас константа калибровки тока, скомпилирую сразу с ней, чтобы не пришлось перенастраивать. Чтобы посмотреть константу, надо подать питание при зажатой кнопке +.
GT TF1 60V 20Ah Chilwee DZF

Паяка

GT TF1 60V 20Ah Chilwee DZF

Паяка

#267
Вариант мини-нагрузки на 4-6А. Вместо стабилизатора тока на LM317 использовано 2 ИТУН на бывших под рукой мосфетах с расширенной SOA и ОУ. Оба в изолированных корпусах, для улучшения теплоотвода зачищенных алмазным напильником до обнажения меди подложки. (Не перестарайтесь, чтобы не разрушить транзистор!) На время сего колхозного действа, выводы транзисторов соединены между собой, дабы не пробить затворы. В медном сердечнике радиатора просверлены глухие отверстия 2.5, нарезана резьба М3, сняты фаски.

Схема. D6 служит тому, чтобы при отключенном разрядном токе напряжение на входе ИТУН гарантированно равнялось практически нулю. Смещение с R22, R25 предназначено для гарантированного покрытия ошибки ОУ. Благодаря этому, при низком логическом уровне на выходе RA3 ИТУНы действительно полностью выключены. Светодиод индикации разряда не нужен, т.к. его роль выполняет вентилятор.

Диод защиты от подключения в неверной полярности D3 установлен на небольшой радиатор. В таких нагрузках стоки теплорассеивающих транзисторов и общий катод защитного диода, т.е. подложки всех силовых элементов, соединены с одной и той же цепью - защищённым силовым плюсом, потому, если есть место на общем радиаторе, можно установить диод и мосфеты на него, без изолирующих прокладок. Но у меня нашёлся не обычный Intel S-478 box в виде массивного алюминиевого блока, а топовый с медным цилиндром, на нижнем торце которого уместились всего 2 корпуса TO-220. Потому защитный диод снабжён отдельным радиатором.
GT TF1 60V 20Ah Chilwee DZF

Паяка

#268
ПО разрядной мини-нагрузки, версия 4.

Добавлены пороги завершения -  7.5, 9, 10.125, 10.5, 11.25, 12, 12.375 вольт.
Теперь нагрузка запоминает в EERPOM слитые ампер*часы, сброс производится длительным нажатием кнопки (-), после чего высвечивается "rst".
При подаче питания с зажатой кнопкой (+) активируется режим ввода константы тока, (-) - секундомера.
В рабочем режиме (+) включает и выключает разрядный ток, (-) переключает пороги. Выбранный порог запоминается в энергонезависимую память при запуске разряда кнопкой (+).
Если производился разряд, и перед отключением питания не был сделан сброс, при подаче питания индикация А*ч будет мигать в течение минуты. Если за это время не нажать ни одну кнопку, по прошествии минуты будет возобновлён разряд до запомненного порога.
Если память А*ч сброшена, при подаче питания до нажатия любой кнопки индицируется состояние компаратора порога напряжения - On, если напряжение выше порога, в противном случае Off.
Как и в версии 3, через минуту после завершения разряда индикация отключается, возобновить её можно нажатием любой кнопки.
Чтобы настроить делитель напряжения, нужно сначала выбрать порог и сохранить его в EEPROM, запустив и остановив разряд, затем сбросить ампер*часы, отключить питание и включить его снова, запитав от источника эталонного напряжения (регулируемого БП с вольтметром). Ориентируясь по индикации On и Off, установить щётку подстроечного резистора в нужное положение.

Исходный код с комментариями
include 16f628a
pragma target clock 4_000_000
pragma target OSC      XT -- кварц 4 МГц
pragma target WDT      DISABLED
pragma target BROWNOUT ENABLED
pragma target LVP      DISABLED
pragma target CP       DISABLED
pragma target CPD      DISABLED
pragma target PWRTE    ENABLED
pragma target MCLR     INTERNAL

pragma EEDATA 0x48, 0x10, 6, 0, 0, 0 -- 4168 мА

--pragma EEDATA 0xB0, 0x04 -- 1200 мА по умолчанию
--pragma EEDATA 0x28, 0x05 -- 1320 мА прототип

-- разряды индикатора пронумерованы слева направо
alias digit1_on is   pin_A0 -- o вкл. 1 разряд
alias cmp_in    is   pin_A1 -- i
alias vrefout   is   pin_A2 -- i
alias dscg_on   is   pin_A3 -- o вкл. разрядный ток
alias digit2_on is   pin_A4 -- i вкл. 2 разряд
alias btn_plus  is   pin_A5 -- i кнопка плюс
alias clkout    is   pin_A6 -- i
alias clkin     is   pin_A7 -- i

alias btn_minus is   pin_A4 -- кнопка минус
var bit minus_dir at TRISA:4
alias dp_on     is   pin_B2 -- вкл. десятичная точка

const byte segments [22] = { -- кодировка сегментов
--  -A-
-- F   B
--  -G-
-- E   C
--  -D-
--FADECpGB -- согласно соединениям на плате
0b11111001, -- 0  ABCDEF
0b00001001, -- 1  BC
0b01110011, -- 2  ABDEG
0b01101011, -- 3  ABCDG
0b10001011, -- 4  BCFG
0b11101010, -- 5  ACDFG
0b11111010, -- 6  ACDEFG
0b01001001, -- 7  ABC
0b11111011, -- 8  ABCDEFG
0b11101011, -- 9  ABCDFG
0b01111010, -- 10 ACDEG
0b10011001, -- 11 BCFE
0b01110000, -- 12 ADE
0b01111000, -- 13 ACDE
0b00011010, -- 14 - n CEG
0b11010010, -- 15 - f AEFG
0b00000000, -- 16 - пусто
0b11010000, -- 17 - r AEF
0b00111011, -- 18 - d BCDEG
0b10101011, -- 19 - y BCDFG
0b10110010, -- 20 - t DЕFG
0b11110000  -- 21 - c ADEF
--FADECpGB
}

const letter_o = 0
const letter_s = 5
const letter_n = 14
const letter_f = 15
const space    = 16
const letter_r = 17
const letter_d = 18
const letter_y = 19
const letter_t = 20
const letter_c = 21

var volatile byte sec_100 = 0 -- сотни секунд
var volatile byte sec_10  = 0 -- десятки
var volatile byte sec_1   = 0 -- единицы
var volatile byte ah_1    = 0 -- единицы А*ч
var volatile byte ah_10   = 0 -- десятые доли
var volatile byte ah_100  = 0 -- сотые доли
var volatile byte ind1 --
var volatile byte ind2 --- вывод на индикатор
var volatile byte ind3 --
var volatile word current -- ток разряда в мА
var byte current_byte[2] at current
var volatile word current_old -- старая константа
var volatile word mas = 0 -- счётчик мА*с
var volatile byte scaler = 0 -- делитель 250Гц на 125
var volatile byte idle = 0    -- счётчик простоя
var volatile byte minus_count = 0 -- удержание кнопки
var volatile byte threshold      -- Порог отключения
var volatile byte threshold_old  -- старый порог
var volatile byte thr_ind       -- Индикация порога
var volatile byte ind_off_count = 0 -- Секунды до откл. индикатора
var bit ind_off_count_64 at ind_off_count:6 -- 64 секунды
var volatile byte cont_count = 0 -- Секунды до возобновления разряда
var bit cont_count_64 at cont_count:6 -- 64 секунды

var volatile byte flags = 0 -- флаги конечного автомата
var bit digit1_next   at flags:0 -- Передача индикации
var bit digit2_next   at flags:1 -- следующему разряду
var bit dp_1          at flags:2 -- Позиция десятичной
var bit dp_2          at flags:3 -- точки
var bit second        at flags:4 -- Прошла секунда
var bit minus_pressed at flags:5 -- Нажата кнопка "-"
var bit plus_pressed  at flags:6 -- Нажата кнопка "+"
var bit reset_ok      at flags:7 -- Ёмкость сброшена

var volatile byte flags1 = 0
var bit clock_stop    at flags1:0 -- Секундомер остановлен
var bit calibr_mode   at flags1:1 -- Режим калибровки
var bit minus_detect  at flags1:2 -- Антидребезг "-"
var bit plus_detect   at flags1:3 -- Антидребезг "+"
var bit even          at flags1:4 -- Делитель 2Гц на 2
var bit minus_hold    at flags1:5 -- Минус удерживался
var bit threshold_set at flags1:6 -- Переключение порогов
var bit dscg_finished at flags1:7 -- Разряд завершён

var volatile byte flags2 = 0
var bit ind_off       at flags2:0 -- Индикатор выключен
var bit cmp_rdy       at flags2:1 -- Компаратор сработал
var bit continue      at flags2:2 -- Продолжать разряд
var bit cmp_state     at flags2:3 -- Индицировать состояние
var bit no_ind        at flags2:4 -- Без индикации

alias cmp_out is CMCON_C2OUT

procedure interrupt is
pragma interrupt
if PIR1_TMR2IF then -- динамическая индикация
  PIR1_TMR2IF = off
  if cmp_state then
   ind1 = letter_o  -- Если не выбран ни разряд,
   if cmp_out then  -- ни секундомер, ни калибровка,
    ind2 = letter_f -- ни переключение порогов,
    ind3 = letter_f -- показываем состояние компаратора
   else
    ind2 = letter_n
    ind3 = space
   end if
   dp_1 = off
   dp_2 = off
  end if
  no_ind = (ind_off|(continue & even)) -- мигание
  -- или отключение индикации
  if digit1_next then    -- включаем 1 разряд
   digit1_next = off
   digit2_next = on
   if no_ind then
    portb = 0
   else
    portb = segments[ind1]
    dp_on = dp_1
   end if
   digit1_on = on
   digit2_on = off
  elsif digit2_next then -- включаем 2 разряд
   digit1_next = off
   digit2_next = off
   if no_ind then
    portb = 0
   else
    portb = segments[ind2]
    dp_on = dp_2
   end if
   minus_dir = 1
   digit2_on = on
   digit1_on = off
  else                   -- включаем 3 разряд
   if !btn_minus then
    minus_detect = on
   else
    if (minus_count > 3) then
     minus_hold = on
    end if
    minus_count = 0
   end if
   digit1_next = on
   digit2_next = off
   if no_ind then
    portb = 0
   else
    portb = segments[ind3]
    dp_on = !(dp_2|dp_1)
   end if
    digit1_on = off
    minus_dir = 0
    digit2_on = off
  end if
end if
if !btn_plus then
  plus_detect = on
end if
scaler = scaler + 1
if (scaler >= 125) then -- прошло 1/2 секунды
  scaler = 0
  if plus_detect then
   plus_detect = off
   plus_pressed = on
  end if
  if minus_detect then
   minus_detect = off
   minus_pressed = on
   minus_count = minus_count + 1
  end if
  even = !even
  if !even then --прошла секунда
   second = on
  end if
end if
end procedure

const byte vrc [8] = { -- настройка опоры
0b11100100, --  6
0b11100101, --  7.5
0b11100110, --  9
0b11000001, -- 10.125
0b11100111, -- 10.5
0b11000010, -- 11.25
0b11101000, -- 12
0b11000010  -- 12.375
}

const byte thr [8] = { -- значения порогов
60,75,90,101,105,0,120,124
}

TRISB    =   0b00000000
TRISA    =   0b11110110
PORTB    =   0b00000000
PORTA    =   0b00000000
CMCON    =   0b00000101 -- 1 независимый компаратор
const vrcon_6    = 0b11100100
const vrcon_105  = 0b11100111
const vrcon_12   = 0b11101000 -- 1,6(6)В при 5В Vdd
const vrcon_1125 = 0b11000010
VRCON    =   vrcon_6
-- Частота кварца 4 МГц, команд 1 МГц.
-- Тактировать конечный автомат удобно частотой 250 Гц.
-- Это оптимально и для динамической индикации,
-- и для подсчёта времени.
-- Для этого настроим предделитель TMR2 на 16,
-- получим 62500 Гц. Период 250, получим 250 Гц.
-- По прерыванию с TMR2 будем обновлять индикатор
-- и прибавлять счётчики антидребезга и секунд

PIE1     =   0b00000010 -- только от TIMER2
PIR1     =   0b00000000 -- регистр флагов прерываний
T2CON    =   0b00000110 -- предделитель 16, постделитель 1
PR2      =   250
INTCON   =   0b11000000

procedure ah_indicate is
if (ah_1 < 12) then    -- 0.00 - 11.99
  ind1 = ah_1
  ind2 = ah_10
  ind3 = ah_100
  dp_1 = on
  dp_2 = off
elsif (ah_1 < 99) then -- 12.0 - 99.9
  ind1 = ah_1 / 10
  ind2 = ah_1 % 10
  ind3 = ah_10
  dp_1 = off
  dp_2 = on
else                   -- 100 - 255
  ind1 = ah_1 / 100
  ind2 = (ah_1 % 100) / 10
  ind3 = ah_1 % 10
  dp_1 = off
  dp_2 = off
end if
end procedure

procedure save_1 is
INTCON_GIE = 0
EEADR = 3
EEDATA = ah_1
EECON1_WREN = 1
EECON2 = 0x55
EECON2 = 0xAA
EECON1_WR = 1
while EECON1_WR loop
end loop
EECON1_WREN = 0
INTCON_GIE = 1
end procedure

procedure save_10 is
INTCON_GIE = 0
EEADR = 4
EEDATA = ah_10
EECON1_WREN = 1
EECON2 = 0x55
EECON2 = 0xAA
EECON1_WR = 1
while EECON1_WR loop
end loop
EECON1_WREN = 0
INTCON_GIE = 1
end procedure

procedure save_100 is
INTCON_GIE = 0
EEADR = 5
EEDATA = ah_100
EECON1_WREN = 1
EECON2 = 0x55
EECON2 = 0xAA
EECON1_WR = 1
while EECON1_WR loop
end loop
EECON1_WREN = 0
INTCON_GIE = 1
end procedure

procedure dscg_count is
pragma inline
-- 1 А*ч = 3600 А*с (кулон)
-- 0.01 А*ч = 36 А*с = 36000 мА*с
mas = mas + current
if (mas >= 36000) then
  mas = mas - 36000
  ah_100 = ah_100 + 1
  if (ah_100 > 9) then
   ah_100 = 0
   ah_10 = ah_10 + 1
   if (ah_10 > 9) then
    ah_10 = 0
    ah_1 = ah_1 + 1
    save_1
   end if
   save_10
  end if
  save_100
end if
end procedure

procedure clock_indicate is -- индикация
pragma inline               -- секунд
ind1 = sec_100
ind2 = sec_10
ind3 = sec_1
dp_1 = off
dp_2 = off
end procedure

procedure clock_count is -- счёт секунд
pragma inline
sec_1 = sec_1 + 1
if (sec_1 > 9) then
  sec_1 = 0
  sec_10 = sec_10 + 1
  if (sec_10 > 9) then
   sec_10 = 0
   sec_100 = sec_100 + 1
   if (sec_100 > 12) then
    sec_100 = 0
   end if
  end if
end if
end procedure

procedure stopwatch is -- режим секундомера
pragma inline
forever loop
  if second then -- если прошла секунда
   second = off
   if !clock_stop then
    clock_count
   end if
   if plus_pressed then -- кнопка плюс
    plus_pressed = off  -- пуск-стоп
    minus_pressed = off -- секундомера
    clock_stop = !clock_stop
   end if -- plus_pressed
   if minus_pressed then -- кнопка минус
    minus_pressed = off  -- сброс секундомера
    sec_1   = 0
    sec_10  = 0
    sec_100 = 0
   end if -- minus_pressed
   clock_indicate
  end if -- second
end loop
end procedure

procedure indicate_thr is -- индикация порога
thr_ind = thr[threshold]
dp_1 = off
dp_2 = on
ind1 = thr_ind / 100
ind2 = (thr_ind % 100) / 10
ind3 = thr_ind % 10
if (thr_ind ==0) then
  ind1 = 11
  ind2 = 2
  ind3 = 5
  dp_1 = on
  dp_2 = off
end if
end procedure

procedure switch_thr is -- переключение порогов
pragma inline
threshold = threshold + 1
if (threshold > 7) then
  threshold = 0
end if
VRCON = vrc[threshold]
indicate_thr
end procedure

procedure reset_ah is
pragma inline
mas    = 0
ah_1   = 0
ah_10  = 0
ah_100 = 0
save_1
save_10
save_100
ind1 = letter_r -- вывод "rst"
ind2 = letter_s
ind3 = letter_t
dp_1 = off
dp_2 = off
reset_ok = on
end procedure

procedure save_thr is -- сохранение порога
pragma inline
if threshold_old != threshold then
  INTCON_GIE = 0
  EEADR = 2
  EEDATA = threshold
  EECON1_WREN = 1
  EECON2 = 0x55
  EECON2 = 0xAA
  EECON1_WR = 1
  while EECON1_WR loop
  end loop
  EECON1_WREN = 0
  INTCON_GIE = 1
  threshold_old = threshold
end if
end procedure

procedure plus_btn is  -- обработчик кнопки плюс
pragma inline
ind_off_count = 0
if ind_off then -- если индикация выключена,
  ind_off = off  -- только включаем её
elsif !(cmp_state|threshold_set|reset_ok) then
-- иначе включаем или выключаем разряд,
-- если это второе нажатие кнопки
  if dscg_on then
   dscg_on = off
   dscg_finished = on
  else
   dscg_on = !cmp_out
   if dscg_on then
    dscg_finished = off
    save_thr      -- сохраняем порог
   end if -- dscg_on
  end if -- dscg_on
end if -- !ind_off
threshold_set = off
reset_ok = off
cmp_state = off
end procedure

procedure minus_btn is -- обработчик кнопки минус
pragma inline
reset_ok = off
cmp_state = off
ind_off_count = 0
if ind_off then -- если индикация выключена,
  ind_off = off  -- только включаем её
else -- иначе обрабатываем нажатие
  if minus_hold  then   -- длинное нажатие
   minus_hold = off     -- сбрасывает ёмкость
   threshold_set = off
   reset_ah
   reset_ok = on
  elsif (minus_count < 3) then -- короткое нажатие
   indicate_thr              -- переключает пороги
   if threshold_set then
    switch_thr
   end if
   threshold_set = on
  end if
end if -- !ind_off
end procedure

procedure main_cycle is
pragma inline
forever loop
  if second then -- если прошла секунда
   second = off
   if !(cmp_state|threshold_set|reset_ok)then
    ah_indicate -- индицируем ёмкость
   end if
   if continue then -- разряд прерван
    cont_count = cont_count + 1 -- считаем секунды
    if cont_count_64 then -- если прошло 64
     continue = off       -- перезапускаем разряд
     dscg_finished = cmp_out
     ind_off_count = 0
     dscg_on = !dscg_finished
    end if
   end if -- continue
   if dscg_finished then -- если разряд завершён
    ind_off_count = ind_off_count + 1 -- считаем секунды
    if ind_off_count_64 then -- если прошло 64
     ind_off_count = 0
     ind_off = on            -- отключаем индикацию
    end if
   end if -- dscg_finished
   if cmp_rdy then
    if cmp_out then -- если напряжение ниже порога,
     if dscg_on then
      dscg_on = off   -- отключаем ток
      dscg_finished = on
      ind_off_count = 0
     end if
    end if
   end if -- cmp_rdy
   cmp_rdy = cmp_out
   if dscg_on then -- если ток идёт,
    dscg_count -- подсчитываем ёмкость
    ah_indicate -- индицируем ёмкость
   end if
   if plus_pressed then
    plus_pressed = off
    continue = off
    minus_pressed = off
    plus_btn
   end if -- plus_pressed
   if minus_pressed then
    minus_pressed = off
    continue = off
    minus_btn
   end if -- minus_pressed
  end if -- second
end loop
end procedure

procedure ma_indicate_1 is
-- индикация калибровки до 1399 мА
  ind1 = current / 100
  ind2 = (current % 100) / 10
  ind3 = current % 10
  dp_1 = off
  dp_2 = off
end procedure

procedure ma_indicate_5 is
-- индикация калибровки от 0.00 до 9.99 А
  ind1 = current / 1000
  ind2 = (current % 1000) / 100
  ind3 = (current % 100) / 10
  dp_1 = on
  dp_2 = off
end procedure

alias ma_indicate is ma_indicate_5

procedure calibrate is
pragma inline
calibr_mode = on
current_old = current
ma_indicate
while !btn_plus loop
end loop -- ждём отпускания кнопки +
plus_pressed = off
second = off
while !second loop
end loop
second = off
while !second loop
end loop
second = off
while !(plus_pressed|minus_pressed) loop
end loop -- ждём нажатия любой кнопки
plus_pressed = off
minus_pressed = off
while (idle < 11) loop
  if second then -- если прошла секунда
   second = off
   idle = idle + 1
  end if
  if plus_pressed then
   plus_pressed = off
   idle = 0
--   if (current < 1398) then
   if (current < 6000) then
    current = current + 1
   else
--    current = 400
    current = 4000
   end if
   ma_indicate
  end if
  if minus_pressed then
   minus_pressed = off
   idle = 0
--   if (current > 401) then
   if (current > 4001) then
    current = current - 1
   else
--    current = 1399
    current = 5999
   end if
   ma_indicate
  end if
end loop
if (current_old != current) then
  INTCON_GIE = 0
  EEADR = 0
  EEDATA = current_byte[0]
  EECON1_WREN = 1
  EECON2 = 0x55
  EECON2 = 0xAA
  EECON1_WR = 1
  while EECON1_WR loop
  end loop
  EEADR = 1
  EEDATA = current_byte[1]
  EECON2 = 0x55
  EECON2 = 0xAA
  EECON1_WR = 1
  while EECON1_WR loop
  end loop
  EECON1_WREN = 0
  INTCON_GIE = 1
end if
ind1 = letter_r -- вывод "rdy"
ind2 = letter_d
ind3 = letter_y
dp_1 = off
dp_2 = off
forever loop
end loop
end procedure

EEADR = 0 -- загрузим калибровочную константу
EECON1_RD = 1
current_byte[0] = EEDATA
EEADR = 1
EECON1_RD = 1
current_byte[1] = EEDATA

procedure prepare is
pragma inline
EEADR = 2 -- загрузим порог напряжения
EECON1_RD = 1
threshold = EEDATA
threshold_old = threshold
VRCON = vrc[threshold]
cmp_rdy = off

EEADR = 3 -- загрузим слитую ёмкость
EECON1_RD = 1
ah_1 = EEDATA
EEADR = 4
EECON1_RD = 1
ah_10 = EEDATA
EEADR = 5
EECON1_RD = 1
ah_100 = EEDATA

if (ah_1 != 0) then -- если питание отключалось
  continue = on      -- без сброса А*ч
end if
if (ah_10 != 0) then
  continue = on
end if
if (ah_100 != 0) then
  continue = on
end if
cmp_state = !continue
end procedure

if !btn_plus then -- если при включении зажат +
plus_pressed = off
minus_pressed = off
calibrate        -- запускаем в режиме калибровки
elsif !btn_minus then -- если при включении зажат -
stopwatch        -- запускаем в режиме секундомера
else              -- иначе
prepare
main_cycle       -- в рабочем режиме
end if


GT TF1 60V 20Ah Chilwee DZF

dvlad666

Цитата: Паяка от 04 Сен. 2019 в 16:04ПО разрядной мини-нагрузки, версия 4.
Затестировал новое ПО, очень понравилось!

4Амперная нагрузка высосала из старой 7Ач VRLA батареи 3Ач до 11.25В и простояла 8 суток.

Сейчас на АКБ было 11.82В под ней (всё это время горел зеленый диод). Повторное включение естественно быстро завалило до 11.0 за неск секунд, но это именно то, что нужно! 👍👍👍

Таким образом, нагрузки [user]Паяки[/user] превратились в по-настоящему годный инструмент не только для подконтрольного лабораторного, но и военно-бытового применения!  :wow: