<?xml version="1.0" encoding="utf-8"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Форум программистов и сисадминов Киберфорум - Блоги - Eddy_Em</title>
		<link>https://www.cyberforum.ru/blogs/1886385/</link>
		<description>КиберФорум - форум программистов, системных администраторов, администраторов баз данных, компьютерный форум, форум по электронике и бытовой технике, обсуждение софта. Бесплатная помощь в решении задач по программированию и наукам, решение проблем с компьютером, операционными системам</description>
		<language>ru</language>
		<lastBuildDate>Fri, 04 Sep 2026 06:35:37 GMT</lastBuildDate>
		<generator>vBulletin</generator>
		<ttl>60</ttl>
		<image>
			<url>https://www.cyberforum.ru//cyberstatic.net/images/misc/rss.jpg</url>
			<title>Форум программистов и сисадминов Киберфорум - Блоги - Eddy_Em</title>
			<link>https://www.cyberforum.ru/blogs/1886385/</link>
		</image>
		<item>
			<title><![CDATA["Прокси" для последовательного порта]]></title>
			<link>https://www.cyberforum.ru/blogs/1886385/10912.html</link>
			<pubDate>Thu, 28 May 2026 13:03:49 GMT</pubDate>
			<description>Эту штуку (https://github.com/eddyem/eddys_snippets/tree/master/serialsock) написал я достаточно...</description>
			<content:encoded><![CDATA[<div><a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/eddys_snippets/tree/master/serialsock" target="_blank" title="https://github.com/eddyem/eddys_snippets/tree/master/serialsock">Эту штуку</a> написал я достаточно давно. Но сейчас вот понадобилось настроить датчик грозы, но при этом не отключать его от &quot;метеодемона&quot;. Соответственно, надо запустить этот &quot;прокси&quot;: метеодемон будет себе парсить то, что ему нужно, а я смогу всякие настройки во время грозы пробовать. А то не дело это, что молнии вовсю шарашат, а этот молчит…<br />
Полез в код &quot;прокси&quot;, а там какая-то допотопная дичь. Переделал под <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/snippets_library" target="_blank" title="https://github.com/eddyem/snippets_library">libusefull_macros v0.3.5.</a>, заодно дипсиком сгенерировал документацию + он мне на пару ошибок указал (и еще штук на пять &quot;фич&quot;, которые он посчитал багами).<br />
Кому надо — пользуйтесь, удобная штука. В отличие от socat, мой &quot;прокси&quot; позволяет многим клиентам одновременно оперировать с портом. А еще, он не помирает после отключения клиента. А в случае отключения устройства пытается перезапуститься, пока опять его не найдет.</div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/10912.html</guid>
		</item>
		<item>
			<title>Переходник USB-CAN-GPIO</title>
			<link>https://www.cyberforum.ru/blogs/1886385/10816.html</link>
			<pubDate>Thu, 19 Mar 2026 21:28:12 GMT</pubDate>
			<description>Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и...</description>
			<content:encoded><![CDATA[<div>Достаточно давно на работе возникла необходимость в переходнике CAN-USB с гальваноразвязкой, оный и <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/stm32samples/tree/master/F0%3AF030%2CF042%2CF072/usbcan_ringbuffer" target="_blank" title="https://github.com/eddyem/stm32samples/tree/master/F0%3AF030%2CF042%2CF072/usbcan_ringbuffer">был разработан</a>. Однако, все меня терзала совесть, что аж 48-ногий МК используется так тупо: просто CAN и USB… Со временем на свободное место платы добавил выводы от некоторых ног МК. И теперь легким движением руки за пару вечеров можно было быстренько добавить нужный функционал, чтобы сделать &quot;временную затычку&quot; (правда, зачастую это &quot;временное&quot; потом годами эксплуатируется) в случае необходимости.<br />
А не так давно появилась необходимость этот &quot;вариативный функционал&quot; сделать доступным для человека, который вообще полный нуль в программировании! Т.е. сделать эдакий &quot;мини-ПЛК с человеческим лицом&quot;.<br />
<br />
Вот он, опутанный МГТФом виновник:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11798 tc=1&amp;d=1773955836" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Итак, привожу документацию (правда, написанную сухим официальным языком) на то, какой новый функционал в железяке появился. Вкратце: теперь можно конфигурировать GPIO как входы (цифровые или АЦП), выходы, I2C, SPI, USART или ШИМ.<br />
<br />
<br />
При подключении устройство создает два интерфейса. При использовании соответствующего udev-скрипта (см. в конце) автоматически возникают ссылки, по умолчанию: <code class="inlinecode">/dev/USB-CANx</code> для &quot;старого&quot; интерфейса CAN-USB и <code class="inlinecode">/dev/USB-GPIOx</code> для &quot;нового&quot;.<br />
Устройство эмулирует два CDC-ACM, имея простейший текстовый протокол.<br />
<br />
<b><font size="3">Общий формат команд</font></b><ul><li>Команды чувствительны к регистру, команды-геттеры и команды-сеттеры отличаются наличием в последних знака &quot;=&quot;.</li>
<li>Параметры сеттера разделяются пробелом или запятой.</li>
<li>Если не оговорено иное, числовые значения параметров могут иметь десятичный, шестнадцатеричный (<code class="inlinecode">0x...</code>), восьмеричный (<code class="inlinecode">0...</code>) или двоичный (<code class="inlinecode">b...</code>) формат.</li>
<li>В таких командах, как <code class="inlinecode">SPI</code> или <code class="inlinecode">I2C</code> все данные в шестнадцатеричном формате без префикса.</li>
<li>Ввод <b>всегда</b> построчный: символ '\n' означает конец строки и парсер, встретив этот символ, начинает разбор предыдущих символов.</li>
</ul><br />
<b><font size="2">Список команд</font></b><ul><li><b>canspeed [=value]</b> – установить скорость CAN-интерфейса по умолчанию (при запуске CAN будет работать на этой скорости). В процессе работы с CAN-USB ее можно временно изменить в соответствии с протоколом (описан на страничке оригинального устройства).</li>
</ul><ul><li><b>curcanspeed</b> – Отобразить текущую скорость CAN.</li>
<li><b>curpinconf</b> – Текущая конфигурация выводов МК (может отличаться от сохраненной в конфигурации в случае ошибки при запуске команды <code class="inlinecode">reinit</code>).</li>
<li><b>dumpconf</b> – Отображение текущей глобальной конфигурации (в т.ч. параметров CAN, SPI и т.п.). Внимание! Эта конфигурация содержит обновленные данные, которые вы могли изменять в рантайме, поэтому она может не соответствовать актуальной. Для сохранения во флеш-память используйте <code class="inlinecode">saveconf</code>.</li>
<li><b>eraseflash</b> – Полная очистка области хранения конфигурации во флеш-памяти.</li>
<li><b>help</b> – Отображение справки.</li>
<li><b>hexinput [=0/1]</b> – Изменение режима ввода:<ul><li>0 — простой текст (данные вводятся и выводятся построчно);</li>
<li>1 — шестнадцатеричный ввод (без префикса <code class="inlinecode">0x</code>) с возможностью ввода текста в кавычках.</li>
</ul>Данный режим влияет лишь на команды <code class="inlinecode">USART</code> и <code class="inlinecode">sendcan</code>.</li>
<li><b>iic=addr data...</b> – Запись данных в I2C. Адрес <code class="inlinecode">addr</code> — несмещенный 7-битный адрес устройства, данные в шестнадцатеричном формате без разделителя, например: <code class="inlinecode">iic=50 01 02</code></li>
<li><b>iicread=addr nbytes</b> – Чтение <code class="inlinecode">nbytes</code> данных по I2C. Данные выводятся в режиме &quot;hexdump&quot;.</li>
<li><b>iicreadreg=addr reg nbytes</b> – Считать <code class="inlinecode">nbytes</code> данных с регистра <code class="inlinecode">reg</code>.</li>
<li><b>iicscan</b> – Сканирование шины I2C в поиске активных устройств. Найденные рабочие устройства отображаются асинхронно.</li>
<li><b>mcutemp</b> – Условная температура МК, ℃ с множителем 10.</li>
<li><b>mcureset</b> – Перезагрузка микроконтроллера (будьте внимательны: это отразится и на интерфейсе CAN-USB).</li>
<li><b>PAx [= ...]</b> и <b>PBx [= ...]</b> – Геттеры и сеттеры для выводов портов GPIOA и GPIOB соответственно (см. раздел «<a rel="nofollow noopener noreferrer" href="https://#pinconfig" target="_blank" title="https://#pinconfig">Конфигурация выводов</a>»).</li>
<li><b>pinout [=function1,function2,...]</b> – Отображение всех настраиваемых выводов. В случае сеттера отобразятся лишь соответствующие функциональные группы (например, <code class="inlinecode">pinout=ADC,PWM</code> отобразит выводы, доступные для конфигурирования как входы АЦП или выходы ШИМ). Если вы видите одинаковые функции (например, <code class="inlinecode">PWM2_2</code> на разных выводах, это — потенциальные конфликты: использовать данный функционал можно лишь на одном из этих выводов.</li>
<li><b>pwmmap</b> – вариант команды <code class="inlinecode">pinout</code> только для выводов с поддержкой ШИМ, конфликты отмечены явно.</li>
<li><b>readconf</b> – Перечитать последнюю сохраненную в флеш-памяти конфигурацию (полезно, если вы что-то испортили в текущей, но не успели ее сохранить, и хотите &quot;откатиться&quot;). Если устройство &quot;девственно&quot;, т.е. ни одной конфигурации не сохранено, это не сработает.</li>
<li><b>reinit</b> – Проверка текущей конфигурации выводов и полная переинициализация. В случае ошибок настройки проблемных выводов будут сброшены в <code class="inlinecode">FL IN</code>, что можно будет увидеть по вызову <code class="inlinecode">curpinconf</code>.</li>
<li><b>saveconf</b> – Сохранить текущие настройки во флеш-память.</li>
<li><b>sendcan</b> – Отправить в <b>USB-интерфейс</b> устройства CAN-USB данные. Внимание! Эта команда не пересылает данные в CAN-шину (используйте для этого непосредственно соответствующий интерфейс), но позволяет передать какую-либо информацию процессу, работающему с этим интерфейсом.</li>
<li><b>setiface=N [=name]</b> – Команда позволяет переименовать интерфейсы (0 = CAN, 1 = GPIO). Используйте удобные для вас наименования, не превышающие 16 символов. Помните, что udev-скрипт будет создавать ссылки с соответствующими именами, поэтому не используйте недопустимых символов (пробелы, слэши и прочее, что не допустимо в именах файлов).</li>
<li><b>SPI=data...</b> или <b>SPI=size</b> – Обмен данными с устройством SPI. Первая команда работает в полнодуплексном режиме или режиме TX-only, передавая все введенные в шестнадцатеричном формате данные. В случае полнодуплексного режима считывается такое же количество данных с MISO и выводится как &quot;hexdump&quot;. В режиме Rx-only используется второй вариант команды, считывая <code class="inlinecode">size</code> байт с SPI.</li>
<li><b>time</b> – Отображение условного времени (в мс), прошедшего с последней перезагрузки МК.</li>
<li><b>USART[=...]</b> – Геттер считывает данные из приемного кольцевого буфера USART, сеттер отправляет перечисленные данные (их формат зависит от выбранного командой <code class="inlinecode">hexinput</code> режима).</li>
<li><b>vdd</b> – Примерное напряжение питания МК (В с множителем 100).</li>
</ul><br />
<b><font size="3">Конфигурация выводов (команды <code class="inlinecode">PAx</code>/<code class="inlinecode">PBx</code>)</font></b><br />
<br />
Общий синтаксис настройки выводов следующий:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="359173689"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="359173689" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">PXx = MODE PULL OTYPE FUNC MISC ...</pre></td></tr></table></div></td></tr></tbody></table></div>Здесь <code class="inlinecode">PX</code> — соответствующий порт (<code class="inlinecode">PA</code> или <code class="inlinecode">PB</code>), <code class="inlinecode">x</code> — номер вывода. После знака равенства идет последовательность ключевых слов с возможными числовыми аргументами.<br />
<br />
Кроме того, эта же команда работает как сеттер/геттер значения, если соответствующий вывод настроен как GPIO, АЦП (только геттер) или ШИМ. Например, если PA1 настроен как <code class="inlinecode">OUT</code>, команда <code class="inlinecode">PA1=1</code> установит его значение в высокое состояние, геттер же отобразит текущее состояние (из регистра <code class="inlinecode">GPIOX-&gt;IDR</code>, т.е. для выхода с открытым стоком в состоянии &quot;1&quot; можно детектировать внешнюю верхнюю или нижнюю подтяжку). Для настройки ШИМ (<code class="inlinecode">PWM</code>) можно изменять заполнение выходного сигнала, например: <code class="inlinecode">PB2=128</code> установит заполнение в 50%.<br />
<br />
<b><font size="2">Ключевые слова</font></b><br />
<br />
Ключевые слова могут идти в любой последовательности.<br />
<br />
<b>MODE</b><br />
<ul><li><b>AIN</b> – Аналоговый вход (АЦП).</li>
<li><b>IN</b> – Цифровой вход.</li>
<li><b>OUT</b> – Цифровой выход.</li>
<li><b>AF</b> – Альтернативная функция (данное ключевое слово не обязательно указывать, т.к. этот флаг установится автоматически при выборе любой функции вроде <code class="inlinecode">USART</code> и т.п.).</li>
</ul><br />
<b>PULL</b> (только для режимов <code class="inlinecode">GPIO</code>)<br />
<ul><li><b>PU</b> – Включена верхняя подтяжка (как для входов, так и для выходов).</li>
<li><b>PD</b> – Включена нижняя подтяжка (хотя для выходов это бессмысленно).</li>
<li><b>FL</b> – Подтяжки выключены.</li>
</ul>Верхняя и нижняя подтяжки взаимоисключающие.<br />
<br />
<b>OTYPE</b> (только для режимов <code class="inlinecode">GPIO</code>)<br />
<ul><li><b>PP</b> – Push-pull.</li>
<li><b>OD</b> – Открытый сток.</li>
</ul><br />
<b>FUNC</b> – выбор альтернативной функции:<br />
<ul><li><b>USART</b> – Вывод будет частью USART (можно выбрать только Rx или Tx).</li>
<li><b>SPI</b> – Вывод — часть SPI (обязательно выбрать SCK и хотя бы один из MISO или MOSI).</li>
<li><b>I2C</b> – Вывод — часть I2C (обязательно выбрать как SCL, так и SDA).</li>
<li><b>PWM</b> – Вывод с функцией ШИМ (частота ШИМ около 23.5 кГц, заполнение от 0 до 255).</li>
</ul><br />
<b>MISC</b><br />
<ul><li><b>MONITOR</b> – Асинхронный мониторинг функционала данного вывода: без запроса пользователя передаются данные, как только значение GPIO входа или АЦП изменится, либо же в случае USART — появятся новые данные.</li>
<li><b>THRESHOLD</b> – Пороговое значение (0..4095) для мониторинга аналогового входа. Изменение асинхронно отображается лишь при превышении текущим значением данного порога относительно предыдущего.</li>
<li><b>SPEED</b> – Установка скорости интерфейса (USART, SPI, I2C), в бодах, Гц или индексе.</li>
<li><b>TEXT</b> – (только USART) Текстовый режим USART: входные и выходные данные буферизуются построчно. В случае включенного мониторинга отображаются лишь новые строки целиком, но не их части (если длина строки не превышает размера входного буфера).</li>
<li><b>HEX</b> – (только USART) Шестнадцатеричный режим USART: блоки входных данных (не превышающих размер внутреннего буфера) разделяются по сигналу IDLE. Вывод — в формате &quot;hexdump&quot;.</li>
<li><b>LSBFIRST</b> – (только SPI) Передача младшего бита первым. По умолчанию — MSBFIRST.</li>
<li><b>CPOL</b> – (только SPI) полярность данных.</li>
<li><b>CPHA</b> – (только SPI) выбор фронта активности данных.</li>
</ul><br />
При выборе функционала, недоступного на данном выводе, сразу же будет выведена ошибка. В случае, если вы неправильно настроите выводы интерфейсов (скажем, забудете указать SCK для SPI), после вызова команды <code class="inlinecode">reinit</code> появится сообщение об ошибке настройки, а проблемные места будут сброшены в значения по умолчанию.<br />
<br />
<br />
<b><font size="3">Альтернативные функции</font></b><br />
<br />
<b><font size="2">USART</font></b><br />
<br />
Данный интерфейс доступен на контактах PA9/PB6 (TX USART1), PA10/PB7 (RX USART1) или PA2 (TX USART2) и PA2 (RX USART2). Несмотря на наличие двух модулей USART, допускается использовать лишь один из них. Соответственно, нельзя настроить смесь для разных интерфейсов (например, PA9 и PA3). Прием и передача данных использует DMA, поэтому большие объемы данных, передаваемые по этому интерфейсу, не будут сказываться на работе преобразователя CAN-USB.<br />
<br />
Для данного интерфейса при конфигурации используются такие ключевые слова, как SPEED, TEXT/HEX и MONITOR. Например,<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="393512230"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="393512230" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1">PA9 = USART SPEED <span class="nu0">115200</span> TEXT MONITOR
PA10 = USART
reinit</pre></td></tr></table></div></td></tr></tbody></table></div>Данная последовательность команд настроит USART1 на выводах PA9/PA10. Скорость 115200 бод, текстовый режим с асинхронным выводом поступающих строк текста. Каждая новая строка будет выведена как <code class="inlinecode">USART = ...</code>.<br />
Обратите внимание: для отличия реального символа конца строки от переноса строки в случае вывода неполного буфера (например, при переполнении входного буфера), &quot;реальный&quot; символ '\n' удваивается.<br />
<br />
Передача строк зависит от формата, например, в формате TEXT команда <code class="inlinecode">USART=Hello, world!\n</code> отправит по USART строку &quot;Hello, world!\n&quot;. А в формате HEX команда <code class="inlinecode">USART=48 65 6c 6c 6f\n</code> отправит пять байт данных &quot;Hello&quot;.<br />
<br />
Команда-геттер <code class="inlinecode">USART</code> отображает содержимое приемного кольцевого буфера. В &quot;текстовом&quot; режиме оно будет выводиться построчно на каждый запрос. В &quot;шестнадцатеричном&quot; режиме — порциями по 256 байт. Если кольцевой буфер пуст, никакого ответа на эту команду не последует. Даже вне режима MONITOR возможен асинхронный вывод данных в случае переполнения буфера: вызывайте геттер чаще, чтобы этого не допустить.<br />
<br />
Длина входного буфера DMA ограничена, поэтому если пользователь настроит USART на слишком высокую скорость, возможна потеря данных (особенно при активной работе второго интерфейса — CAN-USB), т.к. опрос буфера DMA производится без прерываний.<br />
<br />
<b><font size="2">I2C</font></b><br />
<br />
Вы можете выбрать интерфейс на контактах PB6/PB10 (SCL) и PB7/PB11 (SDA). Будьте внимательны: если вместо STM32F042 используется STM32F072, на контактах PB7/PB11 доступен лишь I2C2, но не I2C1. В этом случае настроить I2C на данных контактах будет невозможным (в коде нет поддержки I2C2).<br />
I2C не допускает активации только с одним из этих выводов, поэтому обязательно настроить и SCL, и SDA.<br />
<br />
Для данного интерфейса доступно лишь ключевое слово SPEED. Обратите внимание, что, в отличие от USART и SPI, здесь скорость задается <b>индексом</b>: 0=10kHz, 1=100kHz, 2=400kHz, 3=1MHz.<br />
<br />
Пример:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="146646652"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="146646652" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1">PB6 = I2C SPEED <span class="nu0">2</span>
PB7 = I2C
reinit</pre></td></tr></table></div></td></tr></tbody></table></div>Активирует I2C на PB6/PB7 со скоростью 400кГц.<br />
<br />
Прием и передача данных производится при помощи команд <code class="inlinecode">iic</code>, <code class="inlinecode">iicread</code>, <code class="inlinecode">iicreadreg</code>. Командой <code class="inlinecode">iicscan</code> можно произвести поиск активных устройств на шине.<br />
Все данные вводятся и выводятся в двоичном формате без префикса, в том числе адрес и длина данных.<br />
<br />
<b><font size="2">SPI</font></b><br />
<br />
Доступен SPI на выводах PA5/PB3 (SCK), PA6/PB4 (MISO) и PA7/PB5 (MOSI).<br />
Не обязательно настраивать все три вывода, если вам нужна односторонняя передача данных.<br />
<br />
Ключевые слова:<ul><li><b>SPEED</b> — скорость, Гц, при настройке будет подобран актуальный делитель системной тактовой частоты, наиболее близкий к заданной скорости (не ожидайте получить скорость 30МГц при тактовой 48МГц),</li>
<li><b>CPOL</b> — полярность SCK (1 — высокий в неактивном состоянии),</li>
<li><b>CPHA</b> — фронт SCK на актуальный уровень сигнала (1 — второй фронт),</li>
<li><b>LSBFIRST</b> — передача первым младшего бита.</li>
</ul><br />
По умолчанию флаги CPOL/CPHA/LSBFIRST считаются равными нулю.<br />
<br />
Пример, последовательность команд:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="870281683"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="870281683" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1">PA5 = SPI SPEED <span class="nu0">2000000</span> CPOL CPHA
PA6 = SPI
PA7 = SPI
reinit</pre></td></tr></table></div></td></tr></tbody></table></div>настроит SPI на контактах PA5/PA6/PA7, скорость 2МГц, режим 3 (CPOL=CPHA=1), полный дуплекс.<br />
<br />
В режиме полного дуплекса сеттер <code class="inlinecode">SPI=...</code> передает перечисленные после знака &quot;равно&quot; данные (в шестнадцатеричном формате без разделителя) и принимает такое же количество данных. Принятые данные будут выведены после завершения операции в виде <code class="inlinecode">SPI = ...</code>.<br />
<br />
В RX-only режиме (т.е. когда не сконфигурирован вывод MOSI), формат геттера другой: <code class="inlinecode">SPI = datalen</code>, где указывается количество байт для считывания (<b>в любом формате</b> числа!). Например, <code class="inlinecode">SPI = 0x10</code> считает 16 байт данных, равно как и <code class="inlinecode">SPI=16</code>, <code class="inlinecode">SPI = 020</code> или <code class="inlinecode">SPI=b10000</code>.<br />
<br />
<b><font size="2">ШИМ (PWM)</font></b><br />
<br />
Доступные для работы в режиме ШИМ выводы можно отобразить запросом <code class="inlinecode">pwmmap</code> или <code class="inlinecode">pinout=PWM</code>. При настройке новых режимов командой <code class="inlinecode">reinit</code> будет проведен анализ конфликтов, поэтому в случае выбора ШИМ на конфликтующих контактах (т.е. если один и тот же канал одного и того же таймера выбран в качестве ШИМ-выхода на разных контактах) будет отображено сообщение об ошибке со сбросом конфликтов в значение по умолчанию.<br />
<br />
Для конфигурации никаких дополнительных параметров указывать не нужно, лишь <code class="inlinecode">PXx = PWM</code>. Сеттер позволяет установить требуемое заполнение (0..255), а геттер указывает текущее.<br />
Например,<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="903524091"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="903524091" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1">PA1 = PWM
reinit
PA1=<span class="nu0">128</span></pre></td></tr></table></div></td></tr></tbody></table></div>установит PA1 в ШИМ-режим с заполнением 50%. Частота ШИМ фиксирована: около 23.5 кГц и настройке не подлежит.<br />
<br />
<br />
<b><font size="3">Асинхронный мониторинг</font></b><br />
<br />
При указании флага <code class="inlinecode">MONITOR</code> в настройке контакта в случае, если выбранная функция это поддерживает, по USB будут выдаваться сообщения с новыми данными на этом контакте вне зависимости от запроса пользователя.<br />
<br />
Для входа или выхода с открытым стоком изменение значения будет отображаться, как, например <code class="inlinecode">PB3 = 1</code> при смене низкого уровня сигнала на высокий.<br />
<br />
В случае входа АЦП дополнительным параметром <code class="inlinecode">THRESHOLD</code> задается пороговое значение: если уровень сигнала на входе отличается от предыдущего больше, чем на это пороговое значение, будет выведено соответствующее сообщение, например <code class="inlinecode">PA1 = 3456</code>.<br />
<br />
Также &quot;мониторинг&quot; доступен для асинхронного отображения входящих по USART сообщений (в текстовом режиме данные выводятся построчно, в &quot;hex&quot; — с буферизацией по блокам, разделенным IDLE). Если режим мониторинга отключен, то пользователь должен регулярными вызовами геттера <code class="inlinecode">USART</code> считывать пришедшие данные из кольцевого буфера. В случае переполнения буфера он будет автоматически очищаться, а имеющаяся в нем информация — асинхронно передаваться пользователю.<br />
<br />
Интерфейсы I2C и SPI работают исключительно с блокирующими операциями, поэтому флаг мониторинга к ним не применим.<br />
<br />
<br />
<b><font size="3">Сохранение настроек</font></b><br />
<br />
Если вы окончательно настроили все интерфейсы и контакты, и хотите, чтобы при следующем включении устройство было сконфигурировано точно так же, сохраните настройки во флеш-память при помощи команды <code class="inlinecode">saveconf</code>. Если произойдет ошибка сохранения, попробуйте стереть весь отведенный под хранение настроек блок данных при помощи <code class="inlinecode">eraseflash</code>, а затем сохранить снова.<br />
<br />
При включении устройства МК автоматически загружает последние сохраненные настройки, пользуясь бинарным поиском (что позволяет не тратить слишком много времени на перебор всего объема доступного хранилища, хотя, конечно, для STM32F042 это неактуально).<br />
<br />
Настройки во флеш-памяти хранятся последовательно. При достижении последней записи в отведенном регионе (все незанятые блоки флеш-памяти после микрокода устройства), стирается все хранилище, а затем новая запись пишется первой. В такие моменты будьте осторожными, т.к. сбой питания может повредить настройки, и их придется выставлять заново.<br />
<br />
<br />
<b><font size="3">Внутренние коды ошибок</font></b><br />
<br />
Часть сеттеров, не возвращающих в свою очередь геттеры, выдает следующие коды ошибок:<ul><li><b>OK</b> – Выполнение команды прошло успешно.</li>
<li><b>BADCMD</b> – Введена неправильная команда.</li>
<li><b>BADPAR</b> – Неправильный параметр команды (например, номер контакта вне диапазона 0..15).</li>
<li><b>BADVAL</b> – Неправильное значение сеттера (например, вы ошиблись в написании ключевого слова или ввели неверную скорость и т.п.).</li>
<li><b>WRONGLEN</b> – Неправильная длина сообщения (слишком большое или нулевой длины).</li>
<li><b>CANTRUN</b> – Ошибка выполнения команды (например, при отсутствии на шине I2C устройства с идентификатором, в который пытаются отправить данные).</li>
<li><b>BUSY</b> – Попробуйте вызвать команду позже (актуально лишь для USART: если вы попытаетесь послать следующее сообщение, пока еще не передано предыдущее).</li>
<li><b>OVERFLOW</b> – Переполнение длины входного буфера.</li>
</ul><br />
Некоторые команды не возвращают вообще ничего (например, геттер <code class="inlinecode">USART</code>, если в буфере ничего нет). По запросу геттеров выводится имя команды и данные после знака &quot;равно&quot;.<br />
<br />
<br />
<b><font size="3">Как различать несколько одинаковых подключенных устройств</font></b><br />
<br />
Данное устройство представляет собой &quot;составное устройство USB&quot;, состоящее из двух CDC-ACM интерфейсов. Поэтому по умолчанию при его включении в <code class="inlinecode">/dev</code> вы увидите появление устройств <code class="inlinecode">/dev/ttyACMx</code> и <code class="inlinecode">/dev/ttyACM(x+1)</code> (где x зависит от количества уже подключенных устройств). Чтобы различать интерфейсы (особенно если вы включили несколько одинаковых таких преобразователей CAN-USB-GPIO), в USB-дескрипторах сохраняются символьные имена для соответствующих полей <code class="inlinecode">iInterface</code>. Изменить их вы можете при помощи команды <code class="inlinecode">setiface</code>.<br />
<br />
В терминале при помощи <code class="inlinecode">lsusb -v</code> можно увидеть эти поля.<br />
Т.к. при подключении USB-устройств udev может &quot;перехватить&quot; их и выполнить какие-то действия, приведенный скрипт поможет создавать человекочитаемые симлинки.<br />
<br />
Например, если вы задаете интерфейсам названия «myCAN» и «myGPIO» и сохраняете конфигурацию во флеш-памяти МК, после переподключения устройства вы увидите симлинки: <code class="inlinecode">/dev/ttymyCAN0</code> и <code class="inlinecode">/dev/ttymyGPIO0</code>, что позволит быстро их отождествить (особенно это актуально для служб, запускаемых при старте системы).<br />
<br />
Просто добавьте этот файл в <code class="inlinecode">/etc/udev/rules.d</code>:<br />
<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="290310959"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="290310959" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1">ACTION==&quot;add&quot;, DRIVERS==&quot;usb&quot;, ENV<span class="br0">&#123;</span>USB_IDS<span class="br0">&#125;</span>=&quot;%s<span class="br0">&#123;</span>idVendor<span class="br0">&#125;</span>:%s<span class="br0">&#123;</span>idProduct<span class="br0">&#125;</span>&quot;
ACTION==&quot;add&quot;, ENV<span class="br0">&#123;</span>USB_IDS<span class="br0">&#125;</span>==&quot;067b:<span class="nu0">2303</span>&quot;, ATTRS<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>==&quot;?*&quot;, PROGRAM=&quot;/bin/bash -c \&quot;ls /dev | grep $attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span> | wc -l \&quot;&quot;, SYMLINK+=&quot;$attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>%c&quot;, MODE=&quot;0666&quot;, GROUP=&quot;tty&quot;
ACTION==&quot;add&quot;, ENV<span class="br0">&#123;</span>USB_IDS<span class="br0">&#125;</span>==&quot;0483:<span class="nu0">5740</span>&quot;, ATTRS<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>==&quot;?*&quot;, PROGRAM=&quot;/bin/bash -c \&quot;ls /dev | grep $attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span> | wc -l \&quot;&quot;, SYMLINK+=&quot;$attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>%c&quot;, MODE=&quot;0666&quot;, GROUP=&quot;tty&quot;</pre></td></tr></table></div></td></tr></tbody></table></div></div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11798&amp;d=1773955834" target="attachment" rel="Lightbox" id="attachment11798"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11798&amp;stc=1&amp;thumb=1&amp;d=1773955834" border="0" alt="Нажмите на изображение для увеличения
Название: IMG_20260319_182839.jpg
Просмотров: 721
Размер:	66.0 Кб
ID:	11798" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/10816.html</guid>
		</item>
		<item>
			<title><![CDATA[Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI]]></title>
			<link>https://www.cyberforum.ru/blogs/1886385/10792.html</link>
			<pubDate>Wed, 18 Feb 2026 20:22:31 GMT</pubDate>
			<description><![CDATA[Постепенно допиливаю свою "многоинтерфейсную плату"...]]></description>
			<content:encoded><![CDATA[<div>Постепенно допиливаю свою <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/stm32samples/tree/master/F3%3AF303/InterfaceBoard" target="_blank" title="https://github.com/eddyem/stm32samples/tree/master/F3%3AF303/InterfaceBoard">&quot;многоинтерфейсную плату&quot;</a>. Выглядит вот так:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11617 tc=1&amp;d=1771445347" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Основана на STM32F303RBT6.<br />
На борту пять последовательных интерфейсов (три RS-485, два RS-232, один CAN и один SSI; перемычками можно последний 232 вместо SPI подключить к выходу на датчик, будет RS-422 с нестандартной распиновкой DB9). Все интерфейсы гальванически развязаны.<br />
Вчера закончил отладку последовательных. Проверял на китайском &quot;свистке&quot; на основе CH340, поэтому быстрей 2Мбод скорость не вышло установить.<br />
Пока тестировал 485, после того, как проверил 232, заметил, что MAX3232 сильно греется. Похоже, опять достался &quot;паленый&quot; чип с алиэкспресса (я на такие уже натыкался): чуть поработает, потом &quot;уходит в себя&quot; и перегревается. Жрет столько, что даже DC-DC нагрелась. Перепаяю, может другой чип будет получше.<br />
Т.к. ISOxxxx на 232 я не нашел, то сделал проще: развязал обычными оптопарами (H11L1) сигналы U[S]ARTов, а дальше уже их отправил на MAX3232.<br />
Сегодня добавил CAN, но еще не отладил. У него свой, &quot;стандартный&quot; для меня протокол. Легким движением руки он может быть переделан под протокол, который понимает &quot;can festival&quot;. Но у меня уже столько железок на моем протоколе работает, что менять не хочу.<br />
На плате есть перемычка &quot;Config mode&quot;. Если ее снять, то при включении последний интерфейс (SSI) станет конфигурационным интерфейсом, и можно выполнить кое-какие настройки. Пока настроек немного: скорость CAN по умолчанию, да названия USB интерфейсов (поля iInterface). Простой udev-скрипт позволяет различать интерфейсы при подключении:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="858623866"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="858623866" style="height: 78px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
</pre></td><td class="de1"><pre class="de1">ACTION==&quot;add&quot;, DRIVERS==&quot;usb&quot;, ENV<span class="br0">&#123;</span>USB_IDS<span class="br0">&#125;</span>=&quot;%s<span class="br0">&#123;</span>idVendor<span class="br0">&#125;</span>:%s<span class="br0">&#123;</span>idProduct<span class="br0">&#125;</span>&quot;
ACTION==&quot;add&quot;, ENV<span class="br0">&#123;</span>USB_IDS<span class="br0">&#125;</span>==&quot;067b:<span class="nu0">2303</span>&quot;, ATTRS<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>==&quot;?*&quot;, PROGRAM=&quot;/bin/bash -c \&quot;ls /dev | grep $attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span> | wc -l \&quot;&quot;, SYMLINK+=&quot;$attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>%c&quot;, MODE=&quot;0666&quot;, GROUP=&quot;tty&quot;
ACTION==&quot;add&quot;, ENV<span class="br0">&#123;</span>USB_IDS<span class="br0">&#125;</span>==&quot;0483:<span class="nu0">5740</span>&quot;, ATTRS<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>==&quot;?*&quot;, PROGRAM=&quot;/bin/bash -c \&quot;ls /dev | grep $attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span> | wc -l \&quot;&quot;, SYMLINK+=&quot;$attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>%c&quot;, MODE=&quot;0666&quot;, GROUP=&quot;tty&quot;</pre></td></tr></table></div></td></tr></tbody></table></div>По умолчанию это /dev/usbserialX.x (X - индекс интерфейса, от 0 до 4, x - номер подключенного устройства, если их несколько), /dev/usbSPIx и /dev/usbCANx. Настройки сохраняются во флеш-памяти МК (эмуляция EEPROM).<br />
При сборке в отладочном режиме в &quot;конфигурационный интерфейс&quot; еще и сыплется весь отладочный выхлоп. <br />
Пока что размер бинарника - 17кБ.<br />
Код для USB-CDC практически полностью мой. Никаких калокубов, естественно, не использую. Предельная скорость USB около 6-7Мбод (таки еще и МК должен успевать что-то делать). По идее, если сделать двойную буферизацию, скорость можно увеличить. Но пока и так сойдет.</div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11617&amp;d=1771445346" target="attachment" rel="Lightbox" id="attachment11617"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11617&amp;stc=1&amp;thumb=1&amp;d=1771445346" border="0" alt="Нажмите на изображение для увеличения
Название: board.jpg
Просмотров: 10596
Размер:	254.4 Кб
ID:	11617" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/10792.html</guid>
		</item>
		<item>
			<title>Камера Toupcam IUA500KMA</title>
			<link>https://www.cyberforum.ru/blogs/1886385/10761.html</link>
			<pubDate>Thu, 12 Feb 2026 15:20:31 GMT</pubDate>
			<description><![CDATA[Т.к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо...]]></description>
			<content:encoded><![CDATA[<div>Т.к. у всяких &quot;хикроботов&quot; слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше), натянув gain по самое не балуйся (в итоге получаем изображение с SNR порядка единицы). Приобрели эту камеру для замены.<br />
В течение недели занимаюсь ее внедрением в <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/CCD_Capture" target="_blank" title="https://github.com/eddyem/CCD_Capture">мою ccd_capture</a> (потом &quot;обобщу&quot; и добавлю в старую версию автогида, которая уже давно deprecated, но нечем заменить, т.к. <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/astrovideoguideNG" target="_blank" title="https://github.com/eddyem/astrovideoguideNG">новую</a> на основе ccd_capture мне пилить некогда).<br />
У камеры разрешение 800×600, зато аж 16-микронный пиксель! Понятно, что для БТА по-хорошему нужно минимум 50мкм, но и так уже лучше, чем стандартные 3-3.5мкм.<br />
Как обычно бывает у китайцев, документации на SDK с гулькин нос, а сама SDK — в виде бинарного so-шника и header-файла. Были бы исходники библиотеки или нормальная документация, не пришлось бы наугад дергать все &quot;подвижки&quot;, пытаясь понять, как эту заразу оптимально работать заставить. <br />
Как пример: казалось бы, запускаем экспозицию одного кадра при помощи <code class="inlinecode">Toupcam_Trigger(toupcam.hcam, 1)</code>, а как получаем — запускаем следующий из последовательности. А вот фиг вам! При таком подходе на экспозиции в 10мс получаем фреймрейт всего-то в 10 кадров в секунду! Опытным путем выяснил, что число туда побольше нужно. Вот так: <code class="inlinecode">Toupcam_Trigger(toupcam.hcam, 100)</code> выдает уже около 30 кадров в секунду (увеличение значения уже не меняет фреймрейт).<br />
В свойствах нет управления температурой светоприемника, но есть получение текущей температуры. Вот только вызов функции заканчивается ошибкой…<br />
Никакой документации с кривой квантовой эффективности не нашел. Благо, на астрофоруме подкинули (как ни странно, с фашистского сайта — то-то я ее скачать не мог!). У нее оказалась на удивление классная кривая, и даже на 200нм порядка 35% эффективности, да и в ближнем ИК до 1100нм…<br />
С gain непонятная история: вроде в свойствах указано, что 1..16, а де-факто — 1..8 (как и следует из документации). Фактически же, значения gain вообще непонятные. И на gain=8 средний уровень сигнала всего лишь в три раза выше, чем на gain=1. Маловато будет!!! Ожидал хотя бы тысячу раз! У CMOS принято gain в логарифмической шкале измерять.<br />
Еще, на малых экспозициях вылезает вот такая гадость:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11548 tc=1&amp;d=1770909551" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Когда запустил непосредственный просмотр и &quot;бесконечную молотилку&quot; (как видео), увидел, что эти полосы ползут. Т.е. коррекцией на плоское поле &quot;не лечатся&quot;. Посоветовали отдельный источник питания на 12В подключить, но у нас нет такого разъема и я даже без понятия, как его на алиэкспрессе искать.<br />
Ну, да ладно. Зато нашел несколько багов в своей ccd_capture. Главное — чтобы их исправление не помешало работе с другими камерами (где я вполне мог эти баги как &quot;фичи&quot; использовать).<br />
Как ни появится новая камера, все в общую структуру (в С++ это назвали бы классом) с указателями на функции и свойства камеры норовлю что-то новое добавить. А следствием таких действий является коррекция всех модулей для остальных поддерживаемых камер (Apogee, Basler, FLI, Grasshopper, Hikrobot, Toupcam и ZWO). А поди-ка отладь в таких случаях код, когда под рукой всего набора камер нет!</div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11548&amp;d=1770909551" target="attachment" rel="Lightbox" id="attachment11548"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11548&amp;stc=1&amp;thumb=1&amp;d=1770909551" border="0" alt="Нажмите на изображение для увеличения
Название: toupcam.jpg
Просмотров: 3760
Размер:	111.8 Кб
ID:	11548" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/10761.html</guid>
		</item>
		<item>
			<title>Сравнение датчиков влажности-температуры-давления на шине I2C</title>
			<link>https://www.cyberforum.ru/blogs/1886385/10625.html</link>
			<pubDate>Tue, 14 Oct 2025 13:21:33 GMT</pubDate>
			<description><![CDATA[Накопилось у меня уже прилично всяких датчиков, вот и решил собрать "стенд", чтобы проверить их....]]></description>
			<content:encoded><![CDATA[<div>Накопилось у меня уже прилично всяких датчиков, вот и решил собрать &quot;стенд&quot;, чтобы проверить их. Пока датчики не все: еще с десяток едет с алиэкспресса, но пока опишу в общих чертах суть эксперимента.<br />
Т.к. городить на МК монстра мне совершенно не хочется, я подключил датчики непосредственно к компьютеру через преобразователь на основе CP2112. При этом появляется HID-устройство:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="50058368"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="50058368" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1"><span class="br0">&#91;</span> &nbsp;<span class="nu0">426.027327</span><span class="br0">&#93;</span> cp2112 0003:10C4:EA90.0006: hidraw5: USB HID v1.01 Device <span class="br0">&#91;</span>Silicon Laboratories CP2112 HID USB-to-SMBus Bridge<span class="br0">&#93;</span> on usb-0000:00:<span class="nu0">14.0</span>-<span class="nu0">11</span>/input0
<span class="br0">&#91;</span> &nbsp;<span class="nu0">426.079303</span><span class="br0">&#93;</span> cp2112 0003:10C4:EA90.0006: Part Number: 0x0C Device Version: 0x02</pre></td></tr></table></div></td></tr></tbody></table></div>Чтобы оно заработало, нужно иметь поддержку CP2112 в ядре или в виде отдельного модуля <code class="inlinecode">hid_cp2112</code> (руками его грузить не нужно, т.к. все связанное с plug-and-play уже давным-давно обслуживается udev'ом). <br />
Но у датчиков есть неудобная особенность: очень многие имеют один и тот же адрес, причем зачастую не имеют никаких средств его смены (только у некоторых можно поменять 1-3 младших бита адреса). Поэтому нам понадобится еще и мультиплексор на основе PCA9548a. Ну и небольшая &quot;беспаечная макетка&quot; + источник питания.<br />
Вот так это сейчас выглядит:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11286 tc=1&amp;d=1760446934" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Для часть имеющихся у меня датчиков я уже писал код или под STM32, или под Orange Pi Zero 2 (второй удобней, т.к. его можно вообще почти без изменений использовать).<br />
Набросал тестовую утилитку для работы с датчиками по-одиночке, которая в итоге превратилась в <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/eddys_snippets/tree/master/I2Csensors" target="_blank" title="https://github.com/eddyem/eddys_snippets/tree/master/I2Csensors">библиотеку</a>. Файл для работы по-одиночке я превратил в один из примеров использования библиотеки. Вторым примером как раз написал работу с этими датчиками на макетке (напомню, это еще не все: как через 2-3 недели подъедут оставшиеся датчики, проведу более расширенный тест).<br />
Для простоты перечисления имеющихся датчиков и их адресов в портах мультиплексора, <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/eddys_snippets/blob/master/I2Csensors/examples/logmany.c#L73" target="_blank" title="https://github.com/eddyem/eddys_snippets/blob/master/I2Csensors/examples/logmany.c#L73">сделал так</a>:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="917229237"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="917229237" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="de1"><pre class="de1"><span class="kw4">typedef</span> <span class="kw4">struct</span><span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">const</span> <span class="kw4">char</span> <span class="sy0">*</span>name<span class="sy0">;</span> &nbsp; <span class="co1">// name - for header in log</span>
&nbsp; &nbsp; <span class="kw4">const</span> <span class="kw4">char</span> <span class="sy0">*</span>type<span class="sy0">;</span> &nbsp; <span class="co1">// sensor's name for `sensor_new`</span>
&nbsp; &nbsp; <span class="kw4">uint8_t</span> nch<span class="sy0">;</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="co1">// channel number</span>
&nbsp; &nbsp; <span class="kw4">uint8_t</span> address<span class="sy0">;</span> &nbsp; &nbsp;<span class="co1">// address (0 for default)</span>
&nbsp; &nbsp; sensor_t <span class="sy0">*</span>sensor<span class="sy0">;</span> &nbsp; <span class="co1">// pointer to sensor itself</span>
<span class="br0">&#125;</span> sd_t<span class="sy0">;</span>
&nbsp;
<span class="co1">// amount of all sensors connected</span>
<span class="co2">#define SENSORS_AMOUNT &nbsp;8</span>
&nbsp; &nbsp; 
<span class="co1">// list of sensors - must be sorted by channel number</span>
<span class="kw4">static</span> sd_t all_sensors<span class="br0">&#91;</span>SENSORS_AMOUNT<span class="br0">&#93;</span> <span class="sy0">=</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>.<span class="me1">name</span> <span class="sy0">=</span> <span class="st0">&quot;AHT15&quot;</span><span class="sy0">,</span> .<span class="me1">type</span> <span class="sy0">=</span> <span class="st0">&quot;AHT15&quot;</span><span class="sy0">,</span> .<span class="me1">nch</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>.<span class="me1">name</span> <span class="sy0">=</span> <span class="st0">&quot;SI7005&quot;</span><span class="sy0">,</span> .<span class="me1">type</span> <span class="sy0">=</span> <span class="st0">&quot;SI7005&quot;</span><span class="sy0">,</span> .<span class="me1">nch</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>.<span class="me1">name</span> <span class="sy0">=</span> <span class="st0">&quot;AHT10&quot;</span><span class="sy0">,</span> .<span class="me1">type</span> <span class="sy0">=</span> <span class="st0">&quot;AHT10&quot;</span><span class="sy0">,</span> .<span class="me1">nch</span> <span class="sy0">=</span> <span class="nu0">1</span><span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>.<span class="me1">name</span> <span class="sy0">=</span> <span class="st0">&quot;BMP180&quot;</span><span class="sy0">,</span> .<span class="me1">type</span> <span class="sy0">=</span> <span class="st0">&quot;BMP180&quot;</span><span class="sy0">,</span> .<span class="me1">nch</span> <span class="sy0">=</span> <span class="nu0">1</span><span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>.<span class="me1">name</span> <span class="sy0">=</span> <span class="st0">&quot;BME280a&quot;</span><span class="sy0">,</span> .<span class="me1">type</span> <span class="sy0">=</span> <span class="st0">&quot;BME280&quot;</span><span class="sy0">,</span> .<span class="me1">nch</span> <span class="sy0">=</span> <span class="nu0">1</span><span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>.<span class="me1">name</span> <span class="sy0">=</span> <span class="st0">&quot;BME280b&quot;</span><span class="sy0">,</span> .<span class="me1">type</span> <span class="sy0">=</span> <span class="st0">&quot;BME280&quot;</span><span class="sy0">,</span> .<span class="me1">nch</span> <span class="sy0">=</span> <span class="nu0">2</span><span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>.<span class="me1">name</span> <span class="sy0">=</span> <span class="st0">&quot;AHT21b&quot;</span><span class="sy0">,</span> .<span class="me1">type</span> <span class="sy0">=</span> <span class="st0">&quot;AHT21&quot;</span><span class="sy0">,</span> .<span class="me1">nch</span> <span class="sy0">=</span> <span class="nu0">2</span><span class="br0">&#125;</span><span class="sy0">,</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>.<span class="me1">name</span> <span class="sy0">=</span> <span class="st0">&quot;SHT30&quot;</span><span class="sy0">,</span> .<span class="me1">type</span> <span class="sy0">=</span> <span class="st0">&quot;SHT3x&quot;</span><span class="sy0">,</span> .<span class="me1">nch</span> <span class="sy0">=</span> <span class="nu0">2</span><span class="br0">&#125;</span><span class="sy0">,</span>
<span class="br0">&#125;</span><span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Поле name — условное название датчика, которое будет фигурировать в шапке лога, type — тип (по которому датчик ищется в библиотеке), nch - номер канала мультиплексора (<b>номер бита</b>), address - адрес I2C устройства (если изменен с &quot;умолчательного&quot;), sensor - указатель на сам датчик после обнаружения его библиотекой.<br />
Параметры командной строки минимальные:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="7059723"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="7059723" style="height: 158px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
</pre></td><td class="de1"><pre class="de1">&nbsp; -H, --hlog=arg &nbsp; &nbsp; &nbsp; humidity logging file
&nbsp; -P, --plog=arg &nbsp; &nbsp; &nbsp; pressure logging file
&nbsp; -T, --tlog=arg &nbsp; &nbsp; &nbsp; temperature logging file
&nbsp; -a, --muladdr=arg &nbsp; &nbsp;multiplexer I2C address
&nbsp; -d, --device=arg &nbsp; &nbsp; I2C device path
&nbsp; -h, --help &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; show this help
&nbsp; -i, --interval=arg &nbsp; logging interval, seconds <span class="br0">&#40;</span>default: <span class="nu0">10</span><span class="br0">&#41;</span>
&nbsp; -m, --presmm &nbsp; &nbsp; &nbsp; &nbsp; pressure in mmHg instead of hPa</pre></td></tr></table></div></td></tr></tbody></table></div>Первые результаты достаточно странные. Приведу выжимку из лог-файлов (запустил у себя на столе, поэтому пока от них немного смысла; как будут все датчики, положу эту плату в подкупольное одного из наших малых телескопов: там все параметры достаточно хорошо меняются, разве что влажность выше 85% при закрытом куполе не должна доходить — осушитель не даст).<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="4849656"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="4849656" style="height: 142px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
</pre></td><td class="de1"><pre class="de1"># Temperature, degC
AHT15 &nbsp; SI7005 &nbsp;AHT10 &nbsp; BMP180 &nbsp;BME280a BME280b AHT21b &nbsp;SHT30
<span class="nu0">23.37</span> &nbsp; <span class="nu0">22.94</span> &nbsp; <span class="nu0">23.36</span> &nbsp; <span class="nu0">22.84</span> &nbsp; <span class="nu0">23.25</span> &nbsp; <span class="nu0">24.14</span> &nbsp; <span class="nu0">23.40</span> &nbsp; <span class="nu0">23.77</span>
<span class="nu0">23.33</span> &nbsp; <span class="nu0">22.94</span> &nbsp; <span class="nu0">23.39</span> &nbsp; <span class="nu0">22.86</span> &nbsp; <span class="nu0">23.26</span> &nbsp; <span class="nu0">24.06</span> &nbsp; <span class="nu0">23.36</span> &nbsp; <span class="nu0">23.71</span>
<span class="nu0">23.35</span> &nbsp; <span class="nu0">46.12</span> &nbsp; <span class="nu0">23.38</span> &nbsp; <span class="nu0">22.87</span> &nbsp; <span class="nu0">23.26</span> &nbsp; <span class="nu0">24.06</span> &nbsp; <span class="nu0">23.37</span> &nbsp; <span class="nu0">23.73</span>
<span class="nu0">23.33</span> &nbsp; <span class="nu0">23.00</span> &nbsp; <span class="nu0">23.44</span> &nbsp; <span class="nu0">22.95</span> &nbsp; <span class="nu0">23.31</span> &nbsp; <span class="nu0">24.03</span> &nbsp; <span class="nu0">23.41</span> &nbsp; <span class="nu0">23.73</span>
<span class="nu0">23.31</span> &nbsp; <span class="nu0">198.12</span> &nbsp;<span class="nu0">23.45</span> &nbsp; <span class="nu0">22.93</span> &nbsp; <span class="nu0">23.31</span> &nbsp; <span class="nu0">24.02</span> &nbsp; <span class="nu0">23.37</span> &nbsp; <span class="nu0">23.73</span></pre></td></tr></table></div></td></tr></tbody></table></div><div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="446256382"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="446256382" style="height: 142px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
</pre></td><td class="de1"><pre class="de1"># Pressure, hPa
BMP180 &nbsp;BME280a BME280b
<span class="nu0">878.60</span> &nbsp;<span class="nu0">877.52</span> &nbsp;<span class="nu0">878.20</span>
<span class="nu0">878.58</span> &nbsp;<span class="nu0">877.52</span> &nbsp;<span class="nu0">878.19</span>
<span class="nu0">878.56</span> &nbsp;<span class="nu0">877.52</span> &nbsp;<span class="nu0">878.19</span>
<span class="nu0">878.53</span> &nbsp;<span class="nu0">877.52</span> &nbsp;<span class="nu0">878.19</span>
<span class="nu0">878.52</span> &nbsp;<span class="nu0">877.50</span> &nbsp;<span class="nu0">878.18</span></pre></td></tr></table></div></td></tr></tbody></table></div><div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="6809951"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="6809951" style="height: 142px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
</pre></td><td class="de1"><pre class="de1"># Humidity, percent
AHT15 &nbsp; SI7005 &nbsp;AHT10 &nbsp; BME280a BME280b AHT21b &nbsp;SHT30
<span class="nu0">70.11</span> &nbsp; <span class="nu0">82.93</span> &nbsp; <span class="nu0">71.85</span> &nbsp; <span class="nu0">64.97</span> &nbsp; <span class="nu0">67.84</span> &nbsp; <span class="nu0">74.71</span> &nbsp; <span class="nu0">69.72</span>
<span class="nu0">67.79</span> &nbsp; <span class="nu0">83.08</span> &nbsp; <span class="nu0">69.87</span> &nbsp; <span class="nu0">64.05</span> &nbsp; <span class="nu0">66.84</span> &nbsp; <span class="nu0">72.89</span> &nbsp; <span class="nu0">68.17</span>
<span class="nu0">67.95</span> &nbsp; <span class="nu0">12.84</span> &nbsp; <span class="nu0">69.95</span> &nbsp; <span class="nu0">64.10</span> &nbsp; <span class="nu0">66.85</span> &nbsp; <span class="nu0">73.05</span> &nbsp; <span class="nu0">68.28</span>
<span class="nu0">67.17</span> &nbsp; <span class="nu0">83.00</span> &nbsp; <span class="nu0">69.50</span> &nbsp; <span class="nu0">63.70</span> &nbsp; <span class="nu0">66.71</span> &nbsp; <span class="nu0">72.51</span> &nbsp; <span class="nu0">68.04</span>
<span class="nu0">67.28</span> &nbsp; <span class="nu0">9.83</span> &nbsp; &nbsp;<span class="nu0">69.56</span> &nbsp; <span class="nu0">63.72</span> &nbsp; <span class="nu0">66.78</span> &nbsp; <span class="nu0">72.46</span> &nbsp; <span class="nu0">67.99</span></pre></td></tr></table></div></td></tr></tbody></table></div>(я забыл добавить последним столбцом время; сделаю это позже).<br />
<br />
Видно, что SI7005 периодически &quot;выкаблучивается&quot;, выдавая неправильные данные (в среднем один раз на 20-25 измерений), да еще и по влажности сильно выбивается от остальных.<br />
По температуры &quot;каждый в своей поре&quot;. И даже BME280, которые я считал точными, выдают примерно на 0.7% различающиеся показания.<br />
По давлению тоже как-то вразнобой, но хотя бы в ±0.5гПа укладываются.<br />
<br />
Для калибровки нужны нормальные тарированные психрометр и барометр. Платиновые термодатчики у меня есть, при измерении сразу по трем-пяти точность вполне приличная получается (порядка ±0.1℃). Надеюсь, на БТА можно будет найти советские приборы и попробовать сравнить датчики на точность показаний. Жаль только, для дистанционной записи показаний придется на эти приборы навести видеокамеру и вручную записывать (лень заниматься изготовлением калибровочных приборов самому, да и ртуть для барометра, боюсь, я вряд ли где достану сейчас, а ее хотя бы с поллитра надо).<br />
<br />
P.S. более-менее подробные сравнения датчиков в интернете уже делали, например <a rel="nofollow noopener noreferrer" href="https://www.kandrsmith.org/RJS/Misc/Hygrometers/calib_many.html" target="_blank" title="https://www.kandrsmith.org/RJS/Misc/Hygrometers/calib_many.html">это</a> или <a rel="nofollow noopener noreferrer" href="https://forum.arduino.cc/t/compare-different-i2c-temperature-and-humidity-sensors-sht2x-sht3x-sht85/599609" target="_blank" title="https://forum.arduino.cc/t/compare-different-i2c-temperature-and-humidity-sensors-sht2x-sht3x-sht85/599609">это</a>. <br />
А я решил повторить, заодно написать код для поддержки всех этих датчиков (все равно пригодится).</div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11286&amp;d=1760446934" target="attachment" rel="Lightbox" id="attachment11286"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=11286&amp;stc=1&amp;thumb=1&amp;d=1760446934" border="0" alt="Нажмите на изображение для увеличения
Название: IMG_20251014_160036.jpg
Просмотров: 1816
Размер:	190.8 Кб
ID:	11286" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/10625.html</guid>
		</item>
		<item>
			<title>Многоканальный ИК-болометр на MLX90640</title>
			<link>https://www.cyberforum.ru/blogs/1886385/10596.html</link>
			<pubDate>Thu, 25 Sep 2025 13:35:22 GMT</pubDate>
			<description><![CDATA[Постепенно дошел до "пре-альфы", ссылка на код на гитхабе...]]></description>
			<content:encoded><![CDATA[<div>Постепенно дошел до &quot;пре-альфы&quot;, <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/stm32samples/tree/master/F3%3AF303/MLX90640multi" target="_blank" title="https://github.com/eddyem/stm32samples/tree/master/F3%3AF303/MLX90640multi">ссылка на код на гитхабе</a>.<br />
В release-сборке вполне себе скромненько потребляет:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="725698654"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="725698654" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1">Memory region &nbsp; &nbsp; &nbsp; &nbsp; Used Size &nbsp;Region Size &nbsp;%age Used
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rom: &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">16</span> KB &nbsp; &nbsp; &nbsp; <span class="nu0">128</span> KB &nbsp; &nbsp; <span class="nu0">12.50</span>%
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ram: &nbsp; &nbsp; &nbsp; <span class="nu0">33680</span> B &nbsp; &nbsp; &nbsp; &nbsp;<span class="nu0">40</span> KB &nbsp; &nbsp; <span class="nu0">82.23</span>%
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ccmram: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="nu0">0</span> GB &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">8</span> KB &nbsp; &nbsp; &nbsp;<span class="nu0">0.00</span>%</pre></td></tr></table></div></td></tr></tbody></table></div>Самыми жирными являются imdata+confdata в mlxproc.c (16660 байт), да буфер изображения mlx_image (3072Б) с вычисленными параметрами params (10100Б) в mlx90640.c. Ну и килобайтный кольцевой буфер на отправку в USB. Жаль, нет каких-нибудь простых штатных средств, чтобы отсортировать переменные по потребляемой ОЗУ. Нашел лишь в интернете совет, как посмотреть размер на стадии компиляции (хотя, конечно, можно было бы и в gdb посмотреть):<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="406379989"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="406379989" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">char <span class="br0">&#40;</span>*__kaboom<span class="br0">&#41;</span><span class="br0">&#91;</span>sizeof<span class="br0">&#40;</span> confdata <span class="br0">&#41;</span><span class="br0">&#93;</span> = <span class="nu0">1</span>;</pre></td></tr></table></div></td></tr></tbody></table></div>(при сборке gcc ругается и пишет размер в байтах).<br />
Суммарно получилось где-то на 2.5кБ меньше, чем 33680Б. Вот и интересно, где собака порылась. Понятно, стек там неплохой, мелочь всякая локальная в куче, но таки не пара же килобайт? Может, где что завел временно, да забыл?<br />
<br />
Протокол символьный. Если ввести '?', 'h' или 'H', получим в терминале:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="803138163"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="803138163" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
</pre></td><td class="de1"><pre class="de1">https://github.com/eddyem/stm32samples/tree/master/F3:F303/MLX90640multi build#<span class="nu0">66</span> @ <span class="nu0">2025</span>-09-<span class="nu0">24</span>
&nbsp; &nbsp; management of single IR bolometer MLX90640
aa - change I2C address to a <span class="br0">&#40;</span>a should be non-shifted value!!!<span class="br0">&#41;</span>
c - continue MLX
dn - draw nth image in ASCII
gn - get nth image 'as is' - float array of 768x4 bytes
i0..<span class="nu0">4</span> - setup I2C with speed 10k, 100k, 400k, 1M or 2M <span class="br0">&#40;</span>experimental!<span class="br0">&#41;</span>
l - list active sensors IDs
tn - show temperature map of nth image
p - pause MLX
s - stop MLX <span class="br0">&#40;</span>and start from zero @ 'c'<span class="br0">&#41;</span>
tn - show nth image aquisition time
C - &quot;cartoon&quot; mode on/off <span class="br0">&#40;</span>show each new image<span class="br0">&#41;</span>
Dn - dump MLX parameters for sensor number n
G - get MLX state
Ia addr <span class="br0">&#91;</span>n<span class="br0">&#93;</span> - set &nbsp;device address for interactive work or <span class="br0">&#40;</span>with n<span class="br0">&#41;</span> change address of n'th sensor
Ir reg n - read n words from <span class="nu0">16</span>-bit register
Iw words - send words <span class="br0">&#40;</span>hex/dec/oct/bin<span class="br0">&#41;</span> to I2C
Is - scan I2C bus
T - print current Tms</pre></td></tr></table></div></td></tr></tbody></table></div>По USB эмулирую классический CDC. После подключения udev создает симлинк <code class="inlinecode">/dev/mlx_sensor0</code>. Все вспоминаю <b>COKPOWEHEU</b> добрым словом за идею &quot;маркировать&quot; разные устройства (а также интерфейсы в составном устройстве — как, скажем, в контроллере энкодеров астросибовской монтировки) при помощи простого правила udev — через поле iInterface.<br />
<br />
Когда у меня уже почти все заработало, нарвался натурально на stack overflow. Поначалу как-то миновало (но странно, почему: я в функцию запихнул стековую переменную размером 10100Б), а потом аукнулось. И эту структуру с пересчитанными коэффициентами я выделил отдельно на куче, а передавал в функции лишь ее адрес (или NULL в случае ошибки).<br />
<br />
Однако, таки поначалу я надеялся, что и 8 датчиков можно будет повесить на один STM32, а тут — вона как! 3332 байта на одно изображение, да куча всякой всячины. Сейчас остается 7280Б свободного места. Т.е. хватит еще два датчика добавить, а восьмой — уже некуда. Разве что придумать что-то.<br />
Кстати, можно сократить на 768Б структуру параметров, т.к. я не использую массив маркировок &quot;битых&quot; пикселей. Но это не спасет место, чтобы восьмой датчик впихнуть. Да и ладно: все равно для конкретного устройства нужно пять.<br />
<br />
Алгоритм работы простой: вначале производится сбор &quot;сырых&quot; данных калибровочных параметров каждого датчика. Далее собираются отэкспонированные изображения (&quot;подстраница 0&quot; пропускается, собираются лишь &quot;подстраницы  1&quot; - где и есть вся нужная информация) по мере накопления. Если пользователь запрашивает изображение, рассчитываются калибровочные коэффициенты (увы, вся структура 10100 байт занимает, поэтому для всех пяти уже вычисленные хранить негде; во флеш их засовывать не хочется, но, в принципе, это возможно), а затем обрабатываются данные с болометра и выдается в запрашиваемом формате (условная &quot;картинка&quot; в ASCII, температуры в строковом виде или массив в float little-endian). <br />
Из-за расчетов параметров время обработки одного изображения выросло с 8.5мс до 14мс, что совершенно не критично, т.к. изображения обычно на all-sky камерах меняются раз в 30-60 секунд.<br />
Пересылать на компьютер &quot;сырые&quot; данные и обрабатывать там не хочу, т.к. получится уже не самостоятельное устройство (пусть и не склеивает панорамы, но позволяет получать готовые кадры), а &quot;аппаратно-программный комплекс&quot;, что не очень хорошо.<br />
<br />
Из TODO на дописать/доработать:<br />
- управление питанием (отключать питание датчиков, если кто-то из них заблокирует SCL — а такое бывает иногда);<br />
- отсылку по RS-485 (железка будет на столбе висеть, до компьютера кабель метров 10-15);<br />
- эмуляцию проблем на шине (проверить: будет ли правильно отрабатывать включение/выключение питания и переход между состояниями КА);<br />
- добавить BME280 для определения параметров внешней среды;<br />
- добавить один-два NTC и управление мощным транзистором для подогрева корпуса (осушить в случае осадков или мороси);<br />
- нарисовать печатную плату и корпус;<br />
- изготовить и откалибровать по координатам - чтобы точно можно было &quot;склеить&quot; панораму из пяти снимков в один all-sky (калибровка, боюсь, будет самым длительным процессом).</div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/10596.html</guid>
		</item>
		<item>
			<title>Пытаюсь оптимизировать работу с MLX90640 на МК</title>
			<link>https://www.cyberforum.ru/blogs/1886385/10575.html</link>
			<pubDate>Thu, 11 Sep 2025 17:49:14 GMT</pubDate>
			<description>Я чуть ли не больше года назад начал было работу с этими датчиками. Весело реализовал по даташиту...</description>
			<content:encoded><![CDATA[<div>Я чуть ли не больше года назад начал было работу с этими датчиками. Весело реализовал по даташиту почти весь алгоритм обработки данных, но делал это на STM32F103. Как дошел до корней, понял, что вычисления затянутся очень надолго (ведь у этого МК нет FPU, да еще и тормоз он  - тот еще). Портировал код на &quot;апельсинку&quot; и заметил непонятные вещи: вычисляемые температуры вообще какими-то &quot;от балды&quot; были. Было много более важных дел, так что, забил я до поры до времени.<br />
А на этой неделе решил таки возобновить работу. Сначала взял предоставляемый melexis тестовый файл - для проверки своих &quot;библиотек&quot;. И сразу наткнулся на несоответствие, еще на этапе вычисления коэффициентов. Проверил по даташиту, нашел у себя три опечатки. После этого все заработало четко.<br />
Сегодня вечером перенес код на МК, так что теперь он заработал <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/stm32samples/tree/master/F3%3AF303/MLX90640test" target="_blank" title="https://github.com/eddyem/stm32samples/tree/master/F3%3AF303/MLX90640test">и на STM32F303CBT6</a>. Тесты занимают достаточно много места во флеше (да там еще и математическую библиотеку линковать пришлось ради sqrtf), так что вот:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="424243583"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="424243583" style="height: 94px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
</pre></td><td class="de1"><pre class="de1">Memory region &nbsp; &nbsp; &nbsp; &nbsp; Used Size &nbsp;Region Size &nbsp;%age Used
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rom: &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">30</span> KB &nbsp; &nbsp; &nbsp; <span class="nu0">128</span> KB &nbsp; &nbsp; <span class="nu0">23.44</span>%
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ram: &nbsp; &nbsp; &nbsp; &nbsp;<span class="nu0">5616</span> B &nbsp; &nbsp; &nbsp; &nbsp;<span class="nu0">40</span> KB &nbsp; &nbsp; <span class="nu0">13.71</span>%
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ccmram: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="nu0">0</span> GB &nbsp; &nbsp; &nbsp; &nbsp; <span class="nu0">8</span> KB &nbsp; &nbsp; &nbsp;<span class="nu0">0.00</span>%</pre></td></tr></table></div></td></tr></tbody></table></div>Чуть меньше четырех кБ флеша и 1кБ ОЗУ занимает USB с базовыми строковыми функциями. <br />
<br />
Конечная цель всей этой работы - инфракрасная allsky-камера, чтобы наш комплекс &quot;Астро-М&quot; (из пяти 0.5-м телескопов) наконец-то можно было по-человечески автоматизировать (пока что решение открыть телескоп для начала наблюдений принимает человек, а с этим allsky полностью все будет на совести компьютера). Как говорится, астроном спит - наблюдения идут. Предполагаю расположить 4-5 датчиков с полем 75°×110° так, чтобы захватывать всю полусферу неба (разве что ниже 10-15° над горизонтом не обязательно: там все равно наблюдения не ведутся).<br />
<br />
В принципе, пока что ОЗУ со свистом хватает для пяти датчиков. Еще и на буферы для передачи по USART останется (на компьютер данные через оптоволокно будут идти по RS-232 или RS-485), и на какие-нибудь дополнительные нужды.<br />
Цикл обработки одной &quot;подстраницы&quot; занимает примерно 4.2мс, т.е. целиком обработка страницы уложится в 8.5мс. Одна &quot;подстраница&quot; данных (при том, что там половина - ненужные! Уж не знаю, зачем melexis так нарукожопил…) по I2C на скорости 1МГц передается около 14мс. Следовательно, обработка предыдущей &quot;подстраницы&quot; выполнится быстрей, чем прием следующей (!!!). Вот уж не ожидал… Теперь понятно, как китайцы на экранчике &quot;видосики&quot; рисуют. Самое интересное, что в настройках датчика предельная скорость обновления - 64Гц. Даже если это - для одной &quot;субстраницы&quot;, а не полного кадра, период обновления около 16мс выходит - лишь немногим больше времени, за которое это обновление будет выдано в I2C. Интересно, как чип умудряется с такими скоростями справляться.<br />
Нам же все равно нужно максимум раз в 30с картинку обновлять. Ну, забавы для можно, конечно, и 1Гц поставить. Посмотрим, это нужно уже экспериментально выбирать наиболее оптимальный режим.<br />
<br />
Интересно было бы сравнить с быстродействием &quot;родной&quot; библиотечки от melexis. За какое время у них вычисляется полный кадр на том же самом МК?<br />
Я же, глядя в код, подозреваю, что можно еще немного оптимизировать.<br />
<br />
Еще можно будет попробовать этот код под STM32F103CBT6 собрать. Правда, на 5 датчиков там ОЗУ однозначно не хватит. С  другой стороны, можно ведь схитрить: зачем константы каждый раз считывать в память, если можно их один раз считать, посчитать и сохранить во флеше?</div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/10575.html</guid>
		</item>
		<item>
			<title>И опять про трапециевидный рамп</title>
			<link>https://www.cyberforum.ru/blogs/1886385/10523.html</link>
			<pubDate>Wed, 06 Aug 2025 16:36:08 GMT</pubDate>
			<description>Покуда я простые примеры проверял на своей модели, проблем не было. А вот как начал это применять к...</description>
			<content:encoded><![CDATA[<div>Покуда я простые примеры проверял на своей модели, проблем не было. А вот как начал это применять к коррекции положения телескопа в модели, стал получать уйму косяков — в случае, если для перехода в новую позицию нужно было бы остановиться и продолжить движение в противоположном направлении.<br />
Мучил-мучил дипсик, но он мне постоянно нерабочие решения выдавал. А когда я в итоге выдал свое рабочее, он его изговнял так, что оно опять не работало (еще и сегфолты откуда-то брались) ☺<br />
В общем, вот код:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="643505795"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="643505795" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
</pre></td><td class="de1"><pre class="de1"><span class="co1">// inner part of `calc`, could be called recoursively for hard case</span>
<span class="kw4">static</span> <span class="kw4">void</span> unlockedcalc<span class="br0">&#40;</span>movemodel_t <span class="sy0">*</span>m<span class="sy0">,</span> moveparam_t <span class="sy0">*</span>x<span class="sy0">,</span> <span class="kw4">double</span> t<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="co1">// signs</span>
&nbsp; &nbsp; <span class="kw4">double</span> sign_a01 <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">,</span> sign_a23 <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">,</span> sign_vset <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">;</span> <span class="co1">// accelerations on stages ACCEL and DECEL, speed on maxspeed stage</span>
&nbsp; &nbsp; <span class="co1">// times</span>
&nbsp; &nbsp; <span class="kw4">double</span> dt01 <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">,</span> dt12 <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">,</span> dt23 <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">;</span>
&nbsp; &nbsp; <span class="co1">// absolute speed at stage 23 (or in that point); absolute max acceleration</span>
&nbsp; &nbsp; <span class="kw4">double</span> abs_vset <span class="sy0">=</span> x<span class="sy0">-&gt;</span>speed<span class="sy0">,</span> abs_a <span class="sy0">=</span> m<span class="sy0">-&gt;</span>Max.<span class="me1">accel</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="co1">// absolute target movement</span>
&nbsp; &nbsp; <span class="kw4">double</span> abs_Dx <span class="sy0">=</span> <span class="kw3">fabs</span><span class="br0">&#40;</span>x<span class="sy0">-&gt;</span>coord <span class="sy0">-</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">coord</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>m<span class="sy0">-&gt;</span>state <span class="sy0">==</span> ST_STOP <span class="sy0">&amp;&amp;</span> abs_Dx <span class="sy0">&lt;</span> coord_tolerance<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; DBG<span class="br0">&#40;</span><span class="st0">&quot;Movement too small -&gt; stay at place&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="co1">// signs of Dx and current speed</span>
&nbsp; &nbsp; <span class="kw4">double</span> sign_Dx <span class="sy0">=</span> <span class="br0">&#40;</span>x<span class="sy0">-&gt;</span>coord <span class="sy0">&gt;</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">coord</span><span class="br0">&#41;</span> <span class="sy0">?</span> <span class="nu0">1</span>. <span class="sy0">:</span> <span class="sy0">-</span><span class="nu0">1</span>.<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> v0 <span class="sy0">=</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">speed</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> sign_v0 <span class="sy0">=</span> v0 <span class="sy0">&lt;</span> <span class="nu0">0</span>. <span class="sy0">?</span> <span class="sy0">-</span><span class="nu0">1</span> <span class="sy0">:</span> <span class="nu0">1</span>.<span class="sy0">,</span> abs_v0 <span class="sy0">=</span> <span class="kw3">fabs</span><span class="br0">&#40;</span>v0<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>v0 <span class="sy0">==</span> <span class="nu0">0</span>.<span class="br0">&#41;</span> sign_v0 <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">;</span>
&nbsp; &nbsp; <span class="co1">// preliminary calculations (vset and dependent values could be changed)</span>
&nbsp; &nbsp; dt01 <span class="sy0">=</span> <span class="kw3">fabs</span><span class="br0">&#40;</span>abs_v0 <span class="sy0">-</span> abs_vset<span class="br0">&#41;</span> <span class="sy0">/</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> abs_dx23 <span class="sy0">=</span> abs_vset <span class="sy0">*</span> abs_vset <span class="sy0">/</span> <span class="nu0">2</span>. <span class="sy0">/</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; dt23 <span class="sy0">=</span> abs_vset <span class="sy0">/</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> abs_dx_stop <span class="sy0">=</span> abs_v0 <span class="sy0">*</span> abs_v0 <span class="sy0">/</span> <span class="nu0">2</span>. <span class="sy0">/</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>sign_Dx <span class="sy0">*</span> sign_v0 <span class="sy0">&gt;=</span> <span class="nu0">0</span>. <span class="sy0">&amp;&amp;</span> abs_dx_stop <span class="sy0">&lt;</span> abs_Dx<span class="br0">&#41;</span><span class="br0">&#123;</span> <span class="co1">// we shouldn't change speed direction</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="kw3">fabs</span><span class="br0">&#40;</span>abs_dx_stop <span class="sy0">-</span> abs_Dx<span class="br0">&#41;</span> <span class="sy0">&lt;=</span> coord_tolerance<span class="br0">&#41;</span><span class="br0">&#123;</span> <span class="co1">// simplest case: just stop</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//DBG(&quot;Simplest case: stop&quot;);</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dt01 <span class="sy0">=</span> dt12 <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sign_a23 <span class="sy0">=</span> <span class="sy0">-</span>sign_v0<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dt23 <span class="sy0">=</span> abs_v0 <span class="sy0">/</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span> <span class="kw1">if</span><span class="br0">&#40;</span>abs_vset <span class="sy0">&lt;</span> abs_v0<span class="br0">&#41;</span><span class="br0">&#123;</span> <span class="co1">// move with smaller speed than now: very simple case</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//DBG(&quot;Move with smaller speed&quot;);</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sign_a01 <span class="sy0">=</span> sign_a23 <span class="sy0">=</span> <span class="sy0">-</span>sign_v0<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sign_vset <span class="sy0">=</span> sign_v0<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">double</span> abs_dx01 <span class="sy0">=</span> abs_v0 <span class="sy0">*</span> dt01 <span class="sy0">-</span> abs_a <span class="sy0">*</span> dt01 <span class="sy0">*</span> dt01 <span class="sy0">/</span> <span class="nu0">2</span>.<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">double</span> abs_dx12 <span class="sy0">=</span> abs_Dx <span class="sy0">-</span> abs_dx01 <span class="sy0">-</span> abs_dx23<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dt12 <span class="sy0">=</span> abs_dx12 <span class="sy0">/</span> abs_vset<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span><span class="co1">// move with larget speed</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">//DBG(&quot;Move with larger speed&quot;);</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">double</span> abs_dx01 <span class="sy0">=</span> abs_v0 <span class="sy0">*</span> dt01 <span class="sy0">+</span> abs_a <span class="sy0">*</span> dt01 <span class="sy0">*</span> dt01 <span class="sy0">/</span> <span class="nu0">2</span>.<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>abs_Dx <span class="sy0">&lt;</span> abs_dx01 <span class="sy0">+</span> abs_dx23<span class="br0">&#41;</span><span class="br0">&#123;</span> <span class="co1">// recalculate target speed and other</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; abs_vset <span class="sy0">=</span> <span class="kw3">sqrt</span><span class="br0">&#40;</span>abs_a <span class="sy0">*</span> abs_Dx <span class="sy0">+</span> abs_v0 <span class="sy0">*</span> abs_v0 <span class="sy0">/</span> <span class="nu0">2</span>.<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dt01 <span class="sy0">=</span> <span class="kw3">fabs</span><span class="br0">&#40;</span>abs_v0 <span class="sy0">-</span> abs_vset<span class="br0">&#41;</span> <span class="sy0">/</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; abs_dx01 <span class="sy0">=</span> abs_v0 <span class="sy0">*</span> dt01 <span class="sy0">+</span> abs_a <span class="sy0">*</span> dt01 <span class="sy0">*</span> dt01 <span class="sy0">/</span> <span class="nu0">2</span>.<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dt23 <span class="sy0">=</span> abs_vset <span class="sy0">/</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; abs_dx23 <span class="sy0">=</span> abs_vset <span class="sy0">*</span> abs_vset <span class="sy0">/</span> <span class="nu0">2</span>. <span class="sy0">/</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DBG<span class="br0">&#40;</span><span class="st0">&quot;Can't reach target speed %g, take %g instead&quot;</span><span class="sy0">,</span> x<span class="sy0">-&gt;</span>speed<span class="sy0">,</span> abs_vset<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sign_a01 <span class="sy0">=</span> sign_Dx<span class="sy0">;</span> <span class="co1">// sign_v0 could be ZERO!!!</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sign_a23 <span class="sy0">=</span> <span class="sy0">-</span>sign_Dx<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sign_vset <span class="sy0">=</span> sign_Dx<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">double</span> abs_dx12 <span class="sy0">=</span> abs_Dx <span class="sy0">-</span> abs_dx01 <span class="sy0">-</span> abs_dx23<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; dt12 <span class="sy0">=</span> abs_dx12 <span class="sy0">/</span> abs_vset<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span><span class="kw1">else</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// if we are here, we have the worst case: change speed direction</span>
&nbsp; &nbsp; &nbsp; &nbsp; DBG<span class="br0">&#40;</span><span class="st0">&quot;Hardest case: change speed direction&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// now we should calculate coordinate at which model stops and biuld new trapezium from that point</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">double</span> x0 <span class="sy0">=</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">coord</span><span class="sy0">,</span> v0 <span class="sy0">=</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">speed</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">double</span> xstop <span class="sy0">=</span> x0 <span class="sy0">+</span> sign_v0 <span class="sy0">*</span> abs_dx_stop<span class="sy0">,</span> tstop <span class="sy0">=</span> t <span class="sy0">+</span> abs_v0 <span class="sy0">/</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; m<span class="sy0">-&gt;</span>state <span class="sy0">=</span> ST_STOP<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; m<span class="sy0">-&gt;</span>curparams.<span class="me1">accel</span> <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">;</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">coord</span> <span class="sy0">=</span> xstop<span class="sy0">;</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">speed</span> <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; unlockedcalc<span class="br0">&#40;</span>m<span class="sy0">,</span> x<span class="sy0">,</span> tstop<span class="br0">&#41;</span><span class="sy0">;</span> <span class="co1">// calculate new ramp</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// and change started conditions</span>
&nbsp; &nbsp; &nbsp; &nbsp; m<span class="sy0">-&gt;</span>curparams.<span class="me1">coord</span> <span class="sy0">=</span> x0<span class="sy0">;</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">speed</span> <span class="sy0">=</span> v0<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; m<span class="sy0">-&gt;</span>Times<span class="br0">&#91;</span>STAGE_ACCEL<span class="br0">&#93;</span> <span class="sy0">=</span> t<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; m<span class="sy0">-&gt;</span>Params<span class="br0">&#91;</span>STAGE_ACCEL<span class="br0">&#93;</span>.<span class="me1">coord</span> <span class="sy0">=</span> x0<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; m<span class="sy0">-&gt;</span>Params<span class="br0">&#91;</span>STAGE_ACCEL<span class="br0">&#93;</span>.<span class="me1">speed</span> <span class="sy0">=</span> v0<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; DBG<span class="br0">&#40;</span><span class="st0">&quot;NOW t[0]=%g, X[0]=%g, V[0]=%g&quot;</span><span class="sy0">,</span> t<span class="sy0">,</span> x0<span class="sy0">,</span> v0<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; m<span class="sy0">-&gt;</span>state <span class="sy0">=</span> ST_MOVE<span class="sy0">;</span>
&nbsp; &nbsp; m<span class="sy0">-&gt;</span>movingstage <span class="sy0">=</span> STAGE_ACCEL<span class="sy0">;</span>
&nbsp; &nbsp; <span class="co1">// some knot parameters</span>
&nbsp; &nbsp; <span class="kw4">double</span> a01 <span class="sy0">=</span> sign_a01 <span class="sy0">*</span> abs_a<span class="sy0">,</span> a23 <span class="sy0">=</span> sign_a23 <span class="sy0">*</span> abs_a<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> v1<span class="sy0">,</span> v2<span class="sy0">,</span> x0<span class="sy0">,</span> x1<span class="sy0">,</span> x2<span class="sy0">;</span>
&nbsp; &nbsp; v2 <span class="sy0">=</span> v1 <span class="sy0">=</span> sign_vset <span class="sy0">*</span> abs_vset<span class="sy0">;</span>
&nbsp; &nbsp; x0 <span class="sy0">=</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">coord</span><span class="sy0">;</span>
&nbsp; &nbsp; x1 <span class="sy0">=</span> x0 <span class="sy0">+</span> v0 <span class="sy0">*</span> dt01 <span class="sy0">+</span> a01 <span class="sy0">*</span> dt01 <span class="sy0">*</span> dt01 <span class="sy0">/</span> <span class="nu0">2</span>.<span class="sy0">;</span>
&nbsp; &nbsp; x2 <span class="sy0">=</span> x1 <span class="sy0">+</span> v1 <span class="sy0">*</span> dt12<span class="sy0">;</span>
&nbsp; &nbsp; <span class="co1">// fill knot parameters</span>
&nbsp; &nbsp; moveparam_t <span class="sy0">*</span>p <span class="sy0">=</span> <span class="sy0">&amp;</span>m<span class="sy0">-&gt;</span>Params<span class="br0">&#91;</span>STAGE_ACCEL<span class="br0">&#93;</span><span class="sy0">;</span> <span class="co1">// 0-1 - change started speed</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>accel <span class="sy0">=</span> a01<span class="sy0">;</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>speed <span class="sy0">=</span> m<span class="sy0">-&gt;</span>curparams.<span class="me1">speed</span><span class="sy0">;</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>coord <span class="sy0">=</span> x0<span class="sy0">;</span>
&nbsp; &nbsp; m<span class="sy0">-&gt;</span>Times<span class="br0">&#91;</span>STAGE_ACCEL<span class="br0">&#93;</span> <span class="sy0">=</span> t<span class="sy0">;</span>
&nbsp; &nbsp; p <span class="sy0">=</span> <span class="sy0">&amp;</span>m<span class="sy0">-&gt;</span>Params<span class="br0">&#91;</span>STAGE_MAXSPEED<span class="br0">&#93;</span><span class="sy0">;</span> <span class="co1">// 1-2 - constant speed</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>accel <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">;</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>speed <span class="sy0">=</span> v1<span class="sy0">;</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>coord <span class="sy0">=</span> x1<span class="sy0">;</span>
&nbsp; &nbsp; m<span class="sy0">-&gt;</span>Times<span class="br0">&#91;</span>STAGE_MAXSPEED<span class="br0">&#93;</span> <span class="sy0">=</span> m<span class="sy0">-&gt;</span>Times<span class="br0">&#91;</span>STAGE_ACCEL<span class="br0">&#93;</span> <span class="sy0">+</span> dt01<span class="sy0">;</span>
&nbsp; &nbsp; p <span class="sy0">=</span> <span class="sy0">&amp;</span>m<span class="sy0">-&gt;</span>Params<span class="br0">&#91;</span>STAGE_DECEL<span class="br0">&#93;</span><span class="sy0">;</span> <span class="co1">// 2-3 - decrease speed</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>accel <span class="sy0">=</span> a23<span class="sy0">;</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>speed <span class="sy0">=</span> v2<span class="sy0">;</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>coord <span class="sy0">=</span> x2<span class="sy0">;</span>
&nbsp; &nbsp; m<span class="sy0">-&gt;</span>Times<span class="br0">&#91;</span>STAGE_DECEL<span class="br0">&#93;</span> <span class="sy0">=</span> m<span class="sy0">-&gt;</span>Times<span class="br0">&#91;</span>STAGE_MAXSPEED<span class="br0">&#93;</span> <span class="sy0">+</span> dt12<span class="sy0">;</span>
&nbsp; &nbsp; p <span class="sy0">=</span> <span class="sy0">&amp;</span>m<span class="sy0">-&gt;</span>Params<span class="br0">&#91;</span>STAGE_STOPPED<span class="br0">&#93;</span><span class="sy0">;</span> <span class="co1">// 3 - stop at target</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>accel <span class="sy0">=</span> p<span class="sy0">-&gt;</span>speed <span class="sy0">=</span> <span class="nu0">0</span>.<span class="sy0">;</span>
&nbsp; &nbsp; p<span class="sy0">-&gt;</span>coord <span class="sy0">=</span> x<span class="sy0">-&gt;</span>coord<span class="sy0">;</span>
&nbsp; &nbsp; m<span class="sy0">-&gt;</span>Times<span class="br0">&#91;</span>STAGE_STOPPED<span class="br0">&#93;</span> <span class="sy0">=</span> m<span class="sy0">-&gt;</span>Times<span class="br0">&#91;</span>STAGE_DECEL<span class="br0">&#93;</span> <span class="sy0">+</span> dt23<span class="sy0">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="coMULTI">/**</span>
<span class="coMULTI">&nbsp;* @brief calc - moving calculation</span>
<span class="coMULTI">&nbsp;* @param x - using max speed (&gt;0!!!) and coordinate</span>
<span class="coMULTI">&nbsp;* @param t - current time value</span>
<span class="coMULTI">&nbsp;* @return FALSE if can't move with given parameters</span>
<span class="coMULTI">&nbsp;*/</span>
<span class="kw4">static</span> <span class="kw4">int</span> calc<span class="br0">&#40;</span>movemodel_t <span class="sy0">*</span>m<span class="sy0">,</span> moveparam_t <span class="sy0">*</span>x<span class="sy0">,</span> <span class="kw4">double</span> t<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="co1">//DBG(&quot;target coord/speed: %g/%g; current: %g/%g&quot;, x-&gt;coord, x-&gt;speed, m-&gt;curparams.coord, m-&gt;curparams.speed);</span>
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span>x <span class="sy0">||</span> <span class="sy0">!</span>m<span class="br0">&#41;</span> <span class="kw1">return</span> FALSE<span class="sy0">;</span>
&nbsp; &nbsp; pthread_mutex_lock<span class="br0">&#40;</span><span class="sy0">&amp;</span>m<span class="sy0">-&gt;</span>mutex<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">int</span> ret <span class="sy0">=</span> FALSE<span class="sy0">;</span>
&nbsp; &nbsp; <span class="co1">// Validate input parameters</span>
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>x<span class="sy0">-&gt;</span>coord <span class="sy0">&lt;</span> m<span class="sy0">-&gt;</span>Min.<span class="me1">coord</span> <span class="sy0">||</span> x<span class="sy0">-&gt;</span>coord <span class="sy0">&gt;</span> m<span class="sy0">-&gt;</span>Max.<span class="me1">coord</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; DBG<span class="br0">&#40;</span><span class="st0">&quot;Wrong coordinate [%g, %g]&quot;</span><span class="sy0">,</span> m<span class="sy0">-&gt;</span>Min.<span class="me1">coord</span><span class="sy0">,</span> m<span class="sy0">-&gt;</span>Max.<span class="me1">coord</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">goto</span> ret<span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>x<span class="sy0">-&gt;</span>speed <span class="sy0">&lt;</span> m<span class="sy0">-&gt;</span>Min.<span class="me1">speed</span> <span class="sy0">||</span> x<span class="sy0">-&gt;</span>speed <span class="sy0">&gt;</span> m<span class="sy0">-&gt;</span>Max.<span class="me1">speed</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; DBG<span class="br0">&#40;</span><span class="st0">&quot;Wrong speed [%g, %g]&quot;</span><span class="sy0">,</span> m<span class="sy0">-&gt;</span>Min.<span class="me1">speed</span><span class="sy0">,</span> m<span class="sy0">-&gt;</span>Max.<span class="me1">speed</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">goto</span> ret<span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; ret <span class="sy0">=</span> TRUE<span class="sy0">;</span> <span class="co1">// now there's no chanses to make error</span>
&nbsp; &nbsp; unlockedcalc<span class="br0">&#40;</span>m<span class="sy0">,</span> x<span class="sy0">,</span> t<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="co1">// Debug output</span>
&nbsp; &nbsp; <span class="coMULTI">/*for(int i = 0; i &lt; STAGE_AMOUNT; i++){</span>
<span class="coMULTI">&nbsp; &nbsp; &nbsp; &nbsp; DBG(&quot;Stage %d: t=%.6f, coord=%.6f, speed=%.6f, accel=%.6f&quot;,</span>
<span class="coMULTI">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; i, m-&gt;Times[i], m-&gt;Params[i].coord, m-&gt;Params[i].speed, m-&gt;Params[i].accel);</span>
<span class="coMULTI">&nbsp; &nbsp; }*/</span>
ret<span class="sy0">:</span>
&nbsp; &nbsp; pthread_mutex_unlock<span class="br0">&#40;</span><span class="sy0">&amp;</span>m<span class="sy0">-&gt;</span>mutex<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">return</span> ret<span class="sy0">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Решил написать с нуля, а не пытаться исправить старый код. Исписал формулами сегодня с десяток листов бумаги на работе, обкатывая каждый вариант. Вариант с трапецией с нулевой скорости и ненулевой по формулам — одно и то же, поэтому эти варианты не разделял, а выделил в вариант &quot;продолжи движение с бóльшей скоростью&quot;. Из &quot;нормальных&quot; еще есть вариант &quot;тормози с текущей скорости&quot; (но его вероятность околонулевая) и &quot;продолжи движение с меньшей скоростью&quot;. Разница с первым вариантом только в знаке ускорения в начале движения и ненужности проверять, нет ли вариантов, что указанная скорость недостижима.<br />
Ну и остается самый убогий вариант: тормознуть и продолжить. И тут меня осенило: ведь после останова мы движемся по полноценной трапеции или треугольнику. А почему бы не запустить функцию рекурсивно, начав с точки останова, а потом &quot;подрихтовать&quot; начальный этап? И, действительно, получилось!<br />
А чертов &quot;ИИ&quot; все пытался мне этот код раза в 2-3 раздуть! Те примеры, что видел в интернете, либо вообще рассчитаны исключительно на старт с положения останова, либо рассматривают отдельно каждый вариант, что только запутывает код.<br />
<br />
P.S. <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/small_tel/tree/master/Auxiliary_utils/LibSidServo" target="_blank" title="https://github.com/eddyem/small_tel/tree/master/Auxiliary_utils/LibSidServo">весь код</a>.</div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/10523.html</guid>
		</item>
		<item>
			<title>Вычисляем скорость наименьшими квадратами</title>
			<link>https://www.cyberforum.ru/blogs/1886385/10512.html</link>
			<pubDate>Fri, 01 Aug 2025 05:45:19 GMT</pubDate>
			<description>Вожусь с системой управления телескопами на основе контроллеров sidservo (адская дрянь, но что...</description>
			<content:encoded><![CDATA[<div>Вожусь с системой управления телескопами на основе контроллеров sidservo (адская дрянь, но что есть, то есть). &quot;Особенностью&quot; контроллера является то, что невозможно получить текущее значение скорости, с которой телескоп двигается по обеим осям. Да и сам ответ на запрос состояния приходит через 50-60мс. Никакой стабильности нет. Поэтому единственный вариант - пользоваться осевыми энкодерами, которые показывают реальное положение телескопа, и которые я могу опрашивать с частотой до 4кГц (для этого сделал специальный контроллер на основе STM32: при подключении к компьютеру создаются устройства /dev/encoder_cmd0, /dev/encoder_X0 и /dev/encoder_Y0: настройки и данные с энкодеров в строковом формате).<br />
Сначала вычислял скорость 1 раз в промежуток времени как простое отношение разности координат к разности времен. Конечно, получалось очень шумно и ступенчато. Сейчас запилил &quot;плавающее&quot; вычисление наименьшими квадратами. Значительно красивее вышло. И по &quot;болтанке&quot; скорости на интервале, где она должна быть постоянна, сразу понял, что я неправильно настроил ПИД-регулятор sidservo (то ли I, то ли P задрал выше, чем нужно).<br />
<br />
Код прост до примитивизма: заводим массивы для накопления N данных в соответствии с каждой используемой суммой. При поступлении новых данных в сумму добавляем свежее и вычитаем последнее.<br />
<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="704413813"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="704413813" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
</pre></td><td class="de1"><pre class="de1"><span class="kw4">typedef</span> <span class="kw4">struct</span><span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">double</span> <span class="sy0">*</span>x<span class="sy0">,</span> <span class="sy0">*</span>t<span class="sy0">,</span> <span class="sy0">*</span>t2<span class="sy0">,</span> <span class="sy0">*</span>xt<span class="sy0">;</span> <span class="co1">// arrays of coord/time and multiply</span>
&nbsp; &nbsp; <span class="kw4">double</span> xsum<span class="sy0">,</span> tsum<span class="sy0">,</span> t2sum<span class="sy0">,</span> xtsum<span class="sy0">;</span> <span class="co1">// sums of coord/time and their multiply</span>
&nbsp; &nbsp; <span class="kw4">size_t</span> idx<span class="sy0">;</span> <span class="co1">// index of current data in array</span>
&nbsp; &nbsp; <span class="kw4">size_t</span> arraysz<span class="sy0">;</span> <span class="co1">// size of arrays</span>
<span class="br0">&#125;</span> less_square_t<span class="sy0">;</span>
&nbsp;
less_square_t <span class="sy0">*</span>LS_init<span class="br0">&#40;</span><span class="kw4">size_t</span> Ndata<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>Ndata <span class="sy0">&lt;</span> <span class="nu0">5</span><span class="br0">&#41;</span> <span class="kw1">return</span> NULL<span class="sy0">;</span>
&nbsp; &nbsp; less_square_t <span class="sy0">*</span>l <span class="sy0">=</span> <span class="kw3">calloc</span><span class="br0">&#40;</span><span class="nu0">1</span><span class="sy0">,</span> <span class="kw4">sizeof</span><span class="br0">&#40;</span>less_square_t<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>x <span class="sy0">=</span> <span class="kw3">calloc</span><span class="br0">&#40;</span>Ndata<span class="sy0">,</span> <span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">double</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>t2 <span class="sy0">=</span> <span class="kw3">calloc</span><span class="br0">&#40;</span>Ndata<span class="sy0">,</span> <span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">double</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>t <span class="sy0">=</span> <span class="kw3">calloc</span><span class="br0">&#40;</span>Ndata<span class="sy0">,</span> <span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">double</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>xt <span class="sy0">=</span> <span class="kw3">calloc</span><span class="br0">&#40;</span>Ndata<span class="sy0">,</span> <span class="kw4">sizeof</span><span class="br0">&#40;</span><span class="kw4">double</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>arraysz <span class="sy0">=</span> Ndata<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">return</span> l<span class="sy0">;</span>
<span class="br0">&#125;</span>
<span class="kw4">void</span> LS_delete<span class="br0">&#40;</span>less_square_t <span class="sy0">**</span>l<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="sy0">!</span>l <span class="sy0">||</span> <span class="sy0">!*</span>l<span class="br0">&#41;</span> <span class="kw1">return</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw3">free</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">*</span>l<span class="br0">&#41;</span><span class="sy0">-&gt;</span>x<span class="br0">&#41;</span><span class="sy0">;</span> <span class="kw3">free</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">*</span>l<span class="br0">&#41;</span><span class="sy0">-&gt;</span>t2<span class="br0">&#41;</span><span class="sy0">;</span> <span class="kw3">free</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">*</span>l<span class="br0">&#41;</span><span class="sy0">-&gt;</span>t<span class="br0">&#41;</span><span class="sy0">;</span> <span class="kw3">free</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="sy0">*</span>l<span class="br0">&#41;</span><span class="sy0">-&gt;</span>xt<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw3">free</span><span class="br0">&#40;</span><span class="sy0">*</span>l<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="sy0">*</span>l <span class="sy0">=</span> NULL<span class="sy0">;</span>
<span class="br0">&#125;</span>
<span class="co1">// add next data portion and calculate current slope</span>
<span class="kw4">double</span> LS_calc_slope<span class="br0">&#40;</span>less_square_t <span class="sy0">*</span>l<span class="sy0">,</span> <span class="kw4">double</span> x<span class="sy0">,</span> <span class="kw4">double</span> t<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="sy0">!</span>l<span class="br0">&#41;</span> <span class="kw1">return</span> <span class="nu0">0</span>.<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">size_t</span> idx <span class="sy0">=</span> l<span class="sy0">-&gt;</span>idx<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> oldx <span class="sy0">=</span> l<span class="sy0">-&gt;</span>x<span class="br0">&#91;</span>idx<span class="br0">&#93;</span><span class="sy0">,</span> oldt <span class="sy0">=</span> l<span class="sy0">-&gt;</span>t<span class="br0">&#91;</span>idx<span class="br0">&#93;</span><span class="sy0">,</span> oldt2 <span class="sy0">=</span> l<span class="sy0">-&gt;</span>t2<span class="br0">&#91;</span>idx<span class="br0">&#93;</span><span class="sy0">,</span> oldxt <span class="sy0">=</span> l<span class="sy0">-&gt;</span>xt<span class="br0">&#91;</span>idx<span class="br0">&#93;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> t2 <span class="sy0">=</span> t <span class="sy0">*</span> t<span class="sy0">,</span> xt <span class="sy0">=</span> x <span class="sy0">*</span> t<span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>x<span class="br0">&#91;</span>idx<span class="br0">&#93;</span> <span class="sy0">=</span> x<span class="sy0">;</span> l<span class="sy0">-&gt;</span>t2<span class="br0">&#91;</span>idx<span class="br0">&#93;</span> <span class="sy0">=</span> t2<span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>t<span class="br0">&#91;</span>idx<span class="br0">&#93;</span> <span class="sy0">=</span> t<span class="sy0">;</span> l<span class="sy0">-&gt;</span>xt<span class="br0">&#91;</span>idx<span class="br0">&#93;</span> <span class="sy0">=</span> xt<span class="sy0">;</span>
&nbsp; &nbsp; <span class="sy0">++</span>idx<span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>idx <span class="sy0">=</span> <span class="br0">&#40;</span>idx <span class="sy0">&gt;=</span> l<span class="sy0">-&gt;</span>arraysz<span class="br0">&#41;</span> <span class="sy0">?</span> <span class="nu0">0</span> <span class="sy0">:</span> idx<span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>xsum <span class="sy0">+=</span> x <span class="sy0">-</span> oldx<span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>t2sum <span class="sy0">+=</span> t2 <span class="sy0">-</span> oldt2<span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>tsum <span class="sy0">+=</span> t <span class="sy0">-</span> oldt<span class="sy0">;</span>
&nbsp; &nbsp; l<span class="sy0">-&gt;</span>xtsum <span class="sy0">+=</span> xt <span class="sy0">-</span> oldxt<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> n <span class="sy0">=</span> <span class="br0">&#40;</span><span class="kw4">double</span><span class="br0">&#41;</span>l<span class="sy0">-&gt;</span>arraysz<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> denominator <span class="sy0">=</span> n <span class="sy0">*</span> l<span class="sy0">-&gt;</span>t2sum <span class="sy0">-</span> l<span class="sy0">-&gt;</span>tsum <span class="sy0">*</span> l<span class="sy0">-&gt;</span>tsum<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span><span class="kw3">fabs</span><span class="br0">&#40;</span>denominator<span class="br0">&#41;</span> <span class="sy0">&lt;</span> <span class="nu19">1e-7</span><span class="br0">&#41;</span> <span class="kw1">return</span> <span class="nu0">0</span>.<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw4">double</span> numerator <span class="sy0">=</span> n <span class="sy0">*</span> l<span class="sy0">-&gt;</span>xtsum <span class="sy0">-</span> l<span class="sy0">-&gt;</span>xsum <span class="sy0">*</span> l<span class="sy0">-&gt;</span>tsum<span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#40;</span>numerator <span class="sy0">/</span> denominator<span class="br0">&#41;</span><span class="sy0">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div></div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/10512.html</guid>
		</item>
		<item>
			<title>Контроллер холловского датчика</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8752.html</link>
			<pubDate>Thu, 26 Dec 2024 14:13:46 GMT</pubDate>
			<description>Намедни разработал очередную железяку для СУ БТА: контроллер микрометра...</description>
			<content:encoded><![CDATA[<div>Намедни разработал очередную железяку для СУ БТА: <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/stm32samples/tree/master/F1%3AF103/Hall_linear" target="_blank" title="https://github.com/eddyem/stm32samples/tree/master/F1%3AF103/Hall_linear">контроллер микрометра</a> на основе холловского датчика &quot;Novotechnik TFD-4000&quot;. Нужны эти железки для того, чтобы измерять толщину масляной пленки в азимутальном подшипнике БТА (минимум нужно в трех опорах измерять, но лучше во всех шести).<br />
<br />
Датчик имеет аналоговый вход: от 0.25В на нуле до 4.75В на 14мм. Если магнит вне зоны Холла, на выходе 0 (удобно для детектирования проблем с магнитом). Сам датчик 12-битный. И тут опять та же дурь, как в случае с аналоговыми видеокамерами: сначала полученные с холла данные обрабатывает АЦП, а потом ЦАП наружу выдает напряжение. Почему нельзя было их сделать на цифровом интерфейсе — загадка. Вот, собственно, каждая такая маленькая плата и нужна для того, чтобы по CAN-шине передавать данные измерений. Использую встроенный АЦП STM32F103C6T6, а т.к. диапазон выхода с датчика выше, то делитель 1:2 на резисторах.<br />
<br />
Паяю:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=9135&amp;st= c=1&amp;d=1735222290" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Пока &quot;пап&quot; type-C у меня нет, могу лишь испытать, как работает USB. А вот как приедут разъемы, буду CAN проверять. В принципе, там команд-то раз, два — и обчелся. А выдавал бы датчик сразу CAN или хотя бы RS-485 (пусть даже дебильный модбас, всяко сразу можно было бы к компу подключить), не пришлось бы почти неделю на эту фитюлину тратить. Вот так плата выглядит:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=9136&amp;st= c=1&amp;d=1735222290" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
<br />
Уже когда собрался датчик припаивать, обнаружил, что я забыл нарисовать делитель, поэтому на соплях спаял временный. Все равно это — прототип (на станке отфрезеровали, лень мне заморачиваться с фоторезистом, да и &quot;УФ&quot;-осветитель что-то наполовину помер, надо прозванивать, какой из диодов сдох).</div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=9135&amp;d=1735222290" target="attachment" rel="Lightbox" id="attachment9135"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=9135&amp;stc=1&amp;thumb=1&amp;d=1735222290" border="0" alt="Нажмите на изображение для увеличения
Название: IMG_20241225_165823.jpg
Просмотров: 571
Размер:	293.6 Кб
ID:	9135" /></a>
	&nbsp;
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=9136&amp;d=1735222290" target="attachment" rel="Lightbox" id="attachment9136"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=9136&amp;stc=1&amp;thumb=1&amp;d=1735222290" border="0" alt="Нажмите на изображение для увеличения
Название: IMG_20241226_164648.jpg
Просмотров: 555
Размер:	210.3 Кб
ID:	9136" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8752.html</guid>
		</item>
		<item>
			<title>Оптический конвертер RS232/RS485/RS422</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8721.html</link>
			<pubDate>Mon, 25 Nov 2024 06:49:56 GMT</pubDate>
			<description>Еще осенью закупили мне пять вот таких конвертеров (https://aliexpress.ru/item/33009609846.html),...</description>
			<content:encoded><![CDATA[<div>Еще осенью закупили мне пять <a rel="nofollow noopener noreferrer" href="https://aliexpress.ru/item/33009609846.html" target="_blank" title="https://aliexpress.ru/item/33009609846.html">вот таких конвертеров</a>, чтобы можно было на малых телескопах отключать нагрузку дистанционно.<br />
// кстати, отлично видно сильное подорожание за 2 месяца (4300 → 5500: 28%): и курс доллара тогда был 105, а сейчас 115, да и &quot;распродажа&quot; ведь — на &quot;распродажу&quot; у многих цены резко взлетают.<br />
Соединил коротким патчкордом (где-то с метр длиной) и для начала погонял на 485. До полутора мегабод (включительно) работает! А вот на двух уже не может, но обычно больше 115200 редко бывает нужно.<br />
Тут думаю: так много входов, наверняка ведь такая же ситуация, как с моим преобразователем на USB-232/485 (где и 232, и 485 сводятся на один ch340). Но оказалось гораздо лучше! RS232 работает независимо от RS485. Специально подключил 232 на 256 бод, а 485 - на 100 бод. Запустил длинную передачу с обоих концов 232 и тут же - с одного конца 485. Все данные достигли получателя без ошибок. Понятно, что если одновременно передавать с обоих концов 485, получаешь мусор. USB-RS422 у меня нет, поэтому не смог третий интерфейс проверить, но подозреваю, что он тоже сам по себе.<br />
При включении, если нет оптической связи или вторая сторона выключена, мигает светодиод &quot;SYNC&quot;. Как только связь установлена, он горит постоянно.<br />
Вот, можно будет подключить по 485 в одну гирлянду все модбасовские релюшки для управления пускателями, а по 232 подключить бесперебойники (чего их зря гонять? подал команду &quot;выкл&quot;, а потом и пускатель на нагрузку отключил - &quot;на всякий пожарный&quot;, чтобы если во время грозы бесперебойник вдруг решит &quot;проснуться&quot;, нагрузка не пострадала).<br />
<br />
Вот, для тестов пришлось доставать USB хаб, потому как в компе уже кончились все отверстия USB:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=9054&amp;st= c=1&amp;d=1732517244" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /></div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=9054&amp;d=1732517242" target="attachment" rel="Lightbox" id="attachment9054"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=9054&amp;stc=1&amp;thumb=1&amp;d=1732517242" border="0" alt="Нажмите на изображение для увеличения
Название: IMG_20241125_085706.jpg
Просмотров: 522
Размер:	171.2 Кб
ID:	9054" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8721.html</guid>
		</item>
		<item>
			<title>Раздумья над переходником I2C-USB на основе STM32</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8714.html</link>
			<pubDate>Sat, 16 Nov 2024 15:18:16 GMT</pubDate>
			<description>Очень удобно с I2C работать на одноплатниках, где шина выведена наружу, но: то флешка сдохнет ни с...</description>
			<content:encoded><![CDATA[<div>Очень удобно с I2C работать на одноплатниках, где шина выведена наружу, но: то флешка сдохнет ни с того, ни с сего, то еще какая беда… И тут-то подумалось: наверняка ведь есть аппаратные преобразователи, имеющие готовые модули ядра, чтобы линукс их видел как &quot;стандартные I2C&quot;, и работать можно было бы при помощи того же самого кода, что и на одноплатниках. И, казалось бы, таких устройств гора должна быть, ан нет: нашел лишь <a rel="nofollow noopener noreferrer" href="https://github.com/harbaum/I2C-Tiny-USB" target="_blank" title="https://github.com/harbaum/I2C-Tiny-USB">I2C tiny USB</a>. На убогой аврке. Ну, думаю: уж за полдня-то я, наверное, на STM32 реализую нужное USB устройство, был бы протокол! А вот хрен: нет описания протокола в репозитории. А ковыряться в тонне чужих исходников (в т.ч. и кернельного модуля) мне откровенно лень.<br />
Еще покопавшись на гитхабе, нашел <a rel="nofollow noopener noreferrer" href="https://github.com/gschorcht/i2c-ch341-usb" target="_blank" title="https://github.com/gschorcht/i2c-ch341-usb">модуль ядра</a> для какого-то преобразователя на основе CH341A тоже с интерфейсом CDC. Попробовал собрать. Куча ошибок, да оно и понятно: судя по дате, еще, небось, для четвертого ядра писали. На шестом не работает. А было заманчиво, т.к. там использовался обычный CDC (т.е. можно было и напрямую команды отправлять из терминала).<br />
И вот, из всего кажущегося многообразия фактически остается лишь один-единственный tiny-usb (зато он находится в официальном дереве, т.е. его не придется самому поддерживать, как тот же модуль модуль FLI'шных ПЗС). Сижу, смотрю в код модуля, и вообще не понимаю, как мне организовать это со стороны устройства. Оригинальный код прошивки для аврки еще большее недоразумение вызывает. А нормального словесного описания нигде не нашел.<br />
Вижу, что только одна конечная точка (помимо обязательной 0) используется. И работает на vendor requests. Надо, видимо, пробовать &quot;методом Монте-Карло&quot; ☺<br />
Правда, как-то стремно там все сделано. Такое впечатление, что с I2C по одному байту работа идет вместо того, чтобы сразу заслать команду &quot;читай мне N байт&quot; или &quot;принимай M байт&quot;.<br />
<br />
Или таки наплевать на кернельную поддержку и срукожопить 100500-й самопальный протокол? Устройство будет не только I2C обслуживать, но и по паре RS-232 и RS-485 (плюс, если делать не на STM32F1xx, можно CAN воткнуть, еще и останутся отладочные интерфейсы) - на основе моего &quot;7CDC в одном флаконе&quot;.</div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8714.html</guid>
		</item>
		<item>
			<title>Schematic of chinese FX3U-24MR</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8676.html</link>
			<pubDate>Fri, 04 Oct 2024 07:05:56 GMT</pubDate>
			<description>Дорисовал-таки (https://github.com/eddyem/stm32samples/tree/master/F1%3AF103/FX3U/kicad). Из не...</description>
			<content:encoded><![CDATA[<div><a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/stm32samples/tree/master/F1%3AF103/FX3U/kicad" target="_blank" title="https://github.com/eddyem/stm32samples/tree/master/F1%3AF103/FX3U/kicad">Дорисовал-таки</a>. Из не вошедшего в схему лишь три резистора-перемычки. И если смысл перемычек формата 0603 мне вообще непонятен (под ними нет дорожек, а замена их на резисторы с сопротивлением ничего не даст, наверное — сдувать их с платы уж совсем нафиг-нафиг), то перемычка перемычка 1210 между земляным полигоном и землей аналоговых выходов, наверное, должна была быть мини-дросселем или ферритовой бусиной. <br />
В остальном — косяк на косяке и косяком погоняет. Под катом приведу картинки (целиком картинку схемы не выйдет, дюже огромная, придется бить на функциональные узлы).<br />
<br />
Начнем с питания всего этого дела. Сделано оно достаточно загадочно:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8972&amp;st= c=1&amp;d=1728025040" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Ну, ладно. Дроссель L1 борется с импульсными или синфазными помехами (смотря как намотан). D19 — защита от переполюсовки (хотя, достаточно было бы просто сразу же за предохранителем воткнуть обратно диод между питанием и землей, и не согревать воздух). Но ведь можно было бы вообще без этих шоттки обойтись, т.к. стоит же D20 — TVS на 30В — при переполюсовке он бы сжег F1, и все было бы хорошо. Но нет, нахрена-то шоток натыкали… Потом — самое интересное: после D19 начинается общая точка для питания ОУ выхода ЦАП, опторазвязок дискретных входов, а также (еще через диоды Шоттки!!!) импульсника на 5В и релюшек дискретных выходов!<br />
На вход блока питания 5В воткнули параллельно три кондера на 1000мкФ. Ну, ОК, предположим, что для увеличения времени работы без питания (чтобы настройки успел МК сохранить: для этого еще один кондей на 1000мкФ добавили на выходе 5В). Номиналы большинства SMD кондеев мне не удалось измерить, естественно, поэтому здесь и дальше они пишутся &quot;от балды&quot; (просто в соответствии с традициями и рекомендациями даташитов).<br />
Да, 5В опять через шоттку выходит: ну на кой хрен? Чтобы меньше грелся линейник на 3.3В? Да, только сейчас свой косяк заметил, но уже лень исправлять: питание пятивольтовых потребителей (кроме &quot;кренки&quot; на 3.3В) идет сразу с C2, т.е. там реально 5В, а не ~4.5В, идущих на &quot;кренку&quot;.<br />
Батарейка — это нечто! Понятно, что если она сядет, LSE не будет запитан, пришлось пихать шоттки. Но какие-то странные: вместо традиционных для этой схемы SSxx использовали непонятные стеклянные цилиндрики. Причем, садится на них 0.3В, судя по тестеру. ЕМНИП, для организации батарейного питания есть вполне себе компактные контроллеры, которые имеют значительно меньшее прямое падение напряжения.<br />
Ну, а самый кайф — &quot;power detection&quot;! Т.е. аналоговые входы (см. далее) они защищать и не подумали, а тут аж опторазвязку поставили! Бред Сиверса Меринга, как говорится… И стартует &quot;power detect&quot; опять после шоттки. Весьма странно.<br />
АААААА! До меня дошло!!! D18 нужен для того, чтобы кондеи не разряжались на остальную 24-вольтовую часть. Ну, тогда резонный вопрос: а на кой хрен их вообще туда воткнули, а не после U19? Питали бы себе только МК с обвязкой, на кой хрен они в 24-вольтовой части сдались? Секретное назначение D19 и D2 мне непонятно.<br />
<br />
Микроконтроллер со стандартной обвязкой из кондеров, ну и еще мелочь некоторая:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8976&amp;st= c=1&amp;d=1728025252" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Опять вижу внешнюю подтяжку NRTS к питанию. Товарищи этим хотят сказать, что боятся наводок в цепях, что внутренняя подтяжка не справится? Они этот блок собрались ставить в какой-то шкаф с киловольтными разрядниками?<br />
Назначение RV1 и RV2 не очень понятно. Возможно, в оригинале можно было отверточкой их накрутить и какой-то двухразрядный десятичный адрес задать для платы (наиболее вероятное их назначение). <br />
Интересно, что светодиоды от 3.3В запитаны через 510 Ом, а не 330, как обычно. <br />
Переключатель SW3 сдвоен, но я не понял: физически или на схеме, поэтому на второй половинке на контакте 5 нарисовал &quot;не подключено&quot;. <br />
SWCLK я обозвал &quot;DE_485&quot;, так что, не пугайтесь, что он на выход &quot;Prog&quot; выведен. Вообще, странно, что они этот разъем оставили: какой в нем смысл, если в дальнейшем SDW заблокирован? Ну и прошивали бы через бутлоадер на USART1 (по RS-232), просто добавив какую-нибудь пимпочку на BOOT0, которую можно было бы замкнуть и ввести МК в режим бутлоадера при включении питания…<br />
Про еепромину я раньше уже писал: дичь дикая. Зачем оно надо при таком огромном объеме флеша на МК? <br />
Ну и там слева внизу одинокая такая перемычка R54, видимо, если ее нет, то RS-485 работает на дефолтных 9600 бод.<br />
<br />
Аналоговые входы и выходы:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8972&amp;st= c=1&amp;d=1728025252" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Тут уж замутили — так замутили! Главное — для ЦАПов замутили усилители (ну, оно и понятно: как из 3.3В сделать 10?), ограничение тока резисторами на 120 Ом, фильтрацию какую-то простейшую… А на АЦП — тупо делители напряжения! Где, блин, хотя бы стабилитроны в защите или, еще лучше, микросборки с TVS-ками? Интересно, что входы &quot;по напряжению&quot; как-то фильтруют кондеями, а на входах &quot;по току&quot; кондеев нет. <br />
<br />
Цифровые входы. Здесь ­— просто схематическое подключение гребенки:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8974&amp;st= c=1&amp;d=1728025252" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
А здесь — как раз блочок с опторазвязкой:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8973&amp;st= c=1&amp;d=1728025252" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Пытаясь впихнуть невпихуемое, китайцы отказались от внешней подтяжки входов 6÷15. И, как ни странно, оно же все равно работает! А зачем, спрашивается, внешние подтяжки на 0÷5?  Типа — лотерея: если будет &quot;мегашумно&quot;, то на выходах 6÷15 будет невесть что твориться? Или что?<br />
Здесь, кстати, светодиоды вообще килоомным резистором подтянуты, и ничего — светятся! <br />
Каждый светодиод опторазвязки &quot;на всякий случай&quot; зашунтирован диодом. Но таки в митсубишевском оригинале параллельно еще кондеи стоят.<br />
Самая дикая дичь в том, что: а) &quot;общий&quot; цивровых входов непосредственно связан с земляным полигоном; б) опторазвязки &quot;гвоздями прибиты&quot; к набортным 24В. В общем, в реальной системе это использовать крайне затруднительно и опасно. Как минимум, надо было поставить &quot;биполярные&quot; (со встречными светодиодами) опторазвязки и отвязать вообще вход от платы: чтобы ни питание, ни &quot;земля&quot; не были объединены. А как максимум — вообще вывести наружу по 2 контакта на каждую опторазвязку, чтобы уж при монтаже можно было сделать &quot;общий плюс&quot;, &quot;общий минус&quot; или вообще каждую по-отдельности.<br />
<br />
Цифровые выходы, блочно:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8977&amp;st= c=1&amp;d=1728025252" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Про D2 выше писал — ХЗ, зачем они так извращаются. Релюхи запитываются через дарлингтоновские сборки, а т.к. там внутри уже есть &quot;хитрый&quot; защитный диод, то паять по диоду параллельно катушке каждой релюшки не нужно.<br />
Вот так выглядят сами &quot;кубики&quot; с релюшками:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8979&amp;st= c=1&amp;d=1728025252" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Ничего интересного, все понятно. Разве что из-за попытки впихнуть невпихуемое, вместо того, чтобы с каждой релюхи вывести оба контакта наружу, их в группы объединили: 4+4+2. Это сильно затрудняет использование таких блоков, если земли ни в коем случае объединять нельзя. <br />
<br />
Ну и группа с интерфейсами:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8975&amp;st= c=1&amp;d=1728025252" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Насчет CAN я зря ругался: какая-никакая попытка защиты TVS есть. Таки на плате стоят пустые площадки для TVS. Ну и площадка для опционального терминаторного резистора.<br />
А вообще, стоимость тех же ISO1050 и DC-DC на 5В не такая уж и высокая: можно было бы и гальваноразвязку интерфейса сделать.<br />
Аналогично с остальными интерфейсами: почему они вообще не развязаны? RS-485 как-бы попытались TVS'ками защитить, а вот RS-232 вообще &quot;голой жопой&quot; на улицу торчит. Ну, да ладно: видимо, RS-232 и планировался как связь с расположенным в паре метров рядышком компом. <br />
<br />
В <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/stm32samples/tree/master/F1%3AF103/FX3U" target="_blank" title="https://github.com/eddyem/stm32samples/tree/master/F1%3AF103/FX3U">своей прошивке</a> (о ней можно почитать <a rel="nofollow noopener noreferrer" href="https://eddy-em.livejournal.com/480813.html" target="_blank" title="https://eddy-em.livejournal.com/480813.html">у меня в ЖЖ</a>) я не касался ЦАП, но если понадобится, и этот блок добавлю. Все остальное, как уже раньше писал, реализовал. И из вообще никчемного куска дерьма хоть нечто более-менее полезное получилось: любой может запрограммировать МК на С под свои нужды, особенно имея базовый код.</div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8972&amp;d=1728024996" target="attachment" rel="Lightbox" id="attachment8972"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8972&amp;stc=1&amp;thumb=1&amp;d=1728024996" border="0" alt="Нажмите на изображение для увеличения
Название: analog.png
Просмотров: 1806
Размер:	113.0 Кб
ID:	8972" /></a>
	&nbsp;
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8973&amp;d=1728024996" target="attachment" rel="Lightbox" id="attachment8973"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8973&amp;stc=1&amp;thumb=1&amp;d=1728024996" border="0" alt="Нажмите на изображение для увеличения
Название: in1.png
Просмотров: 1042
Размер:	24.5 Кб
ID:	8973" /></a>
	&nbsp;
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8974&amp;d=1728024996" target="attachment" rel="Lightbox" id="attachment8974"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8974&amp;stc=1&amp;thumb=1&amp;d=1728024996" border="0" alt="Нажмите на изображение для увеличения
Название: inputs.png
Просмотров: 1022
Размер:	154.5 Кб
ID:	8974" /></a>
	&nbsp;
	
		<br /><br />
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8977&amp;d=1728025006" target="attachment" rel="Lightbox" id="attachment8977"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8977&amp;stc=1&amp;thumb=1&amp;d=1728025006" border="0" alt="Нажмите на изображение для увеличения
Название: outputs.png
Просмотров: 1006
Размер:	179.5 Кб
ID:	8977" /></a>
	&nbsp;
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8978&amp;d=1728025006" target="attachment" rel="Lightbox" id="attachment8978"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8978&amp;stc=1&amp;thumb=1&amp;d=1728025006" border="0" alt="Нажмите на изображение для увеличения
Название: power.png
Просмотров: 335
Размер:	114.3 Кб
ID:	8978" /></a>
	&nbsp;
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8979&amp;d=1728025006" target="attachment" rel="Lightbox" id="attachment8979"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8979&amp;stc=1&amp;thumb=1&amp;d=1728025006" border="0" alt="Нажмите на изображение для увеличения
Название: relay1.png
Просмотров: 1030
Размер:	12.2 Кб
ID:	8979" /></a>
	&nbsp;
	
		<br /><br />
	

				</div>
			</fieldset>
		
		
		
			<fieldset class="fieldset">
				<legend>Изображения</legend>
				<table cellpadding="0" cellspacing="3" border="0">
				<tr>
	<td><img loading="lazy" decoding="async" class="inlineimg" src="http://www.cyberforum.ru//cyberstatic.net/images/attach/jpg.gif" alt="Тип файла: jpg" width="16" height="16" border="0" style="vertical-align:baseline" /></td>
	<td><a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8975&amp;d=1728024996">interfaces.jpg</a> (77.1 Кб, 1099 просмотров)</td>
</tr><tr>
	<td><img loading="lazy" decoding="async" class="inlineimg" src="http://www.cyberforum.ru//cyberstatic.net/images/attach/jpg.gif" alt="Тип файла: jpg" width="16" height="16" border="0" style="vertical-align:baseline" /></td>
	<td><a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8976&amp;d=1728024996">mcu.jpg</a> (112.8 Кб, 1073 просмотров)</td>
</tr>
				</table>
				</fieldset>
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8676.html</guid>
		</item>
		<item>
			<title>Обновил свой tty_term</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8349.html</link>
			<pubDate>Tue, 05 Dec 2023 17:34:43 GMT</pubDate>
			<description>Давно уже надо было добавить всяких полезностей в терминальный клиент...</description>
			<content:encoded><![CDATA[<div>Давно уже надо было добавить всяких полезностей в <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/tty_term" target="_blank" title="https://github.com/eddyem/tty_term">терминальный клиент</a> и пофиксить кое-какие баги. Основное — режимы ввода и отображения данных. При вводе доступны такие режимы.<ul><li>TEXT — все, что ввели, отправляется; строки завершаются заданным в параметрах командной строки EOL. Непечатаемые символы можно через escape-последовательности вводить.</li>
<li>RAW — пробелы не учитываются; текст отправляется как текст; числа в пределах 0..255 распознаются в системах по основанию 2, 8, 10 и 16.</li>
<li>HEX — все числа трактуются как шестнадцатеричные; если число длинное, оно разбивается на пары, которые считаются одним байтом; пробелы игнорируются.</li>
<li>RTU RAW — тот же RAW, но каждый раз в конце посылки вставляется контрольная сумма.</li>
<li>RTU HEX — тот же HEX, но с контрольной суммой.</li>
</ul>При выводе доступны режимы TEXT (непечатаемые символы выдаются как &quot;0xXX&quot;), RAW (в 16-й форме с разделением пробелами) и HEX (в формате hexdump -C).<br />
Учитывая то, что в скором времени придут китайские частотники, с которыми надо будет экспериментировать (понимаю ли они широковещательный адрес, или придется каждый оснащать переходником CAN-modbus), очень даже вовремя я это все доделал.<br />
<br />
И немножко картинок. Вот так выглядит экран в режиме вывода HEX:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8386&amp;st= c=1&amp;d=1701797433" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
По F1 можно посмотреть справку:<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8387&amp;st= c=1&amp;d=1701797457" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Заодно добавил возможность вывода сообщений об ошибках (черным на красном фоне поверх строки статуса) — буду пользоваться этим в дальнейшем развитии терминала.<br />
А вот так он принимает в формате RTU HEX и добавляет контрольную сумму (чтобы принимать эхо, я воткнул в USB PL2303 с замкнутыми Rx-Tx):<br />
<img src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8388&amp;st= c=1&amp;d=1701797457" border="0" alt="" style="max-width: 800px; margin: 5px 0px 5px 0px;" /><br />
Избавился от пары сегфолтов (бывает: для увеличения буфера char** на N штук, я увеличивал его на N байт), добавил обновление экрана в реальном времени (до этого wgetch у меня была блокирующей, поэтому после изменения размера экрана нужно было какую-нибудь кнопку нажать, чтобы это все дело отработало).<br />
Вот я еще обратил внимание, что надо бы мне добавить возможность работы с обычным сокет-файлом, т.к. иначе для эмуляции работы с сокетами нужно или сервер какой-то простой рисовать, или пользоваться netcat'ом, socat'ом и подобными вещами.</div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8388&amp;d=1701797432" target="attachment" rel="Lightbox" id="attachment8388"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8388&amp;stc=1&amp;thumb=1&amp;d=1701797432" border="0" alt="Нажмите на изображение для увеличения
Название: 03.png
Просмотров: 369
Размер:	23.8 Кб
ID:	8388" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
			<fieldset class="fieldset">
				<legend>Изображения</legend>
				<table cellpadding="0" cellspacing="3" border="0">
				<tr>
	<td><img loading="lazy" decoding="async" class="inlineimg" src="http://www.cyberforum.ru//cyberstatic.net/images/attach/jpg.gif" alt="Тип файла: jpg" width="16" height="16" border="0" style="vertical-align:baseline" /></td>
	<td><a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8386&amp;d=1701797432">01.jpg</a> (386.4 Кб, 348 просмотров)</td>
</tr><tr>
	<td><img loading="lazy" decoding="async" class="inlineimg" src="http://www.cyberforum.ru//cyberstatic.net/images/attach/jpg.gif" alt="Тип файла: jpg" width="16" height="16" border="0" style="vertical-align:baseline" /></td>
	<td><a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=8387&amp;d=1701797432">02.jpg</a> (71.2 Кб, 371 просмотров)</td>
</tr>
				</table>
				</fieldset>
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8349.html</guid>
		</item>
		<item>
			<title>О махровой антироссейщине в научпопе</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8348.html</link>
			<pubDate>Tue, 05 Dec 2023 17:27:16 GMT</pubDate>
			<description><![CDATA[Уж не думал, что со стороны фонда "Траектория" получу такую подлянку! До этого читал все полученные...]]></description>
			<content:encoded><![CDATA[<div>Уж не думал, что со стороны фонда &quot;Траектория&quot; получу такую подлянку! До этого читал все полученные в подарок книги — интересно и увлекательно. Но последнее время началось что-то совершенно дикое: похоже, в группе Каторжнова завелась тварь, которая активно хочет его упечь за решетку. Советую таки Николаю внимательней относиться к тому, что печатается за его деньги.<br />
К примеру, книга Сары Драй &quot;Воды мира&quot;. Там авторша активно продвигает лживые идеи &quot;зеленых&quot;. И под прикрытием научпопа мы видим подлую агитацию магнатов, набивающих карман на уничтожении природы своими &quot;электроавтомобилями&quot;, &quot;ветряными электростанциями&quot; и прочей дрянью. Прессинг настолько сильный, что книжку я даже на треть не осилил прочитать.<br />
К книге Николя Жизана &quot;Квантовая случайность&quot; у меня нет претензий по поводу антинаучности, но сама по себе книга жутко унылая. Было бы намного лучше, если б автор свое повествование уложил хотя бы в 10 раз лаконичней. Книгу едва дочитал до середины и понял, что дальше читать смысла нет: переливает из пустого в порожнее одно и то же.<br />
А вот книга Майкла Маршалла &quot;Великий квест&quot; вообще вызвала у меня бурю негодования, но таки на кусочки я ее не порвал и в мусорку не выбросил (хотя, стоит это сделать). Осилил не больше 20%. И меня просто замучила антисоветская и антироссийская агитация: как Сталин - так несколько страниц лжи о том, как он младенцев ел, даже Опарин под руку автору попался и превратился в франкенштейновского монстра. А как преступления фашистов - так тихонько одним предложением, как само собой разумеющееся - о том, что они на японцев пару ядреных бомб скинули (и, мол, так и надо было).<br />
<br />
В общем, смотрите внимательно, что пишут в свежих научно-популярных книгах. Дерьмократически-либерастская мразота уж очень сильно активировалась… Будьте бдительны, товарищи!</div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8348.html</guid>
		</item>
		<item>
			<title>SSL_accept обязательно оборачивать в неблокирующую обертку!</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8140.html</link>
			<pubDate>Thu, 15 Jun 2023 18:42:15 GMT</pubDate>
			<description>Как-то не парясь работаю с блокирующими сокетами, используя поллинг. А тут — SSL… И вот никаких...</description>
			<content:encoded><![CDATA[<div>Как-то не парясь работаю с блокирующими сокетами, используя поллинг. А тут — SSL… И вот никаких проблем не замечал, пока не решил проверить: а если я подключусь обычным соединением без рукопожатия. И тут у меня возникла блокировка на SSL_accept. Пришлось таки сокет делать неблокирующим:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="834312871"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="834312871" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1"><span class="kw4">int</span> client <span class="sy0">=</span> accept4<span class="br0">&#40;</span>fd<span class="sy0">,</span> <span class="br0">&#40;</span><span class="kw4">struct</span> sockaddr<span class="sy0">*</span><span class="br0">&#41;</span><span class="sy0">&amp;</span>addr<span class="sy0">,</span> <span class="sy0">&amp;</span>len<span class="sy0">,</span> SOCK_NONBLOCK<span class="br0">&#41;</span><span class="sy0">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>А <code class="inlinecode">SSL_accept</code> оборачивать в неблокирующую обертку:<br />
<div class="codeblock"><table class="c"><thead><tr><td colspan="2" id="529938757"  class="head">C</td></tr></thead><tbody><tr class="li1"><td><div id="529938757" style="height: 286px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
</pre></td><td class="de1"><pre class="de1"><span class="kw4">static</span> <span class="kw4">int</span> timeouted_sslaccept<span class="br0">&#40;</span>SSL <span class="sy0">*</span>ssl<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">double</span> t0 <span class="sy0">=</span> dtime<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">while</span><span class="br0">&#40;</span>dtime<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">-</span> t0 <span class="sy0">&lt;</span> ACCEPT_TIMEOUT<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> x <span class="sy0">=</span> SSL_accept<span class="br0">&#40;</span>ssl<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>x <span class="sy0">&lt;</span> <span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">int</span> sslerr <span class="sy0">=</span> SSL_get_error<span class="br0">&#40;</span>ssl<span class="sy0">,</span> x<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>SSL_ERROR_WANT_READ <span class="sy0">==</span> sslerr <span class="sy0">||</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SSL_ERROR_WANT_WRITE <span class="sy0">==</span> sslerr<span class="br0">&#41;</span> <span class="kw1">continue</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; DBG<span class="br0">&#40;</span><span class="st0">&quot;SSL error %d&quot;</span><span class="sy0">,</span> sslerr<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> FALSE<span class="sy0">;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="kw1">return</span> TRUE<span class="sy0">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; DBG<span class="br0">&#40;</span><span class="st0">&quot;Timeout&quot;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">return</span> FALSE<span class="sy0">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Вот такие пироги…<br />
Добавил <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/eddys_snippets/tree/master/SSL_Socket_snippet" target="_blank" title="https://github.com/eddyem/eddys_snippets/tree/master/SSL_Socket_snippet">сниппет на гитхаб</a>.</div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8140.html</guid>
		</item>
		<item>
			<title>Различаем USB-устройства с одинаковыми VID/PID</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8054.html</link>
			<pubDate>Tue, 11 Apr 2023 14:36:00 GMT</pubDate>
			<description>В возне с прототипом спектрографа ESPriF, наткнулся на то, что все мои три железяки (контроллер...</description>
			<content:encoded><![CDATA[<div>В возне с прототипом спектрографа ESPriF, наткнулся на то, что все мои три железяки (контроллер восьми шаговиков, контроллер объектива Canon и контроллер узла калибровки) абсолютно никак в системе не различаются: те же самые VID/PID/Manufacturer (собственно, эмулирую PL2303). <a href="https://www.cyberforum.ru/linux-hardware/thread3093787.html">Подсказали мне</a>, что можно завести текстовое поле Interface, которое поможет в дальнейшей идентификации. И вот на <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/stm32samples/tree/master/F3:F303/NitrogenFlooding" target="_blank" title="https://github.com/eddyem/stm32samples/tree/master/F3:F303/NitrogenFlooding">&quot;заполнялке азотом&quot;</a> я решил поиграться. Заодно лишний раз оптимизировал USB, выкинув ненужные флаги. Все индексы текстовых дескрипторов задаются в дескрипторе устройства и конфигурационном дескрипторе. Скажем: iManufacturer, iProduct, iSerialNumber и тот самый iInterface. Чтобы не запутаться, проще завести <code class="inlinecode">enum</code>, его поля и использовать как индексы. Если мы не хотим отдавать дескрипторы, задаем вместо индекса нуль. Ну, а дальше компьютер запрашивает нужный индекс и получает текстовую строку, которую и можно использовать в правиле udev, чтобы вместо кучи <code class="inlinecode">/dev/ttyUSBx</code> создать более понятные (например, <code class="inlinecode">/dev/nitrogen_flooding0</code> или <code class="inlinecode">/dev/canusb0</code>).<br />
Вот с правилами UDEV пришлось повозиться подольше: благо, есть <code class="inlinecode">udevadm test</code>, так что не пришлось постоянно шнурок туда-сюда втыкать/вытыкать. Сложность вызвало то, что поле Interface лежит в одном &quot;устройстве&quot;, а поля VID/PID — в &quot;родительских&quot;. Как обычно, <a rel="nofollow noopener noreferrer" href="https://unix.stackexchange.com/a/543695/30098" target="_blank" title="https://unix.stackexchange.com/a/543695/30098">SO помог</a> в решении этой проблемы (что бы мы без Stack Overflow делали вообще? Я, например, по латеху там кучу проблем решил, ну и сам немного людям помог; да и по C, линуксу, башу…). <br />
Одним словом, чтобы различить устройства с одинаковым VID/PID, нам нужно это правило:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="925260036"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="925260036" style="height: 62px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
</pre></td><td class="de1"><pre class="de1">ACTION==&quot;add&quot;, DRIVERS==&quot;usb&quot;, ENV<span class="br0">&#123;</span>USB_IDS<span class="br0">&#125;</span>=&quot;%s<span class="br0">&#123;</span>idVendor<span class="br0">&#125;</span>:%s<span class="br0">&#123;</span>idProduct<span class="br0">&#125;</span>&quot;
ACTION==&quot;add&quot;, ENV<span class="br0">&#123;</span>USB_IDS<span class="br0">&#125;</span>==&quot;067b:<span class="nu0">2303</span>&quot;, ATTRS<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>==&quot;?*&quot;, SYMLINK+=&quot;$attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>%n&quot;</pre></td></tr></table></div></td></tr></tbody></table></div>Т.е. когда udev будет пробегаться по всем &quot;родительским устройствам&quot;, на стадии добавления в систему USB он заведет переменную <code class="inlinecode">USB_IDS</code> а когда пройдется по &quot;дочернему&quot; устройству, проверит, соответствует ли эта переменная нужному VID:PID. Если соответствует — проверит, есть ли поле iInterface (нам не нужно &quot;настоящие&quot; PL2303 там именовать, да и у них все равно нет этого поля), и если оно есть — создаст нужную ссылочку.<br />
В простейшем же случае (в данном) наше устройство отличается от всех остальных полем &quot;DRIVERS&quot; (которое как раз является свойством &quot;подустройства&quot; с полем interface), поэтому можно упростить правило:<br />
<div class="codeblock"><table class="unknown"><thead><tr><td colspan="2" id="346862917"  class="head">Code</td></tr></thead><tbody><tr class="li1"><td><div id="346862917" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">DRIVERS==&quot;pl2303&quot;, ACTION==&quot;add&quot;, ATTRS<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>==&quot;?*&quot;, SYMLINK+=&quot;$attr<span class="br0">&#123;</span>interface<span class="br0">&#125;</span>%n&quot;</pre></td></tr></table></div></td></tr></tbody></table></div>Все, как только добавили устройство с нужным полем DRIVERS и существующим атрибутом interface, создастся нужная символическая ссылка.<br />
Теперь достаточно для каждого USB-устройства только лишь менять название этого поля. И в системе теперь не придется перебирать из кучи <code class="inlinecode">/dev/ttyUSBx</code>, чтобы найти свое устройство — на него будет удобный симлинк. Да и все демоны будут элементарно стартовать (не нужно будет перебирать устройства и запрашивать &quot;ТЫ ХТО, Э?&quot;).<br />
Кстати, <b>COKPOWEHEU</b> еще напомнил мне, что неизвестно, как себя поведет этот &quot;%n&quot; в правиле udev: ведь если ядро будет отдельно нумеровать каждый интерфейс составного устройства, получится совсем не то, что ожидалось (скажем, подключенное составное устройства вместо <code class="inlinecode">/dev/rs485_0</code>, <code class="inlinecode">/dev/rs232_0</code>, <code class="inlinecode">/dev/can0</code> и <code class="inlinecode">/dev/converter_setup0</code> создаст <code class="inlinecode">/dev/rs485_0</code>, <code class="inlinecode">/dev/rs232_1</code>, <code class="inlinecode">/dev/can2</code> и <code class="inlinecode">/dev/converter_setup3</code>).</div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8054.html</guid>
		</item>
		<item>
			<title>CCD_Capture</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8048.html</link>
			<pubDate>Fri, 07 Apr 2023 13:04:55 GMT</pubDate>
			<description><![CDATA[Исправил кое-какие баги в CCD_Capture (https://github.com/eddyem/CCD_Capture"), но таки часть еще...]]></description>
			<content:encoded><![CDATA[<div>Исправил кое-какие баги в <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/CCD_Capture&quot;" target="_blank" title="https://github.com/eddyem/CCD_Capture&quot;">CCD_Capture</a>, но таки часть еще осталась: иногда подвисает передача по сети (особенно когда окно двигаешь — видимо, потоки между собой начинают &quot;драться&quot;); в standalone режиме сегфолтится при отключении камеры (т.е. где-то я что-то прошляпил); возможно, еще какие-то невыявленные пока баги есть (а пока баг не выявлен, обозвать его &quot;фичей&quot; не выйдет).<br />
Почему-то получилось, что использование openmp только тормозило: при openmp выполнение эквализации изоображения в 1Мпиксель занимало 20мс, а без нее — 1мс. Ну, понятно, там требуется синхронизация потоков. Однако, элементарные операции преобразования в псевдоцвета тоже ускорились (!!!), когда я выкинул openmp (а там-то вообще независимо каждый пиксель обрабатывается — ничего синхронизировать не нужно). Еще косяк — с отображением (почему-то без эквализации гистограммы вообще сплошной синий фон, надо будет изменить &quot;линеаризацию&quot;: вычислять на масштабе 0..максимальная яркость кадра, а не 0..65536 — в 8-битном режиме вообще черт знает что выходит).<br />
Провел тесты по скорости. Экспозиция — 1мс, сначала проверил на &quot;dummy&quot; — эмуляторе светоприемника: кадр 1050×1050: 34..62 в режиме standalone, 35..42 — по сети; кадр 100×100: 83..103 — standalone, 36..48 — network.<br />
И на Basler: кадр 1928×1208: 18..19 — standalone, 18..19 — network; 100×100: 30..35 — standalone, 28..31 — network. <br />
Ну, по крайней мере, не 2 кадра в секунду, как было у меня с использованием &quot;куска автогида&quot; от предыдущего спектрографа. Будем запускать напрямую ccd_capture и смотреть хоть локально, хоть по сети (с туннелированием портов посредством ssh). Жаль, что биннинг вообще никак не отражается на скорости считывания (хотя, казалось бы: если биннинг выполняется средствами DSP самой камеры, то даже 2×2 уже должен в 4 раза скорость считывания повысить). Ну, все равно нужно будет включать биннинг 4×4, т.к. уж слишком огромная звезда получается.<br />
Пока забью на некоторые баги и вернусь к <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/improclib" target="_blank" title="https://github.com/eddyem/improclib">improclib</a> — таки надо быстрей сделать автогид для ESPriF.</div>

]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8048.html</guid>
		</item>
		<item>
			<title>Библиотек много не бывает</title>
			<link>https://www.cyberforum.ru/blogs/1886385/8026.html</link>
			<pubDate>Wed, 29 Mar 2023 11:51:53 GMT</pubDate>
			<description><![CDATA[В очередной раз надо "старый новый" автогид делать (практически то же самое, что и на инасановский...]]></description>
			<content:encoded><![CDATA[<div>В очередной раз надо &quot;старый новый&quot; автогид делать (практически то же самое, что и на инасановский оптоволоконный спектрограф, но с другим исполнительным механизмом). Решил, что хватит уже одни и те же куски кода туда-сюда таскать, рискуя выдернуть более старую версию с багами. Завел репу <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/improclib" target="_blank" title="https://github.com/eddyem/improclib">improclib</a> и понемногу оформляю код в виде библиотеки. Кстати, с удивлением обнаружил, что у меня уже есть рабочая <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/fitsmaniplib" target="_blank" title="https://github.com/eddyem/fitsmaniplib">библиотека</a> для работы с FITS-файлами ☺ Но таки подумал, что не стоит мешать эту библиотеку и ту (лучше в случае необходимости буду с тремя сразу линковать - ведь <a rel="nofollow noopener noreferrer" href="https://github.com/eddyem/snippets_library" target="_blank" title="https://github.com/eddyem/snippets_library">usefull_macros</a> у меня уже стала обязательной библиотекой). <br />
<br />
Сейчас у меня реализованы простейшие вещи: чтение и запись jpg/png (при помощи header-only библиотеки stb); конструкторы-деструкторы для разных типов данных (изображения могут быть цветными или же одноканальными: uint8_t, uint16_t, uint32_t, float и double); генерирование простейших &quot;паттернов&quot;: два типа крестов и &quot;звезда&quot; (функция Моффата); рисование прямых и окружностей по Брезенхему; эквализация гистограммы (правда, только для 8- и 16-битных изображений); преобразования между разными типами изображений; рисование текста.<br />
Как всегда, сразу же сопровождаю &quot;примерами&quot; (которые на самом деле используются для тестирования добавляемых функций). Вот, например, простейшее. Изображение, сгенерированное genu16:<br />
[img]https://i.**********/H7Vkf4f.png[/img]<br />
Оно же после эквализации гистограммы equalize:<br />
[img]https://i.**********/CZm3FBv.jpeg[/img]<br />
Еще добавлю рисование сетки (только на цветных изображениях) — бывает нужно иной раз, и, наверное, вырезание подызображения. А там уж можно будет и остальное реализовать — морфологию, связные области и т.п.<br />
<br />
UPD: непонятно, как сделать ссылки на изображения из аттачмента.</div>


<!-- attachments -->
	<div style="margin-top:10px">

		
			<fieldset class="fieldset">
				<legend>Миниатюры</legend>
				<div style="padding:3px">
				
	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7991&amp;d=1680090685" target="attachment" rel="Lightbox" id="attachment7991"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7991&amp;stc=1&amp;thumb=1&amp;d=1680090685" border="0" alt="Нажмите на изображение для увеличения
Название: output.jpg
Просмотров: 279
Размер:	122.5 Кб
ID:	7991" /></a>
	&nbsp;
	

	<a href="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7992&amp;d=1680090685" target="attachment" rel="Lightbox" id="attachment7992"><img loading="lazy" decoding="async" class="thumbnail" src="https://www.cyberforum.ru/blog_attachment.php?attachmentid=7992&amp;stc=1&amp;thumb=1&amp;d=1680090685" border="0" alt="Нажмите на изображение для увеличения
Название: output2.png
Просмотров: 258
Размер:	43.6 Кб
ID:	7992" /></a>
	&nbsp;
	

				</div>
			</fieldset>
		
		
		
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>Eddy_Em</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/1886385/8026.html</guid>
		</item>
	</channel>
</rss>
