Электроника для всех http://easyelectronics.ru Блог о электронике Wed, 16 Mar 2022 16:20:57 +0000 ru-RU hourly 1 Saturn PCB Toolkit http://easyelectronics.ru/saturn-pcb-toolkit.html http://easyelectronics.ru/saturn-pcb-toolkit.html#comments Wed, 16 Mar 2022 16:20:57 +0000 http://easyelectronics.ru/?p=1929 Проектируя главную деталь электронного устройства — печатную плату периодически приходится делать разные расчеты. Обычно у меня это толщины переходных отверстий и дорожек, чтобы прошли по току. Иногда надо рассчитать импенсданс дифференциальной линии или, банально, прикинуть делитель напряжения. Для таких задач под рукой болтается Saturn PCB Toolkit. У меня версия 7.05, старенькая, еще 18 года, но более новую я не нашел. А с официального сайта почему-то нельзя уже скачать. Поэтому выкладываю дитрибутив у себя.

Бегло опишу что умеет.

Conductor Spacing — расчет минимальных зазоров исходя из напряжения, типа платы (есть ли маска, есть ли лак поверх деталей и тд.) и атмосферных условий.

Conductor Impendance — расчет импенданса проводников. Исходя из частоты, ширины, высоты над земляным полигоном, а также расположения в толще платы.

Conversion Data — перевод величин из в мм в дюймы и mils. Усиление из децибелл в величины напряжений, а также координаты из декартовых в полярные и обратно.

Planar Inductors — расчет индуктивностей из дорожек на плате. Причем, что удобно, позволяет делать это не только для кольцевых, но и для прямоугольных или шестиугольных фигур. Просто указываем ширину дороги, расстояние между дорожками и «мотаем» витки по плате, пока не получим нужную индуктивность.

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

Thermal — расчет температуры радиатора. Указывается сколько тепла выдает деталь и сколько может рассеять радиатор, а также окружающая температура. Калькулятор покажет до какой температуры все нагреется. Самое сложное тут узнать рассеяние радиатора. Но, если вы его купили, а не отрезали болгаркой от ближайшего куска алюминия, то найти эти данные наверное можно, на радиаторы тоже есть даташиты. :)

Fusing Current — расчет «бомж» предохранителя из дорожки. Указываем толщину дорожки, а также сколько секунд должна продержаться наша заShit’a и сатурн покажет на какой ток можем рассчитывать.

Mechanical Informations — просто параметры проводов и отверстий. Перевод из AWG в мм и предельные токи для этих проводов.

Padstack Calculator — вот это я не понял что и зачем считать. Показывает размеры контактных площадок и расстояния между ними. А смысл? То же самое сделает и софт для трассировки печатных плат. Тем более отсюда никак никуда не экспортировать.

Differential Pairs — рассчет диффпар. Можно выбирать разное расположение проводников (рядом или друг над другом) и расположение их относительно земляных полигонов.

Bandwidth & MAX Conductor length — расчет максимальной длины проводника, исходя из скорости нарастания сигнала или частоты.

Conductor Properties — свойства проводников. Расчет рассеяния мощности, исходя из плотности проводников, толщины, расстояния между ними, толщины платы, наличия медного полигона на обратной стороне платы.

Via Properties — расчет переходных отверстий. Какой они могут протащить ток через себя, тоже исходя из толщины меди, платы, диаметра, толщины лужения и тому подобных параметров.

Embedded Resistors — расчет встроенных резисторов. Суть в том, что резистор тут выполняется специальным напылением, прям во время изготовления печатной платы. Вживую я такое не видел, но судя по нагугленному, это широко используется в аэрокосмической технике.

PPM Calculator — калькулятор миллионых долей. В PPM часто выражется погрешность каких-либо элемнетов. Например, уход частоты кварца, или сопротивления резистора. В данном случае это про колебания частоты.

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

Wavelength Calculator — расчет длины волны.

Er Effective — расчет задержки исходя из диэлектрической проницательности платы и геометрии расположения дорожки. Суть в чем, любая дорожка образует конденсатор с земляным полигоном снизу. Его емкость зависит от ширины дорожки и толщины диэлектрика под ним (ну и самого диэлектрика тоже). Емкость там, конечно же, мизерная. Но на больших частотах она начинает давать о себе знать. Заваливаются фронты и так вплоть до полной неработоспособности устройства. У воздуха ER eff = 1, в нем сигнал распространяется максимально быстро. А у обычного текстолита FR4 около 4.6. Чем выше этот параметр тем больше задержка. Все это вылезает в полный рост при проектировании ВЧ и СВЧ техники. Ну там много разной черной магии :)

Ohm’s law — Закон Ома. Большая круговая шпора по всем основным зависимостям. А также расчет делителей, на 2-4 резистора и резистора для светодиода.

Reactance — расчет реактивного сопротивления катушек и конденсаторов. Для тех кто прогулял курс ТОЭ :)

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

Скачать Saturn PCB Calculator

]]>
http://easyelectronics.ru/saturn-pcb-toolkit.html/feed 4
Интерфейс RS-485 http://easyelectronics.ru/interfejs-rs-485.html http://easyelectronics.ru/interfejs-rs-485.html#comments Mon, 31 Jan 2022 18:57:20 +0000 http://easyelectronics.ru/?p=1920 Интерфейс RS-485

Последнее время я делаю по большей части промышленные устройства и все чаще там используется именно RS-485. Потому как он используется как физический для множества протоколов, принятых в проме, таких, например, как MODBUS или ProfiBUS.

▌Принцип работы
Интерфейс RS485 хорош тем, что он, по сути дела, является дифференциальным вариантом RS-232 и его можно вешать на банальный USART любого микроконтроллера.

Физически он состоит из двух линий связи. А и B. Наличие земли желательно, но вовсе не обязательно. Отсутствие земли чаще всего чревато тем, что входящие данные будут иногда начинаться с нуля. Т.е. шлешь строку 0xBA 0xDF 0xF0 0x0D, а приходит 0х00 0xBA 0xDF 0xF0 0x0D, а дальше все нормально.

Исходный входной сигнал разделяется на два сигнала и они улетают вдаль по двум свитым проводам, витой паре.

По линии А идет прямой UART, как он есть, а по линии В его зеркальная копия. А в приемнике, на дифференциальном операционном усилителе, одно вычитается из другого и получается исходный сигнал.



Зачем это сделано? Зачем вообще такие сложности? Линия может длиться километры, да, для RS485 длина сегмента допускается до 1200 метров. На таком расстоянии сигнал, если его послать по одному проводу и земле, упадет на сопротивлении линии и до приемника дойдут считанные доли вольта. Тут же, у нас компаратор на входе усилит разность сигнала даже крошечной величины, восстановив исходный сигнал. Нет нужды четко соглассовывать уровень земли приемника и передатчика, на большом расстоянии это может быть тяжело решаемой задачей.

Это первое, но куда более важным является то, что таким образом намного увеличивается помехозащищенность самой линии. Ведь если рядом будет какая-то электромагнитная помеха, которая наведет на наш длиннющий провод колебание напряжения, то, так как оба провода идут рядом, во втором проводе наведется ТОЧНО такая же помеха. А поскольку у нас на входе сигнал разностный А-B, из помехи в проводе А будет вычтена такая же помеха в проводе В и она обнулится.

По такому же принципу, дифференциальной линии, делают очень многие критичные к помехам цепи. USB, Ethernet, LVDS да много где… где то линия одна, как в USB, где то их несколько, как в Ethernet или LVDS. Но суть остается той же.

Естественно по данной линии связи передача может идти только в одну сторону. Т.е. RS485 у нас полудуплексный. Мы вначале в него орем, а потом слушаем что нам ответили с другой стороны. Общаться в обе стороны, как в UART по Rx и Tx не выйдет. Ну или придется пускать уже четыре провода, одна для передачи, другая для приема.

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

На одной линии может висеть несколько приемников и передатчиков. Они подключаются просто параллельно.

Разумеется общаться они могут строго по одному и общий галдеж в линии приведет к полной неработоспособности всей сети. Никакого аппаратного арбитража на основе «приоритета нуля», как в I2C тут нет.

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

▌Железо
Классической микросхемой такого интерфейса служит MAX485 или ST485, или ADM485… В общем, если видите на плате восьминожку с надписью что-то там 485 — скорей всего это оно :)

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

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

Разберемся сначала с резистором-терминатором.

Сигнал идет по проводу быстро, но не мгновенно, более того, он дойдя до конца линии может отразиться и пойти обратно. Как вода в желобе, пускаешь по желобу волну, волна дошла до стенки и пошла обратно. И эта волна может столкнуться с волной следующего импульса, смешаться и получить полную кашу на выходе. Разумеется эти эффекты возникают только при длинных линиях (В ТОЭ прям есть раздел такой — длинные линии, разбирающий все эти волновые эффекты), либо на высоких частотах. Так как с ростом частоты «длинной» может стать линия даже в 5см, например, когда речь идет о гигагерцах.

Поскольку у нас RS485 может работать до скорости вплоть до 10Мбит, а дальность свыше километра, то такие эффекты могут возникнуть. Чтобы подавить отраженную волну и нужен резистор-терминатор. Он стоит у приемника между линиями А и В. Его сопротивление обычно 120ом. Это не спроста так, все дело в том, что волновое сопротивление витой пары, как правило, 120 ом и чтобы погасить волну резистор должен быть с ней согласован.

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

Теперь о подтяжках. Они, как бы, опциональные, будет работать и без них, но лучше их поставить. Хотя бы на первом и последнем устройстве линии. Чтобы линию не телепало помехами и не генерировало вам непонятные сообщения. Подтяжка защитит нас от хаотичных данных при обрыве линии, например.
Конечно у приемника есть гистерезис, примерно на 200мв, т.е. разность между А и В меньше 200мВ не учитывается как сигнал, и на выходе будет 1, но все равно лучше подстраховаться.

Линию А подтягиваем вверх, а линию В вниз. Через резисторы в 1.2кОм с обеих концов.

Единственно, что у такого решения есть минус — через эти резисторы будет всегда течь ток и увеличивать потребление. Что может быть критичным для систем с батарейным питанием, но использующем RS485. Странная экзотика, но чего в жизни не бывает?

В этом случае можно использовать микросхемы с системой true failsafe, например MAX3080. Она позволяет отказаться от резисторов смещения, т.к. они мало того, что встроены в микросхему, так еще и пороги срабатывания там другие. И при обрыве или КЗ линии будут гарантировано давать 1 на выходе.

▌Защита
Так как линия у нас длинная, то на нее наводится всякая фигня. И естественно она прилетает нам в схему, учиняя беспредел. Первое с чем стоить бороться — перенапряжения. Для защиты от этого применяют супрессоры. Это такие мощные стабилитроны, часто собранные в одном корпусе встречно друг другу. И при превышении напряжения они открываются и стравливают перенапряжение в землю или питание, смотря как включено. А там с этой энергией разберутся конденсаторы и блок питания.

Разумеется поможет это только от кратких перенапряжений, от помех. От длительных перенапряжений нужны уже предохранители. Плавкие или самовосстанавливающиеся. Т.е. если что-то начало нам гнать в линию высокое напряжение, то вначале сработает супрессор, высадив его на землю, а потом выжгется предохранитель. Я использую SMBJ-5.0 супрессоры.

Также я ставлю варистор между А и В. Можно и двунаправленный супрессор поставить, но варистор компактней. Это резистор который пробивается на высоком напряжении. Резко уменьшая свое сопротивление с мегаомов до десяток ом. А потом вновь становится обрывом. У меня под это дело чтото вроде JMV0805S5R6T661 который открывается от 5.6 вольт и способен пережить 40А в пике.

Последнее время я не экономлю и делаю полноценную развязку интерфейсной части. Ставя туда питание на AM1D-0505SZ и изолируя интерфейс через ADM2483. Это RS485 трансивер со встроенной опторазвязкой.

Работает просто песня :)

▌Кабель, земля и экран
Вообще, на короткие расстояния, десятки метров, и при небольшой скорости, по 485 интерфейсу можно гнать сигнал через любое говно. Даже через старую, советскую плоскую телефонную лапшу. На практике же, для физического уровня приходится использовать все что под руку попадается и уже проложено на объекте. Например, кабель видеонаблюдения, с волновым сопротивлением в 75 Ом, но ему требуются низкоомные же терминаторы в 75 Ом, что снижает количество девайсов на одном сегменте — трансивер просто не вытащит по току. Второй популярный пример — комповая витуха, у ней волновое сопротивление 100Ом, что уже лучше. И сами кабели дешевые, но у них тонкая жила и по этому высокое сопротивление. Есть и специализированный кабель для RS485 с волновым сопротивлением в 120Ом, как по стандарту. Правда он дорогой, не всегда доступен и зачастую не нужен :)

Для улучшения качества передачи данных хорошо бы использовать экранированный провод. При этом оплетка кабеля подключается к заземлению, а к GND через резистор ом в сто (в случае опторазвязки — к изолированной GND) с одной стороны (!!!!) только с одной стороны! Чтобы не было протекания разных токов по ней.

Если же у нас есть земляной провод, то можно задействовать и его. В данном случае его называют дренажным. Его задача уравнивать потенциалы земель. И он подключается к земле устройства (при опторазвязке к изолированной земле) через сопротивление в сотню ом. Резистор тут надо выбирать хотя бы на пол ватта.

▌Борьба с граблями
Ну и напоследок еще парочка мелких граблей на которые можно наступить, так что лучше их сразу убрать. В момент передачи, микросхема MAX485 держит выход DO в HiZ, и вам туда может нателепать разного мусора. Поэтому линию RxD микроконтроллера подтягиваем к питанию. Либо включаем подтяжку внутри контроллера. Но я всегда это делаю внешним резистором. Надежней.

А линию DE/RE следует подтягивать к нулю. Зачем? А чтобы пока контроллер не стартанул, не проинициализировался и не привел свои ноги в нужный режим этот вывод не телепался без дела и не слал в линию разный мусор.

При перед передачей никогда не помешает сделать синхронизацию кадров. Т.е. передачи нет, все участники сети сидят и слушают. И вдруг какая-то помеха пробилась и сделал старт бит в линию. Естественно все «слушатели» начнут принимать данные и получат мусор. Да хоть тот самый ноль, о котором я выше говорил. Чтобы им и ограничилось крайне желательно сделать следующее. Переводим линию прием/передача в режим передачи, при этом у нас на TxD единичка, т.к. мы еще ничего не шлем. Но драйвер RS485 при этом выдаст уже уровни в линию. Ждем паузу, равную времени передачи двух трех байтов, чтобы весь мусор прошел и не затесался в нашу передачу и только после этого засылаем первый байт нашей передачи в UART. Это повышает надежность и качество передачи на порядок.

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

]]>
http://easyelectronics.ru/interfejs-rs-485.html/feed 16
Контроллер дверей http://easyelectronics.ru/kontroller-dverej.html http://easyelectronics.ru/kontroller-dverej.html#comments Mon, 27 Dec 2021 15:36:18 +0000 http://easyelectronics.ru/?p=1914 Для решения одной локальной проблемы с дверями, таблом и освещением автомойки запилил подобие небольшого ПЛК, или, скорее, умного реле. Проект выходного дня, так сказать. Ничего особо выдающегося собой не представляет, но все равно выложу, мало ли кому понадобится что-то похожее, а тут все уже готовое. Заказывай в китае платы, да делай. А там только свой код написать, но это же не сложно, да? ;) Тем более я покажу как все работает.

Сама задача была простой, по сигналу контроллера от робомойки надо было переключить табло с «Занято» на «Свободно», включить свет в рабочей зоне, и, главное, разделить двери. У оригинальной мойки дверь одна. В какую заехал из той и выехал. А тут нужна была проходная система с двумя дверями. Поэтому входной импульс надо было первый подать на одни двери, второй на другие. Импульс открывает привод дверей, закрываются они сами, по своим концевикам, когда машина выедет.

Пляшем от корпуса. Нам нужен корпус на DIN рейку. Я взял Gainta D2MG

Чтобы сразу попасть во все размеры, была нагуглена и скачана 3D модель этого корпуса в step формате. Импортировал все в Fusion360 и снял размеры платы. Решено было делать два этажа, соединенных проводом. Внизу будут располагаться релюшки и модуль питания, а вверху мозги.

Силовая часть получилась такой:

Схема крупнее

Все довольно тривиально. Релюшки, да транзисторы. Транзисторы взял BCR112E — они идут уже со встроенными подтягивающими и токоограничивающими резисторами. Меньше деталей на плате будет. Использую их повсеместно, так что у меня их большие запасы.

Вход сделал через опторазвязку. Работает на замыкание. Зажигая светодиод оптопары.

Питается все от AC-DC модуля Tenstar Robot он же Hi-Link. Неплохой блочек, купил на алиэкспрессе пару десятков и с тех пор иногда использую в разных штучны проектах. Нареканий не было. Свои 500мА он честно выдает. Бывает на 3.3, 5 и 12 вольт.

Также есть возможность сделать питание от DC установив туда mini360 DC-DC которых у меня тоже валяется дохрена. При желании его можно отвязать через изолирующий DC-DC от Aimtec, про который я писал несколько месяцев назад. Правда на эти Mini360 есть нарекания. Я не сталкивался с их плохой работой, но коллеги жаловались, что дохнут, не держат влажность, пробиваются. Так что я бы с осторожностью к ним относился.

Релюшки взял пятивольтовые. Одна помощней, В2n на 3А — будет коммутировать свет. А остальные три послабже, будут дергать линии табла и дверей G5V1 5DC.

Получилась вот такая вот платка.

Второй этаж, мозговой, еще проще. Там стоит ATTiny2313 в DIP корпусе :) Пара кнопок, да разъем программирования, индикация с диодиками. Ну и джампер выбора режима. Из защитных элементов только супрессор и немного керамики пикофарадной на линиях, чтобы иголки жрать.

Тиньку, да еще и в DIP, взял потому, что у меня их осталось с одного заказа 10 летней давности полтора десятка. Куда еще их девать? Вот и пихнул в эти изделия. Чтобы не валялись.


Схема крупнее

Развел платку.

Выгрузил из KiCAD в step и пихнул обратно в Fusion360, чтобы посмотреть как оно встанет в корпус. Нет ли каких пересечений.

А после отправил в печать платы в JLCPCB.

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

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

▌Код
Код устройства простой, но памяти у меня всего 2кб, ОЗУ и того меньше. Писать на ассемблере мне было ну совершенно вломы, стар я стал и ленив. Мой псевдо RTOS диспетчер, что на си, жирноват будет. Поэтому я ничего не стал изобретать, а сунул туда систему на конечных автоматах. А также систему событий на двух проходах, взятую у А. А. Шалыто из его статей о конечных автоматах (нагугливаются легко).

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

int main(void)
{
	InitIO();         // Настраиваем порты ввода вывода. 
	InitMessages();   // Настраиваем систему сообщений 
	InitTime();       // Настраиваем таймер


// И начинаем запускать все задачи по кругу. В каждой фукнции все делается предельно быстро. Зашел, проверил, вышел. 
	while(1)
	{
	MessagesProcess();
	BlinkerProcess();
	InputProcess();
	logicProcess();
	}

return 0;
}

Функция MessageProcess обеспечивает взаимодействие между функциями. Суть в том, что сигнал на смену состояния автомата передается не флагом или глобальной переменной, а через переменную события за два прохода. Первый шагом сигнал взводится, второй раз, когда пробежит через все автоматы, встает на изготовку. И на третий раз, когда дойдет до адресата — исполняется. Или сбрасывается, если в этом проходе нет того, кто ждет этот сигнал. Описывается она в отдельных файлах, которые я таскаю из проекта в проект когда использую этот подход.

message.h

#ifndef MESSAGES_h
#define MESSAGES_h

#include 

#define MAX_MESSAGES 		5

// Прототипы функций. 
void MessagesProcess(void);
void InitMessages(void);
void SendMessage(uint8_t Msg);
uint8_t GetMessage(uint8_t Msg);

// Обзываем наши события человеческими именами через enum
typedef enum
{
 InPressed = 0,
 Button1Pressed = 1,
 Button2Pressed
}tMessages;


#endif

message.c

#include "message.h"
uint8_t Messages[MAX_MESSAGES]; 	 // Массив ожидающих событий. 

void InitMessages(void)		 	// Инициализируем массив, обнуляя все события. 
{
	uint8_t i;
	for(i=0;i

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

Для программирования выдержек есть программный таймер. Он реализован на принципе глобального времени. Тикаем раз в 1мс и увеличиваем 64 разрядную переменную. 264мс это примерно пол миллиарда лет до перезагрузки. Нам хватит, надеюсь. :) А дальше, при загадывании таймера, просто прибавляем к текущему времени желаемое и смотрим дожили ли мы до него или нет. Если дожили - меняем состояние автомата.

timers.h

#ifndef TIMERS_H
#define TIMERS_H

#include 
#include 

#define MAX_TIMERS 5


void InitTime(void);
void TimerProcess(void);
uint64_t GetTime(uint32_t NewTime);
uint8_t TimeIsExpired(uint64_t Time);

#endif

timers.c

#include "timers.h"

// У нас есть переменная глобального времени. 
uint64_t GlobalTime; 

// Которую мы в прерывании таймера тикаем. 
ISR(TIMER0_COMPA_vect)
{
GlobalTime ++;
}



// Таймер настраиваем так, чтобы он тикал 1000раз в секунду. 
void InitTime(void)
{
	GlobalTime = 0;
	TCCR0A = 1< Time) return 1;
	return 0;
}

Так работает автоматная диспетчерская и ее таймер. А теперь пример реализации остального, на ее основе.

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

void BlinkerProcess(void)
{
static uint8_t state=0;
static uint64_t Time=0;

	switch(state)
	{
		case 0: 		// ON
		{
			LED1ON;		// Макрос включения светодиода. Просто запись в порт. 
			state = 1;		
			Time = GetTime(100);	// Ставим таймер на 100мс. 
			break;
		}

		case 1:			// И ждем пока таймер не сработает. 
		{
			if (TimeIsExpired(Time)) state = 2;
			break;
		}

		case 2:
		{
			LED1OFF;		// Выключаем светодиод
			state = 3;		
			Time = GetTime(1000);	// Ставим таймер на 1000мс.
			break;
		}

		case 3:				// И ждем пока таймер не сработает. 
		{
			if (TimeIsExpired(Time)) state = 0;
			break;
		}
	}
}

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


void InputProcess(void)
{
static uint8_t BounceCounterIN=0;
static uint8_t BounceCounterBT1=0;
static uint8_t BounceCounterBT2=0;

static uint8_t state=0;
static uint64_t Time=0;

	switch(state)
	{
	case 0: 		// Стадия проверки.
		{

			if (GetIN()) // Читаем данные из порта. Если замкнуто... 
			{
				BounceCounterIN++; // Увеличиваем счетчик антидребезга. 
	
				if(BounceCounterIN>5) // Если счетчик достиг 5, то значит это точно замыкание. 
				{
					BounceCounterIN = 0;	// Сбрасываем счетчик антидребезга. 
					SendMessage(InPressed);	// Шлем сообщение, в логику, что у нас есть входной сигнал.
				}
			}
			else  // Если же, вдруг, сигнал отпустился и до 5 не дотикало, значит помеха какая то. Обнуляем  счетчик антидребезга. 
			{
				BounceCounterIN = 0;
			}		


			if (GetB1())  // Аналогично обрабатываем кнопку В1
			{
				BounceCounterBT1++;
	
				if(BounceCounterBT1>5) 
				{
					BounceCounterBT1 = 0;
					SendMessage(Button1Pressed);

				}
			}
			else 
			{
				BounceCounterBT1 = 0;
			}


			if (GetB2())  // Аналогично обрабатываем кнопку В2
			{
				BounceCounterBT2++;
	
				if(BounceCounterBT2>5) 
				{
					BounceCounterBT2 = 0;
					SendMessage(Button2Pressed);
				}
			}
			else 
			{
				BounceCounterBT2 = 0;
			}


		state = 1;	 	// Переходим в стадию ожидания. 		
		Time = GetTime(10);	// Взводим таймер на 10мс, интервал между опросами.
		break;
		}

	case 1:				// Wait
		{
		if (TimeIsExpired(Time)) state = 0;	// Ждем пока не натикает 10мс. 
		break;
		}

	default: state = 0; break;

	}
}

LogicProcess
Главная логика выглядит примерно так, на примере мигалки, этой же платы. Просто набор case с состояниями и переход в следующее если было событие.
В коде логики работа с этим выглядит примерно так:


.... кусочек выдранный из logicProcess(); 

	switch(state)
	{
		case 0:	// Empty State 
		{
			RL1OFF		// Door OFF
			RL3OFF;		// Door OFF

			RL2OFF;		// Light OFF;
			RL4OFF; 	// Table OFF
			LED2OFF;	// LED 2 OFF

			
			if(GetMessage(Button1Pressed))		// Если нажата кнопка
				{
					Time = GetTime(1000);	// Программируем таймер на 1000мс
					state = 4;		// И уходим ждать в стадию 4. 
					break;
				}


			if(GetMessage(InPressed))	state = 1;	// Если замкнули контакт идем на стадию 1... 
			break;
		}

.... 
....

		case 4:	// Wait 3s
		{
			if (TimeIsExpired(Time)) state = 5;		// Ждем пока таймер дотикает, а потом выходим в стадию 5. 
			break;
		}


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

Архив с проектом (код и печатные платы со схемой в KiCad)

]]> http://easyelectronics.ru/kontroller-dverej.html/feed 17 Реанимация засохшей паяльной пасты http://easyelectronics.ru/reanimaciya-zasoxshej-payalnoj-pasty.html http://easyelectronics.ru/reanimaciya-zasoxshej-payalnoj-pasty.html#comments Thu, 09 Dec 2021 15:41:47 +0000 http://easyelectronics.ru/?p=1909 Обычно smd монтаж я делаю просто паяльником, ручками. Даже если устройств надо с десяток. При том, что в JLCPCB или PCBWAY трафарет для пасты делается одной галочкой и стоит баксов 7. И да, я их тоже часто заказываю, но паяю все равно ручками… Дело в том, что устройства требуются внезапно. И редко, но метко. А у паяльной пасты есть одно мерзкое свойство — эта падла моментально сохнет. Вскрыл баночку, израсходовал ну процентов 30.. Через пол года открыл, а она уже засохла. Хоть как храни, хоть в холодильнике. Как ни закрывай, а засыхает. Мелкие же банки, чтобы использовать на один раз, стоят неадекватно. Меня жаба давит.

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

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

Не буду перечислять все способы ее развести, но успешным признан следующий метод:

Берем небольшое количество пасты, примерно 30мл (баночка от соевого соуса, что шел к роллам) и пару пшиков туда из пульверизатора спирта этилового. Просто у меня спирт в пшикалке, сколько там в одном пшике? 0.2мл? Примерно так. И размешиваем, прям от души. Потом еще пару пшиков, опять размешиваем. Закрываем, убираем на сутки. Это надо, чтобы спирт дифундировал в остальной объем. А не был там локальными каплями жидкой фракции. На следующий день повторяем. И так до нужной консистенции. Еще я туда бахнул 0,1 кубика FluxPlus от Nordson. Он еще добавил тягучести и как бы сделал всю эту хрень более «сухой». Размешал тщательно. Выдержал еще сутки.

Попробовал — наносится отлично. Не подтекает под трафарет, не задирается вслед за шпателем, ровный слой, почти как свежая. Запёк в печке с термопрофилем в 160 градусов активации и 250 градусов на 20 секунд оплавление. Не идеально, конечно, грязь от флюса остается, отмывать нужно. Но в целом, вполне приемлемый результат. Для такого помойного расходника.

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

]]>
http://easyelectronics.ru/reanimaciya-zasoxshej-payalnoj-pasty.html/feed 13
Контроллеры от GigaDevice GD32F103xxxx. Попытка миграции с STM32F103xxxx http://easyelectronics.ru/kontrollery-ot-gigadevice-gd32f103xxxx-popytka-migracii-s-stm32f103xxxx.html http://easyelectronics.ru/kontrollery-ot-gigadevice-gd32f103xxxx-popytka-migracii-s-stm32f103xxxx.html#comments Tue, 30 Nov 2021 11:46:46 +0000 http://easyelectronics.ru/?p=1905 ACR |= FLASH_ACR_PRFTBE; /* Flash 2 wait state */ FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); #if SYSCLK_FREQACR |= (uint32_t)FLASH_ACR_LATENCY_0; // Если SystemCoreClock =24000000U && SYSCLK_FREQACR |= (uint32_t)FLASH_ACR_LATENCY_1; // Если 24< SystemCoreClock =48000000U FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; // Если больше 48, то через два такта. #endif То есть выборка команд будет через два такта. Что же у ГД по этому адресу прячется? Лезем в мануал: Все то же самое, те же биты отвечающие за задержку чтения из флеша, но с пометочкой, которую я не сразу заметил. О том, что вся эта радость работает только если поставить бит WSEN в FMC_WSEN, а иначе оно не используется. В STM32 никакого такого регистра естественно нет и задержка работает если выставлена. Зачем китайцы встрелили себе в ногу, поломав совместимость в такой простой фигне непонятно. Что им мешало сделать так, чтобы все работало идентично? Ничего не мешало. Но тем не менее. Можно, конечно, тут добавить запись бита в байт по этому адресу, убедившись только, что на STM32 выстрел уйдет в молоко, попав в очередную Reserved секцию. Окей, добавляем. Поскольку этого адреса у STM32 нет, то я его добавлю вручную, просто через указатель: uint32_t *FMC_WSEN; FMC_WSEN = (uint32_t*)0x400220FC; Бит WSEN там нулевой, поэтому достаточно по этому указателю записать единичку. Правда запись туда запрещена, нужно сначала разблокировать флеш. Записав два раза в регистр FLASH_KEYR ключевое слово 1 и слово 2. Эти слова есть в хидерах на STM32 и на GD. Они одинаковые для обоих камней. Кому интересно FLASH_KEY1 = 0x45670123, а FLASH_KEY2 = 0xCDEF89AB. FLASH->KEYR = FLASH_KEY1; FLASH->KEYR = FLASH_KEY2; Разблокировали запись во флеш, записываем бит WSEN: *FMC_WSEN = (uint32_t)1; После чего выставляем задержку памяти: #ifndef SYSCLK_FREQ #define SYSCLK_FREQ 72000000U #warning SYSCLK_FREQ set up to MAX automatically!!! Check this shit! #endif /* Enable Prefetch Buffer */ FLASH->ACR |= FLASH_ACR_PRFTBE; /* Flash 2 wait state */ FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); #if SYSCLK_FREQACR |= (uint32_t)FLASH_ACR_LATENCY_0; // Если SystemCoreClock =24000000U && SYSCLK_FREQACR |= (uint32_t)FLASH_ACR_LATENCY_1; // Если 24< SystemCoreClock =48000000U FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; // Если больше 48, то через два такта. #endif LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); И включаем снова блокировку флеша, на всякий случай. FLASH->CR |= FLASH_CR_LOCK; По идее, можно включить блокировку флеша сразу же после *FMC_WSEN = (uint32_t)1; А для настроек во FLASH_ACR разблокировка не нужна. Но это не работает, должно пройти какое то время, видимо, чтобы бит успел записаться во флеш и только потом включать снова блокировку. Правда тут тоже не вышло счастья :)))) Оказалось, что с задержкой в два такта GD32 медленней чем STM32 c задержкой в эти же два такта. Тестовый импульс у GD32 на полной скорости у нас был 23мкс, на двух тактах задержки памяти стал 54мкс, а на одном такте задержки 37мкс. В то время как STM32 на двух тактах давал 37мкс. То есть в любом случае нам придется как то узнавать где мы находимся и исходя из этого подгонять тайминги. Ковыряясь в даташите на GD32 я увидел, что следующим после FMC_WSEN идет регистр FMC_PID и в нем сидит какое-то число, уникальный номер кристалла (или его памяти). Но у STM32 этот же адрес возвращает какую-то фигню. Которая еще и меняется. Хотя эти адреса никак не документированы. Так что вариант так себе. Посоветовался с коллегами, покурил даташиты и документацию на ARM ядро и нашел, что по адресу 0xE00FFFD0 и далее прячутся Peripheral ID регистры. Которые содержат циферки присущие только конкретному семейству и производителю. В частности там зашито номер ревизии чипа, JEP 106 код и еще всякая лабуда. Но, главное, что у STM32 и GD32 эти байты различаются, не меняются, всегда одни и те же от чипа к чипу, в отличии от индивидуального 96 битного ID чипа, который уникальный для каждого экземпляра. Поэтому поглядел под отладчиком что там, да написал простенькую процедурку для опознания где мы: bool UseGD32(void) { uint8_t *TestByte; TestByte = (uint8_t*)0xE00FFFD0; if (*TestByte == 7) return 1; return 0; } Проверил в железе — работает. Вот и славно. Пляшем дальше! :) А в сухом остатке, из нескольких дней ковыряния GD32, из того что проверил у нас без проблем, идентично, работает: SysTick USART’ы все Timer2 DWT GPIO Хватаю дисплейный модуль от другого проекта, но с этим же камнем. На нем есть FSMC интерфейс. Я на нем управлял дисплеем. Работает на отлично. Добавляем к списку проверенной периферии FSMC. FSMC Хватаю другой проект, на этой же плате. Но уже боевой дисплей от компрессорной установки. Заливаю… Все работает, но жууууутко мееееееедленнно. Я поначалу решил, что я тупо кварц залил флюсом и у меня HSE не поехал. Промыл, просушил. Включил… все жууууутко меееедленно осталось. Странно. К сожалению исходников этого проекта у меня нет, знаю только что он написан на SPL и возможно что-то где-то недоинициализировалось в режиме тактирования. Надыбаю исходники, перепишу и будет ясно в чем был затык. Но я уже четко вижу, что нормально работают каналы DMA. Все не проверял, но UART там сделан через DMA это я знаю точно. В общем, по мере освоения периферии буду добавлять в этот пост подробности о том, что же у нас по совместимости. UPD В комментариях набросили официальную доку по совместимости от GD. Прикладываю ее тут:]]> В связи с тем. что последнее время цена на контроллеры растет быстрей чем стоимость битков, а, например, наш основной STM32F103VGT6 стал стоить вместо 500р аж 5000+, да еще с непонятными сроками ожидания от года и более, то мы начали вынужденную миграцию на аналоги. И взгляд пал на GD32, как на наиболее вменяемого и адекватного представителя китайпрома. А главная задача стала сделать универсальную прошивку которая бы одинаково работала как на STM32 так и на GD32. Чтобы можно было не глядя лить в наши машины смерти, не обращая внимания на то на какой архитектуре там мозги.

Купили мы небольшую партию этих чипов на Алиэкспрессе :))) Уже звучит жутко, но вариантов особо не было :)

Итак, на смену STM32F103VGT6 идет GD32F103VGT6 — китайцы не заморачивались вообще с названиями. И то правда. Чего нам париться? Совместимость у него по ногам полная, так что впаиваем его как есть.

А вот дальше начинаются различия. Во первых, памяти у него может быть больше. Аж до трех мегабайт флеша, против мегабайта у STM. Что, впрочем, не более чем потенциальная возможность, в моем случае, т.к. GD32F103VGT6 по объему памяти идентичен STM овскому камню. А еще у китайца тактовая частота выше, 108Мгц против 72Мгц у STM. Подозреваю Errata там тоже исправлена. Но, не факт что это к лучшему :)

Качаю Даташит, User Manual, а также подобие SPL только свою собственную. С примерами и кучей сорцев из которых прям торчат уши STM ;) Где то они даже копирайты не вычистили.

Беглое чтение user manual дает ощущение дежавю. Ну да, почти полная бинарная совместимость с STM32 на уровне регистров их адресов. В некоторых местах, там где им не хватило конфигурационных бит, они использовали то, что у STM32 зовется как Reserved.

STM32

GD32

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

Сама же структура юзермануала списана почти один в один, как старательный троечник списывает курач, чтобы препод «не догадался». Но это даже к лучшему, проще находить если что.

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

Беру свой рабочий проект над которым мы копаемся уже несколько лет и, как есть, байт в байт, ничего не правя вообще, заливаю в GD32…

Чем заливаю? Да тем же китайским ST-Link за сто рублей:

ST-Link Utility восприняла ускоглазого сынка как родного. Для нее чужих детей не бывает. :) Все корректно зашилось и … заработало. Подозрительно…

Хм, как прикольно. А что с отладкой? Жму Debug и… все заработало.

Тут, правда, стоит оговориться, что работаю я не с STM TrueStudio, а уже много лет пишу в EmBitz и с недавних пор они используют свой отладчик EbLink и вот ему пофигу что отлаживать, хоть STM хоть GD. Оно там просто работает. Брейкпоинты ставятся, память и регистры видятся, по шагам шагается, флеш прошивается.

С TrueStudio это уже не прокатывает. Они говорят, что мол это не STM и мы этих косоглазых знать не знаем, а что похожи, так это просто совпадение. Для Keil же GigaDevice, я слышал, выкатила плагин.

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

Да щаз! При попытке пошевелить шаговыми движками наша машина смерти рванула с такой прытью, что я думал из нее все гайки ща посыпятся, даром что на нейлоне. Начинаю разбираться. Скорость тиков шаговых двигателей ровно в полтора раза выше. Но при этом мигалка blinker’a, а также все бодрейты уартов тикают штатно. Мигалка ровно раз в секунду на 100мс, а уарты заданы жестко и перебоев со связью нет. Из этого вывод, что как минимум SysTick тикает с правильной частотой. А от него и AHB APB и прочие частоты тоже. Но не может же так быть…

Опять углубляюсь в юзермануалы, сравниваю все побитно. Все совпадает. Все значения делителей тактовых частот совпадают. Один к одному, просто у GD множители PLL идут дальше и позволяют множить аж до х32. Проверяю по SysTick, просто инвертируя бит порта по его прерыванию — тикает верно. Проверяю по DWT таймеру — тикает верно. Timer2 тактуется тоже верно. То есть, по всем признакам работы периферии, SysClock идентичная. А работает быстрей.

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

Делаю тупую задержку на цикле:

void stupid(uint32_t delay)
{
volatile  uint32_t i;
    i = delay;
    while(i)
    {
        i--;
    }
}

    while(1)
    {
    stupid(0xFFFF);//delay_us(1000);
    IO_InvertLine(io_Blink1);
    }

Сравниваю моргание на оригинальном STM и на GD — на GD в полтора раза примерно быстрей. И либо даташит врет и на самом деле SysClock работает на 108Мгц, а значения битов делителей значат вовсе не то, что написано и приводят со 108Мгц до стандартных частот шин, либо код и вправду исполняется быстрей за счет выборки команд.
Первый вариант весьма шизофреничен, т.к. какой смысл так извращаться, а на опечатку это не тянет вообще, т.к. это уже заговор какой то. А вот второй… второй может быть вероятен. Просто за счет того, что у GD более быстрая память и он команды из флеша берет быстрей.

Но вот что странно, судя по вскрытиями чипов, у GD память реализована путем напаивания отдельного (!!!) кристалла поверх кристалла контроллера и все это уже заливается в корпус. По идее, такая конструкция должна работать медленней. Китайцы сделали какое то кэширование? А может вообще суперскалярность с предсказанием переходов?

Ответ должен быть в сравнении битов настройки задержки выборки флеша. Сравниваю в STM32:

Регистр FLASH_ACR по адресу 0x40022000 и там у нас:

Младшие три байта отвечают за задержку. Я частоты конфигурирую ручками. Не верю я CMSISовскому SystemInit. Слишком часто его переписывали то так то эдак. Хрен знает, что там будет в очередной версии, а мне сюрпризы не нужны. Поэтому я иницилизацию частот написал сам, ручками. В моем коде сделано так:

   #ifndef SYSCLK_FREQ
    #define SYSCLK_FREQ 72000000U
    #warning SYSCLK_FREQ set up to MAX automatically!!! Check this shit!
    #endif

    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

    #if SYSCLK_FREQ<24000000U
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0; // Если SystemCoreClock <= 24 МГц
    #endif

    #if SYSCLK_FREQ>=24000000U && SYSCLK_FREQ<48000000U
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1; // Если 24< SystemCoreClock <= 48, через такт.
    #endif

    #if SYSCLK_FREQ>=48000000U
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;  // Если больше 48, то через два такта.
    #endif

То есть выборка команд будет через два такта. Что же у ГД по этому адресу прячется? Лезем в мануал:

Все то же самое, те же биты отвечающие за задержку чтения из флеша, но с пометочкой, которую я не сразу заметил. О том, что вся эта радость работает только если поставить бит WSEN в FMC_WSEN, а иначе оно не используется. В STM32 никакого такого регистра естественно нет и задержка работает если выставлена. Зачем китайцы встрелили себе в ногу, поломав совместимость в такой простой фигне непонятно. Что им мешало сделать так, чтобы все работало идентично? Ничего не мешало. Но тем не менее. Можно, конечно, тут добавить запись бита в байт по этому адресу, убедившись только, что на STM32 выстрел уйдет в молоко, попав в очередную Reserved секцию.

Окей, добавляем. Поскольку этого адреса у STM32 нет, то я его добавлю вручную, просто через указатель:

uint32_t *FMC_WSEN;
FMC_WSEN = (uint32_t*)0x400220FC;

Бит WSEN там нулевой, поэтому достаточно по этому указателю записать единичку. Правда запись туда запрещена, нужно сначала разблокировать флеш. Записав два раза в регистр FLASH_KEYR ключевое слово 1 и слово 2. Эти слова есть в хидерах на STM32 и на GD. Они одинаковые для обоих камней. Кому интересно FLASH_KEY1 = 0x45670123, а FLASH_KEY2 = 0xCDEF89AB.

FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;

Разблокировали запись во флеш, записываем бит WSEN:

*FMC_WSEN = (uint32_t)1;

После чего выставляем задержку памяти:

    #ifndef SYSCLK_FREQ
    #define SYSCLK_FREQ 72000000U
    #warning SYSCLK_FREQ set up to MAX automatically!!! Check this shit!
    #endif

    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 2 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

    #if SYSCLK_FREQ<24000000U
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0; // Если SystemCoreClock <= 24 МГц
    #endif

    #if SYSCLK_FREQ>=24000000U && SYSCLK_FREQ<48000000U
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1; // Если 24< SystemCoreClock <= 48, через такт.
    #endif

    #if SYSCLK_FREQ>=48000000U
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;  // Если больше 48, то через два такта.
    #endif

    LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
 

И включаем снова блокировку флеша, на всякий случай.

    FLASH->CR |= FLASH_CR_LOCK;

По идее, можно включить блокировку флеша сразу же после *FMC_WSEN = (uint32_t)1; А для настроек во FLASH_ACR разблокировка не нужна. Но это не работает, должно пройти какое то время, видимо, чтобы бит успел записаться во флеш и только потом включать снова блокировку.

Правда тут тоже не вышло счастья :)))) Оказалось, что с задержкой в два такта GD32 медленней чем STM32 c задержкой в эти же два такта. Тестовый импульс у GD32 на полной скорости у нас был 23мкс, на двух тактах задержки памяти стал 54мкс, а на одном такте задержки 37мкс. В то время как STM32 на двух тактах давал 37мкс.

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

Ковыряясь в даташите на GD32 я увидел, что следующим после FMC_WSEN идет регистр FMC_PID и в нем сидит какое-то число, уникальный номер кристалла (или его памяти). Но у STM32 этот же адрес возвращает какую-то фигню. Которая еще и меняется. Хотя эти адреса никак не документированы. Так что вариант так себе.

Посоветовался с коллегами, покурил даташиты и документацию на ARM ядро и нашел, что по адресу 0xE00FFFD0 и далее прячутся Peripheral ID регистры. Которые содержат циферки присущие только конкретному семейству и производителю. В частности там зашито номер ревизии чипа, JEP 106 код и еще всякая лабуда. Но, главное, что у STM32 и GD32 эти байты различаются, не меняются, всегда одни и те же от чипа к чипу, в отличии от индивидуального 96 битного ID чипа, который уникальный для каждого экземпляра.

Поэтому поглядел под отладчиком что там, да написал простенькую процедурку для опознания где мы:

bool UseGD32(void)
{
uint8_t *TestByte;
    TestByte = (uint8_t*)0xE00FFFD0;
    if (*TestByte == 7) return 1;
    return 0;
}

Проверил в железе — работает. Вот и славно. Пляшем дальше! :)

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

  • SysTick
  • USART’ы все
  • Timer2
  • DWT
  • GPIO

Хватаю дисплейный модуль от другого проекта, но с этим же камнем. На нем есть FSMC интерфейс. Я на нем управлял дисплеем. Работает на отлично. Добавляем к списку проверенной периферии FSMC.

  • FSMC

Хватаю другой проект, на этой же плате. Но уже боевой дисплей от компрессорной установки. Заливаю… Все работает, но жууууутко мееееееедленнно. Я поначалу решил, что я тупо кварц залил флюсом и у меня HSE не поехал. Промыл, просушил. Включил… все жууууутко меееедленно осталось. Странно. К сожалению исходников этого проекта у меня нет, знаю только что он написан на SPL и возможно что-то где-то недоинициализировалось в режиме тактирования. Надыбаю исходники, перепишу и будет ясно в чем был затык. Но я уже четко вижу, что нормально работают каналы DMA. Все не проверял, но UART там сделан через DMA это я знаю точно.

В общем, по мере освоения периферии буду добавлять в этот пост подробности о том, что же у нас по совместимости.

UPD
В комментариях набросили официальную доку по совместимости от GD. Прикладываю ее тут:

]]>
http://easyelectronics.ru/kontrollery-ot-gigadevice-gd32f103xxxx-popytka-migracii-s-stm32f103xxxx.html/feed 26
Аккумуляторная бормашина Dremel 8220 http://easyelectronics.ru/akkumulyatornaya-bormashina-dremel-8220.html http://easyelectronics.ru/akkumulyatornaya-bormashina-dremel-8220.html#comments Sat, 09 Oct 2021 10:34:00 +0000 http://easyelectronics.ru/?p=1902

Купил я ее несколько лет назад, активно пользуюсь. Раз в неделю то точно. Что могу сказать — чего же я не купил ее раньше то!!! :) Не, гравер у меня был. Похожей мощности, размера и веса. Только проводной. Какой то Bort…. чето там. Вполне себе приятная зуделка была, единственное почему я ей редко пользовался — провод, мать его. Этож надо взять, размотать, найти розетку, потом смотать. Да ну нахрен, проще надфилем поддрочить и все делов. В итоге, пользовался я ей редко. А потом как наткнулся на аккумуляторный вариант, так сразу и купил. И с тех пор это один из самых юзаемых девайсов на рабочем столе. Сравнимый с шуруповертом. Подточить, подрезать, отпилить, просверлить в неудобном месте.

▌Внешний вид
Обычный гравер. Ухватистый, тяжеленький. Сзади втыкается аккумулятор, полностью совместимый с бошевской домашней, «зеленой», серией.

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

И он прекрасно моделируется в Fusion360 одной из стандартных резьб (Тип резьбы ANSI Unified Screw Threads шаг резьбы 3/4-12UN ), что позволяет мне моделировать и печатать на 3D принтере свои насадки и приблуды на раз два.

Поверх резьбы гайка EZ Twist, фича которой в том, что на ней есть стальная вставка, позволяющая ей затягивать цангу, как ключом.

Просто скручиваем чуток эту гайку и прихватываем ей за лыски цанги.

Удобное решение. Причем я о нем узнал вообще случайно. В мануале об этой супер способности гайки видимо упомянули как-то вскользь. Так бы не догадался. Ну мало ли что там за пластина торчит, а надпись EZ Twist принял за очередной высер маркетологов, лишь бы что-то обозвать. С них станется и простой гайке название придумать позажигательней. Ан нет, фирменная фишечка :)

Сбоку спереди — включатель, а сзади регулятор оборотов. И, что самое ценное, что выделяет этот гравер от остальных, обороты регулируются от 6000, а не от 10000, как обычно у подобных машинок. Т.е. на малых оборотах можно уже нормально сверлить, не перегревая сверло. Что-то нежно шкурить или отрезать. Собственно именно поэтому я и пользуюсь ей так часто. Обычно на минимальной скорости. На самой малой скорости еще и момент существенно проседает. Я правда еще не решил баг это или фича. Т.к. иногда полезно, что инструмент останавливается под нагрузкой. Но уже следующее деление регулятора скорости и момент существенно возрастает. И машинку уже не стопорит.

Стальная дужка, идущая вокруг регулятора, это скоба. Ее можно отщелкнуть, повернуть и за нее повесить машинку на подвес. Удобно то, что она фиксируется в пазах и не болтается, не мешает когда не нужна.

Баланс у машинки, честно говоря, так себе. Зад с аккумулятором ощутимо перевешивает, поэтому для долгих аккуратных работ она подходит не очень. Но, собственно, сам формат и не располагает к долгой работе. Батарейку она кушает очень даже весело и задорно. Особенно на максимальных оборотах и под нагрузкой. Прогрессбар заряда аккумулятора тает прям на глазах.

Но это смотря какая работа. Вхолостую, если просто включить на максимальные обороты и поставить, то полностью заряженной батарейки хватит на 40 минут жжужания. Легкая гравировка малыми камушками — сравнительно. А вот отрезка чего либо кругом, уже существенно большая нагрузка и тут хватит минут на 10 тяжелой работы. Но за эти 10 минут она успеет сделать реально многое. Мощности ей хватает вершить великие дела и пару раз она меня прям удивила и выручила.

Случилось мне как то раз подорваться в свою квартиру срочно менять замок. Вот прям срочно, а времени было часов так 7 вечера. Были неприятные обстоятельства, писал об этом пару лет назад в своем бложике. С собой я взял болгарку, шуруповерт и вот эту бормашинку, заусенцы там поправить и все дела. Коробка двери была сварена из П образного профиля, с толщиной стенки ну миллиметров так 8, охватывающую железобетонную плиту по периметру проема, сама дверь была из стали миллиметра 4, может даже 5. Массивная как сейф (когда новый жилец этой квартиры зачем то поменял эту дверь на современную гламурную жестянку, я себе фейспалмом чуть лицо не разбил). Наследие буйных 90х годов. Такую только танком выносить. И вот в этом великолепии мне надо было выпилить отверстия под замочную скважину, а также под ригеля нового замка и сам замок врезать. Только я начал, как у меня ломается диск болгарки. Единственный. Успел всего ничего. Время позднее, купить что-то уже не вариант, замок надо поменять во что бы то ни стало. Чисто ради лулзов попробовал этим дремелем, дисочком по металлу… и… оно пошло. Да как пошло! Я за пол часа выпилил в этой броне отверстие под ригеля, напомню там сталь чуть ли не с палец толщиной. А также сделал пропилы под тело замка и запилил новую замочную скважину. При этом у меня от диска еще что-то осталось и ушло два аккумулятора, тот что в ней и шуруповертовский.

Цепляются диски на фирменную оправку. Speed Click или как то так. Штука удобная, но насквозь проприетарная. Это тебе не опенсорцный болт :) Чтобы натянуть диск надо потянуть вниз вон за ту зеленую бобышку и откроется замок, из которого можно достать диск.

В общем, диски по металлу у Dremel прям отличные. Еще я им пилил валы каленые для ЧПУ станков, 8мм. Всякие железки и прочее. У меня есть болгарка, но обычно доставать эту дурмашину лень, вот обзаведусь аккумуляторной… ;) Обхожусь мелким, но злым дремелем.

▌Комплектация
Вместе с ним шел зарядник. Полубесполезный фонарик и прозрачный щиток для защиты глаз, навинчивающийся на его резьбу. Комплектацию я взял самую дешманскую. Т.к. 90% всех этих фрезочек, шкурочек и прочего барахла, что идет в большом наборе мне не нужны и будут валяться. Я лучше их прикуплю по непосредственной необходимости.

]]>
http://easyelectronics.ru/akkumulyatornaya-bormashina-dremel-8220.html/feed 9
Гальваническая развязка аналогового сигнала http://easyelectronics.ru/galvanicheskaya-razvyazka-analogovogo-signala.html http://easyelectronics.ru/galvanicheskaya-razvyazka-analogovogo-signala.html#comments Thu, 26 Aug 2021 07:42:32 +0000 http://easyelectronics.ru/?p=1897 Порой приходится делать гальваническое разделение аналогового сигнала. Например, чтобы отделить АЦП контроллера от высоковольтной части. И если с передачей дискретных сигналов все более менее понятно, там можно обойтись обычным оптроном, работающим в режиме вкл-выкл, то что делать с аналоговым сигналом?

Первое что приходит на ум, так это взять какую-нибудь оптопару и попробовать питать ее светодиод не номинальным напряжением, а нашим аналоговым сигналом. Ведь если напряжение на входе меньше, то светодиод горит тусклее и у фотодиода или фототранзистора на выходе будет совсем другое открытие. Если посмотреть даташит на какую-нибудь оптрон, вроде дешевого и популярного LTV817, то да, можно увидеть вполне характерную зависимость тока выхода (IC от тока входящего в светодиод (IF):

И даже можно попробовать на нем что-то изобразить. Но возникает несколько проблем. И главная даже не в нелинейности. В конце концов, в большинстве случаев, у нас сигнал все равно идет на АЦП какое-нибудь. А там нелинейность можно бы и программно исправить — бомбануть табличку или по формулам с кусочно-линейной аппроксимацией. Нет, главная проблема тут в разбросе параметров самих оптронов от штуки к штуке, даже в пределах одной партии, более того, они еще и с температурой очень сильно изменяют свои характеристики. Получится система которую сложно повторить и откалибровать. Скорей получится сделать всратый термометр чем линию связи :)

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

Первым делом он поможет нам линеаризовать сигнал. Т.е. можно будет смело забыть про эти кривые передаточные характеристики оптического канала и все что влезло вылезет в том же виде. А это существенно все упрощает.

Делаем обратную связь через оптический канал. Как это работает. Допустим, в начальном состоянии, фототранзистор затемнен, закрыт и точка А подтянута к +V, пусть там будет вольт 15. А на точку В подали, скажем, 3 вольта входного сигнала. На выходе будет (15-3) * дохрена = напряжение которое зажжет светодиод оптопары и начнет открывать фототранзистор. А он, в свою очередь, просадит напряжение подтяжки в точке А до тех пор, пока оно не сравняется с напряжением на точке В и ОУ не успокоится, замерев в этом устойчивом положении.

Если промоделировать, то увидим, что напряжения идентичные.

Желтый луч это входной с генератора, а синий с обратной связи.

Почти… у выходного (Сигнал В) сигнала есть небольшая плоскость внизу. Это связано с тем, что транзистор оптопары не может придавить сигнал совсем в ноль. Чтобы от нее избавиться надо чуток приподнять входной сигнал, добавив к нему смещение в пол вольта-вольт. Например, сделав сумматор из ОУ. Но это уже не большая проблема, сумматор можно собрать на другом ОУ из той же микросхемы.

Окей, классно. Приравняли мы напряжение А и В с помощью ОУ. А что нам это дает? Они ведь все равно на одной стороне находятся. Что дальше? А дальше мы можем взять вторую, точно такую же оптопару, а лучше второй канал сдвоенной оптопары (чтобы максимально идентичные свойства были) и насадить на тот же выходной ток с нашего ОУ. И он будет дублировать напряжение на той стороне. Вот так:

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

На модели все также:

Если делать смещение, то тут же, на принимающем ОУ, его можно и отрезать.

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

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

Если промоделировать, то все работает идентично.

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

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

Вот такой вот способ передачи аналогового сигнала с гальванической развязкой. В следующий раз я наброшу еще несколько способов.

]]>
http://easyelectronics.ru/galvanicheskaya-razvyazka-analogovogo-signala.html/feed 29
Простая работа с биполярным сигналом датчика http://easyelectronics.ru/prostaya-rabota-s-bipolyarnym-signalom-datchika.html http://easyelectronics.ru/prostaya-rabota-s-bipolyarnym-signalom-datchika.html#comments Wed, 04 Aug 2021 12:14:40 +0000 http://easyelectronics.ru/?p=1894 Работая с разными аналоговыми датчиками часто натыкаешься на то, что у датчика сигнал биполярный. Ну то есть он не 0…5 вольт, а, например, -2.5…+2.5. И вот ради такой фигни городить двуполярное питание ну совсем не хочется, добавлять ОУ, чтобы сместить уровень до съедобного для АЦП тоже. Если точность позволяет, то есть такое вот простое и ультрадешевое решение:

Да да, берем и вешаем наш биполярный сигнал и через делитель бросаем его на плюс питания. Делителем масштабируем его как нам угодно и все :)

Ну, а считается он элементарно. Скажем, минимальное напряжение сигнала -2 вольта. Ток в АЦП не течет, значит весь ток идет только по ветке In — R2 — R1 — 5V При -2 вольтах на входе, разница потенциалов с питанием будет 7 вольт. По закону Ома 7V / 20kOhm = 0.00035A. Падение на резисторе R1 будет 3.5 вольта. А значит на средней точке делителя будет 5-3,5 = 1.5 вольта.

Если же на входе 2 вольта, то точно также: Разница напряжений 3V, ток в ветви 3V / 20kOhm = 0.00015A. Падение на резисторе R1 будет 1.5 вольта, а значит на средней точке делителя будет 5-1.5 = 3.5 вольта.

Понятно, что у данного решения хватает минусов. Например то, что плаванье питания непременно скажется на амплитуде выходного сигнал нашего датчика. Можно, конечно, застабилизировать его каким-нибудь LOW-DROP стабилизатором, выведя на отдельную ветку от основного. Но тут надо смотреть, чтобы стабилизатор не стал дороже нормального решения на ОУ :) Также мы теряем в размахе сигнала. На входе был размах в 4 вольта (-2…2), а на выходе получили всего 2 (1.5…3.5) вольта.

Еще не помешает защитный диод. Его задача не дать напряжению обратной полярности входного сигнала пролезть в питание и натворить там дел.

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

]]>
http://easyelectronics.ru/prostaya-rabota-s-bipolyarnym-signalom-datchika.html/feed 12
Торцовочная пила Proxxon KGS-80 http://easyelectronics.ru/torcovochnaya-pila-proxxon-kgs-80.html http://easyelectronics.ru/torcovochnaya-pila-proxxon-kgs-80.html#comments Sat, 22 May 2021 02:52:08 +0000 http://easyelectronics.ru/?p=1890 ▌Прецезионна пальцерезка
Я последнее время частенько мастерю разную умную и, порой, всратую механику для вендинговых автоматов, которые делают странное. Например, убивают людей кучей разных изощренных способов :) А под это дело постоянно приходится отпиливать разные валы, конструкционный профиль, отпиливать кусочки от кругляка с последующей токаркой. И делать это с достаточной точностью. Ну чтобы попасть хотя бы в треть миллиметра.

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

▌Устройство
Собрано все на квадратном основании, со стороной в 23см.

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

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

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

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

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

Конструкция — говно, т.к. вот эта вот черная кочерга на конце этого стержня плавает от малейшего нажатия. Нахер она такая убогая — великая тайна есть. Сэкономили.

На станине есть педалька, которая фиксирует поворотный стол по 15 градусов.

Хорошо фиксирует, без люфтов. А вот если надо выставить произвольнй градус, то для фиксации есть барашка сбоку.

И работает она херово, т.к. при попытке зажать, даже с минимальным усилием, барабан смещается вверх аж на миллиметр. При том, что люфтов, как таковых, там нет, т.е. основание или ось имеет недостаточную жесткость и всю конструкцию ведет.

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

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

Мотор удерживается вверху довольно тугой пружиной. Мощность мотора всего 200 ватт, но для такого маленького диска этого более чем достаточно.

Мотор, естественно, коллекторный.

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

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

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

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

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

Срез бруска из оргстекла. Сделал чисто по приколу, по прозрачности будет понятна шершавость.

А вот латунный пруток:

Изначально хотел отрезать 1мм, чиркнул рисочкой и… попал :)

C первого раза :)

Максимальный размер который в эту пилу можно сунуть всего 30мм. Поэтому вот этот пруток почти предельный размер. Алюминиевая кругляха 25мм диаметров.

И конструкционный профиль туда же:

На его распил ушло секунд 15 наверное. Вжих и всех, только стружка хлопьями во все стороны.

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

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

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

Главный недостаток этой пилы — совершенно конская цена, совершенно не соответствующая качеству. Благо я ее купил со скидкой почти в 40% (видимо по реальной цене желающих не нашлось вообще :) ) Собственно, как и вся техника от Proxxon, но реально маленькие станки делают только они. Ее можно в боевом виде, как есть, спокойно засунуть в ящик тумбочки или стандартую клеточку от Ikea. Но если вам не так критичные габариты, то стоит за эти деньги поискать аналог от какой нибудь инструментальной фирмы вроде Metabo, Bosh и прочих. Думаю будет лучше.

]]>
http://easyelectronics.ru/torcovochnaya-pila-proxxon-kgs-80.html/feed 13
Объединение JLCPCB и EasyEDA http://easyelectronics.ru/obedinenie-jlcpcb-i-easyeda.html http://easyelectronics.ru/obedinenie-jlcpcb-i-easyeda.html#comments Mon, 17 May 2021 09:29:35 +0000 http://easyelectronics.ru/?p=1888 Недавно две дружественные конторы JLCPCB и EasyEDA слились в одну. Теперь это единая экосистема из облачного САПРа и производителя плат. Собственно оно уже давно так, видать теперь это как то юридически произошло. Ждем когда в эту же когорту окончательно войдет еще и LCSC, чтобы уже официально. И тогда можно будет в один тык отправлять сразу на производство готового изделия.

Но на всю эту корпоративную возню как бы наплевать, если бы они под этот повод не выдавали купоны на 10 баксов под новый заказ. Выдают их тут. Я правда не понял можно ли им оплатить сразу весь заказ или только часть. А если часть, то какую. Кто попробует — напишите в комментах. Если не получится, то тоже напишите :)

]]>
http://easyelectronics.ru/obedinenie-jlcpcb-i-easyeda.html/feed 2