Самодельное зарядное устройство для аккумуляторов Makita LXT

В одном из предыдущих обзоров я рассказывал о неоригинальных аккумуляторах Makita LXT и проблемах их зарядки. Но, на самом деле, история началась несколько раньше – в августе 2024-го года, когда в моем парке инструментов наконец появился первый шуруповерт Makita и пара неоригинальных батарей. Тогда-то впервые и встал вопрос, чем и как их заряжать. И после непродолжительных поисков и раздумий было принято решение делать свою зарядку. О том, что у меня получилось и пойдет речь сегодня.
На рынке присутствует большое количество зарядных устройств для LXT-аккумуляторов, которые условно можно разделить на три группы:
С оригинальными зарядками всё просто – они предназначены для зарядки оригинальных аккумуляторов Makita. Также в них можно заряжать совместимые аккумуляторы, которые имеют желтый разъем и поддерживают базовые команды протокола Макиты. Основные модели – DC18SD и DC18RC. Еще существует двухпортовая DC18RD, но она встречается заметно реже. Выбирать зарядный ток в оригинальных зарядках нельзя, производитель делает этот выбор за вас. В случае DC18SD это «скромные» 2.6 А, а в случае DC18RC – до 9 А, поэтому последней категорически не стоит заряжать китайские аккумуляторы, зачастую для них это оказывается слишком много.
Неоригинальные зарядки с желтым разъемом предназначены, прежде всего, для зарядки неоригинальных аккумуляторов с таким же желтым разъемом. Заряжать оригинальные аккумуляторы в них теоретически можно, но лучше не стоит, так как это может заблокировать контроллер батареи, и дальнейшая её судьба окажется под вопросом (в сети есть проект разблокировки таких батарей, но, говорят, работает не со всеми). Устройств с регулировкой тока в этой категории я тоже не встречал, в основном это что-то фиксированное между 1.5 и 3 А и зависит от конкретной модели. Заряжать аккумуляторы без желтого разъема в таких зарядка не выйдет, они туда физически не встанут.
Наконец, неоригинальные зарядки без желтого разъема предназначены для зарядки таких же неоригинальных батарей и составляют самую многочисленную группу. Здесь можно найти как зарядки форм-фактора DC18XX Makita, так и зарядки меньшего размера, напоминающие подставку под батарею, и даже зарядки форм-фактора «блок питания» с круглым разъемом на выходе. Зарядные напряжения, токи, качество изготовления и цена таких зарядок очень сильно отличается, последнее время стали попадаться даже версии без прямого контроля выходного напряжения и тока буквально «за копейки». Поэтому пользоваться такими зарядками без предварительного анализа их характеристики и схемотехники я бы не рекомендовал. Также следует отметить, что сами батареи без желтого разъема часто предназначаются для «совместимого инструмента» и могут не работать с оригинальным без их доработки.
Проанализировав собранную информацию, я пришел к выводу, что универсального решения с возможностью настройки зарядного тока (и, возможно, даже подстройки напряжения), на рынке нет, поэтому остается только делать зарядное устройство самому. Тогда оно будет обладать именно теми характеристиками, которые мне нужны, заряжать именно так, как мне надо, да и просто потому, что полноценного диайвая в мире становится всё меньше, надо компенсировать.
Отдельно хочу добавить, что разрабатывать свое зарядное устройство и писать данную статью я начал раньше, чем разобрался с основными нюансами зарядки батарей Макита, которые описал в предыдущем обзоре, поэтому с самого начала желтого разъема в моей зарядке не было, что вы и увидите на многих фотографиях. Добавлен он был несколько позже, однако править уже написанный текст и обновлять фотографии не стал, пусть история останется в хронологическом порядке.
Самым простым вариантом самоделки было бы взять готовую китайскую CV/CC понижайку, добавить блок питания, регулятор, а также индикатор тока и напряжения и запихнуть это в какой-то походящий (возможно, напечатанный) корпус. Но таких проектов и без меня достаточно, вряд ли вам будет интересно читать про подобное еще раз. Да и я удовольствия от простого соединения проводов не получу, нужно что-то посложнее. Поэтому, будем собирать «с нуля». А если так, то начнем с желаемых характеристик:
Чуть позже, подумав, решил сделать её еще более универсальной и добавить:
С требованиями определились, теперь перейдем к HLD. В качестве «мозга» зарядки был выбран «народный» микроконтроллер ATMega328p. Выбрал его по нескольким причинам: во-первых, он всё еще широко распространен, и, если вдруг кто-то захочет повторить данное устройство, с мегой будет проще, чем с тем же STM32. Во-вторых, у AVR по современным меркам весьма ограниченные ресурсы, а писать программу в таких условиях значительно интересней простого закидывания кода очередным уровнем абстракций. Ну, и, в-третьих, эти меги у меня есть, так почему бы не найти им применение получше, чем лежание на полке?
Первоначально хотел, чтобы регулирующая часть была чисто аналоговой, выполненной в виде DC-DC на готовом чипе вроде XL4016, а МК лишь бы отдавал ей указания, какое напряжение (или ток) выдавать на выход. Но первое практическое испытание показало, что внешние управление XL4016 работает не очень хорошо, ведь внутреннее опорное напряжение неизвестно, а коэффициент усиления встроенного ОУ ошибки уменьшить нельзя. Получается очень нестабильная петля ОС, и схема то и дело желает перейти в генераторный режим. Да и у меги не очень высокая частота ШИМ для большой разрядности аналогового напряжения. Поэтому склонился в сторону выполнения DC-DC непосредственно на самой меге, воспользовавшись её ШИМ-генератором.
Теперь нужен экран для отображения напряжения, тока и отданной ёмкости. Сначала хотел использовать пару 8-рязрядных 7-сегментных индикаторов на MAX7219, но потом вдруг осознал – кому в наше время интересны красные сегментные индикаторы? Сейчас в моде цветные экраны с высоким PPI, как в смартфонах. И ведь такой есть у меня – им оказался небольшой IPS-дисплей с разрешением 240х240 точек и очень приятной цветопередачей, практически, маленький монитор:

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

Чтобы обеспечить на выходе напряжение 21 В, на вход необходимо подать больше. Я выбрал 24 В как стандартный номинал, найти блок на такое напряжение не составит труда. Но для того, чтобы запитать МК, необходимо 5 В, значит нужен понижающий DC-DC. Когда в устройство ставятся понижающие преобразователи, приоритет следует отдавать тем чипам, которые формируют требуемые напряжения без внешних деталей. Так надежней – если вдруг цепочка делителя обратной связи повредится, на выход может пройти более высокое напряжение, которое выведет из строя остальную часть схемы. Поэтому изначально я планировал использовать XL1509E-5.0, но в местном Чиподипе случился «пересорт» и указанной микросхемы в наличии не оказалось. Пришлось быстро искать на замену что-то подходящее по их каталогу, и таким преобразователем оказался TPS5430 (U5), после чего схема и плата были переделаны под него. В принципе, здесь подойдет любой другой DC-DC на 5 В, т.к. нагрузка небольшая, а у TPS5430 есть недостаток с точки зрения радиолюбителя – снизу корпуса у него расположен 9-й контакт, который необходимо обязательно подключить к общему проводу, без этого преобразователь не будет работать. То есть, запаять такую микросхему только паяльником не получится, нужен фен или нижний подогрев.
Для питания дисплея требуется напряжение 3.3 В. Оно получается из 5 В с помощью линейного стабилизатора AMS1117 (U3). Поскольку МК питается от 5 В, необходимо согласовать уровни напряжений выходных сигналов, идущих к дисплею. Вариантов согласования есть несколько, но я выбрал самый простой – гасящие резисторы. Такой вариант не самый красивый, но допустим, т.к. контроллер дисплея имеет в своем составе защитные диоды, идущие от каждого входа на плюс питания. Через эти диоды все излишки входного напряжения будут отправляться на питание контроллера, главное ограничить входной ток. При указанном номинале резисторов R2, R3, R6 и R7, ток через каждый не будет превышать 4.2 мА, что в сумме никогда не превысит 20 мА, которые потребляет дисплей в любом режиме. Дисплей подключается к плате через разъем J9.
За генерацию ШИМ-сигнала преобразователя будет отвечать канал А таймера 0 МК. Этот сигнал с выхода OC0A через усилитель на Q11, Q17 и Q13 идет на затвор P-канального полевого транзистора Q1. Конечно, сначала хотелось применить в схеме N-канальный транзистор, ведь у него и ниже сопротивление канала, и для управления можно использовать готовый чип вроде IR2110 или HCPL-3120. Но тогда понадобился бы отдельный источник +12 В для цепи затвора, стандартные схемы «вольтдобавки» здесь не подойдут, они все требуют непрерывной генерации, а тут преобразователь может быть выключен на неопределенное время. Поэтому, скрепя сердце, установил в схему P-канальный IRF4905, которые были куплены на Али много лет назад. Они определенно поддельные, но недавно в комментариях меня несколько утешили, предположив, что в ключевом режиме их использовать еще можно. Конечно, они значительно слабее оригинала, но у меня и мощность на нем рассеиваться будет в пределах 10 Вт, так что попробую.
Для управления ключом остановился на усилителе на дискретных компонентах. Q11 инвертирует сигнал и усиливает его по амплитуде до 12 В, затем двухтактный усилитель на Q13 и Q17 усиливает ток, чтобы быстро перезаряжать ёмкость затвора ключа Q1. Все транзисторы в усилителе переключаются быстро, потому что никогда не входят в насыщение. Q11 за счет резистора R33 в цепи эмиттера, а Q13 и Q17 – потому что включены по схеме с общим коллектором. А чтобы броски тока при перезаряде ёмкости затвора Q1 не вывели транзисторы из строя, в схему добавлен ограничительный резистор R30.
Испытания показали, что блок управления ключом обладает неплохими временными характеристиками – и нарастание, и спад сигнала на затворе происходят примерно за 150 нс, что позволяет применять такую схему на частотах даже в сотни килогерц:


На осциллограмме желтым цветом показан сигнал на выходе OC0A МК, розовым – на коллекторе Q11, а голубым – на затворе Q1. На следующих осциллограммах розовым цветом показан сигнал на стоке Q1, а желтый и голубой остались прежними:


Хорошо видно, что ключ очень быстро открывается за 10 нс с задержкой 35 нс относительно управляющего сигнала. С закрытием ситуация похуже – задержка составляет 180 нс, а само закрытие около 50 нс (на осциллограмме разрешение по оси Х уже 100 нс/дел). Тем не менее, это прекрасный результат, учитывая, что данной схеме предстоит работать на частоте всего 62.5 КГц.
Остальная часть ШИМ-преобразователя достаточно стандартная и состоит из дросселя L2, диода D1, снаббера C30+R48 и выходных конденсаторов C12 – C14. Далее напряжение через нормально разомкнутые контакты 3-5 реле К1 и токоизмерительный шунт R29 поступает на выход устройства.
Реле К1 на выходе установлено по двум причинам. Во-первых, МК будет отключать аккумулятор, если вдруг во время зарядки пропадет питающее напряжения, чтобы предотвратить разряд аккумулятора на внутренние цепи обесточенного зарядного устройства. А, во-вторых, оно позволит МК разорвать цепь, если вдруг транзистор Q1 выйдет из строя, и, таким образом, защитить аккумулятор от бесконтрольного заряда. Функция аварийного отключения крайне важна при заряде совместимых аккумуляторов Makita, ведь они могут не иметь в своем составе полноценных BMS, целиком полагаясь на контроль со стороны зарядного устройства. А литий-ионные аккумуляторы ни в коем случае не следует перезаряжать, поэтому при выходе зарядного устройства из строя и отсутствии защиты имеется вполне реальный шанс возгорания аккумулятора. Дополняя этот факт использованием ключевого транзистора сомнительного качества, становится очевидно, что наличие защиты в схеме просто необходимо.
Измерение выходного тока осуществляется с помощью шунта R29 сопротивлением 10 мОм. При таком номинале и максимальном токе 6 А на шунте будет падать 60 мВ и рассеиваться 0.36 Вт, что является оптимальным соотношением. Но 60 мВ – слишком мало для непосредственного измерения с помощью АЦП МК, поэтому напряжение с шунта подается на инструментальный усилитель с коэффициентом усиления 10, выполненный на U1.2. Так как опорное напряжение АЦП задается электронным стабилитроном D2 ICL8069 и примерно равно 1.22 В, максимально возможное измеряемое значение тока составляет 12.2 А. Это больше 6 А, которые я хочу снимать с устройства, но такой запас оказался полезен, позже я поясню почему.
Аналогичный инструментальный усилитель с коэффициентом усиления 1/20, выполненный на U1.1 используется для измерения выходного напряжения зарядного устройства, которое снимается непосредственно с выходных клемм. Использование четырехпроводной схемы позволяет компенсировать падение напряжения на проводниках, дорожках печатной платы, контактах реле, а также на токоизмерительном шунте, что, в свою очередь, позволяет установить шунт в минусовой провод устройства и немного упростить схему. Данный усилитель не увеличивает, а уменьшает напряжение в 20 раз, что позволяет МК измерять значения примерно до 24.4 В.
Несмотря на сложное название, инструментальный усилитель выполняет простую функцию. Это усилитель разности напряжений – он берет значение напряжения на прямом входе, вычитает из него значение напряжения на инверсном входе и усиливает полученную разницу в заданное число раз. Существует несколько известных схем инструментальных усилителей, из которых наиболее правильная – на трех ОУ. А самая простая на одном. К недостаткам простой схемы относится необходимость точного подбора резисторов делителей так, чтобы коэффициенты деления двух цепочек были очень близки, что затруднительно в серийном производстве, поэтому там применяют более сложные схемы. А для самодельного устройства вполне подойдет и простая, если предварительно подобрать мультиметром резисторы с максимально близкими сопротивлениями. Подбирать следует пары R4/R14, R5/R15, R18/R22 и R19/R23. Точное значение не так важно – это позже можно будет скорректировать программно, главное, чтобы резисторы в парах были максимально одинаковы.
Сначала я использовал в инструментальном усилителе распространенный LM358, ведь высоких требований к быстродействию ОУ здесь нет, но на этапе тестирования выяснилось, что у него прослеживается ощутимая зависимость выходного напряжения каналов друг от друга, а также от температуры. Поэтому ОУ был сменен на TL082C, где эта зависимость ниже.
Отдельно следует рассмотреть питание ОУ. Начало шкалы измерений АЦП МК лежит ровно в нуле вольт, поэтому ОУ должны иметь возможность выдавать такое напряжение на своих выходах. Казалось бы, можно просто взять R2R ОУ, но даже они не в состоянии выдать ровно ноль вольт, их минимум начинается где-то от 25 мВ и сильно зависит от нагрузки. А 25 мВ – это примерно 21 единица шкалы АЦП или 2%, и это слишком большая погрешность при измерении тока. Поэтому необходим дополнительный источник отрицательного напряжения для питания ОУ.
Чтобы не ставить еще один преобразователь, было решено получить отрицательное напряжение с помощью диодного-ёмкостного умножителя на C22, D9, D10 и C24, подключенного к выходу понижающего преобразователя U5 через ограничительный резистор R40. При нормальной работе преобразователя под нагрузкой на его выходе присутствует меандр амплитудой 24 В, который «отражается» умножителем, и конденсатор C24 заряжается напряжением порядка -22 В. Это напряжение уменьшается до -4.7 В стабилитроном D11 и используется для питания ОУ. Для преобразователя умножитель выполняет роль снаббера, уменьшая выбросы на его выходе, но и немного увеличивая нагрев.
Поскольку напряжение на выходах ОУ теперь может оказаться отрицательным, необходимо защитить от него МК. Эту роль выполняют резисторы R11 и R20, которые совместно с конденсаторами C4 и C9 также образуют ФНЧ, дополнительно фильтрующие высокочастотные помехи.
Еще одним нюансом схемы является резистор R44. Его задача – сдвинуть точку нуля токовой шкалы в область положительных напряжений. Дело в том, что за счет неидеальности ОУ и других элементов схемы, на входе АЦП МК оказывается небольшое (несколько милливольт) отрицательное напряжение смещения, которое препятствует измерению малых значений выходного тока. Да, это смещение можно скорректировать программно, чтобы получить правильные измерения на больших токах, но измерять малые токи всё равно не получится. Поэтому требуется аппаратная корректировка. Сопротивление R44 подбирается так, чтобы при отсутствии выходного тока напряжение на входе АЦП МК было чуть больше нуля, у меня это достигается на значении 620 КОм. Если вдруг корректировка окажется несколько чрезмерной, ничего страшного – отклонение в положительную сторону отлично корректируется программно.
В принципе, ИУ напряжения тоже нужна похожая корректировка, но ей можно пренебречь, ведь его коэффициент усиления мал, да и работа с околонулевыми выходными напряжениями в зарядке не предусматривается вообще.
В остальной части схемы нет ничего интересного. Выход канала B таймера 0 генерирует сигнал PWM
с той же частотой 62.5 КГц, используемый для управления вентилятором обдува. Этот сигнал преобразуется в напряжение элементами Q2, L1, D4, C5. В контроле результирующего напряжения необходимости нет, требуемые значения PWM всё равно подбираются экспериментально под используемую модель вентилятора.
16-разрядный таймер 1 МК используется для генерации звуковых сигналов. Его выход А управляет транзистором Q4, который подает напряжение на пьезокерамический излучатель PZ1. Использование резисторов R21 и R47 достаточно больших номиналов совместно с ёмкостью излучателя образует ФНЧ, что позволяет изменять громкость звучания с помощью длины импульсов, а для её общего повышения излучатель питается от 24 В.
На ОУ U4.1 реализован датчик снижения напряжения питания. ОУ работает в режиме компаратора с небольшим гистерезисом, обеспечиваемым положительной обратной связью через резистор R49. Пороговое напряжение срабатывания датчика – порядка 23.5 В, напряжение восстановления – около 23.7 В. U4.2 используется для анализа напряжения на 4-м контакте желтого разъема Макиты, снижение которого ниже примерно 1.3 В (установлено опытным путем) сигнализирует о проблемах со стороны батареи и необходимости остановить зарядку. К сожалению, установка желтого разъема в зарядку произошла уже на этапе отладки, когда основная плата была полностью готова, поэтому необходимые дополнительные детали разместились на отдельной небольшой плате.

На всех входах ОУ, подключенных к внешним контактам зарядного устройства применяется защита от статического напряжения на диодах D3, D5, D6 и D7.
Для измерения температуры я использовал цифровые датчики TMP100A, которые уже успешно применял в своих предыдущих проектах. Это небольшая 6-выводная микросхема в корпусе SOT23-6, позволяющая измерять собственную температуру с разрешением 0.06 градуса и общающаяся с МК по протоколу I²C, за счет чего на один интерфейс можно подключить до 8 таких датчиков.

В зарядном устройстве я использовал два – один для измерения температуры радиатора платы и другой для косвенного измерения температуры батареи. Датчики располагаются на отдельных платах и подключаются к основной плате через разъем J13.
Я намеренно оставил выводы TxD и RxD МК свободными, т.к. на этапе проектирования предполагал возможное подключение зарядного устройства к ПК по последовательному порту. Однако, по мере написания прошивки контроллера стало очевидно, что такое подключение не нужно, поэтому в финальном варианте эти выводы просто не задействуются.
Печатные платы делать не люблю, с удовольствием заказывал бы готовые, если бы их могли делать быстро. Иначе может получиться, что пока плату будут изготавливать, интерес к устройству пройдет и проект будет заброшен, поэтому приходится делать самому. В основном, использую две технологии изготовления – фоторезист и ЛУТ. Фоторезист дает значительно более высокое качество, чем ЛУТ, но и требует больше усилий, поэтому делаю этим способом большие и важные платы, а для маленьких сейчас использую ЛУТ. Изготовление качественных двухсторонних плат тоже не освоил, стараюсь разводить всё в одном слое с перемычками. Если есть возможность, предпочитаю использовать старые through-hole/DIP компоненты, потому что надо их куда-то тратить, да и разводить односторонние платы для них проще.
Основная плата зарядки получилась размерами 130х60 мм и, надо сказать, это уже предел для моего принтера. Несмотря на то, что срок годности фоторезиста Ordyl истек еще в 2017 году, плата вышла отличная, лишь немного пришлось уменьшить время экспозиции (до 60 секунд):


На фото вытравленная плата представлена в первоначальном варианте, а нарисованная – в обновленном. В процессе сборки и наладки схема претерпела небольшие изменения, рисунок платы менялся. Свою же переделывать не стал, просто удалял существующие дорожки и «креативил» новые перемычками из проволоки. Также пропаял все силовые цепи медной проволокой диаметром чуть меньше 1 мм, чтобы снизить их нагрев на максимальном токе. Для пайки использовал свой основной паяльник Т12, TS101 как-то не «зашел». Почти всю плату спаял жалом ВС2 на 285-ти градусах, кроме «тяжелых» мест, где применял ВС3. Фото собранной платы с нижней стороны не сделал – из-за доработок там получилось всё несколько страшненько, а фотографии со стороны деталей будут дальше.
Для датчиков температуры TMP100 сделал отдельные небольшие платы, позволяющие закреплять их винтами М3, прижимая микросхему корпусом к измеряемому элементу. Один датчик разместил на радиаторе ключа и диода, второй – на минусовом контакте батареи, так с ней будет хоть какая-то тепловая связь. Платы делал ЛУТом, из-за чего их качество существенно ниже основной. Вот так они выглядят вблизи:


То ли я что-то неправильно делаю, то ли мой принтер не подходит для ЛУТ, но тонер не обеспечивает равномерной защиты медного слоя, и он подтравливается. Собранная плата выглядит следующим образом:

Кроме самого датчика на ней установлен конденсатор по питанию, провода шины I²C и две перемычки, определяющие адрес датчика на шине. Все части платы, кроме самой микросхемы, защищены от электрического контакта с измеряемой деталью с помощью каптонового скотча.
В качестве блока питания был выбран недавно обозревавшийся тут Suswe U-shaped 24 В 10 А (фотография со страницы товара):

Блок питания не самый дешевый (в начале осени заказывал за 2155 рублей с доставкой), но это LLC, он имеет хороший запас по току и активный PFC – пора и в самодельных устройствах переходить на новый уровень. В принципе, нареканий на него нет, но есть пара нюансов. Во-первых, плата снизу чуть грязновата:

Во-вторых, изначально в блоке была плохо согнута Г-образная пластина, на которую устанавливаются высоковольтные транзисторы, из-за чего их выводы оказались на расстоянии меньше 1 мм от указанной пластины! Для 400 В это слишком мало, попадет немного пыли, повысится влажность и будет пробой. А это замена деталей, обугливание платы, в общем, ничего хорошего.
Когда стал разбирать блок, чтобы подогнуть пластину, тактильно обнаружил, что высоковольтный конденсатор более 10 минут сохраняет заряд! Все дело в том, что для достижения минимального тока ХХ в этом блоке на конденсаторе нет разрядных резисторов, а контроллер блокируется UVLO, из-за чего высокое напряжение в первичной цепи сохраняется достаточно долгое время. Так делать нельзя, поэтому добавил разрядный резистор самостоятельно:

Еще оказалось, что выходное напряжение блока по умолчанию было примерно 23.8 В, что для меня слишком мало. Поднял его до 24.5 В запаиванием резистора R23 на плату, там специально для этого есть пустое место. Номинала, к сожалению, сейчас не помню, но его несложно посчитать при необходимости.
Написание программы для МК в таком проекте – не самый сложный, но наиболее трудозатратный этап. Уже сейчас исходные коды программы занимают практически 200 КБ, а это еще даже не все желаемые функции реализованы, некоторые еще только предстоит запрограммировать.
Обычно для AVR я использую IDE от производителя – Microchip Studio. Но это затрудняет повторение проекта, ведь ПО специфическое, оно есть далеко не у всех. Поэтому в этот раз решил целиком реализовать проект на PlatformIO, open source плагине для MS Visual Studio Code, позволяющим писать программы под разные МК с использованием разных фреймворков. Среди них, кстати, есть и Ардуино, но, когда речь идет о быстром и качественном ПО для AVR, к сожалению, Ардуино нам не помощник. Поэтому проект будет написан «с нуля» без использования фреймворков. Не буду подробно описывать моменты создания и настройки проекта, перейду сразу к описанию программного решения.
Основная функция устройства – зарядка аккумуляторов или управляемый понижающий DC-DC преобразователь с контролем выходного напряжения и тока. Для повышения КПД сейчас большинство таких преобразователей используют PWM, то есть, работают за счет изменения продолжительности управляющих импульсов. Описываемая зарядка не является исключением, сигнал PWM формируется МК аппаратно с помощью канала А таймера 0. Таймер 8-разрядный, работает от тактовой частоты МК, равной 16 МГц, что дает результирующую частоту PWM 62.5 КГц – не очень много по современным меркам, но вполне достаточно. Для поддержания выходного напряжения и тока на заданном уровне, их значения измеряются с помощью встроенного в МК 10-разрядного АЦП и подаются на вход ПИД-регулятора, который управляет шириной генерируемых импульсов. Так петля управления замыкается.
Код более высокого уровня выставляет желаемые значения выходного напряжения и тока в зависимости от текущего режима работы, что и обеспечивает требуемое функционирование устройства. Еще на более высоком программном уровне реализовано взаимодействие с пользователем, позволяющее ему выбирать и контролировать режим работы зарядного устройства. Для этой цели используется графический дисплей, подключенный к МК по интерфейсу SPI и поворотный энкодер, обработка сигналов которого осуществляется программно.
Основная часть кода написана на языке С/С++, однако, так как речь идет о достаточно слабом по современным меркам МК AVR, не обошлось и без ассемблера, и некоторые функции написаны на нём. Здесь хочу отдельно отметить, что программирование на ассемблере под AVR мне очень нравится, так как позволяет раскрыть полный потенциал этих МК. Система команд достаточно простая, есть четкие тайминги их выполнения, а разработчику доступно много регистров общего назначения. Всё это позволяет писать компактные, быстрые и эффективные куски ассемблерного кода.
Отдельно отмечу интересную особенность gcc, используемого для компиляции исходного кода в PlatformIO – ассемблерные файлы здесь имеют расширение (*.s). Причем, если вы укажете расширение с маленькой буквой (*.s), для компилятора это будет чистый ассемблерный файл, поддерживающий только синтаксис ассемблера. Если же указать расширение с большой буквы (*.S), это уже будет ассемблерный файл с поддержкой некоторых директив компилятора С, таких как, например, #define. Это позволяет подключать заголовочные файлы С/С++ с определениями различных констант МК непосредственно в ассемблерный код, чтобы избежать указания их числовых значений напрямую. По этой причине все ассемблерные файлы проекта имеют расширение *.S.
Разрядность АЦП – всего 10 бит. При максимальном напряжении 24 В, разрешение измерений составляет 23 мВ, то есть, не позволяет устройству оперировать даже сотыми долями вольта. Поэтому я решил суммировать 4 последовательных измерения, чтобы повысить итоговое разрешение до 6 мВ. В реальности, конечно, это не означает, что я могу получать точный 12-битный результат каждые 4 измерения, но на длинной дистанции это работает. Ток будет измеряться с разрешением 3 мА, что тоже приемлемо, а измерения тока и напряжения будут происходить попеременно, чтобы получить максимально релевантный результат.
В итоге, я получаю новые 12-битные значения тока и напряжения через каждые 8 прерываний таймера или 7812.5 раз в секунду. И каждый раз, получив эти значения, запускается алгоритм ПИД и корректирует ширину импульсов PWM. Это позволяет получить приемлемое для зарядного устройства время отклика регулирующей цепи.
Сам алгоритм ПИД, примененный в зарядке – упрощенный. По сути, он является ПИ-алгоритмом, так как не использует дифференциальную составляющую, потому что в моих предварительных экспериментах от неё было больше помех, чем пользы. Также ПИ-коэффициенты не вынесены в настройки, а жестко заданы в коде и являются степенями двойки, чтобы упростить вычисления слабенькому 8-разрядному МК. Но это сильно не сказывается на качестве работы алгоритма, ведь на выходе стабилизатора установлены конденсаторы суммарной ёмкостью 940 мкФ, а чтобы зарядить или разрядить такую емкость нужно время.
Первым шагом ПИД-алгоритма является сравнение измеренных значений тока и напряжения с заданными, и, если какое-то из них превышает установленное, алгоритм меняет режим работы, выбирая СС или CV, соответственно. В случае же, когда и ток, и напряжение оказались меньше заданных, алгоритм продолжает работать в прежнем режиме. Это очень важно, ведь в цифровом решении такое происходит постоянно, когда очередное измеренное значение вдруг оказалось на единицу меньше предыдущего за счет простой ошибки измерения.

Затем ПИД-алгоритм обновляет значение интегратора и высчитывает новый коэффициент PWM. Первоначально я сделал его 8-разрядным, так как именно такая разрядность у таймера меги. Однако, эксперименты показали, что в этом случае выходное напряжение имеет слишком большую амплитуду хаотичных пульсаций – до 200 мВ, причем эта амплитуда меняется в зависимости от того, какое именно постоянное напряжение сейчас создается на выходе стабилизатора. Очевидно, что 8 разрядов для управления PWM не хватает, ведь это всего лишь 256 возможных градаций, что дает мгновенное разрешение стабилизатора около 100 мВ.
Тогда был введен программный dithering — размер коэффициента PWM был увеличен до 16 бит, из которых старшие 8 идут непосредственно в регистр таймера, а младшие 8 суммируются в дополнительной 8-разрядной переменной. Если после выполнения очередной операции сложения возникает переполнение и устанавливается флаг переноса С, то значение коэффициента PWM в регистре таймера увеличивается на 1 для следующего импульса. Так как коэффициент PWM обновляется один раз за 8 прерываний таймера, такое решение фактически добавляет 3 дополнительных бита к разрешению, поэтому после его внедрения хаотичные пульсации значительно снизились.
Еще один нюанс управления PWM заключается в том, что мега ни при каком значении регистра OCR0A таймера не позволяет получить на выходе абсолютный логический ноль. То есть, полностью выключить PWM лишь изменением его коэффициента невозможно, даже при значении 0 в сигнале остаются короткие иголки длительностью 62.5 нс. Поэтому приходится полностью отключать генерацию выходного сигнала таймера с помощью регистра управления TCCR0A в моменты, когда преобразователь нужно выключить.

Но еще более интересная особенность была найдена значительно позже, когда устройство уже было полностью собрано и смонтировано в корпус. Оказывается, из-за того, что момент старта измерения АЦП полностью синхронизирован с частотой PWM, если плавно увеличивать коэффициент PWM, есть такой диапазон его значений, когда генерируемая в момент закрытия ключа помеха попадает на момент сэмплирования входного сигнала преобразователем и результат измерения искажается! Искажается не очень сильно (где-то на 20 единиц АЦП или на 2%), но внешне это проявляется как наличие у стабилизатора участка с отрицательной передаточной характеристикой, где увеличение коэффициента PWM приводит к уменьшению выходного напряжения. Поскольку проявлялась эта особенность при выходном напряжении около 6.8 В, то есть, вне рабочего диапазона зарядки, можно было бы просто закрыть на это глаза. Но я люблю ночью спать спокойно, а не мучаться в кошмарах, поэтому решил недостаток устранить.
Наиболее правильным было бы защитить схему измерения от помех. Экспериментально выяснил, что помеха проходит по цепи общего провода, где избавиться от неё значительно сложнее. Добавление индуктивности приличного номинала действительно помогало, но она добавляла смещение, и хоть инструментальный усилитель на входе и должен был его нивелировать, точность измерения тока существенно падала. Да и плата на тот момент была уже полностью собрана, что-либо переделывать не хотелось.
Следующим вариантом была попытка перевода АЦП в режим автоматических измерений и, таким образом, отвязки момента старта измерения от частоты PWM. Это тоже помогло, участок с отрицательной передаточной характеристикой исчез, однако, выводимые на экран измеренные значения начали хаотично прыгать в десятых долях. Логично, ведь теперь помеха попадала на момент измерения периодически, а не только в узком диапазоне коэффициентов PWM. То есть, изначальное решение синхронизации АЦП и PWM было правильным.
Решение нашлось неожиданно – поделился проблемой с супругой, и она спросила, зачем я провожу измерения именно в то время, когда на вход попадает помеха. И ведь да, зачем? Я же точно знаю, когда начинается и заканчивается выходной импульс, так как сам задаю его ширину, также я точно знаю, когда начинается измерение, т.к. сам его запускаю. Значит, если я понимаю, что закрытие ключа ожидается в момент начала измерения, мне просто надо перенести измерение на другое время.
Очевидно, что сдвигать измерение надо не менее, чем на 1 такт АЦП или на 16 тактов МК. Но слишком далеко переносить тоже нельзя, ведь само измерение занимает 208 тактов, а через 256 тактов придет новое прерывание и, если начать измерение слишком поздно, результат не будет готов к следующему прерыванию. Посчитал команды, оказалось, в обычной ситуации я запускаю измерение через 43 такта от начала обработчика, поэтому решил переносить «назад», то есть, на более раннее время. Написал дополнительную ветку кода, обсчитал её – 26 тактов, то есть, на 17 тактов раньше. Отлично, это ровно то, что нужно! Дальше подобрал оптимальное значение порогового коэффициента, и проблема действительно ушла – участок с отрицательной характеристикой исчез, а показания остались стабильными, как и прежде. Это была маленькая победа.
В коде, кроме дополнительной ветки добавились всего две строчки:

Теперь, когда есть пригодные для отображения результаты измерений, надо их, собственно, отобразить. Вряд ли кому-либо будет интересно видеть «голые» значения, считанные из АЦП, они неинформативны. Для отображения их надо преобразовать в удобочитаемые числа, отражающие привычные нам вольты и амперы. АЦП – штука линейная, поэтому преобразование будет тоже линейным, для чего достаточно двух калибровочных коэффициентов – смещения и множителя. То есть:
Vdisp = (Vadc + Vofs)*Vk
Idisp = (Iadc + Iofs)*Ik
Числа с плавающей точкой для AVR – это как обычному человеку пробежать марафон: может и реально, но лучше не надо, поэтому я использую только целочисленную арифметику. Напряжение и ток должны отображаться с двумя знаками после запятой, то есть максимальные значения составят 2400 и 999. В 8 бит такие числа не помещаются, поэтому придется использовать 16. А если уж использовать 16 бит, то можно и пределы увеличить в 10 раз, до 24000 и 9999, соответственно. Это положительно скажется на точности, да и значения будут в понятных единицах – в милливольтах и миллиамперах.
Максимальное значение, считываемое из АЦП равно 1023*4 = 4092, поэтому перепишем формулу следующим образом:
VdispX1000 = ((Vadc + Vofs)*Vk)/4096
IdispX1000 = ((Iadc + Iofs)*Ik)/4096
Тогда Vofs и Iofs будут корректирующими коэффициентами, позволяющими выставить правильное начальное смещение измерений, а Vk и Ik – множители тока и напряжения, численно равные максимально возможному измеренным величинам (то есть, примерно 24500 и 12200). Код преобразования измерений не будет выполняться часто, быстродействие тут не нужно, поэтому пишу его на си:

Но, к сожалению, без ассемблера и тут не обошлось – в алгоритме требуется деление на 4096 или сдвиг вправо на 12 разрядов. Я бы мог еще понять, если gcc не умеет эффективно сдвигать на 4 разряда, но на 8-то сдвиг делается простым присвоением регистров! Но нет, gcc всё это уложил в цикл из 12 итераций, из-за чего его код выполняется 84 такта. Да, с точки зрения работы программы это мелочь, такие преобразования вызываются считанные разы в секунду, но я люблю оптимальные программы, поэтому переписал эти две функции на ассемблере:

Не считая времени на вызов и возврат, такой сдвиг выполняется всего 9 тактов, то есть, в 9 раз быстрее gcc.
Следующей интересной задачей оказался подсчет отданной в аккумулятор ёмкости. Хоть это значение во многих случаях и не очень полезно, без него зарядное устройство теряет всю свою привлекательность – человеку обязательно нужно видеть увеличивающееся число. Это завораживает, это как смотреть на горящий огонь или печатающий 3Д-принтер, это индикатор прогресса, индикатор жизни, и только так человек понимает, что зарядка работает. Поэтому делать обязательно надо. Но как?
Опуская все этапы размышлений, подробно описанные в комментариях в файле timer_int.S, скажу, что, на самом деле, это достаточно просто. У меня есть измерения выходного тока, выполняемые с некоторой периодичностью. Если численно умножить каждое такое измерение на интервал времени между соседними измерениями, мы и получим ёмкость, отданную за этот интервал. А если сложить несколько таких измерений за некоторый промежуток и снова умножить – получим ёмкость, отданную за этот промежуток. То есть, всё, что надо делать – это просто складывать значение тока после каждого измерения, а непосредственно перед выводом пользователю умножать эту сумму на определенный коэффициент.
Подсчеты показали, если я хочу иметь возможность считать до 100 Ач, для сложения измерений без потери точности нужна переменная размером 44 бита. Или 6 байт. Это много для AVR, но, к счастью, все эти 48 бит не нужны для отображения результата – ведь достаточно трех цифр после запятой. В итоге, после расчета всех коэффициентов у меня получился вот такой простой код:

Эта функция сразу формирует строку, содержащую отданную емкость в текстовом виде и пригодную для печати на экран, которую она сохраняет в глобальную переменную g_buffer. В современном С++ существует тенденция осуждения использования глобальных переменных, и на то есть весьма обоснованные причины. Но для микроконтроллеров такое использование вполне оправдано, ведь оно позволяет отказаться от менеджера памяти, передачи лишних параметров и, таким образом, экономить ресурсы. Поэтому я всегда использую глобальные переменные в своих программах там, где это не противоречит программной логике.
На этом этапе код, отвечающий за формирование и измерение выходного напряжения и тока можно считать завершенным. Следующий шаг – работа с дисплеем.
Для данного дисплея в Ардуино есть отдельная библиотека, которая называется Adafruit_ST7735_and_ST7789_Library. Скачиваем её и начинаем разбираться, параллельно подглядывая в даташит на сам контроллер. И первые вопросы возникают тут же – дисплей подключается к МК по протоколу SPI, и в Ардуино SPI инициализируется в режим 2 (выдача очередного бита данных по переднему фронту тактового сигнала), в то время как даташит показывает, что нам нужен режим 3 (выдача данных по заднему фронту). Как такое может быть, и почему код Ардуино работает у множества людей?
Провел тест, и он показал, что дисплею действительно нужен режим 3, хотя он работает и в режиме 2, только менее стабильно – помните, для согласования уровней сигналов МК и дисплея я использовал простые резисторы? Я начал постепенно увеличивать их сопротивления, уменьшая таким образом временные характеристики соединения, и в режиме 2 дисплей начал давать сбои, в то время как в режиме 3 продолжал еще работать нормально. Почему же дисплей вообще работает в режиме 2? Оказывается, если внимательно посмотреть осциллограммы сигналов на шинах SPI, можно заметить, что тактовый сигнал запаздывает относительно сигнала данных на несколько наносекунд. Дисплей достаточно быстрый, и вот это небольшое, практически незаметное «цифровому глазу» запаздывание позволяет ему правильно принимать данные во втором режиме SPI. Интересно, Atmel сделали это намеренно?
В итоге, мой код инициализации дисплея получился сильно меньше того, что в Ардуино:

Ну, а дальше началось самое интересное. Чтобы обновить изображение на дисплее целиком, ему нужно передать 240*240*2 = 115200 байт = 921600 бит в 16-битном режиме цветности. Это весьма много для скромной меги, SPI которой может работать максимум на 8 МГц. И режима 8-битной цветности, которого бы вполне хватило для моей задачи у дисплея тоже нет (есть режим 12 бит, но он совершенно неудобен). В принципе, тут можно честно сказать, что этот дисплей «великоват» для меги. Но МК уже выбран, часть кода написана и другого дисплея под рукой нет, так что продолжаем продолжать.
Основное, что надо выводить на дисплей в зарядном устройстве – это текст. Значит, снова идем в наш любимый Ардуино, чтобы подсмотреть вывод текста там (Adafruit_GFX_Library). Но то, что я увидел просто повергло меня в ужас. Вывод текста там реализован двумя вложенными циклами, внутри которых для каждого закрашенного пикселя шрифта вызывается отдельная функция drawPixel, которая выбирает на дисплее новое «окно» размером один пиксель, после чего заполняет его нужным цветом. Мало того, что это крайне медленно, так еще и не позволяет перетирать одну строчку текста другой – ведь на дисплей передаются только закрашенные пиксели и текст от двух строчек просто наложится. Сами авторы библиотеки об этом знают, но считают, что реализовать по-другому просто невозможно:

Моргание измеряемых значений на экране неприемлемо, таким устройством будет невозможно пользоваться, надо делать что-то свое. Подумав, я решил взять из библиотеки Ардуино само графическое изображение открытого шрифта Open Sans (чтобы не изобретать велосипед), а весь код его вывода написать с нуля и на ассемблере, так как очевидно, что на Си он будет недостаточно быстрым.
Эксперименты с SPI показали, что помещать в регистр SPDR данные можно не чаще, чем один раз в 18 тактов, иначе передача сбивается. Это дает максимальную пропускную способность в 889 КБ/сек или 7.7 FPS на выбранном дисплее. Немного, но для зарядного устройства вполне хватит – большинство мультиметров производят всего 3 измерения в секунду и это всех устраивает, значит, здесь тоже можно ориентироваться на такую частоту. В общем, требуется написать такой код вывода символа, который будет выводить изображение вместе с заднем фоном и подавать очередной байт в регистр SPDR ровно через 18 тактов.
Ситуацию несколько усложняет формат, в котором хранится шрифт в Ардуино – для уменьшения места, занимаемого в памяти, от каждого символа хранится только центральный прямоугольник, где имеются закрашенные пиксели, и он для каждого символа свой. То есть, код вывода должен будет рисовать вокруг символа рамочку цветом заднего фона, рисовать сам символ и, что самое главное, делать это в реальном времени, подавая очередной байт в SPDR ровно через 18 тактов!
%symb%
И такой код был написан, это функция PrintGlyph в файле display_asm.S. Она устанавливает окно в контроллере дисплея по внешнему размеру символа, после чего попиксельно выводит символ в рамке слева-направо сверху-вниз. За счет того, что символ выводится с закрашенным задним фоном, становится возможно замещать на экране одну строку текста другой без моргания. А учитывая, что ширина всех цифр в шрифте Open Sans одинаковая, это позволяет красиво обновлять любые цифровые значения. Именно то, что было нужно.
Дальше я написал функцию FillRect, которая закрашивает указанный прямоугольник указанным цветом. С помощью этой же функции можно рисовать вертикальные и горизонтальные линии, если задать ширину или высоту прямоугольника достаточно малой. Функция спроектирована точно таким же образом, чтобы подавать очередной байт в регистр SPDR ровно через 18 тактов. Только здесь это сделать было значительно проще.
Поскольку для несложных графических интерфейсов данных двух функций вполне достаточно, решил ими и ограничиться. Конечно, можно было бы еще написать код вывода небольших спрайтов, однако, ПЗУ такого простого контроллера как ATMega328 банально на них не хватит – ведь даже небольшая иконка 32х32 пикселя будет занимать целых 2 КБ или 1/16 от всего объема ПЗУ! Так что интерфейс будет без иконок.

Этот код запускается каждое 8-е прерывание таймера, то есть, с частотой 7 812,5 Гц, что позволяет отлавливать примерно до двух тысяч тиков энкодера в секунду, чего более чем достаточно для любого применения. А вот анализ нажатия кнопки энкодера производится уже в обработчике таймера на С++, который вызывается 100 раз в секунду:

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

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

Для генерации звуковых сигналов используется 16-разрядный Timer 1, работающий в режиме Phase Correct PWM. Максимальное значение счетчика и, соответственно, частота выходного сигнала задается регистром ICR1, что при входной частоте 2 МГц позволяет получить на выходе практически любой звуковой тон. А значение регистра OCR1A задает ширину импульса, которая определяет громкость воспроизводимого сигнала. Осталось прикрутить какой-либо «плеер» музыки, и дело в шляпе.
Музыкой профессионально я никогда не занимался, но в институте увлекался разными трекерами (типа Fast Tracker, Impulse Tracker, Open ModPlug Tracker и т.д.), пытался подбирать мелодии, редактировать и даже писать что-то свое. Поэтому базовое понимание основ имеется, для такой простой задачи, как управление одноголосым синтезатором таких знаний вполне хватит. Постараюсь кратко их изложить.
Итак, мелодия состоит из нот, каждая из которых однозначно определяет основную частоту генерируемого звукового сигнала. Всего разных нот – двенадцать, дальше они начинают повторяться, но уже в соседней октаве. Соседние октавы отличаются друг от друга по частоте ровно в два раза, а ноты распределены по каждой октаве равномерно, если смотреть на логарифмической шкале. То есть, соседние ноты отличаются друг от друга в корень двенадцатой степени из двух или в 1,0595 раза. Это так называемый равномерный строй, который сейчас повсеместно используется. Добавляя к этой зависимости отправную точку – ноту Ля 4-й октавы (обозначается А4), частота которой составляет 440 Гц, можно вычислить весь звуковой ряд. Кстати, для этого я написал отдельный скрипт на языке Perl — sound.pl.
Традиционно считается, что для практического большинства мелодий достаточно 88 разных нот, звучащих в диапазоне от 27.5 Гц до 4186 Гц, поэтому на классическом фортепиано 88 клавиш. Более низкие частоты человек попросту не слышит, а более высокие – не различает, поэтому при построении мелодий нет смысла их использовать. То есть, с точки зрения информации для хранения ноты достаточно 6.5 бит. Самым простым решением было бы использовать для этого отдельный байт, тогда с его значением не надо проводить никаких манипуляций. Но ведь в мелодии у нот кроме тона есть еще и продолжительность, которую тоже надо хранить. То есть, получается, для одной ноты надо уже два байта.
Казалось бы, какая мелочь в наше-то время эти два байта на ноту. Однако, микроконтроллер у нас «плюшевый», и памяти у него всего 32 КБ, так что попробуем уложиться в один байт. Для этого, прежде всего, ограничим количество разных нот – их будет только 32, от Ми 4-й октавы (Е4) до Си 6-й октавы (В6). Такого количества нот вполне хватит для воспроизведения основной партии практически любой популярной мелодии, а другие в зарядке и не нужны. Зато нота теперь будет занимать 5 бит, позволяя использовать три оставшихся для указания её длительности, что дает 8 различных вариантов. Точнее, их будет 7, потому что 8-й со значением 0 будет использоваться для указания дополнительных действий, таких как окончания мелодии, продления звучания текущей ноты (если она длиннее 7-ми тактов) и паузы.
Что касается длительности нот – она измеряется в тактах, продолжительность которых зависит от темпа мелодии. Темп задается в традиционных для музыки единицах, BPM (Beats Per Minute) – количестве ударов в минуту. При этом, для размера 4/4 (наиболее популярный музыкальный размер) один удар состоит из четырех тактов. Таким образом, если взять темп 125 ВРМ 4/4, на одну секунду будет приходиться 2.083 удара или 8.333 тактов. То есть, продолжительность одного такта составит ровно 120 миллисекунд. Поскольку у меня в коде есть таймер, выполняющийся с частотой 100 Гц, удобно повесить музыкальный плеер на него. В данном случае новый такт будет наступать через 12 вызовов таймера.
Просуммировав всё сказанное выше, был написан код музыкального плеера, уместившегося в 35 строчек:

А для упрощения задания нот в исходном коде были написаны небольшие макросы, с использованием которых закодированная мелодия выглядит следующим образом:

На этом, наверное, следует завершить рассмотрение программной части, иначе я не уложусь в допустимый объем обзора. Поэтому перейдем к интерфейсу пользователя.
Поскольку в зарядке используется цветной графический дисплей, обойтись простым накидыванием на экран показаний тока и напряжения не выйдет, необходимо проработать полноценный графический интерфейс. Это удобно делать на ПК в хорошем графическом редакторе, например, в фотошопе. А чтобы нарисованный интерфейс потом было несложно перенести в код МК, при рисовании следует использовать только те графические примитивы, которые умеет рисовать МК. То есть, в моем случае это строки текста размером 12 и 18 пунктов, линии и закрашенные прямоугольники. Что касается цветов, то так как экран 16-битный, можно использовать всю палитру RGB.
Поскольку я взял шрифты из библиотеки Арудино, первым делом следует подобрать аналогичный размер шрифтов на ПК. Точнее, я буду подбирать разрешение картинки, чтобы требуемый размер шрифта в пунктах в фотошопе соответствовал символам точно такого же или близкого размера как в библиотеке. И таким значением оказалось 140 пикселей на дюйм. По мне, весьма странное разрешение, т.к. не соответствует никаким стандартным, но и каких-либо сложностей это тоже не вызовет.
Итак, определившись с разрешением, можно начать рисовать интерфейс. Первым экраном, который я сделал был экран режима лабораторного источника питания:

В принципе, экран получится достаточно простой и, в то же время, информативный. В верхней строке выводится текущий режим работы – Power Supply. В центральной части слева выводятся мгновенные значения напряжения, тока и мощности, а справа расположены индикаторы текущего режима работы – CV или CC и индикатор включения выхода OUT. Ниже более мелким шрифтом отображается счетчик отданной ёмкости и время работы в режиме блока питания. На следующей строчке отображается температура зарядного устройства с префиксом С (Charger), температура батареи с префиксом В (Battery) и текущая скорость работы вентилятора в процентах от максимальной. В самой нижней строке отображаются заданные значения напряжения и тока, тут же и происходит их изменение.
Следующим был нарисован экран режима зарядки аккумуляторов:

Экран имеет пять различных вариантов отображения. В каждом из них в верхней строке отображается текущий режим работы – Charger. В центральной части слева отображается выбранный режим зарядки (CC/CV или ССС) и выбранный зарядный ток. Чуть позже я добавил туда третью строчку с отображением включенных опций зарядки, но в макеты изменения вносить уже не стал. В предпоследней строке отображается текущая температура зарядного устройства и время зарядки аккумулятора, а в самой нижней строке отображается выбранный профиль зарядки.
Первый вариант экрана (No battery) отображается сразу после перехода в режим зарядки, если в зарядное устройство не установлена батарея. Он отображает лишь статический текст, предлагающий вставить батарею для начала зарядки.
Второй вариант (Invalid battery) отображается в случае вставки в зарядное устройство не той батареи, которая ожидается для выбранного профиля зарядки. Контроль типа батареи осуществляется по её напряжению, которое в данном варианте отображается в нижней части экрана оранжевым цветом.
Третий вариант (Charging) отображается непосредственно в процессе зарядки батареи. В этом варианте в центральной части экрана с правой стороны выводится текущий процент заряда батареи в процентах и в виде анимированной иконки элемента питания и температура батареи. Ниже отображаются мгновенные значения напряжения, тока и мощности, а также отданная ёмкость.
Четвертый вариант (Charge complete) отображается по завершению зарядки батареи до тех пор, пока она не будет отключена от зарядного устройства. Здесь в центре экрана более крупным шрифтом выводится итоговая отданная зарядным устройством ёмкость.
И, наконец, последний экран (Battery error) отображается в случае возникновения в процессе зарядки каких-либо проблем со стороны батареи. Такими проблемами могут быть или снижение напряжения статусного контакта батареи (для Makita-совместимых батарей), или её перегрев. В этом варианте в центральной части экрана отображается текущее напряжение и температура батареи, а также, если идет зарядка Makita-совместимой батареи, состояние 4-го контакта интерфейсного разъема строкой FAIL или OK. Я решил, что выход из критической ситуации должен быть обязательно ручным, поэтому дополнительно на экране отображается пункт Continue, позволяющий продолжить зарядку.

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

Теперь, когда схема отлажена и работает, а программная часть, по большей части, написана, настает время придать устройству законченный вид, поместив его в корпус. Но какой корпус использовать? Сначала я думал скачать из интернета готовый сокет LXT и просто прикрутить его к коробке подходящих размеров, но так и не смог найти такого варианта сокета, который бы мне понравился. Параллельно я размышлял, где буду хранить готовую зарядку, и все сошлось к тому, что надо в некоторой степени повторить корпус DC18SD/RC. Тогда и внешний вид будет красивым, и хранить её можно будет в кейсе MacPac 2 вместе с шуруповертом. Тем более, что размеры оригинальной зарядки позволяют разместить в этом корпусе мою плату и выбранный блок питания. Поэтому, запускаю любимый SolidWorks и рисую:

Как и у оригинальной зарядки, сокет для аккумулятора располагается с левой стороны на верхней части корпуса, поэтому дисплей, энкодер и выходные терминалы-бананы размещаются справа. Последние нужны для снятия выходного напряжения с зарядки в режиме блока питания.
Большим преимуществом современного 3д-моделирования является возможность создавать сборки из нескольких деталей – это позволяет легко, просто и правильно разместить внутри корпуса все компоненты, точно убедиться, что они туда влезут, а также досконально проработать способы их крепления. Поэтому дополнительно создал приближенные модели основных компонентов, после чего разместил их в корпусе:

Входной разъем для подключения сетевого кабеля решил использовать стандартный, IEC с выключателем-индикатором и предохранителем. Он несколько крупноват, зато имеет три контакта и позволяет подключать к устройству провод защитного заземления PE. Возможно, наличие заземления и не обязательно для зарядки, но уж точно необходимо блоку питания, поэтому в моем устройстве оно быть должно. Вариант прямого ввода сетевого кабеля внутрь устройства без дополнительного разъема я считаю крайне неудобным и не рассматриваю, так что будет крупный IEC. Разместил его с левой стороны на задней стенке корпуса заподлицо.
В качестве разъема для обновления прошивки решил использовать DB-9F, такие в далекие времена ставили в ПК на ком-порты. Только я установил в устройство «маму», а не «папу», как в ПК. Этот выбор был осознанным, чтобы минимизировать вероятность убивания устройства статикой при случайном прикосновении к разъему пальцем. Также это исключает случайное подключение в этот разъем кабелей старой компьютерной периферии. Разъем установил на заднюю стенку корпуса справа, но только немного утопил его вглубь.
К сожалению, в процессе размещения компонентов пришлось увеличить корпус по высоте на 15 мм, иначе не помещался вентилятор охлаждения. Такое увеличение никак не скажется на возможности хранить зарядку в MacPac’е, так как там по высоте имеется вполне достаточный запас, однако, поместить зарядку в обычный кейс от инструмента уже не выйдет. Этим пришлось пожертвовать ради хорошего охлаждения.
Наконец, чтобы корпус было возможно распечатать на 3д-принтере без сумасшедшего количества поддержек, разделил его на три части – нижняя крышка, основная часть и сокет LXT. Между собой части соединяются с помощью маленьких шурупов 2х6 и вплавляемых резьбовых втулок М3. Корпус распечатал из черного PETG:





Печать не обошлась без косяков – в основной части корпуса оказалось навесание с углом примерно 65°, которое распечаталось не очень хорошо. Поэтому пришлось немного обработать деталь наждачкой. А чтобы вернуть PETG его былой блеск – еще и пройти потом дихлорметаном.
Контакты для аккумулятора разработал полностью свои, вырезал их из кусочка листовой латуни толщиной 0.8 мм, специально купленной для этого в интернет-магазине:

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


Панель для механической защиты экрана выпилил из оргстекла толщиной 4 мм, она будет закрепляться в корпусе с помощью клея В7000:

Затем приступил непосредственно к сборке. Сначала вплавил все резьбовые втулки

Затем прикрутил сокет LXT, установил стекло, экран, энкодер и выходные терминалы. После этого прикрутил к отрицательному контакту батареи датчик температуры:

Далее установил блок питания и основную плату, а также соединил всё проводами:




В последнюю очередь установил и подключил вентилятор:

В итоге, получилась вот такая симпатичная (на мой взгляд) зарядка:




Первые же испытания зарядки большим током показали, что ТКС обычного китайского «шунта» в виде SMD-резистора 2516 слишком велик, значение выходного тока отклонялось более чем на 2% при умеренном нагреве. Тогда я попытался использовать в качестве шунта константановую проволоку, и мне даже удалось отрезать кусочек с сопротивлением 10 мОм, но оказалось, что у константана слишком велико значение термо-ЭДС, из-за чего показания при нагреве также уплывали. Делать было нечего, оставался дорогой манганин, поэтому в Китае были заказаны вот такие красавцы:

Варианта на 10 мОм не нашлось, а переделывать что-либо в зарядке уже не хотелось, поэтому просто соединил два таких резистора последовательно и припаял на плату. Манганин показал себя значительно лучше всего остального, показания практически перестали меняться при нагреве, так что, если у кого-то стоит вопрос выбора – однозначно рекомендую.
Дальнейшие испытания зарядки прошли успешно – пока плата не была установлена в корпус, она отлично выдавала ток 5 А даже без какого-либо активного охлаждения. В корпусе с вентилятором 6 А дались ей так же легко, поэтому было решено увеличить максимальный предел до 8 А. И термические испытания показали вполне умеренный нагрев при работе с таким током – за полчаса работы на КЗ точка максимального нагрева на корпусе оказалась около выходных терминалов, где температура составила только 40 градусов (тепловизор занижает):

Радиатор же нагрелся до 60-ти:

При работе на нагрузку (8 А 21 В = 168 Вт) максимальная температура корпуса составила те же 40 градусов:

Измерений температуры внутри не проводил, но плата зарядки в таком режиме должна греться даже меньше, потому что падение напряжения на открытом транзисторе меньше падения на диоде Шоттки. А вот блоку питания будет тяжелее. Но учитывая, что это около 80% от его заявленного максимума, да и на него тоже идет поток воздуха от вентилятора, думаю, он выдержит.
Как только испытания были закончены, сразу ввел зарядку в эксплуатацию, правда, не по основному её назначению – первым реальным применением стала подзарядка автомобильного аккумулятора после длительного простоя, которая проводилась в режиме блока питания:


Всё прошло хорошо и за ночь зарядка не сгорела. При выходном токе 2 А радиатор платы периодически прогревался до 45 градусов, что вызывало включение вентилятора на минимальных оборотах, после чего плата остывала до 40 градусов и вентилятор выключался. В таком режиме зарядка оставалась практически бесшумной, о работе вентилятора можно было только догадываться по индикации на экране.
К сожалению, в таком виде применять зарядку по её прямому назначению было невозможно, т.к. имевшиеся в наличии совместимые аккумуляторы Макита без подключения желтого разъема не включали зарядный транзистор, а заряжать батарею через силовой терминал в обход штатной BMS было попросту небезопасно. В деталях этот момент был подробно описан в предыдущем обзоре, поэтому здесь лишь подведу итог, что надо было добавлять в зарядку желтый разъем.
Для этого на Али был приобретен вот такой кабель-переходник, с одного конца которого находится желтый разъем для установки на зарядку, а с другого – разъем JST PH (с шагом 2 мм).

Поскольку плата была уже полностью собрана и переделывать ничего не хотелось, все необходимые дополнительные компоненты были установлены на отдельную небольшую плату, схема которой приводилась ранее. Компаратор U4.2 был переоборудован для сравнения статусного напряжения батареи с пороговым значением около 1.4 В и подключен к ранее не используемому в зарядке выводу MISO, а вывод РС3 использован для реализации протокола 1-Wire. После этого зарядка стала «полноценной» и её доработки, к счастью, закончились. Правда, основную печатную плату я так и не обновил до конца, по-хорошему, надо бы разместить все компоненты на ней.
Так как для управления процессом зарядки используется микроконтроллер, становится возможным реализовать совершенно любой алгоритм заряда аккумулятора, что было бы весьма затруднительно сделать в чисто аналоговой схеме. Одним из таких решений и стал алгоритм, который я назвал Continuous Constant Current или сокращенно ССС.
В этом режиме аккумулятор всегда заряжается заданным постоянным током, независимо от текущего напряжения. А чтобы избежать перезаряда, раз в 10 секунд зарядный ток отключается, после чего осуществляется контроль напряжения холостого хода аккумулятора, и, если оно превышает 4.2 В на банку, заряд считается завершенным. Конечно, так можно заряжать только аккумулятор без БМС, иначе она отключит его раньше по превышению напряжения банок.
Не могу сказать, вреден ли данный режим зарядки для батарей, если кто-то обладает такой информацией – прошу написать в комментариях. Однако, у меня есть предположения, что этот алгоритм уже используют некоторые производители бытовой техники (например, мой пылесос ILife) для отказа от этапа CV и, таким образом, сокращения времени заряда.
Считаю, что проект удался, получившейся зарядкой я очень доволен. Она не только выполняет свои основные функции, но и обладает отличной гибкостью, позволяя настраивать параметры зарядки практически любым образом. Возможно, гибкость нужна далеко не всем, но в моем понимании зарядка должна быть именно такой. Также зарядка может работать в режиме весьма тихого лабораторного источника питания, где она хоть и уступает по выходным характеристикам обычным аналоговым стабилизаторам, но вполне подходит для нетребовательных применений вроде подзарядки автомобильного аккумулятора или временного питания небольшого силового потребителя.
Конечно, весь проект оказался достаточно трудоемким, и занял значительно больше времени и сил, чем изначально предполагалось, но зато в процессе разработки мне удалось немного глубже разобраться с аккумуляторными технологиями Makita LXT и поделиться этим с вами.
На данный момент программная часть зарядки всё еще требует небольшой доработки – в ней не хватает аварийного выключения при перегреве радиатора, а также аварийной остановки зарядки при перегреве батареи. Надеюсь, я соберусь с силами и добавлю их в ближайшее время, потому что, честно говоря, этот проект меня немного вымотал.
На этом у меня всё, всем добра!
Исходные коды прошивки, корпус и макеты экранов доступны в моем репозитории:
https://github.com/kdekaluga/makita_charger
Вступление или зачем делать самому?
На рынке присутствует большое количество зарядных устройств для LXT-аккумуляторов, которые условно можно разделить на три группы:
- Оригинальные зарядки Makita
- Неоригинальные зарядки с желтым разъемом
- Неоригинальные зарядки без желтого разъема
С оригинальными зарядками всё просто – они предназначены для зарядки оригинальных аккумуляторов Makita. Также в них можно заряжать совместимые аккумуляторы, которые имеют желтый разъем и поддерживают базовые команды протокола Макиты. Основные модели – DC18SD и DC18RC. Еще существует двухпортовая DC18RD, но она встречается заметно реже. Выбирать зарядный ток в оригинальных зарядках нельзя, производитель делает этот выбор за вас. В случае DC18SD это «скромные» 2.6 А, а в случае DC18RC – до 9 А, поэтому последней категорически не стоит заряжать китайские аккумуляторы, зачастую для них это оказывается слишком много.
Неоригинальные зарядки с желтым разъемом предназначены, прежде всего, для зарядки неоригинальных аккумуляторов с таким же желтым разъемом. Заряжать оригинальные аккумуляторы в них теоретически можно, но лучше не стоит, так как это может заблокировать контроллер батареи, и дальнейшая её судьба окажется под вопросом (в сети есть проект разблокировки таких батарей, но, говорят, работает не со всеми). Устройств с регулировкой тока в этой категории я тоже не встречал, в основном это что-то фиксированное между 1.5 и 3 А и зависит от конкретной модели. Заряжать аккумуляторы без желтого разъема в таких зарядка не выйдет, они туда физически не встанут.
Наконец, неоригинальные зарядки без желтого разъема предназначены для зарядки таких же неоригинальных батарей и составляют самую многочисленную группу. Здесь можно найти как зарядки форм-фактора DC18XX Makita, так и зарядки меньшего размера, напоминающие подставку под батарею, и даже зарядки форм-фактора «блок питания» с круглым разъемом на выходе. Зарядные напряжения, токи, качество изготовления и цена таких зарядок очень сильно отличается, последнее время стали попадаться даже версии без прямого контроля выходного напряжения и тока буквально «за копейки». Поэтому пользоваться такими зарядками без предварительного анализа их характеристики и схемотехники я бы не рекомендовал. Также следует отметить, что сами батареи без желтого разъема часто предназначаются для «совместимого инструмента» и могут не работать с оригинальным без их доработки.
Проанализировав собранную информацию, я пришел к выводу, что универсального решения с возможностью настройки зарядного тока (и, возможно, даже подстройки напряжения), на рынке нет, поэтому остается только делать зарядное устройство самому. Тогда оно будет обладать именно теми характеристиками, которые мне нужны, заряжать именно так, как мне надо, да и просто потому, что полноценного диайвая в мире становится всё меньше, надо компенсировать.
Отдельно хочу добавить, что разрабатывать свое зарядное устройство и писать данную статью я начал раньше, чем разобрался с основными нюансами зарядки батарей Макита, которые описал в предыдущем обзоре, поэтому с самого начала желтого разъема в моей зарядке не было, что вы и увидите на многих фотографиях. Добавлен он был несколько позже, однако править уже написанный текст и обновлять фотографии не стал, пусть история останется в хронологическом порядке.
Конструкция
Самым простым вариантом самоделки было бы взять готовую китайскую CV/CC понижайку, добавить блок питания, регулятор, а также индикатор тока и напряжения и запихнуть это в какой-то походящий (возможно, напечатанный) корпус. Но таких проектов и без меня достаточно, вряд ли вам будет интересно читать про подобное еще раз. Да и я удовольствия от простого соединения проводов не получу, нужно что-то посложнее. Поэтому, будем собирать «с нуля». А если так, то начнем с желаемых характеристик:
- Зарядка батарей форм-фактора Makita LXT 18 В
- Регулируемый ток заряда от 1 до 6 А
- Возможность корректировки напряжения заряда
- Отображение текущего напряжения, тока (2 знака после запятой) и отданной ёмкости (3 знака после запятой)
- Звуковая индикация окончания заряда
- Отсутствие ощутимого разряда батареи, если во время зарядки вдруг пропадет сетевое напряжение
Чуть позже, подумав, решил сделать её еще более универсальной и добавить:
- Возможность зарядки любых литий-ионных батарей до 5s (до 21 В)
- Режим лабораторного источника питания 0 – 23 В, 0 – 6 А
С требованиями определились, теперь перейдем к HLD. В качестве «мозга» зарядки был выбран «народный» микроконтроллер ATMega328p. Выбрал его по нескольким причинам: во-первых, он всё еще широко распространен, и, если вдруг кто-то захочет повторить данное устройство, с мегой будет проще, чем с тем же STM32. Во-вторых, у AVR по современным меркам весьма ограниченные ресурсы, а писать программу в таких условиях значительно интересней простого закидывания кода очередным уровнем абстракций. Ну, и, в-третьих, эти меги у меня есть, так почему бы не найти им применение получше, чем лежание на полке?
Первоначально хотел, чтобы регулирующая часть была чисто аналоговой, выполненной в виде DC-DC на готовом чипе вроде XL4016, а МК лишь бы отдавал ей указания, какое напряжение (или ток) выдавать на выход. Но первое практическое испытание показало, что внешние управление XL4016 работает не очень хорошо, ведь внутреннее опорное напряжение неизвестно, а коэффициент усиления встроенного ОУ ошибки уменьшить нельзя. Получается очень нестабильная петля ОС, и схема то и дело желает перейти в генераторный режим. Да и у меги не очень высокая частота ШИМ для большой разрядности аналогового напряжения. Поэтому склонился в сторону выполнения DC-DC непосредственно на самой меге, воспользовавшись её ШИМ-генератором.
Теперь нужен экран для отображения напряжения, тока и отданной ёмкости. Сначала хотел использовать пару 8-рязрядных 7-сегментных индикаторов на MAX7219, но потом вдруг осознал – кому в наше время интересны красные сегментные индикаторы? Сейчас в моде цветные экраны с высоким PPI, как в смартфонах. И ведь такой есть у меня – им оказался небольшой IPS-дисплей с разрешением 240х240 точек и очень приятной цветопередачей, практически, маленький монитор:

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

Чтобы обеспечить на выходе напряжение 21 В, на вход необходимо подать больше. Я выбрал 24 В как стандартный номинал, найти блок на такое напряжение не составит труда. Но для того, чтобы запитать МК, необходимо 5 В, значит нужен понижающий DC-DC. Когда в устройство ставятся понижающие преобразователи, приоритет следует отдавать тем чипам, которые формируют требуемые напряжения без внешних деталей. Так надежней – если вдруг цепочка делителя обратной связи повредится, на выход может пройти более высокое напряжение, которое выведет из строя остальную часть схемы. Поэтому изначально я планировал использовать XL1509E-5.0, но в местном Чиподипе случился «пересорт» и указанной микросхемы в наличии не оказалось. Пришлось быстро искать на замену что-то подходящее по их каталогу, и таким преобразователем оказался TPS5430 (U5), после чего схема и плата были переделаны под него. В принципе, здесь подойдет любой другой DC-DC на 5 В, т.к. нагрузка небольшая, а у TPS5430 есть недостаток с точки зрения радиолюбителя – снизу корпуса у него расположен 9-й контакт, который необходимо обязательно подключить к общему проводу, без этого преобразователь не будет работать. То есть, запаять такую микросхему только паяльником не получится, нужен фен или нижний подогрев.
Для питания дисплея требуется напряжение 3.3 В. Оно получается из 5 В с помощью линейного стабилизатора AMS1117 (U3). Поскольку МК питается от 5 В, необходимо согласовать уровни напряжений выходных сигналов, идущих к дисплею. Вариантов согласования есть несколько, но я выбрал самый простой – гасящие резисторы. Такой вариант не самый красивый, но допустим, т.к. контроллер дисплея имеет в своем составе защитные диоды, идущие от каждого входа на плюс питания. Через эти диоды все излишки входного напряжения будут отправляться на питание контроллера, главное ограничить входной ток. При указанном номинале резисторов R2, R3, R6 и R7, ток через каждый не будет превышать 4.2 мА, что в сумме никогда не превысит 20 мА, которые потребляет дисплей в любом режиме. Дисплей подключается к плате через разъем J9.
За генерацию ШИМ-сигнала преобразователя будет отвечать канал А таймера 0 МК. Этот сигнал с выхода OC0A через усилитель на Q11, Q17 и Q13 идет на затвор P-канального полевого транзистора Q1. Конечно, сначала хотелось применить в схеме N-канальный транзистор, ведь у него и ниже сопротивление канала, и для управления можно использовать готовый чип вроде IR2110 или HCPL-3120. Но тогда понадобился бы отдельный источник +12 В для цепи затвора, стандартные схемы «вольтдобавки» здесь не подойдут, они все требуют непрерывной генерации, а тут преобразователь может быть выключен на неопределенное время. Поэтому, скрепя сердце, установил в схему P-канальный IRF4905, которые были куплены на Али много лет назад. Они определенно поддельные, но недавно в комментариях меня несколько утешили, предположив, что в ключевом режиме их использовать еще можно. Конечно, они значительно слабее оригинала, но у меня и мощность на нем рассеиваться будет в пределах 10 Вт, так что попробую.
Для управления ключом остановился на усилителе на дискретных компонентах. Q11 инвертирует сигнал и усиливает его по амплитуде до 12 В, затем двухтактный усилитель на Q13 и Q17 усиливает ток, чтобы быстро перезаряжать ёмкость затвора ключа Q1. Все транзисторы в усилителе переключаются быстро, потому что никогда не входят в насыщение. Q11 за счет резистора R33 в цепи эмиттера, а Q13 и Q17 – потому что включены по схеме с общим коллектором. А чтобы броски тока при перезаряде ёмкости затвора Q1 не вывели транзисторы из строя, в схему добавлен ограничительный резистор R30.
Испытания показали, что блок управления ключом обладает неплохими временными характеристиками – и нарастание, и спад сигнала на затворе происходят примерно за 150 нс, что позволяет применять такую схему на частотах даже в сотни килогерц:


На осциллограмме желтым цветом показан сигнал на выходе OC0A МК, розовым – на коллекторе Q11, а голубым – на затворе Q1. На следующих осциллограммах розовым цветом показан сигнал на стоке Q1, а желтый и голубой остались прежними:


Хорошо видно, что ключ очень быстро открывается за 10 нс с задержкой 35 нс относительно управляющего сигнала. С закрытием ситуация похуже – задержка составляет 180 нс, а само закрытие около 50 нс (на осциллограмме разрешение по оси Х уже 100 нс/дел). Тем не менее, это прекрасный результат, учитывая, что данной схеме предстоит работать на частоте всего 62.5 КГц.
Остальная часть ШИМ-преобразователя достаточно стандартная и состоит из дросселя L2, диода D1, снаббера C30+R48 и выходных конденсаторов C12 – C14. Далее напряжение через нормально разомкнутые контакты 3-5 реле К1 и токоизмерительный шунт R29 поступает на выход устройства.
Реле К1 на выходе установлено по двум причинам. Во-первых, МК будет отключать аккумулятор, если вдруг во время зарядки пропадет питающее напряжения, чтобы предотвратить разряд аккумулятора на внутренние цепи обесточенного зарядного устройства. А, во-вторых, оно позволит МК разорвать цепь, если вдруг транзистор Q1 выйдет из строя, и, таким образом, защитить аккумулятор от бесконтрольного заряда. Функция аварийного отключения крайне важна при заряде совместимых аккумуляторов Makita, ведь они могут не иметь в своем составе полноценных BMS, целиком полагаясь на контроль со стороны зарядного устройства. А литий-ионные аккумуляторы ни в коем случае не следует перезаряжать, поэтому при выходе зарядного устройства из строя и отсутствии защиты имеется вполне реальный шанс возгорания аккумулятора. Дополняя этот факт использованием ключевого транзистора сомнительного качества, становится очевидно, что наличие защиты в схеме просто необходимо.
Измерение выходного тока осуществляется с помощью шунта R29 сопротивлением 10 мОм. При таком номинале и максимальном токе 6 А на шунте будет падать 60 мВ и рассеиваться 0.36 Вт, что является оптимальным соотношением. Но 60 мВ – слишком мало для непосредственного измерения с помощью АЦП МК, поэтому напряжение с шунта подается на инструментальный усилитель с коэффициентом усиления 10, выполненный на U1.2. Так как опорное напряжение АЦП задается электронным стабилитроном D2 ICL8069 и примерно равно 1.22 В, максимально возможное измеряемое значение тока составляет 12.2 А. Это больше 6 А, которые я хочу снимать с устройства, но такой запас оказался полезен, позже я поясню почему.
Аналогичный инструментальный усилитель с коэффициентом усиления 1/20, выполненный на U1.1 используется для измерения выходного напряжения зарядного устройства, которое снимается непосредственно с выходных клемм. Использование четырехпроводной схемы позволяет компенсировать падение напряжения на проводниках, дорожках печатной платы, контактах реле, а также на токоизмерительном шунте, что, в свою очередь, позволяет установить шунт в минусовой провод устройства и немного упростить схему. Данный усилитель не увеличивает, а уменьшает напряжение в 20 раз, что позволяет МК измерять значения примерно до 24.4 В.
Несмотря на сложное название, инструментальный усилитель выполняет простую функцию. Это усилитель разности напряжений – он берет значение напряжения на прямом входе, вычитает из него значение напряжения на инверсном входе и усиливает полученную разницу в заданное число раз. Существует несколько известных схем инструментальных усилителей, из которых наиболее правильная – на трех ОУ. А самая простая на одном. К недостаткам простой схемы относится необходимость точного подбора резисторов делителей так, чтобы коэффициенты деления двух цепочек были очень близки, что затруднительно в серийном производстве, поэтому там применяют более сложные схемы. А для самодельного устройства вполне подойдет и простая, если предварительно подобрать мультиметром резисторы с максимально близкими сопротивлениями. Подбирать следует пары R4/R14, R5/R15, R18/R22 и R19/R23. Точное значение не так важно – это позже можно будет скорректировать программно, главное, чтобы резисторы в парах были максимально одинаковы.
Сначала я использовал в инструментальном усилителе распространенный LM358, ведь высоких требований к быстродействию ОУ здесь нет, но на этапе тестирования выяснилось, что у него прослеживается ощутимая зависимость выходного напряжения каналов друг от друга, а также от температуры. Поэтому ОУ был сменен на TL082C, где эта зависимость ниже.
Отдельно следует рассмотреть питание ОУ. Начало шкалы измерений АЦП МК лежит ровно в нуле вольт, поэтому ОУ должны иметь возможность выдавать такое напряжение на своих выходах. Казалось бы, можно просто взять R2R ОУ, но даже они не в состоянии выдать ровно ноль вольт, их минимум начинается где-то от 25 мВ и сильно зависит от нагрузки. А 25 мВ – это примерно 21 единица шкалы АЦП или 2%, и это слишком большая погрешность при измерении тока. Поэтому необходим дополнительный источник отрицательного напряжения для питания ОУ.
Чтобы не ставить еще один преобразователь, было решено получить отрицательное напряжение с помощью диодного-ёмкостного умножителя на C22, D9, D10 и C24, подключенного к выходу понижающего преобразователя U5 через ограничительный резистор R40. При нормальной работе преобразователя под нагрузкой на его выходе присутствует меандр амплитудой 24 В, который «отражается» умножителем, и конденсатор C24 заряжается напряжением порядка -22 В. Это напряжение уменьшается до -4.7 В стабилитроном D11 и используется для питания ОУ. Для преобразователя умножитель выполняет роль снаббера, уменьшая выбросы на его выходе, но и немного увеличивая нагрев.
Поскольку напряжение на выходах ОУ теперь может оказаться отрицательным, необходимо защитить от него МК. Эту роль выполняют резисторы R11 и R20, которые совместно с конденсаторами C4 и C9 также образуют ФНЧ, дополнительно фильтрующие высокочастотные помехи.
Еще одним нюансом схемы является резистор R44. Его задача – сдвинуть точку нуля токовой шкалы в область положительных напряжений. Дело в том, что за счет неидеальности ОУ и других элементов схемы, на входе АЦП МК оказывается небольшое (несколько милливольт) отрицательное напряжение смещения, которое препятствует измерению малых значений выходного тока. Да, это смещение можно скорректировать программно, чтобы получить правильные измерения на больших токах, но измерять малые токи всё равно не получится. Поэтому требуется аппаратная корректировка. Сопротивление R44 подбирается так, чтобы при отсутствии выходного тока напряжение на входе АЦП МК было чуть больше нуля, у меня это достигается на значении 620 КОм. Если вдруг корректировка окажется несколько чрезмерной, ничего страшного – отклонение в положительную сторону отлично корректируется программно.
В принципе, ИУ напряжения тоже нужна похожая корректировка, но ей можно пренебречь, ведь его коэффициент усиления мал, да и работа с околонулевыми выходными напряжениями в зарядке не предусматривается вообще.
В остальной части схемы нет ничего интересного. Выход канала B таймера 0 генерирует сигнал PWM
с той же частотой 62.5 КГц, используемый для управления вентилятором обдува. Этот сигнал преобразуется в напряжение элементами Q2, L1, D4, C5. В контроле результирующего напряжения необходимости нет, требуемые значения PWM всё равно подбираются экспериментально под используемую модель вентилятора.
16-разрядный таймер 1 МК используется для генерации звуковых сигналов. Его выход А управляет транзистором Q4, который подает напряжение на пьезокерамический излучатель PZ1. Использование резисторов R21 и R47 достаточно больших номиналов совместно с ёмкостью излучателя образует ФНЧ, что позволяет изменять громкость звучания с помощью длины импульсов, а для её общего повышения излучатель питается от 24 В.
На ОУ U4.1 реализован датчик снижения напряжения питания. ОУ работает в режиме компаратора с небольшим гистерезисом, обеспечиваемым положительной обратной связью через резистор R49. Пороговое напряжение срабатывания датчика – порядка 23.5 В, напряжение восстановления – около 23.7 В. U4.2 используется для анализа напряжения на 4-м контакте желтого разъема Макиты, снижение которого ниже примерно 1.3 В (установлено опытным путем) сигнализирует о проблемах со стороны батареи и необходимости остановить зарядку. К сожалению, установка желтого разъема в зарядку произошла уже на этапе отладки, когда основная плата была полностью готова, поэтому необходимые дополнительные детали разместились на отдельной небольшой плате.

На всех входах ОУ, подключенных к внешним контактам зарядного устройства применяется защита от статического напряжения на диодах D3, D5, D6 и D7.
Для измерения температуры я использовал цифровые датчики TMP100A, которые уже успешно применял в своих предыдущих проектах. Это небольшая 6-выводная микросхема в корпусе SOT23-6, позволяющая измерять собственную температуру с разрешением 0.06 градуса и общающаяся с МК по протоколу I²C, за счет чего на один интерфейс можно подключить до 8 таких датчиков.

В зарядном устройстве я использовал два – один для измерения температуры радиатора платы и другой для косвенного измерения температуры батареи. Датчики располагаются на отдельных платах и подключаются к основной плате через разъем J13.
Я намеренно оставил выводы TxD и RxD МК свободными, т.к. на этапе проектирования предполагал возможное подключение зарядного устройства к ПК по последовательному порту. Однако, по мере написания прошивки контроллера стало очевидно, что такое подключение не нужно, поэтому в финальном варианте эти выводы просто не задействуются.
Плата
Печатные платы делать не люблю, с удовольствием заказывал бы готовые, если бы их могли делать быстро. Иначе может получиться, что пока плату будут изготавливать, интерес к устройству пройдет и проект будет заброшен, поэтому приходится делать самому. В основном, использую две технологии изготовления – фоторезист и ЛУТ. Фоторезист дает значительно более высокое качество, чем ЛУТ, но и требует больше усилий, поэтому делаю этим способом большие и важные платы, а для маленьких сейчас использую ЛУТ. Изготовление качественных двухсторонних плат тоже не освоил, стараюсь разводить всё в одном слое с перемычками. Если есть возможность, предпочитаю использовать старые through-hole/DIP компоненты, потому что надо их куда-то тратить, да и разводить односторонние платы для них проще.
Основная плата зарядки получилась размерами 130х60 мм и, надо сказать, это уже предел для моего принтера. Несмотря на то, что срок годности фоторезиста Ordyl истек еще в 2017 году, плата вышла отличная, лишь немного пришлось уменьшить время экспозиции (до 60 секунд):


На фото вытравленная плата представлена в первоначальном варианте, а нарисованная – в обновленном. В процессе сборки и наладки схема претерпела небольшие изменения, рисунок платы менялся. Свою же переделывать не стал, просто удалял существующие дорожки и «креативил» новые перемычками из проволоки. Также пропаял все силовые цепи медной проволокой диаметром чуть меньше 1 мм, чтобы снизить их нагрев на максимальном токе. Для пайки использовал свой основной паяльник Т12, TS101 как-то не «зашел». Почти всю плату спаял жалом ВС2 на 285-ти градусах, кроме «тяжелых» мест, где применял ВС3. Фото собранной платы с нижней стороны не сделал – из-за доработок там получилось всё несколько страшненько, а фотографии со стороны деталей будут дальше.
Для датчиков температуры TMP100 сделал отдельные небольшие платы, позволяющие закреплять их винтами М3, прижимая микросхему корпусом к измеряемому элементу. Один датчик разместил на радиаторе ключа и диода, второй – на минусовом контакте батареи, так с ней будет хоть какая-то тепловая связь. Платы делал ЛУТом, из-за чего их качество существенно ниже основной. Вот так они выглядят вблизи:


То ли я что-то неправильно делаю, то ли мой принтер не подходит для ЛУТ, но тонер не обеспечивает равномерной защиты медного слоя, и он подтравливается. Собранная плата выглядит следующим образом:

Кроме самого датчика на ней установлен конденсатор по питанию, провода шины I²C и две перемычки, определяющие адрес датчика на шине. Все части платы, кроме самой микросхемы, защищены от электрического контакта с измеряемой деталью с помощью каптонового скотча.
Блок питания
В качестве блока питания был выбран недавно обозревавшийся тут Suswe U-shaped 24 В 10 А (фотография со страницы товара):

Блок питания не самый дешевый (в начале осени заказывал за 2155 рублей с доставкой), но это LLC, он имеет хороший запас по току и активный PFC – пора и в самодельных устройствах переходить на новый уровень. В принципе, нареканий на него нет, но есть пара нюансов. Во-первых, плата снизу чуть грязновата:

Во-вторых, изначально в блоке была плохо согнута Г-образная пластина, на которую устанавливаются высоковольтные транзисторы, из-за чего их выводы оказались на расстоянии меньше 1 мм от указанной пластины! Для 400 В это слишком мало, попадет немного пыли, повысится влажность и будет пробой. А это замена деталей, обугливание платы, в общем, ничего хорошего.
Когда стал разбирать блок, чтобы подогнуть пластину, тактильно обнаружил, что высоковольтный конденсатор более 10 минут сохраняет заряд! Все дело в том, что для достижения минимального тока ХХ в этом блоке на конденсаторе нет разрядных резисторов, а контроллер блокируется UVLO, из-за чего высокое напряжение в первичной цепи сохраняется достаточно долгое время. Так делать нельзя, поэтому добавил разрядный резистор самостоятельно:

Еще оказалось, что выходное напряжение блока по умолчанию было примерно 23.8 В, что для меня слишком мало. Поднял его до 24.5 В запаиванием резистора R23 на плату, там специально для этого есть пустое место. Номинала, к сожалению, сейчас не помню, но его несложно посчитать при необходимости.
Программа МК
Написание программы для МК в таком проекте – не самый сложный, но наиболее трудозатратный этап. Уже сейчас исходные коды программы занимают практически 200 КБ, а это еще даже не все желаемые функции реализованы, некоторые еще только предстоит запрограммировать.
Обычно для AVR я использую IDE от производителя – Microchip Studio. Но это затрудняет повторение проекта, ведь ПО специфическое, оно есть далеко не у всех. Поэтому в этот раз решил целиком реализовать проект на PlatformIO, open source плагине для MS Visual Studio Code, позволяющим писать программы под разные МК с использованием разных фреймворков. Среди них, кстати, есть и Ардуино, но, когда речь идет о быстром и качественном ПО для AVR, к сожалению, Ардуино нам не помощник. Поэтому проект будет написан «с нуля» без использования фреймворков. Не буду подробно описывать моменты создания и настройки проекта, перейду сразу к описанию программного решения.
Основная функция устройства – зарядка аккумуляторов или управляемый понижающий DC-DC преобразователь с контролем выходного напряжения и тока. Для повышения КПД сейчас большинство таких преобразователей используют PWM, то есть, работают за счет изменения продолжительности управляющих импульсов. Описываемая зарядка не является исключением, сигнал PWM формируется МК аппаратно с помощью канала А таймера 0. Таймер 8-разрядный, работает от тактовой частоты МК, равной 16 МГц, что дает результирующую частоту PWM 62.5 КГц – не очень много по современным меркам, но вполне достаточно. Для поддержания выходного напряжения и тока на заданном уровне, их значения измеряются с помощью встроенного в МК 10-разрядного АЦП и подаются на вход ПИД-регулятора, который управляет шириной генерируемых импульсов. Так петля управления замыкается.
Код более высокого уровня выставляет желаемые значения выходного напряжения и тока в зависимости от текущего режима работы, что и обеспечивает требуемое функционирование устройства. Еще на более высоком программном уровне реализовано взаимодействие с пользователем, позволяющее ему выбирать и контролировать режим работы зарядного устройства. Для этой цели используется графический дисплей, подключенный к МК по интерфейсу SPI и поворотный энкодер, обработка сигналов которого осуществляется программно.
Основная часть кода написана на языке С/С++, однако, так как речь идет о достаточно слабом по современным меркам МК AVR, не обошлось и без ассемблера, и некоторые функции написаны на нём. Здесь хочу отдельно отметить, что программирование на ассемблере под AVR мне очень нравится, так как позволяет раскрыть полный потенциал этих МК. Система команд достаточно простая, есть четкие тайминги их выполнения, а разработчику доступно много регистров общего назначения. Всё это позволяет писать компактные, быстрые и эффективные куски ассемблерного кода.
Отдельно отмечу интересную особенность gcc, используемого для компиляции исходного кода в PlatformIO – ассемблерные файлы здесь имеют расширение (*.s). Причем, если вы укажете расширение с маленькой буквой (*.s), для компилятора это будет чистый ассемблерный файл, поддерживающий только синтаксис ассемблера. Если же указать расширение с большой буквы (*.S), это уже будет ассемблерный файл с поддержкой некоторых директив компилятора С, таких как, например, #define. Это позволяет подключать заголовочные файлы С/С++ с определениями различных констант МК непосредственно в ассемблерный код, чтобы избежать указания их числовых значений напрямую. По этой причине все ассемблерные файлы проекта имеют расширение *.S.
Timer 0, АЦП и ПИД
В документации меги сказано, что при максимальном разрешении АЦП хорошо работает на тактовой частоте от 50 до 200 КГц, а каждое преобразование занимает 13 тактов, что дает только 15 тысяч преобразований в секунду. На практике же можно поднять эту частоту до 1 МГц, и АЦП всё еще будет неплохо работать, что даст уже до 77 тысяч преобразований в секунду. Тогда преобразование займет 13*16 = 208 тактов МК, то есть, даже меньше интервала между соседними импульсами PWM, который составляет 256 тактов. Это позволяет запускать новое преобразование АЦП прямо в коде обработчика прерывания таймера, то есть, синхронизировать процесс измерения с частотой PWM, что должно положительно сказаться на точности измерений.Разрядность АЦП – всего 10 бит. При максимальном напряжении 24 В, разрешение измерений составляет 23 мВ, то есть, не позволяет устройству оперировать даже сотыми долями вольта. Поэтому я решил суммировать 4 последовательных измерения, чтобы повысить итоговое разрешение до 6 мВ. В реальности, конечно, это не означает, что я могу получать точный 12-битный результат каждые 4 измерения, но на длинной дистанции это работает. Ток будет измеряться с разрешением 3 мА, что тоже приемлемо, а измерения тока и напряжения будут происходить попеременно, чтобы получить максимально релевантный результат.
В итоге, я получаю новые 12-битные значения тока и напряжения через каждые 8 прерываний таймера или 7812.5 раз в секунду. И каждый раз, получив эти значения, запускается алгоритм ПИД и корректирует ширину импульсов PWM. Это позволяет получить приемлемое для зарядного устройства время отклика регулирующей цепи.
Сам алгоритм ПИД, примененный в зарядке – упрощенный. По сути, он является ПИ-алгоритмом, так как не использует дифференциальную составляющую, потому что в моих предварительных экспериментах от неё было больше помех, чем пользы. Также ПИ-коэффициенты не вынесены в настройки, а жестко заданы в коде и являются степенями двойки, чтобы упростить вычисления слабенькому 8-разрядному МК. Но это сильно не сказывается на качестве работы алгоритма, ведь на выходе стабилизатора установлены конденсаторы суммарной ёмкостью 940 мкФ, а чтобы зарядить или разрядить такую емкость нужно время.
Первым шагом ПИД-алгоритма является сравнение измеренных значений тока и напряжения с заданными, и, если какое-то из них превышает установленное, алгоритм меняет режим работы, выбирая СС или CV, соответственно. В случае же, когда и ток, и напряжение оказались меньше заданных, алгоритм продолжает работать в прежнем режиме. Это очень важно, ведь в цифровом решении такое происходит постоянно, когда очередное измеренное значение вдруг оказалось на единицу меньше предыдущего за счет простой ошибки измерения.

Затем ПИД-алгоритм обновляет значение интегратора и высчитывает новый коэффициент PWM. Первоначально я сделал его 8-разрядным, так как именно такая разрядность у таймера меги. Однако, эксперименты показали, что в этом случае выходное напряжение имеет слишком большую амплитуду хаотичных пульсаций – до 200 мВ, причем эта амплитуда меняется в зависимости от того, какое именно постоянное напряжение сейчас создается на выходе стабилизатора. Очевидно, что 8 разрядов для управления PWM не хватает, ведь это всего лишь 256 возможных градаций, что дает мгновенное разрешение стабилизатора около 100 мВ.
Тогда был введен программный dithering — размер коэффициента PWM был увеличен до 16 бит, из которых старшие 8 идут непосредственно в регистр таймера, а младшие 8 суммируются в дополнительной 8-разрядной переменной. Если после выполнения очередной операции сложения возникает переполнение и устанавливается флаг переноса С, то значение коэффициента PWM в регистре таймера увеличивается на 1 для следующего импульса. Так как коэффициент PWM обновляется один раз за 8 прерываний таймера, такое решение фактически добавляет 3 дополнительных бита к разрешению, поэтому после его внедрения хаотичные пульсации значительно снизились.
Еще один нюанс управления PWM заключается в том, что мега ни при каком значении регистра OCR0A таймера не позволяет получить на выходе абсолютный логический ноль. То есть, полностью выключить PWM лишь изменением его коэффициента невозможно, даже при значении 0 в сигнале остаются короткие иголки длительностью 62.5 нс. Поэтому приходится полностью отключать генерацию выходного сигнала таймера с помощью регистра управления TCCR0A в моменты, когда преобразователь нужно выключить.

Но еще более интересная особенность была найдена значительно позже, когда устройство уже было полностью собрано и смонтировано в корпус. Оказывается, из-за того, что момент старта измерения АЦП полностью синхронизирован с частотой PWM, если плавно увеличивать коэффициент PWM, есть такой диапазон его значений, когда генерируемая в момент закрытия ключа помеха попадает на момент сэмплирования входного сигнала преобразователем и результат измерения искажается! Искажается не очень сильно (где-то на 20 единиц АЦП или на 2%), но внешне это проявляется как наличие у стабилизатора участка с отрицательной передаточной характеристикой, где увеличение коэффициента PWM приводит к уменьшению выходного напряжения. Поскольку проявлялась эта особенность при выходном напряжении около 6.8 В, то есть, вне рабочего диапазона зарядки, можно было бы просто закрыть на это глаза. Но я люблю ночью спать спокойно, а не мучаться в кошмарах, поэтому решил недостаток устранить.
Наиболее правильным было бы защитить схему измерения от помех. Экспериментально выяснил, что помеха проходит по цепи общего провода, где избавиться от неё значительно сложнее. Добавление индуктивности приличного номинала действительно помогало, но она добавляла смещение, и хоть инструментальный усилитель на входе и должен был его нивелировать, точность измерения тока существенно падала. Да и плата на тот момент была уже полностью собрана, что-либо переделывать не хотелось.
Следующим вариантом была попытка перевода АЦП в режим автоматических измерений и, таким образом, отвязки момента старта измерения от частоты PWM. Это тоже помогло, участок с отрицательной передаточной характеристикой исчез, однако, выводимые на экран измеренные значения начали хаотично прыгать в десятых долях. Логично, ведь теперь помеха попадала на момент измерения периодически, а не только в узком диапазоне коэффициентов PWM. То есть, изначальное решение синхронизации АЦП и PWM было правильным.
Решение нашлось неожиданно – поделился проблемой с супругой, и она спросила, зачем я провожу измерения именно в то время, когда на вход попадает помеха. И ведь да, зачем? Я же точно знаю, когда начинается и заканчивается выходной импульс, так как сам задаю его ширину, также я точно знаю, когда начинается измерение, т.к. сам его запускаю. Значит, если я понимаю, что закрытие ключа ожидается в момент начала измерения, мне просто надо перенести измерение на другое время.
Очевидно, что сдвигать измерение надо не менее, чем на 1 такт АЦП или на 16 тактов МК. Но слишком далеко переносить тоже нельзя, ведь само измерение занимает 208 тактов, а через 256 тактов придет новое прерывание и, если начать измерение слишком поздно, результат не будет готов к следующему прерыванию. Посчитал команды, оказалось, в обычной ситуации я запускаю измерение через 43 такта от начала обработчика, поэтому решил переносить «назад», то есть, на более раннее время. Написал дополнительную ветку кода, обсчитал её – 26 тактов, то есть, на 17 тактов раньше. Отлично, это ровно то, что нужно! Дальше подобрал оптимальное значение порогового коэффициента, и проблема действительно ушла – участок с отрицательной характеристикой исчез, а показания остались стабильными, как и прежде. Это была маленькая победа.
В коде, кроме дополнительной ветки добавились всего две строчки:

Измерения
Дальше надо подумать об отображении измеренных значениях напряжения и тока. Если для ПИД хорошо, что он вызывается достаточно большое число раз в секунду, то для отображения такая частота не нужна. А вот усреднение показаний, чтобы они меньше прыгали – было бы очень желательно. Поэтому решил вычислять среднее из 256 последних измерений напряжения и тока, это даст частоту обновления 30.5 Гц, чего более, чем достаточно для отображения.Теперь, когда есть пригодные для отображения результаты измерений, надо их, собственно, отобразить. Вряд ли кому-либо будет интересно видеть «голые» значения, считанные из АЦП, они неинформативны. Для отображения их надо преобразовать в удобочитаемые числа, отражающие привычные нам вольты и амперы. АЦП – штука линейная, поэтому преобразование будет тоже линейным, для чего достаточно двух калибровочных коэффициентов – смещения и множителя. То есть:
Vdisp = (Vadc + Vofs)*Vk
Idisp = (Iadc + Iofs)*Ik
Числа с плавающей точкой для AVR – это как обычному человеку пробежать марафон: может и реально, но лучше не надо, поэтому я использую только целочисленную арифметику. Напряжение и ток должны отображаться с двумя знаками после запятой, то есть максимальные значения составят 2400 и 999. В 8 бит такие числа не помещаются, поэтому придется использовать 16. А если уж использовать 16 бит, то можно и пределы увеличить в 10 раз, до 24000 и 9999, соответственно. Это положительно скажется на точности, да и значения будут в понятных единицах – в милливольтах и миллиамперах.
Максимальное значение, считываемое из АЦП равно 1023*4 = 4092, поэтому перепишем формулу следующим образом:
VdispX1000 = ((Vadc + Vofs)*Vk)/4096
IdispX1000 = ((Iadc + Iofs)*Ik)/4096
Тогда Vofs и Iofs будут корректирующими коэффициентами, позволяющими выставить правильное начальное смещение измерений, а Vk и Ik – множители тока и напряжения, численно равные максимально возможному измеренным величинам (то есть, примерно 24500 и 12200). Код преобразования измерений не будет выполняться часто, быстродействие тут не нужно, поэтому пишу его на си:

Но, к сожалению, без ассемблера и тут не обошлось – в алгоритме требуется деление на 4096 или сдвиг вправо на 12 разрядов. Я бы мог еще понять, если gcc не умеет эффективно сдвигать на 4 разряда, но на 8-то сдвиг делается простым присвоением регистров! Но нет, gcc всё это уложил в цикл из 12 итераций, из-за чего его код выполняется 84 такта. Да, с точки зрения работы программы это мелочь, такие преобразования вызываются считанные разы в секунду, но я люблю оптимальные программы, поэтому переписал эти две функции на ассемблере:

Не считая времени на вызов и возврат, такой сдвиг выполняется всего 9 тактов, то есть, в 9 раз быстрее gcc.
Следующей интересной задачей оказался подсчет отданной в аккумулятор ёмкости. Хоть это значение во многих случаях и не очень полезно, без него зарядное устройство теряет всю свою привлекательность – человеку обязательно нужно видеть увеличивающееся число. Это завораживает, это как смотреть на горящий огонь или печатающий 3Д-принтер, это индикатор прогресса, индикатор жизни, и только так человек понимает, что зарядка работает. Поэтому делать обязательно надо. Но как?
Опуская все этапы размышлений, подробно описанные в комментариях в файле timer_int.S, скажу, что, на самом деле, это достаточно просто. У меня есть измерения выходного тока, выполняемые с некоторой периодичностью. Если численно умножить каждое такое измерение на интервал времени между соседними измерениями, мы и получим ёмкость, отданную за этот интервал. А если сложить несколько таких измерений за некоторый промежуток и снова умножить – получим ёмкость, отданную за этот промежуток. То есть, всё, что надо делать – это просто складывать значение тока после каждого измерения, а непосредственно перед выводом пользователю умножать эту сумму на определенный коэффициент.
Подсчеты показали, если я хочу иметь возможность считать до 100 Ач, для сложения измерений без потери точности нужна переменная размером 44 бита. Или 6 байт. Это много для AVR, но, к счастью, все эти 48 бит не нужны для отображения результата – ведь достаточно трех цифр после запятой. В итоге, после расчета всех коэффициентов у меня получился вот такой простой код:

Эта функция сразу формирует строку, содержащую отданную емкость в текстовом виде и пригодную для печати на экран, которую она сохраняет в глобальную переменную g_buffer. В современном С++ существует тенденция осуждения использования глобальных переменных, и на то есть весьма обоснованные причины. Но для микроконтроллеров такое использование вполне оправдано, ведь оно позволяет отказаться от менеджера памяти, передачи лишних параметров и, таким образом, экономить ресурсы. Поэтому я всегда использую глобальные переменные в своих программах там, где это не противоречит программной логике.
На этом этапе код, отвечающий за формирование и измерение выходного напряжения и тока можно считать завершенным. Следующий шаг – работа с дисплеем.
Графика
Для проекта я выбрал 16-битный IPS дисплей разрешением 240х240 точек, управляемый контроллером ST7789. Почему именно такой – прежде всего потому, что он у меня был. Чтобы быстрее подключить дисплей и начать с ним работать, я обратился к помощи Ардуино – там есть много готового кода для различных устройств, в который можно подглядывать в процессе работы над своими проектами. К сожалению, брать его в неизменном виде зачастую нельзя, т.к. написан он, мягко говоря, не очень.Для данного дисплея в Ардуино есть отдельная библиотека, которая называется Adafruit_ST7735_and_ST7789_Library. Скачиваем её и начинаем разбираться, параллельно подглядывая в даташит на сам контроллер. И первые вопросы возникают тут же – дисплей подключается к МК по протоколу SPI, и в Ардуино SPI инициализируется в режим 2 (выдача очередного бита данных по переднему фронту тактового сигнала), в то время как даташит показывает, что нам нужен режим 3 (выдача данных по заднему фронту). Как такое может быть, и почему код Ардуино работает у множества людей?
Провел тест, и он показал, что дисплею действительно нужен режим 3, хотя он работает и в режиме 2, только менее стабильно – помните, для согласования уровней сигналов МК и дисплея я использовал простые резисторы? Я начал постепенно увеличивать их сопротивления, уменьшая таким образом временные характеристики соединения, и в режиме 2 дисплей начал давать сбои, в то время как в режиме 3 продолжал еще работать нормально. Почему же дисплей вообще работает в режиме 2? Оказывается, если внимательно посмотреть осциллограммы сигналов на шинах SPI, можно заметить, что тактовый сигнал запаздывает относительно сигнала данных на несколько наносекунд. Дисплей достаточно быстрый, и вот это небольшое, практически незаметное «цифровому глазу» запаздывание позволяет ему правильно принимать данные во втором режиме SPI. Интересно, Atmel сделали это намеренно?
В итоге, мой код инициализации дисплея получился сильно меньше того, что в Ардуино:

Ну, а дальше началось самое интересное. Чтобы обновить изображение на дисплее целиком, ему нужно передать 240*240*2 = 115200 байт = 921600 бит в 16-битном режиме цветности. Это весьма много для скромной меги, SPI которой может работать максимум на 8 МГц. И режима 8-битной цветности, которого бы вполне хватило для моей задачи у дисплея тоже нет (есть режим 12 бит, но он совершенно неудобен). В принципе, тут можно честно сказать, что этот дисплей «великоват» для меги. Но МК уже выбран, часть кода написана и другого дисплея под рукой нет, так что продолжаем продолжать.
Основное, что надо выводить на дисплей в зарядном устройстве – это текст. Значит, снова идем в наш любимый Ардуино, чтобы подсмотреть вывод текста там (Adafruit_GFX_Library). Но то, что я увидел просто повергло меня в ужас. Вывод текста там реализован двумя вложенными циклами, внутри которых для каждого закрашенного пикселя шрифта вызывается отдельная функция drawPixel, которая выбирает на дисплее новое «окно» размером один пиксель, после чего заполняет его нужным цветом. Мало того, что это крайне медленно, так еще и не позволяет перетирать одну строчку текста другой – ведь на дисплей передаются только закрашенные пиксели и текст от двух строчек просто наложится. Сами авторы библиотеки об этом знают, но считают, что реализовать по-другому просто невозможно:

Моргание измеряемых значений на экране неприемлемо, таким устройством будет невозможно пользоваться, надо делать что-то свое. Подумав, я решил взять из библиотеки Ардуино само графическое изображение открытого шрифта Open Sans (чтобы не изобретать велосипед), а весь код его вывода написать с нуля и на ассемблере, так как очевидно, что на Си он будет недостаточно быстрым.
Эксперименты с SPI показали, что помещать в регистр SPDR данные можно не чаще, чем один раз в 18 тактов, иначе передача сбивается. Это дает максимальную пропускную способность в 889 КБ/сек или 7.7 FPS на выбранном дисплее. Немного, но для зарядного устройства вполне хватит – большинство мультиметров производят всего 3 измерения в секунду и это всех устраивает, значит, здесь тоже можно ориентироваться на такую частоту. В общем, требуется написать такой код вывода символа, который будет выводить изображение вместе с заднем фоном и подавать очередной байт в регистр SPDR ровно через 18 тактов.
Ситуацию несколько усложняет формат, в котором хранится шрифт в Ардуино – для уменьшения места, занимаемого в памяти, от каждого символа хранится только центральный прямоугольник, где имеются закрашенные пиксели, и он для каждого символа свой. То есть, код вывода должен будет рисовать вокруг символа рамочку цветом заднего фона, рисовать сам символ и, что самое главное, делать это в реальном времени, подавая очередной байт в SPDR ровно через 18 тактов!
%symb%
И такой код был написан, это функция PrintGlyph в файле display_asm.S. Она устанавливает окно в контроллере дисплея по внешнему размеру символа, после чего попиксельно выводит символ в рамке слева-направо сверху-вниз. За счет того, что символ выводится с закрашенным задним фоном, становится возможно замещать на экране одну строку текста другой без моргания. А учитывая, что ширина всех цифр в шрифте Open Sans одинаковая, это позволяет красиво обновлять любые цифровые значения. Именно то, что было нужно.
Дальше я написал функцию FillRect, которая закрашивает указанный прямоугольник указанным цветом. С помощью этой же функции можно рисовать вертикальные и горизонтальные линии, если задать ширину или высоту прямоугольника достаточно малой. Функция спроектирована точно таким же образом, чтобы подавать очередной байт в регистр SPDR ровно через 18 тактов. Только здесь это сделать было значительно проще.
Поскольку для несложных графических интерфейсов данных двух функций вполне достаточно, решил ими и ограничиться. Конечно, можно было бы еще написать код вывода небольших спрайтов, однако, ПЗУ такого простого контроллера как ATMega328 банально на них не хватит – ведь даже небольшая иконка 32х32 пикселя будет занимать целых 2 КБ или 1/16 от всего объема ПЗУ! Так что интерфейс будет без иконок.
Считывание энкодера
Более продвинутые контроллеры вроде STM32 умеют работать с энкодером аппаратно, в меге же приходится все делать руками. Однако, ничего сложного в этом нет – за поворот энкодера отвечают два сигнала: DATA и CLOCK. Если опустить все подробности внутреннего устройства, то можно сказать, что мы отлавливаем, например, передний фронт сигнала CLOCK и в этот момент анализируем уровень сигнала DATA, который и определяет, в какую сторону был повернут энкодер. Это несколько упрощенный, однако, вполне рабочий алгоритм. Его можно реализовать с использованием прерываний PCINT, но у меня уже «прижился» код, который периодически считывает уровни сигналов и формирует соответствующие команды для основной программы.
Этот код запускается каждое 8-е прерывание таймера, то есть, с частотой 7 812,5 Гц, что позволяет отлавливать примерно до двух тысяч тиков энкодера в секунду, чего более чем достаточно для любого применения. А вот анализ нажатия кнопки энкодера производится уже в обработчике таймера на С++, который вызывается 100 раз в секунду:

Программа различает три вида нажатия на кнопку – короткое (обычное), долгое (более 1 секунды) и сервисное (6 секунд). Короткое и долгое обрабатываются в соответствии с алгоритмом текущей функции, а вот сервисное вызывает безусловный перезапуск кода микроконтроллера. Сделано это на случай потенциального логического зависания кода прошивки или других ошибок программы, однако, пока что ни разу по назначению не использовалось.
TWI
Для считывания температуры с датчиков TMP100 программа должна поддерживать протокол TWI. К счастью, базовые функции его поддержки присутствуют в меге аппаратно, поэтому понадобилось лишь обернуть их небольшой интерфейсной оберткой. Поскольку TWI использует прерывания, также написал основную часть кода на ассемблере. Из особенностей тут можно отметить только лишь запрещение прерываний TWI при старте обработчика и последующее разрешение прерываний контроллера – так сделано для того, чтобы минимизировать временное отклонение (или джиттер) вызова основного прерывания таймера. Если вдруг прерывание таймера придет во время обработки прерывания TWI, оно прервет его. Конечно, в более сложных микроконтроллерах приоритет прерываний можно задавать, но здесь пользуемся тем, что есть.
Общий подход работы с TWI в зарядке – асинхронный, обмен данными с датчиками инициируется в коде прерывания таймера на С++, а его результат анализируется в момент обработки следующего прерывания. Также на последнем шаге осуществляется коррекция скорости вращения вентилятора обдува.

1-wire
Для зарядки совместимых батарей Макита с желтым разъемом в программу была добавлена поддержка протокола 1-wire, который используется для обмена данными между зарядкой и батареей. Если в двух словах, то поддержка полностью программная, состоит из двух частей – примитивного ассемблерного кода, который выполняется каждое прерывание основного таймера и кода на С++, который управляет работой ассемблерного. Более подробно этот протокол и его реализация были рассмотрена в предыдущем обзоре, повторять их необходимости нет, так как никаких обновлений в код за это время внесено не было.Генерация звука
Вы же знаете, что оригинальная зарядка Makita DC18RC умеет играть небольшие мелодии? Если не знали, то быстрая установка и снятие аккумулятора с зарядки (до 5 секунд) изменяет текущую мелодию, можете поэкспериментировать. А раз оригинальная зарядка умеет, надо и самодельную научить, ведь ничего сложного в этом, на самом деле, нет.Для генерации звуковых сигналов используется 16-разрядный Timer 1, работающий в режиме Phase Correct PWM. Максимальное значение счетчика и, соответственно, частота выходного сигнала задается регистром ICR1, что при входной частоте 2 МГц позволяет получить на выходе практически любой звуковой тон. А значение регистра OCR1A задает ширину импульса, которая определяет громкость воспроизводимого сигнала. Осталось прикрутить какой-либо «плеер» музыки, и дело в шляпе.
Музыкой профессионально я никогда не занимался, но в институте увлекался разными трекерами (типа Fast Tracker, Impulse Tracker, Open ModPlug Tracker и т.д.), пытался подбирать мелодии, редактировать и даже писать что-то свое. Поэтому базовое понимание основ имеется, для такой простой задачи, как управление одноголосым синтезатором таких знаний вполне хватит. Постараюсь кратко их изложить.
Итак, мелодия состоит из нот, каждая из которых однозначно определяет основную частоту генерируемого звукового сигнала. Всего разных нот – двенадцать, дальше они начинают повторяться, но уже в соседней октаве. Соседние октавы отличаются друг от друга по частоте ровно в два раза, а ноты распределены по каждой октаве равномерно, если смотреть на логарифмической шкале. То есть, соседние ноты отличаются друг от друга в корень двенадцатой степени из двух или в 1,0595 раза. Это так называемый равномерный строй, который сейчас повсеместно используется. Добавляя к этой зависимости отправную точку – ноту Ля 4-й октавы (обозначается А4), частота которой составляет 440 Гц, можно вычислить весь звуковой ряд. Кстати, для этого я написал отдельный скрипт на языке Perl — sound.pl.
Традиционно считается, что для практического большинства мелодий достаточно 88 разных нот, звучащих в диапазоне от 27.5 Гц до 4186 Гц, поэтому на классическом фортепиано 88 клавиш. Более низкие частоты человек попросту не слышит, а более высокие – не различает, поэтому при построении мелодий нет смысла их использовать. То есть, с точки зрения информации для хранения ноты достаточно 6.5 бит. Самым простым решением было бы использовать для этого отдельный байт, тогда с его значением не надо проводить никаких манипуляций. Но ведь в мелодии у нот кроме тона есть еще и продолжительность, которую тоже надо хранить. То есть, получается, для одной ноты надо уже два байта.
Казалось бы, какая мелочь в наше-то время эти два байта на ноту. Однако, микроконтроллер у нас «плюшевый», и памяти у него всего 32 КБ, так что попробуем уложиться в один байт. Для этого, прежде всего, ограничим количество разных нот – их будет только 32, от Ми 4-й октавы (Е4) до Си 6-й октавы (В6). Такого количества нот вполне хватит для воспроизведения основной партии практически любой популярной мелодии, а другие в зарядке и не нужны. Зато нота теперь будет занимать 5 бит, позволяя использовать три оставшихся для указания её длительности, что дает 8 различных вариантов. Точнее, их будет 7, потому что 8-й со значением 0 будет использоваться для указания дополнительных действий, таких как окончания мелодии, продления звучания текущей ноты (если она длиннее 7-ми тактов) и паузы.
Что касается длительности нот – она измеряется в тактах, продолжительность которых зависит от темпа мелодии. Темп задается в традиционных для музыки единицах, BPM (Beats Per Minute) – количестве ударов в минуту. При этом, для размера 4/4 (наиболее популярный музыкальный размер) один удар состоит из четырех тактов. Таким образом, если взять темп 125 ВРМ 4/4, на одну секунду будет приходиться 2.083 удара или 8.333 тактов. То есть, продолжительность одного такта составит ровно 120 миллисекунд. Поскольку у меня в коде есть таймер, выполняющийся с частотой 100 Гц, удобно повесить музыкальный плеер на него. В данном случае новый такт будет наступать через 12 вызовов таймера.
Просуммировав всё сказанное выше, был написан код музыкального плеера, уместившегося в 35 строчек:

А для упрощения задания нот в исходном коде были написаны небольшие макросы, с использованием которых закодированная мелодия выглядит следующим образом:

На этом, наверное, следует завершить рассмотрение программной части, иначе я не уложусь в допустимый объем обзора. Поэтому перейдем к интерфейсу пользователя.
Интерфейс пользователя
Поскольку в зарядке используется цветной графический дисплей, обойтись простым накидыванием на экран показаний тока и напряжения не выйдет, необходимо проработать полноценный графический интерфейс. Это удобно делать на ПК в хорошем графическом редакторе, например, в фотошопе. А чтобы нарисованный интерфейс потом было несложно перенести в код МК, при рисовании следует использовать только те графические примитивы, которые умеет рисовать МК. То есть, в моем случае это строки текста размером 12 и 18 пунктов, линии и закрашенные прямоугольники. Что касается цветов, то так как экран 16-битный, можно использовать всю палитру RGB.
Поскольку я взял шрифты из библиотеки Арудино, первым делом следует подобрать аналогичный размер шрифтов на ПК. Точнее, я буду подбирать разрешение картинки, чтобы требуемый размер шрифта в пунктах в фотошопе соответствовал символам точно такого же или близкого размера как в библиотеке. И таким значением оказалось 140 пикселей на дюйм. По мне, весьма странное разрешение, т.к. не соответствует никаким стандартным, но и каких-либо сложностей это тоже не вызовет.
Итак, определившись с разрешением, можно начать рисовать интерфейс. Первым экраном, который я сделал был экран режима лабораторного источника питания:

В принципе, экран получится достаточно простой и, в то же время, информативный. В верхней строке выводится текущий режим работы – Power Supply. В центральной части слева выводятся мгновенные значения напряжения, тока и мощности, а справа расположены индикаторы текущего режима работы – CV или CC и индикатор включения выхода OUT. Ниже более мелким шрифтом отображается счетчик отданной ёмкости и время работы в режиме блока питания. На следующей строчке отображается температура зарядного устройства с префиксом С (Charger), температура батареи с префиксом В (Battery) и текущая скорость работы вентилятора в процентах от максимальной. В самой нижней строке отображаются заданные значения напряжения и тока, тут же и происходит их изменение.
Следующим был нарисован экран режима зарядки аккумуляторов:

Экран имеет пять различных вариантов отображения. В каждом из них в верхней строке отображается текущий режим работы – Charger. В центральной части слева отображается выбранный режим зарядки (CC/CV или ССС) и выбранный зарядный ток. Чуть позже я добавил туда третью строчку с отображением включенных опций зарядки, но в макеты изменения вносить уже не стал. В предпоследней строке отображается текущая температура зарядного устройства и время зарядки аккумулятора, а в самой нижней строке отображается выбранный профиль зарядки.
Первый вариант экрана (No battery) отображается сразу после перехода в режим зарядки, если в зарядное устройство не установлена батарея. Он отображает лишь статический текст, предлагающий вставить батарею для начала зарядки.
Второй вариант (Invalid battery) отображается в случае вставки в зарядное устройство не той батареи, которая ожидается для выбранного профиля зарядки. Контроль типа батареи осуществляется по её напряжению, которое в данном варианте отображается в нижней части экрана оранжевым цветом.
Третий вариант (Charging) отображается непосредственно в процессе зарядки батареи. В этом варианте в центральной части экрана с правой стороны выводится текущий процент заряда батареи в процентах и в виде анимированной иконки элемента питания и температура батареи. Ниже отображаются мгновенные значения напряжения, тока и мощности, а также отданная ёмкость.
Четвертый вариант (Charge complete) отображается по завершению зарядки батареи до тех пор, пока она не будет отключена от зарядного устройства. Здесь в центре экрана более крупным шрифтом выводится итоговая отданная зарядным устройством ёмкость.
И, наконец, последний экран (Battery error) отображается в случае возникновения в процессе зарядки каких-либо проблем со стороны батареи. Такими проблемами могут быть или снижение напряжения статусного контакта батареи (для Makita-совместимых батарей), или её перегрев. В этом варианте в центральной части экрана отображается текущее напряжение и температура батареи, а также, если идет зарядка Makita-совместимой батареи, состояние 4-го контакта интерфейсного разъема строкой FAIL или OK. Я решил, что выход из критической ситуации должен быть обязательно ручным, поэтому дополнительно на экране отображается пункт Continue, позволяющий продолжить зарядку.

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

Корпус
Теперь, когда схема отлажена и работает, а программная часть, по большей части, написана, настает время придать устройству законченный вид, поместив его в корпус. Но какой корпус использовать? Сначала я думал скачать из интернета готовый сокет LXT и просто прикрутить его к коробке подходящих размеров, но так и не смог найти такого варианта сокета, который бы мне понравился. Параллельно я размышлял, где буду хранить готовую зарядку, и все сошлось к тому, что надо в некоторой степени повторить корпус DC18SD/RC. Тогда и внешний вид будет красивым, и хранить её можно будет в кейсе MacPac 2 вместе с шуруповертом. Тем более, что размеры оригинальной зарядки позволяют разместить в этом корпусе мою плату и выбранный блок питания. Поэтому, запускаю любимый SolidWorks и рисую:

Как и у оригинальной зарядки, сокет для аккумулятора располагается с левой стороны на верхней части корпуса, поэтому дисплей, энкодер и выходные терминалы-бананы размещаются справа. Последние нужны для снятия выходного напряжения с зарядки в режиме блока питания.
Большим преимуществом современного 3д-моделирования является возможность создавать сборки из нескольких деталей – это позволяет легко, просто и правильно разместить внутри корпуса все компоненты, точно убедиться, что они туда влезут, а также досконально проработать способы их крепления. Поэтому дополнительно создал приближенные модели основных компонентов, после чего разместил их в корпусе:

Входной разъем для подключения сетевого кабеля решил использовать стандартный, IEC с выключателем-индикатором и предохранителем. Он несколько крупноват, зато имеет три контакта и позволяет подключать к устройству провод защитного заземления PE. Возможно, наличие заземления и не обязательно для зарядки, но уж точно необходимо блоку питания, поэтому в моем устройстве оно быть должно. Вариант прямого ввода сетевого кабеля внутрь устройства без дополнительного разъема я считаю крайне неудобным и не рассматриваю, так что будет крупный IEC. Разместил его с левой стороны на задней стенке корпуса заподлицо.
В качестве разъема для обновления прошивки решил использовать DB-9F, такие в далекие времена ставили в ПК на ком-порты. Только я установил в устройство «маму», а не «папу», как в ПК. Этот выбор был осознанным, чтобы минимизировать вероятность убивания устройства статикой при случайном прикосновении к разъему пальцем. Также это исключает случайное подключение в этот разъем кабелей старой компьютерной периферии. Разъем установил на заднюю стенку корпуса справа, но только немного утопил его вглубь.
К сожалению, в процессе размещения компонентов пришлось увеличить корпус по высоте на 15 мм, иначе не помещался вентилятор охлаждения. Такое увеличение никак не скажется на возможности хранить зарядку в MacPac’е, так как там по высоте имеется вполне достаточный запас, однако, поместить зарядку в обычный кейс от инструмента уже не выйдет. Этим пришлось пожертвовать ради хорошего охлаждения.
Наконец, чтобы корпус было возможно распечатать на 3д-принтере без сумасшедшего количества поддержек, разделил его на три части – нижняя крышка, основная часть и сокет LXT. Между собой части соединяются с помощью маленьких шурупов 2х6 и вплавляемых резьбовых втулок М3. Корпус распечатал из черного PETG:





Печать не обошлась без косяков – в основной части корпуса оказалось навесание с углом примерно 65°, которое распечаталось не очень хорошо. Поэтому пришлось немного обработать деталь наждачкой. А чтобы вернуть PETG его былой блеск – еще и пройти потом дихлорметаном.
Контакты для аккумулятора разработал полностью свои, вырезал их из кусочка листовой латуни толщиной 0.8 мм, специально купленной для этого в интернет-магазине:

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


Панель для механической защиты экрана выпилил из оргстекла толщиной 4 мм, она будет закрепляться в корпусе с помощью клея В7000:

Затем приступил непосредственно к сборке. Сначала вплавил все резьбовые втулки

Затем прикрутил сокет LXT, установил стекло, экран, энкодер и выходные терминалы. После этого прикрутил к отрицательному контакту батареи датчик температуры:

Далее установил блок питания и основную плату, а также соединил всё проводами:




В последнюю очередь установил и подключил вентилятор:

В итоге, получилась вот такая симпатичная (на мой взгляд) зарядка:




Испытания
Первые же испытания зарядки большим током показали, что ТКС обычного китайского «шунта» в виде SMD-резистора 2516 слишком велик, значение выходного тока отклонялось более чем на 2% при умеренном нагреве. Тогда я попытался использовать в качестве шунта константановую проволоку, и мне даже удалось отрезать кусочек с сопротивлением 10 мОм, но оказалось, что у константана слишком велико значение термо-ЭДС, из-за чего показания при нагреве также уплывали. Делать было нечего, оставался дорогой манганин, поэтому в Китае были заказаны вот такие красавцы:

Варианта на 10 мОм не нашлось, а переделывать что-либо в зарядке уже не хотелось, поэтому просто соединил два таких резистора последовательно и припаял на плату. Манганин показал себя значительно лучше всего остального, показания практически перестали меняться при нагреве, так что, если у кого-то стоит вопрос выбора – однозначно рекомендую.
Дальнейшие испытания зарядки прошли успешно – пока плата не была установлена в корпус, она отлично выдавала ток 5 А даже без какого-либо активного охлаждения. В корпусе с вентилятором 6 А дались ей так же легко, поэтому было решено увеличить максимальный предел до 8 А. И термические испытания показали вполне умеренный нагрев при работе с таким током – за полчаса работы на КЗ точка максимального нагрева на корпусе оказалась около выходных терминалов, где температура составила только 40 градусов (тепловизор занижает):

Радиатор же нагрелся до 60-ти:

При работе на нагрузку (8 А 21 В = 168 Вт) максимальная температура корпуса составила те же 40 градусов:

Измерений температуры внутри не проводил, но плата зарядки в таком режиме должна греться даже меньше, потому что падение напряжения на открытом транзисторе меньше падения на диоде Шоттки. А вот блоку питания будет тяжелее. Но учитывая, что это около 80% от его заявленного максимума, да и на него тоже идет поток воздуха от вентилятора, думаю, он выдержит.
Как только испытания были закончены, сразу ввел зарядку в эксплуатацию, правда, не по основному её назначению – первым реальным применением стала подзарядка автомобильного аккумулятора после длительного простоя, которая проводилась в режиме блока питания:


Всё прошло хорошо и за ночь зарядка не сгорела. При выходном токе 2 А радиатор платы периодически прогревался до 45 градусов, что вызывало включение вентилятора на минимальных оборотах, после чего плата остывала до 40 градусов и вентилятор выключался. В таком режиме зарядка оставалась практически бесшумной, о работе вентилятора можно было только догадываться по индикации на экране.
Желтый разъем Makita
К сожалению, в таком виде применять зарядку по её прямому назначению было невозможно, т.к. имевшиеся в наличии совместимые аккумуляторы Макита без подключения желтого разъема не включали зарядный транзистор, а заряжать батарею через силовой терминал в обход штатной BMS было попросту небезопасно. В деталях этот момент был подробно описан в предыдущем обзоре, поэтому здесь лишь подведу итог, что надо было добавлять в зарядку желтый разъем.
Для этого на Али был приобретен вот такой кабель-переходник, с одного конца которого находится желтый разъем для установки на зарядку, а с другого – разъем JST PH (с шагом 2 мм).

Поскольку плата была уже полностью собрана и переделывать ничего не хотелось, все необходимые дополнительные компоненты были установлены на отдельную небольшую плату, схема которой приводилась ранее. Компаратор U4.2 был переоборудован для сравнения статусного напряжения батареи с пороговым значением около 1.4 В и подключен к ранее не используемому в зарядке выводу MISO, а вывод РС3 использован для реализации протокола 1-Wire. После этого зарядка стала «полноценной» и её доработки, к счастью, закончились. Правда, основную печатную плату я так и не обновил до конца, по-хорошему, надо бы разместить все компоненты на ней.
Режим ССС
Так как для управления процессом зарядки используется микроконтроллер, становится возможным реализовать совершенно любой алгоритм заряда аккумулятора, что было бы весьма затруднительно сделать в чисто аналоговой схеме. Одним из таких решений и стал алгоритм, который я назвал Continuous Constant Current или сокращенно ССС.
В этом режиме аккумулятор всегда заряжается заданным постоянным током, независимо от текущего напряжения. А чтобы избежать перезаряда, раз в 10 секунд зарядный ток отключается, после чего осуществляется контроль напряжения холостого хода аккумулятора, и, если оно превышает 4.2 В на банку, заряд считается завершенным. Конечно, так можно заряжать только аккумулятор без БМС, иначе она отключит его раньше по превышению напряжения банок.
Не могу сказать, вреден ли данный режим зарядки для батарей, если кто-то обладает такой информацией – прошу написать в комментариях. Однако, у меня есть предположения, что этот алгоритм уже используют некоторые производители бытовой техники (например, мой пылесос ILife) для отказа от этапа CV и, таким образом, сокращения времени заряда.
Выводы
Считаю, что проект удался, получившейся зарядкой я очень доволен. Она не только выполняет свои основные функции, но и обладает отличной гибкостью, позволяя настраивать параметры зарядки практически любым образом. Возможно, гибкость нужна далеко не всем, но в моем понимании зарядка должна быть именно такой. Также зарядка может работать в режиме весьма тихого лабораторного источника питания, где она хоть и уступает по выходным характеристикам обычным аналоговым стабилизаторам, но вполне подходит для нетребовательных применений вроде подзарядки автомобильного аккумулятора или временного питания небольшого силового потребителя.
Конечно, весь проект оказался достаточно трудоемким, и занял значительно больше времени и сил, чем изначально предполагалось, но зато в процессе разработки мне удалось немного глубже разобраться с аккумуляторными технологиями Makita LXT и поделиться этим с вами.
На данный момент программная часть зарядки всё еще требует небольшой доработки – в ней не хватает аварийного выключения при перегреве радиатора, а также аварийной остановки зарядки при перегреве батареи. Надеюсь, я соберусь с силами и добавлю их в ближайшее время, потому что, честно говоря, этот проект меня немного вымотал.
На этом у меня всё, всем добра!
Исходные коды прошивки, корпус и макеты экранов доступны в моем репозитории:
https://github.com/kdekaluga/makita_charger
Страх и ненависть самодельщика
У меня был реноватор, три шуруповерта, аккумуляторная болгарка, лобзик, сабельная пила, гайковерт, несколько насадок Starlock и целое множество бит всех сортов и расцветок, пилки, а также отрезные круги, пара фрез, перфоратор, коронки и 2 дюжины сверл разного диаметра. Не то чтобы это был необходимый запас для самодельщика, но если начал покупать инструменты Makita, становится трудно остановиться. Единственное, что вызывало у меня опасение – это аккумуляторы. Ничто в этом мире не бывает более беспомощным, безответственным и бесполезным, чем человек, у которого села батарея в инструменте. Но я знал, что рано или поздно такое случится и мне придется заряжать эту дрянь.
Самые обсуждаемые обзоры
+52 |
2558
72
|
Осталось запустить в серию, думаю я первый готов купить!
Китайские акки заряжаю через не оригинал, оригинальные акки через оригинальную.
Есть еще китайские акки с круглым гнездом, заряжаются через мелкое ЗУ типа телефонного.
Но. Режим блока питания, экран, в целом все эти возможности и даже больше есть в IMAX b6, b6neo еще компактнее и мощнее, есть и более дорогие и крутые модельные зарядки. И по цене они не так уж и дороги, а блок питания можно использовать едва ли не любой…
Второе НО: есть у меня проблема, собрал я отцу мощные аккумуляторы для инструмента, 10 и 9 а/ч (4 рядный 18650 и 2 рядный 21700), заряжать их нужно большим током (хочется ведь быстро), вывел я балансировочный разьем, и силовой хт60, выглядит это немного колхозно и немного мешается в работе. Но главное не это. Отцу 65 лет, дал я ему b6neo и вроде объяснил, как пользоваться, но сложно ему кучу кнопочек нажимать и понимать что там написано.
Так вот я к чему, собственно: если запускать данную зарядку в массы, думаю было бы удобно добавить несколько кнопок «профилей», которые один раз настроил, прилепил на корпус наклейку с надписями, какой профиль под какой акум. Даже в рамках макитовского формата, есть китайские акумы на 1300мА, есть, допустим 5 а*ч и есть 10 а*ч, пишем на них цифру профиля, человек берет акб, смотрит какая там цифра, нажимает цифру профиля и ставит его на зарядку.
Возможно сумбурно описал и с ошибками, с телефона пишу и тороплюсь, заранее извиняюсь)
В принципе, если есть желание, можно их добавить и в данную зарядку как вместо, так и вместе с энкодером.
То есть, в программировании всё достаточно гибко. А вот если бы датчик тока не начал давать адекватные повторяемые показания, проект бы вообще не состоялся. Поэтому, по мне, основные сложности таких разработок далеко не в коде.
Я бы просто громко вспомнил о женщине с низкой социальной ответственностью. :)
А что именно вам кажется ненадежным?
Это не зарядка для стройки) Для стройки (и, вообще, профессионального применения) имхо проще брать оригинальный инструмент, чтобы не задумываться о таких вещах и иметь возможность обратиться по гарантии.
У инженеров Макита есть неоспоримое преимущество перед нами — у них есть опыт. Поэтому как инженер я склоняюсь в поклоне перед вашими знаниями и упорством, но как эксплуатант я это покупать или сам собирать не буду.
Если вдруг что-то случится с резистором в цепи обратной связи, последствия действительно могут быть печальными. Но давайте посмотрим на ситуацию честно — во-первых, вероятность этого низкая, т.к. по этим резисторам не течет большого тока. Во-вторых, с такой же вероятностью то же самое может произойти и в оригинальной зарядке, и никто не знает, какие последствия будут там. Фотографии сгоревших Макит в интернете есть, конечно, там утверждается, что виноваты батареи, но кто знает, как оно на самом деле. И, наконец, в третьих, если мы рассматриваем возможные электронные проблемы, мне кажется, с большей вероятностью какой-то отказ произойдет в БМС китайской батареи — они и сомнительного качества могут быть, и при эксплуатации вибрацию испытывают, и токи там больше.
То есть, если вы совершенно не используете китайские батареи, вам и зарядка такого типа не нужна, вы всё будете заряжать оригиналом. А если же вы используете китайские батареи, то, скорее, следует думать об их безопасности, чем о безопасности данной зарядки. Да и сравнивать эту зарядку тогда надо с китайскими, а там вообще может быть что угодно, вплоть до отсутствия прямого контроля напряжения вторички (недавно обзор был).
А еще у них есть задача сокращения времени заряда. Поэтому, например, DC18RC заряжает током до 9 А. А чем выше ток заряда, тем выше вероятность негативных последствий. Поэтому тут еще подумать надо, что безопасней. Я, например, по этой причине DC18SD взял — ну, не готов я 3 Ач заряжать током 9 А.
Отсюда простой вывод — лучше не оставлять заряжаться аккумуляторы без присмотра. Хоть оригиналом, хоть такой зарядкой.
Ну и соглашусь, что чем меньше ток тем безопаснее. Родных АКБ Макита у меня нет, поэтому заряжаю всё штатными китайскими зарядками на полампера. Ставлю на ночь и к завтраку всё готово.
Пока что это море неисправностей, по большей части, придумано.
Тогда не понимаю ваших претензий к надежности данной зарядки, ведь вы сами используете устройства непонятного происхождения. Тут у меня хотя бы защита есть — если МК перестанет работать, watchdog его сбросит и отключится выходное реле.
Вот по теме, лампочка покупная чуть дом не сожгла, они все такие в подвесном потолке, уже сталкивался, чаcть поменял, а эту забыл, выходит из строя светодиод, драйвер выдает 310В и пробивает его обугливая и далее тлеет гетинакс задымляя помещение, благо открытого огня нет, но запах есть
В моем светильнике замыкания не было, драйвер как источник тока гнал ток через обугленный светодиода и далее через гетинакс разогревая его. Ток был ограничен, только напряжение повысилось, ограниченное сетевым.
Проблем тут 2, глупый драйвер и плата не алюминиевая, и не стеклотекстолит даже, а гетинакс самый дешевый. И корпус пластиковый, но они везде такие примерно.
Это отвлекся. Самоделку такого уровня еще сделать надо постараться. Гетинакс даже не знаю где купить )) Делая для себя светильник можно сделать лучше и безопаснее в 1000 раз. А покупные и лампочки и светильники часто вижу что там дичь безграмотная, и в китайских светильниках и российского производства. И схемотехнические решения и охлаждения нет и т.п. При мне меняли тысячу светильников купленных централизованно, они перегрелись и вышли из строя за несколько месяцев. От драйвера теплоотвода не было нормального. С виду красивый, все сертификаты, российское производство, но сделаны безграмотно или не тестировались вообще.
Так же и уличные дорожные светильники. Смотрю натриевые горят над трассой все до одной (дорожники следят), а светодиодные через одну, то мигают как стробоскопы, то сегменты часть не горят, вероятно поменять их просто так не могут или починить, просто лампочку не заменить же в них, а замена всего светильника трудоемкая и дорогая операция.
Туда не заходит провод, в который розетка охотно отдаст 220 вольт 16 ампер?
Нарушение режима зарядки не вздует, а то и взорвёт ваш аккумулятор? Ах да, там же стоит китайский бмс, гарантия 146%.
А можно нубский вопрос, для чего нужен и как работает конденсатор С27 между входами ОУ?
Когда-то тактильно измерил напряжение на конденсаторе фотовспышки, до сих пор помню ощущения ;)
А зачем его разряжать, с заряженным при следующем включении бросок тока будет меньше.
На всякий случай, может кому-то пригодится: есть относительно недорогие готовые инструментальные усилители с неплохими характеристиками: TPA1286. Нужен всего один точный резистор для выставления коэффициента усиления.
Изначально, когда я проверял концепт программного ШИМ, в качестве датчика тока установил резистор 0.5 Ом, с которого снимал достаточный для АЦП сигнал уже при 1 А. Концепт заработал, после чего я нарисовал схему, добавив в неё усилитель тока — казалось бы, что могло пойти не так? В реальности проверил такую конфигурацию я уже только на собранной плате, и оказалось, что она совершенно не работает. Показания тока, считанные АЦП, заметно менялись даже от простого прикосновения пальцем к земляной клемме выхода. В тот момент я в первый раз подумал, что ничего не получится :) Но стал экспериментировать, менять резисторы, подключать конденсаторы.
И вдруг оказалось, что если снизить сопротивление резисторов обвязки ОУ в 100 раз (входные с 10 К до 100 Ом) и добавить вот этот конденсатор, то усилитель тока переставал реагировать на странные помехи и начинал работать стабильно. Этот вариант и оставил. Кстати, временная постоянная, вносимая данной цепочкой составляет 20 микросекунд, то есть, даже не оказывает заметного влияния на полосу усилителя тока.
Думаю, основная проблема в том, что помеха идет по земляному проводу. Я выяснил это, когда временно добавил в цепь питания земли МК дроссель с индуктивностью несколько мГн. Соответственно, конденсатор между входами ОУ сглаживает эту помеху, не позволяя ей сильно менять считываемые значения.
Думаю, разряжаться он всё таки будет, просто очень медленно. И если следующее включение произойдет, например, через сутки, он уже будет разряжен. Поэтому, с этой точки зрения практической пользы от отсутствия резисторов нет. А вот с точки зрения безопасности — есть, ведь шанс полезть внутрь через 10 минут после выключения достаточно велик.
Немного погуглив, нашёл похожее решение у классиков Хоровица/Хилла:
http://the-epic-file.com/text/bookz/aoe_3/ch_05/aoe3_05_16.htm#x_05_16_04
Только источником у меня выступает собственный же преобразователь. Наверное, надо было еще и плату несколько иначе разводить, силовую часть полностью отдельно ставить.
Зеленый график — АЧХ этого диффусилителя без конденсаторов. Красный график — с конденсатором 100 нФ между входами ОУ. Синий график — плюс цепочка 1 кОм/100нФ на выходе.
Ну, конечно, АЧХ он вредит, но по вашему графику видно, что влияния от него на 10 КГц нет вообще. А у меня ПИД работает с еще более низкой частотой, так что всё, что выше уже не особо важно. А вот без него показаний вообще нормальных было не прочесть, они менялись практически от положения руки. Прямо терминвокс какой-то.
Ну, и интересный момент, что влияние от выходной RC-цепочки значительно больше, чем от этого конденсатора. Но это я предполагал и по номиналам.
Выходная цепочка 1 кОм + 100 нФ, а тут 200 Ом + 100 нФ.
Попробую выставить блок в CV, сымитировать такую нагрузку мосфетом, генератором и резистором и посмотреть сигнал непосредственно на выходе ОУ и на входе МК.
А пока вопрос. Во-первых, какой ОУ вы в модели использовали? Во-вторых, каким бы образом сами решали аналогичную проблему?
www.chipdip.ru/product0/8021253727
На Алиэкспрессе и то дороже выходит и ждать месяц
https://aliexpress.ru/item/1005008586844659.html
(добавил в заметки себе, обычно ОУ такого уровня дороже стоили)
Я каюсь, конечно я еще не читал всю статью, прочёл только начало, но там это все о чем было сказано, это желание регулировать ток самому.
Ну, да, началось всё именно с этого. А потом оказалось, что ей, например, очень удобно подзаряжать автомобильный аккум. При этом, она оказалась значительно проще и тише любого другого имеющегося варианта. Плюс, ёмкость отданную считает.
А зарядки оказалось нет, заказал пришла но! Совсем другой корпус Fuxtec EC20 4 вывода C- T ID C+
а у аккумулятора 5. P+ C+ ID T P-
Соеденил P- C- ID ID T T C+
И вот голову ломаю, заряда нет. Блок выдаёт 40в акб 35
Чтобы появилось 21в на выходе зарядки:
Средние контакты это id и термодатчик, на оба нужно вешать резисторы на минус.
Для id это 36к, 47к или 56к, соответствует емкости 2, 4 и 5 а/ч,
сопротивление термодатчика 10кОм.
И напряжение на выходе зарядки появляется только после подключения аккумулятора!!!
У вас может быть аналогичное решение.
P-T =12,43k
P- ID =11.98K
P- C+=35V
p- p+=35v
Если в зарядное то без АКБ
P-T=5v
P- ID 5v P- C=41v
P- P+ =35v
Тоже самое и с подключенным акб.
Напряжение есть, тока нет!
резисторы вешал.
пока сижу на 78 форуме
Вспомнился старинный анекдот про Игоря Николаева и пять нот. Но под таким суровым текстом он скорее всего будет неуместен.)
Поэтому в нотных заморочках я редкостный интернет-специалист, могу рассуждать до бесконечности. И имя нам — легион.))
Кстати, в интернетах говорят, что брат Гвидо придумал 6 нот (Си не было). И потом несколько сотен лет это никого не волновало.
Поэтому брат Гвидо между Николаевым и журналистом.;)
Вообще, изначально никто не задумывался про количество нот, просто подбирали по звучанию, поэтому в разных местах их число разное. Позже, на этой основе родился «натуральный строй» — он весьма близок к равномерному, но отличается, в результате чего там есть, кажется, «волчья квинта», которая не звучит. Она, в принципе, не особо мешает, но не дает произвольно транспонировать мелодию. Поэтому потом к вопросу подключились те, кто умеет считать и решили, что пусть ноты будут распределены равномерно (логарифмически равномерно), тогда проблем с транспозицией не будет.
Кстати, поклонники натурального строя есть и сейчас, они настраивают свои музыкальные инструменты именно так, и считают, что по-другому нельзя.
А так да, в принципе можно задать звуки тип sin(10*t) + sin(20*t) и будет тот же звук ))
1. «у AVR по современным меркам весьма ограниченные ресурсы, а писать программу в таких условиях значительно интересней» — воспринял это как стёб :)
2. «Поскольку МК питается от 5 В, необходимо согласовать уровни напряжений выходных сигналов, идущих к дисплею. Вариантов согласования есть несколько, но я выбрал самый простой – гасящие резисторы.» — да, способ не очень красивый. Чтобы не завалить фронты, нужны низкоомные резисторы. Но тогда страшно за защитные диоды. Лучше поставить полноценные делители. Хотя в данном проекте, вроде, ничто не мешало запитать ATmega от 3.3 В?
3. «Q11 инвертирует сигнал и усиливает его по амплитуде до 12 В» — для большей скорости усиление можно было делать каскадом с ОБ, а не ОЭ. Но в данном случае скорости более чем хватает.
4. «необходимость точного подбора резисторов делителей так, чтобы коэффициенты деления двух цепочек были очень близки, что затруднительно в серийном производстве» — наоборот, в интегральных инструментальных усилителях получается гораздо лучшее согласование компонентов, чем при дискретной реализации. К тому же, там резисторы находятся при одинаковой температуре, а для дискретной схемы даже градиенты температуры на плате вызывают снижение подавления синфазного сигнала. Что касается схемы на 3-х ОУ, они есть разные, одна из конфигураций накладывает менее жесткие требования на точность резисторов при условии большого усиления. Кроме этого, у схемы есть еще достоинства — регулировка усиления одним резистором, высокое входное сопротивление по обоим входам (усилитель на одном ОУ имеет низкие и РАЗНЫЕ входные сопротивления, есть конфигурация на 2-х ОУ, исправляющая это, автор David Birt).
5. «R2R ОУ, но даже они не в состоянии выдать ровно ноль вольт, их минимум начинается где-то от 25 мВ и сильно зависит от нагрузки. А 25 мВ – это примерно 21 единица шкалы АЦП или 2%, и это слишком большая погрешность при измерении тока.» — можно просто сместить шкалу вверх на какие-нибудь 100 мВ, потеряем незначительную часть шкалы АЦП. Диффусилители имеют вывод REF, относительно которого они представляют свое выходное напряжение. Здесь он заземлен (резисторы R4, R18), но можно его подключить к опоре 100 мВ. Эту опору можно мерить еще одним входом АЦП и вычитать. Но правильней делать калибровку и вычитать опору вместе со смещением ОУ. Такой прием использую в своем ЛБП PSL-3604. Хоть там двухполярное питание ОУ, но сами ОУ могут иметь отрицательное смещение, что погубит точность без принятия этой меры.
6. «Еще одним нюансом схемы является резистор R44. Его задача – сдвинуть точку нуля токовой шкалы в область положительных напряжений.» — если сделать как в пункте 5, то это будет лишним.
7. «Платы делал ЛУТом, из-за чего их качество существенно ниже основной.» — почему-то сильно подтравливаются полигоны. Такое замечал при плохом тонере, старался использовать фирменный. Но в последнее время с ним напряг, поэтому попробовал купить новый ктиайский картридж. Взял CACTUS. Результат — отличный.
8. «Написание программы для МК в таком проекте – не самый сложный» — как по мне, так это сложнее составления схемы и изготовления механики. Сколько проектов похоронило ненаписанное ПО!
9. «дает результирующую частоту PWM 62.5 КГц» — интересный факт: STM32F334 может генерировать 8-битный PWM частотой до 18 МГц.
10. «На практике же можно поднять эту частоту до 1 МГц, и АЦП всё еще будет неплохо работать, что даст уже до 77 тысяч преобразований в секунду» — из моего опыта, точность измерений при повышении частоты преобразований выше 15 кГц заметно падает. Но конкретные результаты не сохранил.
11. «Еще один нюанс управления PWM заключается в том, что мега ни при каком значении регистра OCR0A таймера не позволяет получить на выходе абсолютный логический ноль.» — надо включить инверсное управление выходом OC и загружать инвертированный код. Тогда будет абсолютный ноль, но не будет абсолютной единицы, что тут и не надо.
12. «поделился проблемой с супругой, и она спросила, зачем я провожу измерения именно в то время, когда на вход попадает помеха» — афигеть, где таких супруг выдают?
13. «это даст частоту обновления 30.5 Гц, чего более, чем достаточно для отображения» — это же очень много, обычно делают не более 10 Гц.
14. «сохраняет в глобальную переменную g_buffer» — наверное, буфер может принадлежать классу дисплея, данные всегда должны принадлежать кому-то конкретному. А в эту функцию просто передавать на него указатель.
15. «отлавливать примерно до двух тысяч тиков энкодера в секунду» — так быстро для энкодера и не надо. Обычно опрашиваю раз в 1 мс. С энкодером есть ряд нюансов. Шаг вперед и назад должен производится в одной точке, чтобы небольшое качание энкодера туда-сюда не приводило к постоянному inc (или dec). Переключение должно совпадать с моментом механического щелчка. Надо давить дребезг, для чего я использую тот факт, что на каждый щелчок меняется 4 состояния энкодера и требую последовательного их прохождения. Но все равно обработкой доволен не полностью. Аппартная обработка в STM32 предназначена для других энкодеров, которые на валах двигателей. Она не давит дребезг.
16. «Корпус распечатал из черного PETG» — это вкусовщина, конечно, но корпус из-под 3-D принетера на мой взгляд ужас-ужас из-за плохой текстуры поверхности. Портит все впечатление об устройстве. Особенно плохо выглядит на последнем фото. Вроде, простая прямоугольная коробка, но из нормального пластика, была бы лучше?
17. «Не то чтобы это был необходимый запас для самодельщика» — вроде, тоже самоделю, но зачем столько инструмента — не понимаю. Это же забарахляет жизненное пространство.
18. «мне придется заряжать эту дрянь» :))) Пока у меня в жизни не было ни одного аккумуляторного инструмента. Вот думаю — доживу ли я свой век без них?
Часто думал о том, что при описании готовых проектов никогда нет описания прошивки. Только ссылка на скачивание. А схемы и чертежи подробно рассматриваются. В результате по журнальным статьям невозможно научиться делать такое же, они не учат писать прошивки. И вот в этой статье подробно рассмотрена программа. Ощущения двойственные. Хорошо, но очень тяжело разбираться. С ассемблером — вообще невозможно. И очень плохо, что вставки текста в виде картинок. Должен быть текст, даже если форматирование и подсветка синтаксиса исчезнет.
Какой на выходе выброс тока при переходе CV-CC (например, при внезапном КЗ)?
Сколько времени ушло в сумме на проект?
Ну и еще раз — проект прекрасен, все придирки высасывал из пальца, теперь он болит :)
Почему? Может раскрутиться? Типа, нет двухэтапного зажатия?
Люфт шпинделя ужасный, и ничего не поддаётся улучшению. Хотел тоже для мелкой фрезеровки приспособить, заменив подшипники на роликовые, но не бывает таких…
И всё плачевно хлипкое.
Удивительно, но я особого люфта не замечал. Возможно, у нас разные понимания о люфте, но как сверлильный для самоделок он меня полностью устраивает. Есть небольшие биения патрона, «фрезерное» сверло с али 0.6 мм при полном углублении в заготовку он ломает, но 1 мм уже нет. В принципе, для таких мелких сверл есть у меня сверлильный станочек помельче, но периодически приходят в голову мысли поменять патрон и у этого, т.к. в интернете пишут, что тогда биения полностью уходят. Но вот пока не собрался, т.к. контр-винт не выкручивается, его надо высверливать. В общем, это уже серьезный шаг.
Нравится в нем регулировка и поддержание оборотов, а также цифровая линейка — крайне удобная штука с разрешением 0.1 мм.
Вовсе нет. У меня сейчас по работе шаблон на шаблоне и шаблоном погоняет. Задачи не алгоритмические, а из разряда «куда бы еще шаблон впихнуть». После такого программирование под AVR (особенно на асме) — отдых.
Там ток 4 мА через них, выдержат. По поводу питания — по даташиту надо не менее 4.5 В для 16 МГц, иначе бы именно так и поступил.
Согласен, в своем лабораторном БП я тоже примерно так делал. Здесь не стал, наверное, потому, что в наличии R2R ОУ всё равно нет, думал сначала вообще на ширпотребе LM358 сделать, а там 100 мВ не хватит.
У меня тонер еще фирменный, что с принтером шел. Наверное, у меня не такой принтер, придется смириться :) У меня Pantum 2500W. Хотя картридж дополнительный от кактуса я к нему еще пару лет назад прикупил, но пока ни разу не использовал. Надо будет попробовать.
Это может быть долго, порой неинтересно (из-за однообразности), но не самое сложное. В случае данной зарядки у меня три раза было желание бросить, и ни один из них не был связан с программированием. Первый и третий были связаны с аналоговой схемотехникой, а второй — с невозможностью заряжать аккумуляторы без желтого разъема.
Ого, F3 серию не смотрел, но это же 4.6 ГГц тактовая частота? Или там какие-то хитрости?
Сам проверял и разница с 100 КГц была в 1, редко 2 единицы, причем, при низкой частоте показания были устойчивыми, а при более высокой — просто начинали чуть прыгать. Может быть, вы смотрели на более старых чипах и сейчас что-то поправили?
Хм, интересное замечание, спасибо! Позволит сэкономить пару тактов)
Очень часто человеку, длительно решающему какую-то достаточно сложную задачу свойственно смотреть на неё и свое решение однобоко, как будто её можно решить только таким способом. В этом случае общение с человеком, не вовлеченным в задачу может дать неожиданные результаты)
Конечно. Я тут хотел сказать, что этого будет вполне достаточно, чтобы, скажем, выводить значения с комфортной частотой 5 Гц.
Тут «один поток», можно работать и со статическим буфером, чтобы избежать передачи лишних параметров. Ведь всё равно кроме вызывающего кода этим буфером сейчас никто не пользуется, тогда зачем указатель? )
Да. Мой вариант — не очень хороший, ибо не давит дребезг и не контролирует прохождение полного цикла. Обдумываю, чтобы его доработать. Давить дребезг, кстати, можно или аппаратно, или требованием, чтобы два последовательных считывания возвращали одинаковый результат.
Нет. Во-первых, в реальности корпус выглядит лучше, чем на фото, фото всегда подчеркивают дефекты 3д-печати, которые не так сильно заметны в жизни. Во-вторых, для вещи такого применения это не имеет совершенно никакого значения, ведь она не ставится для украшения, а используется строго по её (достаточно узкому) назначению. Я больше скажу — я даже не пытался улучшить печать уменьшением высоты слоя и/или снижением скорости, хотя это вполне возможно. Только деталь бы печаталась 12 часов, а не 3 ) И, в-третьих, мне нужен был корпус, который повторяет форму зарядки от Макиты, чтобы он вошел в «штатное место» макпака. Но, при этом, он должен быть чуть выше — такой готовый не найти. А напечатать — легко.
Но если уж прямо не нравится текстура, можно печатать из ABS — он токсичен (при печати), но значительно легче обрабатывается. Как механически, так и химически. Многие печатают, шкурят, красят и получают деталь, практически аналогичную заводской.
Ну, это вам решать :) Аккумуляторный шуруповерт у меня уже лет 15, вещь крайне удобная. Как по прямому назначению, так и для сверления, если не нужна особая точность, например, при сборке мебели. Остальному аккумуляторному инструменту раньше не доверял, типа, не сравнится с мощностью сетевого. Но сейчас частично меняю свое мнение, т.к. иногда свобода от провода компенсирует меньшую мощность.
Я с вами полностью согласен. Но этот обзор уже на пределе по объему текста, поэтому на такую жертву я пошел осознанно, иначе материал бы просто не вместился. Я даже думал, что если не уложусь, придется и основной текст вставлять картинками :)
Именно КЗ обрабатывается отдельно, поэтому там все быстро:
Сложно сказать, т.к. занимался в свободное от работы и других дел время. Но много. Начал в августе прошлого года, более-менее закончил к НГ, но потом занимался изучением особенностей зарядки Макиты, после чего дорабатывал.
Вовсе нет, всегда интересно и полезно читать аргументированную критику, ведь практически всегда есть возможность сделать лучше) Вопрос лишь только, где остановиться)
Ну там 4.5 В это для 0 — 20 МГц. На графиках рисуют до 17 МГц при 4 В. Но на практике работает на 16 МГц при 3.3 В, для хоббийных проектов вполне можно использовать, разгон совсем небольшой.
Это спасает не только от неидеальной «рэйловости» возле земли, но и просто от смещения, если оно отрицательное.
Мне тяжело дется программирование. Там всё можно сделать по-разному, на каждом шагу приходится принимать решения. Что выматывает. И постоянно есть чувство неудовлетворенности от некрасивой структуры программы. А как сделать красиво — непонятно.
Да, эквивалентная частота тактирования для таймеров HRTIM именно такая. Там используется DLL (delay-locked loop).
На ATmega8.
Смотря с какой частотой опрашивать. У механического дребезга есть своя характерная частота, если опрашивать быстро, то и при дребезге соседние значения будут одинаковые. Можно делать по-другому — требовать прохода промежуточного состояния. Но надо сказать, что проблема остается. Через лет 5 энкодеры начинают плохо работать (окисляются контакты?) — при быстром вращении пропускают события.
Это я понимаю, но тут просто такое личное восприятие. Напечатанные детали я использую на работе, там есть дорогой принтер, но даже и в мыслях не было печатать что-то себе. Почему-то поверхность (неровная, а еще и блестящая) вызывает стойкое отторжение. Когда на этом сайте критикую 3-D печать, мне доказывают, что бывает и лучше. Но реальные изделия здесь только такие. Не берите это в голову, это лишь моя дурь.
Не знал про ограничение. Как раз планирую обзор самодельной паяльной станции, очень похожий на этот, тоже хотел написать с разбором программы. Но когда сам почитал, то уже сомневаюсь, что это надо делать. Я хоть и довольно плотно в этой теме, но читать про чужую программу очень тяжело.
Што-то меня на общеизвестное понесло. Весна? )
chat.deepseek.com/
Что делает код на картинке
Задумался о будущем программистов-разработчиков.
Вот пример, безработный программист ищет работу, генерация картинки
А космическая тема не обошлась без округлых форм)
Зато вид из окон, на 20 км видно всё ))
А когда вне проводника вообще непонятно, радиоволну с круговой поляризацией я не могу представить ни как, как оно возможно, а это обычный сигнал же ))
Согласен, решение правильное, мелкое смещение в районе 5 мВ сделать надо было, тем более, делается просто — вместо заземления подключаем к точке с таким напряжением.
Сделать по-разному можно везде :) Даже при кладке кирпичей. Другое дело, что в программировании всё абсолютно четко и детерминировано, корректно написанная программа будет работать совершенно одинаково независимо от внешних факторов. А в аналоговой электронике не так. Там сейчас схема работает хорошо, а завтра появились мелкие помехи по питанию (от соседнего БП, например) и приехали, схему надо переделывать.
Я тоже не люблю некрасивого кода, поэтому, если решение мне кажется некрасивым, просто ухожу от компьютера и обдумываю, как можно сделать лучше. А потом возвращаюсь и делаю. При этом, красота — понятие относительное даже для одного человека — сегодня я могу сделать так, а через месяц переписать иначе, потому что в голову пришла другая мысль. Это нормально.
Такое есть и у промышленных аппаратов. Например, на моем предыдущем осциллографе Ригол энкодер чувствительности стал настолько плохо работать, что уже было проблематично задать настройку. Наверное, здесь не стоит искать идеала, ведь лучшее — враг хорошего.
Ну, нет :) Вот пример воздуходувки, купленной мной на али:
За всех не могу говорить, но мне такие вещи нравятся. Всегда интересно читать, как автор что-то реализует, будь то схема или программа. А если уж прямо совсем не интересно, можно же пропустить.
Не спасет, слишком мало. TL082 имеет типовое смещение 5 мВ, здесь оно усилится в 10 раз, получим до 50 мВ на выходе усилителя. А максимальное смещение по datasheet для него вообще 20 мВ, на выходе будет 200 мВ.
Наверное, не только текстура портит вид, но и блеск. Или их сочетание, не знаю. 3-D печать с эстетикой почему-то не дружит.
Блеск от материала зависит. PETG глянцевый, блестит. PLA обычный нет, ABS, вроде как, тоже нет. Но, с другой стороны, много и заводских пластиковых товаров изначально блестящие — фен, например, зубные щетки электрические.
У меня Мишка 5. Кило этого пластика отпечатал, шестерни как новые. Сопло медное с никелировкой использую по до все, за год не стерлось. Конечно, при хоббийных нагрузках, не производственных.
Когда покупал, повелся на wifi — и, да, правда удобно, принтер может в другой части квартиры стоять, но для ЛУТ оказался плохим.
На 3.3 может не завестись на 16 МГц… Сталкивался с экземплярами АВРок (АТМЕГА128) — на 3.3 заводятся с кварцем на 12 МГц, но не заводятся — на 16 МГц.
Но повышение питания до 3.6 вольта решает проблему почти всегда. Хотя, согласно документации, мега все равно не в режиме.
Для 328 меги в ДШ есть график зависимости максимальной тактовой частоты от напряжения питания.
Согласно него — 16 МГц можно при питании ~3.78 вольт.
Мне кажется, у меня была такая или похожая мега. В общем, для разового применения провести тесты можно, но для постоянного — не стоит.
ПС. Инверсия ШИМа хороша будет для батарейных устройств, когда надо управлять подсветкой дисплея, например. Не нужно будет дергать регистры таймера.
Так же вопрос, почему управляете дисплеем по 16-битам, а не по 8-ми? Вроде на меге дополнительной производительности от этого особо нет, а вот лишние 8 пинов занимает.
Мне проще на старой доброй атмеге.
И вообще, если копнуть историю, то у меня были часы с календарем и таймером-будильником. Но интернет-сообществу захотелось еще плюшек — радио, управление внешними устройствами… Вот пришлось делать на 128 меге.
Почему 16, а не 8? Да потому что дисплей 16 бит… А ног у меги хавтает.
Да все такие контроллеры обычно переключаются между 16 бит/8 бит/SPI/I2C. 8 бит для меги оптимально, т.к. совпадает с разрядностью.
Но если смотреть на выигрыш производительности между разными вариантами, то при переходе от SPI к 8-бит он огромен, при переходе от 8-ми к 16-ти на реальных данных он не будет уже так заметен, но целых 8 пинов мы потеряем. Хорошо, у вас портов много, но для меги328, например, 8 бит еще вполне реализуемо, 16 уже нет.
Я сейчас вообще стараюсь такие дисплеи не рассматривать в связке с AVR.
STM32 е его тактовой под сотню, вагоном ОЗУ и флеша — как раз катит под такие задачки.там еше и SPI 16 бит, и DMA…
Весьма интересный проект. Но почему бейсик? Может быть, лучше было бы в таком формате сделать эмулятор спектрума? На него куча игр была в свое время.
мне было проще 16.
да то вообще странная идея-фикс была — сделать что то мелкое для убивания туалето-часов. Чисто с несколькими тупыми игрушками. Но хотелось расширяемое малой кровью. И в какой то момент родился бейсик.
Ну и плюс это был вызов самому себе — заделать полноценный парсер и компилятор языка. И среду выполнения. Там еще интернет-знакомая помогла немного… В частности, менеджер памяти — основная идея и реализация — ее рук дело.
А эмуляторов спектрума вагон и тележка, куда еще? (И, увы, спекки прошел мимо меня по причине отсутствия возможностей его собрать)
А он у вас компилируемый? В байт-код или в нативные машинные? И парсер прямо полностью свой или используется что-то вроде flex?
Жаль, в детстве была игрушка, что надо. Я тоже, кстати, не собирал — 48К подарили, а 128К купил уже собранную плату, которую потом только дорабатывал и ремонтировал.
Вот тут бы эмулятор спектрума подошел идеально :) Там было достаточное количество игрушек, которыми можно развлекаться в процессе. Причем, как более-менее динамичные, так и полностью логические. Хотя, последнее время для этой цели используется смартфон)
Ну, детство у меня прошло под флагом желания Радио86-РК собрать. А спектрум — время голодного студенчества… Финансово не складывалось. А когда сложилось, уже был 98-99 год, у меня случился нормальный комп
Но в плюсах мне именно и нравится их низкий уровень, что они ближе к ассемблеру. Мне нравится то, что при желании я могу небезопасно превратить указатель в любой другой, что могу взять адрес элемента структуры, вычесть из неё адрес структуры и получить таким образом смещение. Мне кажется, это именно то, что надо для микроконтроллера. Более того, здесь часто и все фишки С++ не используются, много кода пишется просто на С.
Хотя мне лично жаль, что автор кажется умышленно усложнял себе задание. Выбрав слабенький МК и выжимая из него все соки. ИМХО, было бы прикольно, увидеть подобный проект, использующий связку из ESP32 + IPS/AMOLED экрана, которых сейчас множество расплодилось от китайцев, ну и платку чтобы можно было заказать заводскую, тогда и Bluetooth/WiFi из коробки сделать можно со всеми плюшками (типа извещения об окончания заряда на мобилку, или обновлений прошивки на лету).
С другой стороны, здесь говорят, что аппаратного PWM нет. И кому верить? )
Для подобного проекта нужно:
а) аппаратная PWM
б) организация чтения минимум двух каналов ADC на прерываниях
в) синхронизация ADC и PWM для повышения точности
Вот это я не знаю как организовать на ESP, а остальное — да, простым кодом в Ардуино можно написать. Если же с перечисленными пунктами будут проблемы, тут уже надо хорошо архитектуру знать, чтобы понимать, чем лучше заменить.
Но когда-нибудь я дойду до этого) Потому что сейчас ESP выглядит значительно более перспективно, чем STM.
https://aliexpress.ru/item/1005008391813630.html
б и в) имхо, для тока и напряжения, лучше использовать дешевое специализированное решение, типа INA226 (до 36 В) или INA236 (до 48 В). Там 16 битный АЦП, выдающий сразу и напряжение, и ток, и мощность. Такой точности AVR, да и другим встроенным АЦП даже не снилось. Обвязка буквально 2 резистора для шины I2C и кондюк по питанию, не нужно даже делители напряжения городить. Есть программная калибровка и усреднение данных АЦП. Учитывая, что данные микросхемы могут иметь до 16 адресов, то можно, довольно легко, сделать многоканальную зарядку.
Во-вторых, я не смогу синхронизировать момент измерения с частотой PWM, а это, как оказалось, тоже повышает точность.
То есть, при таком подходе следует сразу принять, что МК будет лишь указывать, какое напряжение/ток нужно получить на выходе, а некая последующая аналоговая схема CC/CV будет его формировать. Да, так делать тоже можно, но это потребует значительно больше дополнительных компонентов, чем в моей схеме.
И, по итогу, чем такое решение окажется лучше обозреваемого с точки зрения пользователя? Только тем, что экраны будут быстрее меняться? Ну, это сущая мелочь. Тем, что можно WiFi прикрутить — а оно правда надо? )
Насколько я понял, 7K получилось только из максимального выжимания сока конкретного МК, а не потому, что задача была достигнуть именно 7К. Почему не взять МК мощнее и получить, к примеру 70К, или даже 700К (то же касается и частоты PWM). Где та грань?
Кроме того, Вы же используете АЦП, и так не затачивавшийся на высокую точность (так как это бюджетный МК общего назначения), ещё и в разогнанном в 5 раз выше от рекомендуемых производителем значений. Можно ли в данном случае говорить о высокой точности?
Да хоть обновлением прошивки по воздуху :) И экран будет не только быстрее меняться, а и может быть больше и с большим разрешением.
Можно. Но, опять же, зачем? Если бы речь шла о запуске в производство, то имело бы смысл экономить на дросселе, конденсаторе, радиаторе и повышать частоту ШИМ. Но с точки зрения пользователя устройство работало бы ровно так же — вставил батарею, зарядил, вытащил.
Даже 10 бит — это точность 0.1%, то есть, в 10 раз точнее применяемых повсеместно резисторов. Точность упирается не в МК и его АЦП, а в банальные пассивные компоненты.
Обновление прошивки не нужно) Один раз нормально написал и пользуешься, даже китайские компании типа фнирси не обновляют, что уж говорить про самодельщиков.
Экран и тут обновляется порядка 5-7 раз в секунду — в рабочем же режиме его весь перерисовывать не надо. Новый экран рисуется медленно, да, но это мелочь, переходы между экранами в реальной эксплуатации почти не встречаются.
Разрешение измерений, да, можно было бы на другом МК сделать выше. Но ведь это не повысит точность, которая определяется пассивными компонентами, просто больше цифр вывести.
Резюмируя — если бы мне сейчас пришлось повторить проект с нуля, я бы сделал, скорее всего, на СТМ32. Но просто потому, что на АВР я уже делал и было бы интересно сравнить решения и получившийся результат. Схемотехнику бы тоже чуть подправил, но не сильно, всё же это не супер-пупер ЛБП, а простая зарядка.
На ЕСП, скорее всего, делать бы не стал — нет на неё нормальной документации, чтобы можно было досконально разобраться, как там ШИМ аппаратный работает и как его с АЦП синхронизировать.
P.S. Для ЕСП, кстати, у меня уже пару лет другой проект есть, но там сервер домашний нужен, лень поднимать.
Сколько из этих 10 бит являются эффективной разрядностью, а сколько шума? Особенно при разгоне?
Тут прям завидую. Если конечно не в стиле «облом дорабатывать и так сойдет» :)
Ну про FNIRSI, это стиль компании, прошивки обновляют новыми устройствами. А у меня к примеру есть умная зарядка HOTA D6 Pro, прошивок вышло несколько десятков за 4-5 лет (там правда по USB обновление).
Для таких устройств прошивка обычно пишется один раз, в ней отлавливаются все баги, после чего она просто работает. Желания добавить что-то новое обычно не возникает, т.к. это функциональное устройство, если свою функцию оно выполняет, больше ничего не требуется. А если же вдруг в процессе работы будет обнаружен баг, конечно, я его поправлю.
А что самое заметное было доработано?
Что-то у меня очень большие сомнения, далеко не все мультиметры такую точность обеспечивают. А тут сборка по сути из того, что было под рукой (вроде не покупали специально какие-то высокоточные компоненты), тем более под нагревом (в отличии от мультиметра).
Просто я много игрался с различными цифровыми датчиками, и то там шумы заметные. А тут на копеечном АЦП, разогнали 4 семпла усреднили, и на тебе супер точность. Я как бы значительно больше семплов брал (мне не нужна была скорость в килогерцы, и пробовал до нескольких сотен сэмплов), и фильтрацию значительно сложнее простого усреднения (тот же Фильтр Калмана и другие). И то шумы есть. Да можно конечно сильнее сгладить, но нужно же не пропустить настоящего всплеска. Я просто дружу с Web-разработкой, и привык для мониторинга процессов использовать Grafana. Поэтому девайсы через WiFi по MQTT сбрасывали данные для мониторинга на сервак. А там уже в Grafana можно по всякому их анализировать.
PS. Кстати, был удивлен, но та самая точность в 0.2% получается, в основном, из-за нелинейности АЦП. И это не из-за складывания 4-х значений, т.к. проявляется она периодически через некоторые, достаточно большие, интервалы. То есть, это какая-то нелинейность в средних разрядах АЦП.
Т.е. грубо говоря, у Вас максимум 24 В делим на 1024 округлим до 0,02 В. У INA 24/65536 округлим до 0,0004 В.
Допустим у нас идеальный случай напряжение линейно растет и шумов и прочих глюков АЦП нет. АЦП INA показывает 3,02 В, 3,0204 В, 3,0208 В… и так 64 значения до 3,04 В. В то же время АЦП AVR будет показывать одинаковое напряжение 3,02 В, в течении 32 измерений, потом оно меняется на 3,04 и следующие 64 значения показывает 3,04 В, хотя в то же время INA может показывать 3,032 В или 3,046 В, AVR их физически не различит.
Вот и спрашивается, как в данной ситуации вместо 64 одинаковых значений получение 128 одинаковых значений (AVR же в вашем девайсе в 2 раза быстрее INA) увеличивает точность устройства?
Ну и опять же, Вы говорили о сложности INA, но Вы же и так используете I2C для измерения температуры, ладно бы Вы и температуру АЦПшкой измеряли. А так шина уже рабочая есть, добавить микросхему с кондером и подключить их к шунту. При этом выкинуть ОУ, те самые резисторы делители, не нужно отрицательное питание на плате и прочих заморочек. Такое ощущение, что просто хотелось повозиться со схемотехникой в данном случае.
Если использовать ИНА, то только совместно с отдельным аналоговым ШИМом и аналоговой петлей ОС. Тогда можно смело снизить количество сэмплов, чтобы повысить точность. Но для этого понадобится:
— Отдельный ШИМ-контроллер
— Аналоговая обвязка CC и CV.
— ФНЧ для МК, чтобы задавать напряжение и ток.
То есть, ничего выкинуть не удастся, ОУ превратится в аналоговую обвязку, плюс добавится ШИМ-контроллер и ФНЧ (еще, как минимум, на одном ОУ). И вот тогда, да, точность станет выше. Но это не точно.
К сожалению (или к счастью?), все ваши великолепные рассуждения (непонятно, кстати, откуда взятые, ведь 1 LSB INA по напряжению = 1.5 мВ) с треском разбиваются о резисторы 1%.
Я вот к такому присматриваюсь
https://aliexpress.ru/item/1005006366553545.html
https://aliexpress.ru/item/1005005877610085.html
С зарядкой могло то же самое быть. Статус работы покажет светодиодом или 7-сегментным индикатором, а детально можно через телефон посмотреть, это не часто нужно обычно. Ну можно и через экран конечно, свои плюсы во всём.
Вот, например, у меня 3D-принтер Bambulab A1 mini. И уже несколько раз были очень полезны извещения на телефон, что запутался филамент на катушке. Да, я не спорю, раньше вроде и на Anet A8 печатал, а у него даже нет распознавания такой ошибки, что с филаментом что-то не так. Фигачил бы до упора, хорошо если не сломает сам себя. Но раз уж зашла речь о дополнительных удобствах, то почему нет.
Но чтобы делать качественные проекты на какой-то платформе, нужно эту платформу хорошо знать, чтобы не городить костылей, а решать задачи эффективно. Изучить ЕСП — это большая работа, много времени. А его нет, ведь мы ведем речь о хобби, которым удается заниматься тогда, когда нет основных задач.
Ну и характеристики/цена тоже имеют значение. Базовые модели ЕСП дешевы, ту же ноду на плате можно взять меньше двух долларов. И это просто первая ссылка из поиска.
И всё это весьма дешево, те же платки ESP32-C3 (что-то типа Arduino Micro Pro) стоят на Taobao $1.1 (за плату, не голый чип). А это 32-битный проц 160 Мгц, памяти не 1-2 КБ, а 400 КБ, ROM 384 КБ, ещё и дополнительная флеш-память на 4МБ. И ко всему этому WiFi/BT, множество режимов сна с энергосбережения.
www.youtube.com/watch?v=SSiRkpgwVKY
Я себе давно хочу сделать такие, но никак руки не доходят — сначала по эстетическим причинам, т.к. не было подходящего корпуса. Теперь корпус можно напечатать, но я в свое время закупил белые светодиодные матрицы, а теперь понимаю, что для ночи они совершенно не подходят, слишком ярко светят.
Увлечение самодельными часами связано только с тем, что больше заняться нечем. Кризис радиолюбительских проектов.
Так лучше ситуация не станет, поэтому любой проект хорош.
А если нужна производительность, можно перепрыгнуть 32-битные МК и взять сразу Raspberry Pi с гигабайтами памяти и HDMI выходом и программировать на Питоне каком-нибудь.
Или вообще ход конем и использовать FPGA простенькие, появились от 2 тыс. рублей мощные платы на которых можно эмулировать виртуальный комп и Линукс запускать.
https://aliexpress.ru/item/1005003182761076.html
(Sipeed Lychee Tang Nano 4K FPGA макетная плата)
Да и что там делать? Лампочкой помигать проще чем на микроконтроллере.
Вот проекты уровня Ардуино для новичков на FPGA, начиная от мигающей елки до HDMI / Ethernet сигналов.
marsohod.org/?ysclid=m8gg13tzj8483942274
Но тема специфическая весьма да, очень редко кому требуется ))
https://aliexpress.ru/item/1005005855211993.html
И вторая:
https://aliexpress.ru/item/1005005933529451.html
Правда, сейчас почему-то на обеих пишется, что «не доставляется» ко мне. Но, может быть, к вам будет доставка.
В целом хочу запилить свое управление скоростью вентиля ноута так как оригинальное мне не нравится и настроек никаких нет ни в биосе ни через софт. с интерфейсом через блютуз. Зависимость будет не от температуры как принято, так как у меня нет к ней хардварного доступа (свой датчик не вариант, нужно ведь из проца брать температуру чтобы быстро реагировать), а от оригинильного ШИМ сигнала.
В случае использования синхронного выпрямителя в БП надо предусмотреть чтобы не было «обратного» тока от АКБ к БП (диод Шоттки или для больших токов — мосфет+ОУ).
Кстати, подобным образом работает китайское ЗУ на 50А для 12v LiFePO4 сборок. ЗУ на основе серверного БП.
Я писал уже выше, что если использовать ИНА, то только с внешним ШИМ-контроллером. Это потребует дополнительно сам ШИМ-контроллер и ОУ для ФНЧ, чтобы МК формировал опорное напряжение для аналогового ШИМ. То есть, схема становится сложнее на два компонента, поэтому совершенно непонятно, о каком упрощении вы говорите.
Синхронный выпрямитель всегда работает в обратном включении транзистора, там не будет никакого обратного тока.
Зачем вам вообще какой-то дополнительный ШИМ контроллер в этой схеме???
Вы ЦАПу указываете какое напряжение на нем будет. Соответственно и ток заряда АКБ.
А с какой частотой — это уже Ваше дело. На следующей итерации — корректируете. Если хотите — можете это делать по прерыванию таймера с ЛЮБОЙ, удобной для вас частотой.
в этом случае используется ШИМ контроллер самого БП. У него же на вход управления заведена часть выходного напряжения БП. Вы просто это напряжение немного корректируете в нужных вам пределах чтобы получить нужный вам ток заряда АКБ.
Во-первых, БП используется для питания самого устройства, я не могу отдать команду на его выключение. А мне такое нужно, например, чтобы измерить напряжение на АКБ. Во-вторых, с чего вы взяли, что готовый купленный БП на 24 В позволит регулировать выходное напряжение в таких пределах? Вообще-то БП тоже свои ШИМ-контроллеры питают от своего же трансформатора, что и не позволяет менять напряжение на выходе в широких пределах.
На самом деле, такое решение реализуемо и, например, сделано в оригинальных зарядках от Макиты. Но у них там а) специальный БП, позволяющий регулировать выходное напряжение в нужных пределах, б) дополнительный маломощный БП для вспомогательного питания. Реализовывать такое решение намного более сложно, это имеет смысл только для промышленного применения.
К сожалению, ваши слова прямо указывают на критическое отсутствие у вас знаний в предметной области — на практике, судя по всему, с таким вы не сталкивались. А если бы столкнулись, то поняли бы, насколько предлагаемые вами варианты сложнее. При этом, с точки зрения пользователя, зарядка, выполненная по вашей архитектуре мало чем будет отличаться от моей.
Вот, наконец-то смотрите на задачу под правильным углом. 0.5% отклонения по напряжению, вполне допустимые при зарядке литиевых аккумуляторов — это целых 0.1 В при напряжении 21 В! Абсолютно незачем двух или даже трехкратно усложнять схему ради того, чтобы получить на выходе 0.1% вместо 0.5%.
Более внимательно посмотрел на схему. Вы правы. Не должен течь. Это сильно упрощает мое ЗУ. Спасибо.
Сильно зависит от схемы. Для 4S Li-Ion надо дельту всего в 5 вольт (12-17в). С учетом «отскока» можно даже 13-17.
Если ограничивать диапазон выходных напряжений — тогда может и получится, надо непосредственно проверять имеющийся БП. Причем, очень желательно проверять с разной нагрузкой, т.к. это может влиять на питание ШИМ-контроллера БП. И лучше непосредственно это питание измерить и посмотреть, как оно соотносится с тем, что в даташите, чтобы вдруг не попасть впросак. Еще деталь — желательно предусмотреть аналоговую обратную связь для защиты от перенапряжения. То есть, отдельный оптрон, который подключается к выходному напряжению через стабилитрон и резистор. Пока всё в норме, он не работает, но если напряжение на выходе по какой-то причине сильно возрастает, он срабатывает и блокирует ШИМ. Так делают во многих мощных БП.
Мне же такой вариант не подходит по причине, что на выходе нужен весь диапазон питающих напряжений, т.к. устройство может работать как ЛБП. Видите, задачи весьма разные, поэтому и оптимальные решения тоже отличаются.
Впрочем, такая точность измерений может быть нужна если вы в вашем алгоритме заряда хотите регистрировать небольшие снижения напряжения на элементе в конце заряда (Ni-Cd) или что-либо малозаметное еще.
Небольшое замечание: усреднение по 4-м точкам не даст вам 2 дополнительных бита. Там квадратичная зависимость и потребуется 16 выборок.
Небольшое замечание: усреднение по 4-м точкам не даст вам 2 дополнительных бита. Там квадратичная зависимость и потребуется 16 выборок.
Посоветую доку от ST an5537: how to use adc oversampling techniques to improve signal to noise ratio.
А поскольку ПИД работает с 12-битными данными, то на выходе у меня получается напряжение с разрешением 12 бит, только какая-то часть из них занята шумом. Наверное, можно сказать, что SNR соответствует 10-битному разрешению или 20 мВ, что, в принципе, неплохо для блока питания такой категории.
А вот при отображении применяется еще дополнительное усреднение 256 12-битных семплов или 1024 10-битных. То есть, если опираться на эту статью, я должен получать плюс 5 ENOB, или, если предположить что АЦП меги имеет ENOB 8-9 бит, всего 13-14 бит. То есть, очевидно, для вывода двух цифр после запятой должно хватать.
Грандиозно и неповторимо!!!
А не посещала мысль замахнуться на побаночную балансировку на борту??
Он отказывается только по причине отсутствия третьего контакта. Выбирайте батареи с тремя контактами и таких проблем не будет.
Это недвусмысленно намекает на то, что БМС батареи не тянет пусковой ток инструмента.
Если бы было так, инструмент бы проверял наличие чипа еще до старта и не запускался.
Например, в этой китай-плате для сборки на ячейках 21700 можно задействовать пины 3, 5, 6, 7?? Разумеется без возможности заряжать штатным з/у?
Плюс, оригинальная зарядка еще используется пин 3 или 5 (не помню), от него провод идет к её МК. Если у батареи там будет вывод какой-то ячейки, вставка такой батареи в оригинальную зарядку выведет последнюю из строя.
Эти варианты я уже тоже рассматривал — мое предположение, что Макита специально не стали выводить ячейки на желтый разъем, т.к. их будет легко замкнуть какой-нибудь случайно попавшей туда стружкой. Поэтому балансировка зарядкой, к сожалению, возможна только колхозными методами.
Отсюда простой вывод — если вам нужна балансировка, проще поставить в батарею отдельную плату. С большим дисбалансом она не справится, но если он появился, это повод ремонта батареи.
Вот если такой аккумулятор попадет в мощную зарядку, он опасно разогреется и надежда что клапан разорвет цепь.
А если уж говорить про возможность замкнуть, то гораздо проще металлической пыли попасть внутрь батареи через прорези контактов и замкнуть что-нить на плате защиты. В устройствах, которые могут пострадать от такого замыкания, типа сварочных аппаратов, обычно всю плату заливают эпоксидкой или компаундом. Но у плат защиты в батареях такого не видел.
Относительно маловероятно. Но вероятность далеко не нулевая. И если вдруг попадет, в лучшем случае этот разъем расплавится.
Видел полностью залитые платы у оригинальной Макиты. Но одно дело, это стружке через отверстия контактов попасть внутрь и замкнуть что-то на плате, и другое — это замкнуть непосредственно контакты в разъеме.
Но если это важно, то легко напечатать затычку для разъёма. А чтобы не терялась и не забывали её вставлять, закрепить её тонким шнурком. Так что, если заглушка не будет вставлена, не получится подключить инструмент.
Есть и другое решение. Можно выбрать другой тип разъёма, поменять папу на маму. Правда мне такие на али не попались. Так как ещё важно механическое крепление разъёма к корпусу, а не со всеми типами разъёмов это просто сделать. Но если поменять тип разъёма, тогда стружка ничего не замкнёт.
Остаётся только по-хорошему позавидовать наличию такого количества свободного времени. У меня даже на чтение всех комментов терпения не хватило. А уж чтобы взять слабенький АВР и так… повозиться, реализуя задуманное, чтобы прибегать к ассемблеру? Вроде времена не те… И не принуждает же никто, и об экономии речи не идёт. Ан нет, не перевелись ещё настоящие
динозаврымастера старой школы.Себя частично узнаю…
Кстати, а где блок питания покупали?
БП брал традиционно на али.
Я тоже долго с ассемблера не слезал. Нравилось исхитряться… Но сейчас уже возвращаться не тянет даже эпизодически. Время дороже. Но я не профессионал. Может, поэтому.
Успехов!
А на али появилась новая версия этого БП, правда пока дороговато:ссылка
Да, уж, весьма дороговато. Да и вызывает вопросы — что это за слабый выходной дроссель? И как они собрались 16 А через такой маленький коннектор пропускать.
Но для себя выбрал переделку зарядки HIPER HLT-119 (в базе 125 Вт, нормальная схемотехника) — сделал переключатель 2/4 А.
Чтобы появилось 21в на выходе зарядки:
Средние контакты это id и термодатчик, на оба нужно вешать резисторы на минус.
Для id это 36к, 47к или 56к, соответствует емкости 2, 4 и 5 а/ч,
сопротивление термодатчика 10кОм.
И напряжение на выходе зарядки появляется только после подключения аккумулятора!!!