Geosan

Сен 162019
 

Arduino проект выходного дня – футболка на светодиодах SK6812

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

a8ce3f6346f54f69a3407cfa91a530d2.jpg

Я потратил на изготовление этой футболки два вечера, а потом еще неделю игрался, выдумывая различные фигуры для её оживления. Из чего это сделано:

1. Arduino Nano – она маленькая и её очень удобно вшивать в подобные конструкции. Только ножки отпаяйте!
2. 64 светодиода SK6812. Для матрицы 8 х 8. Это RGBW светодиоды с пиксельной адресацией. RGBW – это значит, что в них три кристалла RGB и одна “яичница” белого свечения. Очень яркая!
3. Кнопка для смены эффектов.
4. Аккумулятор 1800 мА.час.
5. Провод МГТФ.
6. Припой, флюс, и 8 часов свободного времени.

Что должно получится:

Носимую матрицу 8 х 8 делаем так – берем лоскут ткани 20 на 20 см. и приклеиваем к ней «Моментом» все 64 светодиода на расстоянии 2,5 см. Обратите внимание – первая строчка из восьми светодиодов яичницей вверх, втора вниз, затем вверх, вниз и.т.д. Если перепутаете замучаетесь соединять… Держаться они очень крепко отодрать можно только с тканью. Дальше соединяем их по схеме:

39b832365bfc436ea859b622528ab30c.jpg
Здесь тоже строго. В скетче описана матрица из светодиодов сигнальные линии, которых соединяются как на схеме. Сверху вниз и поочередно слева направо, затем справа налево.

Питание светодиодов в любом направлении. Питание я делал тоже “змейкой”. Вход первого светодиода подключаем к 12 входу ардуины. Сама ардуина пришита на этот же лоскут. Маленькая Nano, без ножек её под футболкой почти не видно.

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

В конструкции ещё есть кнопка для смены эффектов и аккумулятор. Они пока в заднем кармане.

Теперь о скетче. Писать, рисовать очень просто. В ролике на футболке у моей помощнице Екатерины сначала поочередно зажигаются буквы – KATRINDETKA. Ниже проиллюстрировано как написать букву K. Первая строчка буквы – 11100011. 1 – светодиоды светятся, 0 – нет.

Виндусовым калькулятором в режиме программиста переводим бинарный код в HEX получаем 0xE3.

В скетче (файл LEDS_64_panel.h) смотрим на строчку:

const uint8_t DIG_0[] PROGMEM = { 0xE3, 0xE7, 0xEE, 0xFC, 0xFC, 0xEE, 0xE7, 0xE3, }; //k

Это буква К, все восемь строчек. Первая строчка как раз 0xE3. Мне кажется дальше всё понятно.

1d92ca1bb8ce489a9188d2b0e980a5ae.jpg

Это отображение картинки в байтах. Но можно и бинарном коде без перевода в HEX. Ищите ниже массив:

const uint8_t SQUARE_1[PIXEL_NUM] PROGMEM = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, };

Это квадрат на футболке. На видео после нажатия кнопки. Он описывается просто в двоичном коде. Можно изменить цвет и яркость фона или рисунка.

BACK_COLOUR
MAIN_COLOUR

Можно изменить частоту кадров

SHOW_DELAY
TETRIS_DELAY

Схема очень простая, скетч тоже. Работа очень кропотливая! Зато результат невероятно красивая техно одежда. Видео не передает и десятую долю вау эффекта.

Как работают светодиоды с пиксельной адресацией, рассказывать не буду. Просто сделайте красивую вещь!

Хороших вам выходных!
Скетч LEDS_64_panel.h

p.s. Очень удобно для рисования использовать редактор шрифтов, коих в интернете немерено. Мне понравился этот. Он же на последней картинке за калькулятором. Генерит строчки в С.

И ещё — будут нужны библиотеки: Adafruit_NeoPixel и PinChangeInt. Найдёте у Ады ладно?

Добавлено 09.06.2017
Скетч для цветной матрицы. Скачать.
и ролик с демонстрацией

Теги:

ЧИТАЮТ СЕЙЧАС

Сен 092019
 

Здравствуйте. Имеется идея изготовления повышающих dc-dc преобразователей, которые продаются на Ali-express, в домашних условиях.

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

Схему нашёл на просторах ютуба у одного человека на канале, добра ему.

Помогите определить номинал C1, C2, C7, C8, C9, C10

tl494.jpg

Изготовление плат

 Arduino  Комментарии к записи Изготовление плат отключены
Авг 212019
 

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

Итак, вводная – надо собрать дюжину плат с SMD-деталями типоразмера 0603 и Bluetooth-модулем на CC2541. Плату я нарисовал в DipTrace, заказал в Резоните изготовление собственно плат, а в OSH Stencils – трафарета из полиимидной пленки. Детали куплены частично на алиэкспрессе (собственно сами Bluetooth-модули), а частично – в Чип-и-Дипе и Электронщике. И вот со всей этой фигней мы попытаемся взлететь 🙂

paste-printer

По-хорошему, нужен трафаретный принтер, который натягивает трафарет и правильно позиционирует его относительно платы, и есть даже неплохие “самодельные” варианты – но для кустарных условий сойдет и такое приспособление из обрезков других плат той же толщины.

paste-ready

Паста размазывается чем-нибудь типа шпателя или пластиковой карты, при небольшом навыке это делается довольно быстро и непринужденно – на 12 плат у меня ушло меньше 10 минут.

placing

Расстановка деталей – довольно муторный этап, особенно, если делать это обычным пинцетом – но с перерывами я расставил две сотни деталей за два часа. Для сравнения – у самого-самого простого “любительского” установщика типа какого-нибудь Liteplacer заявленная производительность составляет 500-600 деталей в час (хотя с учетом времени на его программирование этот процесс занял бы примерно то же время).

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

into-the-oven

Дальше загружаем платы в печку.

oven-running

Это обычная бытовая электродуховка, снабженная специальным контролером, который обеспечивает “правильный” температурный профиль. Цикл пайки занимает несколько минут.

oven-done

В течение еще нескольких минут платы остывают.

boards

Готово! Остается запаять лишь пару разъемов.

Монтаж

 Arduino  Комментарии к записи Монтаж отключены
Авг 212019
 

Монтаж

И вот тут, конечно, начинается самое интересное — платы есть, компоненты есть, дальше-то что?

Главный тезис: современные платы паяльником вручную не собирают.

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

На современных платах абсолютное большинство компонентов — SMD, и более того, когда вы попробуете минимально пристойные методики сборки, вы будете плакать каждый раз, когда будете вынуждены ставить THD-компонент.

SMD-компоненты паяются пастой — смесью из флюса и микронного размера шариков припоя (мы используем Multicore CR36, но это не обязательно).

Паста наносится строго на контактные площадки компонентов одним из двух способов:

  • пневматическим — компрессором на 4-6 атмосфер (подойдёт любой с ресивером, чтобы обеспечить стабильность давления) и диспенсером типа такого. Диспенсер стоит у китайцев баксов сто и обеспечивает простую вещь — при нажатии педали подаёт в шприц с пастой воздух под заданным давлением в течение заданного времени, выжимая заданное количество пасты. Немного муторно, но среднего размера плату вы заплюёте минут за пятнадцать-двадцать, причём при определённой сноровке можно работать даже с компонентами 0402. Паста для диспенсеров продаётся уже в шприцах, мы используем EFD SolderPlus (точнее, почти не используем, ибо диспенсер минимум 364 дня в году просто покрывается пылью).
  • по трафарету — листу стали или пластика с вырезанными в нём отверстиями контактных площадок, толщиной 100-125 мкм. Трафарет кладётся сверху на плату, на него вываливается шлепок паяльной пасты и размазывается шпателем или просто пластиковой карточкой. В идеале для этого процесса нужен ручной трафаретный принтер, обеспечивающий вертикальное поднимание и опускание трафарета, но в небольших масштабах можно просто закреплять плату и трафарет малярным скотчем на столе. Обработка одной платы занимает, очевидно, всего пару минут.

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

wydtchrcepcswghlapp16zdsv_m.jpeg

Данная часть была бы не столь весёлой — трафарет штука довольно дорогая — если бы не одно чудесное изобретение человечества: режущий плоттер Silhouette Curio, предназначенный для вырезания аппликаций для скрапбуков, но также прекрасно справляющийся с «прозрачками» для проекторов. Последние имеют толщину 100 мкм — думаете, это просто так, совпадение?

Плоттер принимает на вход файлы DXF (причём в бесплатной версии софта; платная добавляет поддержку очень нужного для скрапбуков SVG) и без проблем справляется с компонентами размером вниз до SOIC и 0603. Пассивка 0402 выходит похуже, но ещё приемлемо, а во всяких QFN приходится убирать отдельные ножки и делать сплошную прорезь.

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

После вырезания и намазывания идёт расстановка деталей.

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

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

В отличие от обычных пинцетов, эта штука позволяет брать компоненты любой формы и с любой поверхности, в том числе прямо из лент, а в отличие от механических вакуумных пинцетов с кнопкой и резиновой грушей внутри, не даёт рывка при отпускании детали. Стоит такой пинцет копейки — меньше 1500 рублей у китайцев, а при желании можно сделать и самому натурально из аквариумного воздушного компрессора. Иголки со временем забиваются паяльной пастой, но без проблем покупаются отдельно, как наборами разного диаметра, так и пакетами одного диаметра по 10-20-50-100 штук.

Обычным пинцетом останется расставить только самые крупные компоненты, вроде процессоров в LQFP-корпусах.

Важный момент: на дворе XXI век, расстановку по бумажной распечатке из CAD’а никто уже не делает.

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

evkvnpabpeihivvznqryiljfoxa.png

Более того, VisualPlace умеет группировать компоненты по полю value, так что, взяв в руки катушку транзисторов SI2333 и ткнув в группу с ними, вы увидите сразу все места, где они должны стоять.

Авторами утилита писалась явно в первую очередь для себя (и, кстати, они же делают прекрасную маленькую терминалку Termite), поэтому, с одной стороны, она не перегружена ненужным хламом и красивыми иконками, с другой — есть много шероховатостей в понимании единиц измерения (дюймы или миллиметры), точки отсчёта координат в герберах (рекомендую всегда ставить начало на нижний левый угол платы) и т.п. На это иногда накладываются ещё и особенности CAD’ов — например, DipTrace на системе с русской локалью сохраняет числа с десятичным разделителем «,», а VisualPlace ждёт «.» независимо от локали.

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

Где-то примерно в этот момент вы почувствуете всю прелесть такого подхода к монтажу. Сравните — паяльник:

  • в правую руку паяльник, в левую — припой
  • поставить каплю припоя на одну площадку резистора
  • отложить припой, отложить паяльник
  • вытряхнуть резистор из ленты, перевернуть маркировкой вверх
  • в левую руку пинцет, взять резистор пинцетом, поставить на плату
  • не отпуская резистор, взять в правую руку паяльник, прихватить ту площадку, на которую был нанесён припой
  • отложить пинцет, взять припой
  • прихватить вторую площадку
  • повторить для остальных 146 компонентов

Паста:

  • намазать всю плату пастой
  • взять вакуумный пинцет, расставить все компоненты прямо из лент и поддонов
  • сунуть плату в печку

О, да. После того, как вы расставили компоненты (ставить надо с небольшим усилием, чтобы они впечатались в пасту), приходит пора печки.

Задача печки — нагреть пасту с заданной скоростью до 140-160 градусов (температура активации и испарения флюса), потом до 220-230 (плавление припоя), подержать недолго и охладить.

Строго говоря, на совсем штучных изделиях можно прогревать пасту феном, но это годится только буквально на 5-10 экземпляров, а также подвергает компоненты серьёзному стрессу из-за больших градиентов температур. Печка же греет равномеро и плавно.

Опять же, что очень радует — хотя китайцы делают вполне себе недорогие печки, совсем самодельную можно сделать из совершенно грошовой электродуховки (я не рекомендую данную конкретную модель, это просто ссылка) или аэрогриля, добавив к ним сделанный хоть на Arduino контроллер температуры, выдерживающий нужный профиль по градусам и по минутам. Стоимость такого решения в наколенном варианте будет меньше 5 тысяч рублей за всё в сумме.

Собственно, всё. После запекания остаётся на компонентах с мелким шагом проверить ножки на предмет возможных залипаний (вопреки утверждениям в многочисленных руководствах — нет, паяльная паста далеко не всегда сама идеально собирается точно на ножке, если её чуть больше, чем надо, или размазана она сильнее, чем надо — поверхностного натяжения не хватит, чтобы разорвать перемычку между соседними ножками), всё найденное убрать обычным паяльником, на чипах с длинными ногами и мелким шагом, вроде LQFP или TSSOP с шагом 0,5 мм, — с оплёткой для выпайки.

Изменение размера изображения средствами PHP

 Arduino  Комментарии к записи Изменение размера изображения средствами PHP отключены
Авг 212019
 

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

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

<?php class SimpleImage { var $image; var $image_type; function load($filename) { $image_info = getimagesize($filename); $this->image_type = $image_info[2]; if( $this->image_type == IMAGETYPE_JPEG ) { $this->image = imagecreatefromjpeg($filename); } elseif( $this->image_type == IMAGETYPE_GIF ) { $this->image = imagecreatefromgif($filename); } elseif( $this->image_type == IMAGETYPE_PNG ) { $this->image = imagecreatefrompng($filename); } } function save($filename, $image_type=IMAGETYPE_JPEG, $compression=75, $permissions=null) { if( $image_type == IMAGETYPE_JPEG ) { imagejpeg($this->image,$filename,$compression); } elseif( $image_type == IMAGETYPE_GIF ) { imagegif($this->image,$filename); } elseif( $image_type == IMAGETYPE_PNG ) { imagepng($this->image,$filename); } if( $permissions != null) { chmod($filename,$permissions); } } function output($image_type=IMAGETYPE_JPEG) { if( $image_type == IMAGETYPE_JPEG ) { imagejpeg($this->image); } elseif( $image_type == IMAGETYPE_GIF ) { imagegif($this->image); } elseif( $image_type == IMAGETYPE_PNG ) { imagepng($this->image); } } function getWidth() { return imagesx($this->image); } function getHeight() { return imagesy($this->image); } function resizeToHeight($height) { $ratio = $height / $this->getHeight(); $width = $this->getWidth() * $ratio; $this->resize($width,$height); } function resizeToWidth($width) { $ratio = $width / $this->getWidth(); $height = $this->getheight() * $ratio; $this->resize($width,$height); } function scale($scale) { $width = $this->getWidth() * $scale/100; $height = $this->getheight() * $scale/100; $this->resize($width,$height); } function resize($width,$height) { $new_image = imagecreatetruecolor($width, $height); imagecopyresampled($new_image, $this->image, 0, 0, 0, 0, $width, $height, $this->getWidth(), $this->getHeight()); $this->image = $new_image; } } ?>

Скачать клаcc SimpleImage

Теперь после того как мы поместили данный файл класса SimpleImage к себе на сервер посмотрим как его можно использовать.

Следующий участок кода загрузит изображение image.jpg, изменить его ширину до 400 пикселей и высоту до 200 пикселей, а затем сохранит как image1.jpg.

<?php include('classSimpleImage.php'); $image = new SimpleImage(); $image->load('image.jpg'); $image->resize(400, 200); $image->save('image1.jpg'); ?>

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

<?php include('classSimpleImage.php'); $image = new SimpleImage(); $image->load('image.jpg'); $image->resizeToWidth(250); $image->save('image1.jpg'); ?>

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

<?php include('classSimpleImage.php'); $image = new SimpleImage(); $image->load('image.jpg'); $image->scale(50); $image->save('image1.jpg'); ?>

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

<?php header('Content-Type: image/jpeg'); include('classSimpleImage.php'); $image = new SimpleImage(); $image->load('image.jpg'); $image->resizeToWidth(150); $image->output(); ?>

Автор данного класса Simon Jarvis, на своем сайте предлагает следующий пример для изменения размера изображения загруженного через форму.

<?php if (isset($_POST['submit']) ) { include('classSimpleImage.php'); $image = new SimpleImage(); $image->load($_FILES['uploaded_image']['tmp_name']); $image->resizeToWidth(150); $image->output(); } else { $form = '<form action="upload.php" method="post" enctype="multipart/form-data"> <input type="file" name="uploaded_image" /> <input type="submit" name="submit" value="Upload" /> </form>'; echo $form; }

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

Режимы для фрез/сверл/резьбофрез по металлам, ал юминию, дереву, пластикам

 Arduino  Комментарии к записи Режимы для фрез/сверл/резьбофрез по металлам, ал юминию, дереву, пластикам отключены
Авг 152019
 

Режимы для фрез/сверл/резьбофрез по металлам, алюминию, дереву, пластикам

Дерево/Пластики Алюминий (стр.58) Металлы (стр.59) Резьбофрезы (стр.61) Свёрла (стр.62)

Гироскутер

 Arduino  Комментарии к записи Гироскутер отключены
Авг 112019
 

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

Что может программа:
1. Управление от RC передатчика ppm-sum в этом случае работают два колеса не зависимо друг от друга (вперед, назад, вправо и в лево).
y4eacz_thumb.jpeg
uhfhmj_thumb.jpeg
приемник подключается на прямую к контроллеру гироскутера.

2. Управление от джойстика необходим джойстик от видеоигры плейстейшен. (вперед,назад, вправо и в лево).
uxm0x2_thumb.jpeg

3. Управление переменным сопротивлением, вперед, назад и переключение скоростей информация предоставлена Viktor_7
ссылка
1mfppw1_thumb.jpeg
Подходит для самокатов и машинок можно ставить ограничение по скорости максимальная скорость 25 км час.

4. То что использую Я это управление arduino по протоколу uart.

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

Выбирайте на ваше усмотрение.
Дальше больше :exactly:

Сам контроллер гироскутера
1350e45_thumb.jpeg

Так как программа написана на языке С++ ее надо скомпилировать для так сказать волшебного превращения в прошивку для контроллера гироскутера.

рассмотрим настройку программы под свои проекты.
это файл в программе где вы делаете свои установки config.h

#pragma once
#include «stm32f1xx_hal.h»

// ############################### Менять данные запрещено 100% выход из строя контроллера ну или его не работа

#define PWM_FREQ 16000 // PWM частота 16 кГц
#define DEAD_TIME 32 // PWM deadtime

#define DELAY_IN_MAIN_LOOP 5 // in ms. default 5. it is independent of all the timing critical stuff. do not touch if you do not know what you are doing.

#define TIMEOUT 5 // number of wrong / missing input commands before emergency off

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

// ############################### GENERAL ###############################

// How to calibrate: connect GND and RX of a 3.3v uart-usb adapter to the right sensor board cable (be careful not to use the red wire of the cable. 15v will destroye verything.). if you are using nunchuck, disable it temporarily. enable DEBUG_SERIAL_USART3 and DEBUG_SERIAL_ASCII use asearial terminal.

// Battery voltage calibration: connect power source. see <How to calibrate>. write value nr 5 to BAT_CALIB_ADC. make and flash firmware. then you can verify voltage on value 6 (devide it by 100.0 to get calibrated voltage).
#define BAT_CALIB_REAL_VOLTAGE 43.0 // установить напряжение измеренное тестером на вашем аккумуляторе (в данный момент используется 43 вольта)

#define BAT_CALIB_ADC 1704 // BAT_CALIB_ADC -это калибровочный коэффициент для расчёта напряжения, т.е. число 1704 — это количество
отсчётов, при подаче на вход делителя напряжения НАПРЯЖЕНИЯ = 43.0

#define BAT_NUMBER_OF_CELLS 10 // количество ячеек в аккумуляторе: 10s
#define BAT_LOW_LVL1_ENABLE 0 // вкл/выкл звука при низком напряжении, 1 or 0
#define BAT_LOW_LVL1 3.6 // пищит на этом уровне напряжения. [В/эл.]
#define BAT_LOW_LVL2_ENABLE 1 // to beep or not to beep, 1 or 0
#define BAT_LOW_LVL2 3.5 // your battery is almost empty. Charge now! [V/cell]
#define BAT_LOW_DEAD 3.37 // undervoltage poweroff. (while not driving) [V/cell]

#define DC_CUR_LIMIT 15 // DC current limit in amps per motor. so 15 means it will draw 30A out of your battery. it does not disable motors, it is a soft current limit.

// Board overheat detection: the sensor is inside the STM/GD chip. it is very inaccurate without calibration (up to 45В°C). so only enable this funcion after calibration! let your board cool down. see <How to calibrate>. get the real temp of the chip by thermo cam or another temp-sensor taped on top of the chip and write it to TEMP_CAL_LOW_DEG_C. write debug value 8 to TEMP_CAL_LOW_ADC. drive around to warm up the board. it should be at least 20В°C warmer. repeat it for the HIGH-values. enable warning and/or poweroff and make and flash firmware.
#define TEMP_CAL_LOW_ADC 1655 // temperature 1: ADC value
#define TEMP_CAL_LOW_DEG_C 35.8 // temperature 1: measured temperature [В°C]
#define TEMP_CAL_HIGH_ADC 1588 // temperature 2: ADC value
#define TEMP_CAL_HIGH_DEG_C 48.9 // temperature 2: measured temperature [В°C]
#define TEMP_WARNING_ENABLE 0 // to beep or not to beep, 1 or 0, DO NOT ACTIVITE WITHOUT CALIBRATION!
#define TEMP_WARNING 60 // annoying fast beeps [В°C]
#define TEMP_POWEROFF_ENABLE 0 // to poweroff or not to poweroff, 1 or 0, DO NOT ACTIVITE WITHOUT CALIBRATION!
#define TEMP_POWEROFF 65 // overheat poweroff. (while not driving) [В°C]

#define INACTIVITY_TIMEOUT 8 // установка времени отключения если вы не используете включено устройство

// ############################### LCD DEBUG ###############################

Здесь вы включаете или выключаете работу дисплея ( дисплей 128х64 i2c ssd1306 или 1602 i2c
выводит напряжение и обороты каждого колеса.

//#define DEBUG_I2C_LCD // standard 16×2 or larger text-lcd via i2c-converter on right sensor board cable

// ############################### UART протокол ###############################

#define DEBUG_SERIAL_USART3 // PB10,PB11 disable if I2C (nunchuck or lcd) is used!
#define DEBUG_BAUD 115200 // UART
//#define DEBUG_SERIAL_SERVOTERM
#define DEBUG_SERIAL_ASCII // «1:345 2:1337 3:0 4:0 5:0 6:0 7:0 8:0\r\n» сам протокол

// ############################### INPUT ###############################

// ###### CONTROL VIA UART (serial) ######
//#define CONTROL_SERIAL_USART2 // left sensor board cable, disable if ADC or PPM is used!

скорость передачи общения между контроллером и Ардуино
#define CONTROL_BAUD 19200 // control via usart from eg an Arduino or raspberry

эту строчку надо вписать в ваш скетч для управления ардуино.
// for Arduino, use void loop(void){ Serial.write((uint8_t *) &steer, sizeof(steer)); Serial.write((uint8_t *) &speed, sizeof(speed));delay(20); }

// ###### использование PPM-SUMM######
// left sensor board cable. Channel 1: steering, Channel 2: speed.
//#define CONTROL_PPM // use PPM-Sum as input. disable DEBUG_SERIAL_USART2!
//#define PPM_NUM_CHANNELS 6 // количество каналов

// ###### CONTROL VIA TWO POTENTIOMETERS ######
// ADC-calibration to cover the full poti-range: connect potis to left sensor board cable (0 to 3.3V) (do NOT use the red 15V wire in the cable!). see <How to calibrate>. turn the potis to minimum position, write value 1 to ADC1_MIN and value 2 to ADC2_MIN. turn to maximum position and repeat it for ADC?_MAX. make, flash and test it.
#define CONTROL_ADC // use ADC as input. disable DEBUG_SERIAL_USART2!
#define ADC1_MIN 0 // min ADC1-value while poti at minimum-position (0 — 4095)
#define ADC1_MAX 4095 // max ADC1-value while poti at maximum-position (0 — 4095)
#define ADC2_MIN 0 // min ADC2-value while poti at minimum-position (0 — 4095)
#define ADC2_MAX 4095 // max ADC2-value while poti at maximum-position (0 — 4095)

// ###### CONTROL VIA NINTENDO NUNCHUCK ######
// left sensor board cable. keep cable short, use shielded cable, use ferrits, stabalize voltage in nunchuck, use the right one of the 2 types of nunchucks, add i2c pullups. use original nunchuck. most clones does not work very well.
//#define CONTROL_NUNCHUCK // use nunchuck as input. disable DEBUG_SERIAL_USART3!

// ############################### DRIVING BEHAVIOR ###############################

// inputs:
// — cmd1 and cmd2: analog normalized input values. -1000 to 1000
// — button1 and button2: digital input values. 0 or 1
// — adc_buffer.l_tx2 and adc_buffer.l_rx2: unfiltered ADC values (you do not need them). 0 to 4095
// outputs:
// — speedR and speedL: normal driving -1000 to 1000
// — weakr and weakl: field weakening for extra boost at high speed (speedR > 700 and speedL > 700). 0 to ~400

#define FILTER 0.1 // lower value == softer filter. do not use values <0.01, you will get float precision issues.
#define SPEED_COEFFICIENT 0.5 // higher value == stronger. 0.0 to ~2.0?
#define STEER_COEFFICIENT 0.5 // higher value == stronger. if you do not want any steering, set it to 0.0; 0.0 to 1.0
#define INVERT_R_DIRECTION
#define INVERT_L_DIRECTION
#define BEEPS_BACKWARD 1 // 0 or 1

//Turbo boost at high speeds while button1 is pressed:
//#define ADDITIONAL_CODE \
if (button1 && speedR > 700) { /* field weakening at high speeds */ \
weakl = cmd1 — 700; /* weak should never exceed 400 or 450 MAX!! */ \
weakr = cmd1 — 700; } \
else { \
weakl = 0; \
weakr = 0; }

// ###### МАЛЕНЬКАЯ МАШИНКА ######
// for better bobbycar code see: ссылка
// #define FILTER 0.1
// #define SPEED_COEFFICIENT -1
// #define STEER_COEFFICIENT 0

// #define ADDITIONAL_CODE \
if (button1 && speedR < 300) { /* drive backwards */ \
speedR = speedR * -0.2f; \
speedL = speedL * -0.2f; } \
else { \
direction = 1; } \
if (button1 && speedR > 700) { /* field weakening at high speeds */ \
weakl = speedR — 600; /* weak should never exceed 400 or 450 MAX!! */ \
weakr = speedR — 600; } \
else { \
weakl = 0; \
weakr = 0; }

// ###### КРЕСЛО ######
// #define FILTER 0.05
// #define SPEED_COEFFICIENT 0.5
// #define STEER_COEFFICIENT -0.2

// #define ADDITIONAL_CODE if (button1 && scale > 0.8) { /* field weakening at high speeds */ \
weakl = speedL — 600; /* weak should never exceed 400 or 450 MAX!! */ \
weakr = speedR — 600; } \
else {\
weakl = 0;\
weakr = 0;

// ############################### VALIDATE SETTINGS ###############################

#if defined CONTROL_SERIAL_USART2 && defined CONTROL_ADC
#error CONTROL_ADC and CONTROL_SERIAL_USART2 not allowed. it is on the same cable.
#endif

#if defined CONTROL_SERIAL_USART2 && defined CONTROL_PPM
#error CONTROL_PPM and CONTROL_SERIAL_USART2 not allowed. it is on the same cable.
#endif

#if defined DEBUG_SERIAL_USART3 && defined CONTROL_NUNCHUCK
#error CONTROL_NUNCHUCK and DEBUG_SERIAL_USART3 not allowed. it is on the same cable.
#endif

#if defined DEBUG_SERIAL_USART3 && defined DEBUG_I2C_LCD
#error DEBUG_I2C_LCD and DEBUG_SERIAL_USART3 not allowed. it is on the same cable.
#endif

#if defined CONTROL_PPM && defined CONTROL_ADC && defined CONTROL_NUNCHUCK || defined CONTROL_PPM && defined CONTROL_ADC || defined CONTROL_ADC && defined CONTROL_NUNCHUCK || defined CONTROL_PPM && defined CONTROL_NUNCHUCK
#error only 1 input method allowed. use CONTROL_PPM or CONTROL_ADC or CONTROL_NUNCHUCK.
#endif

есть еще один файл установки main но он для продвинутых пользователей его я разберу позже.

забегу немного в перед эта прошивка ссылка работает с RPiZeroW платформа для робота.
tkzbbj.jpeg

Пишите, спрашивайте что знаю то отвечу.


* 1ow004c.jpeg (290.12 кБ, 2000×1230 — просмотрено 21565 раз.)

MH-Z19B

 Arduino  Комментарии к записи MH-Z19B отключены
Авг 072019
 

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

К сожалению, датчик подарил головоломку. Подробности — под катом.

(Внимание — в обзоре много «программизма», ругани в адрес китайских даташитов, присутствует шестнадцатеричная математика — так что если тема DIY вам не близка, проходите мимо, иначе будете разочарованы).

Датчик «MH-Z19B» сделан китайской компанией «Winsen» (даташит, PDF) и неоднократно упоминался на Habrahabr и Geektimes. Это вторая ревизия, с буквой «b» в названии, по результатам китайской «работы над ошибками». Первую ревизию одним неверным движением можно было ввести в режим калибровки, для которой требовалась атмосфера с нулевым содержанием CO2. Бедолагам, которые в это влетали, приходилось искать баллон с чистым азотом или кислородом, чтобы её организовать. В ревизии «b» китайцы сделали так, что модуль «эталонной» считает смесь с 400ppm углекислоты — то есть его можно, теоретически, перекалибровать просто в лесу или в парке.

Модуль пришёл в паре с небольшим шлейфом, основная плата имеет надпил, позволяющий отломать кусок с разъёмом и вместо этого припаять гребёнки. Модуль работает в двух режимах — UART (передавая показания по последовательному порту на 9600 бод) и PWM, контакты слева и справа, соответственно:

1183e04671.jpg

Для удобства я обрезал шлейф и насадил на провода дюпоновские наконечники. Правда, выяснилось, что часть проводов вообще ни к чему не подключена. Напротив, PWM оказался не выведен на шлейф, к контакту пришлось дополнительно подпаиваться, завернув из предосторожности датчик в плёнку поплотнее:

2cf726.jpg

Датчик работает по следующему принципу — он получает по UART девятибайтовые команды (последний байт — CRC) и отвечает также девятибайтовыми пакетами. Замер концентрации СО2 выполняется командой с байтом 0x86:

c71935.jpg

Также показания можно прочитать, померяв ширину PWM-сигнала:

2e5c04.png

Тут подстерегала первая проблема — как узнать текущую размерность измерений? Даташит упоминает, что датчик может мерять в диапазаонах от нуля как до 2000, так и от нуля до 5000ppm:

039492.jpg

Запросить текущее значение у датчика нельзя, поэтому остаётся только явно задавать размерность при каждом старте. Даташит описывает формат команды, которая скажет модулю, в какой шкале работать:

2a7f4c.jpg

Почему-то ни одна инструкция в интернете этого вопроса не касается — никто толком не интересовался настройками датчика и просто принимают их как данность. Кряхтим и пишем код для Ардуино, который пошлёт модулю нужную команду:

  • 2000 ppm: «2000» в десятичной системе это «0x07 d0» в шестнадцатеричной, получается — третий байт команды будет 0x07, четвёртый байт — 0xD0, CRC (девятый байт) 0x8F
  • 5000 ppm: третий байт 0x13, четвёртый байт 0x88, CRC (девятый байт) 0xCB

(CRC вычисляем по формуле из того же даташита, (NOT(Byte1 + Byte2 + Byte3 + Byte4 + Byte5 + Byte6 + Byte7)) +1)

Пробуем и так, и эдак, но в результате получаем на выходе дикие неправдоподобные значения концентрации СО2, вылетающие за паспортные диапазоны показаний датчика в разы. Уже испугавшись, что запороли дорогой прибор, через какое-то время нагугливаем ссылку revspace.nl/MHZ19 со словами

According to the MH-Z19B datasheet, you can configure the measurement range by putting the desired range in byte 3 and 4. However, unlike what the MH-Z19B datasheet says, you can set the range using the following command (in this case 0x07d0 = 2000 ppm in byte 6 and 7)

Замечательные китайцы ухитрились ошибиться в даташите! Материмся, и вместо третьего и четвёртого байта пишем в шестой и седьмой. Благодаря подсказке неизвестного голландца — модуль воскресает.

Поскольку теперь доверия модулю нет никакого, решил разобраться с его показаниями досконально и сравнить результаты по UART и PWM. Пишем код под Ардуино, который сначала, в блоке setup, даёт команду установки размерности, а потом в цикле loop делает замеры. Модуль располагаем на сквозняке у форточки.
Код (финальный, уже включающий все позднейшие *открытия*

Все замеры проводим, подключив модуль к питанию от 5 вольт; при 3.3 вольтах он выдаёт очевидно некорректные значения по верху диапазона.

В режиме PWM при заданном диапазоне значений от 0 до 2000ppm получаем, в условиях центра города, заполночь у форточки во двор, 1208ppm, что, безусловно, завышено. UART выдаёт нам близкое значение 1227ppm — различия вполне объяснимы ошибками оцифровки PWM-показаний.

Для сравнения, вот примерные дапазоны концентраций СО2, найденные в интернете:

— 350 — 450 ppm: Нормальный уровень на открытом воздухе.
— < 600 ppm: Приемлемые уровни. Уровень. рекомендованный для спален, детских садов и школ.
— 600 — 1000 ppm: Жалобы на несвежий воздух, возможно снижение концентрации внимания.
— 1000 ppm: Максимальный уровень стандартов ASHRAE (American Society of Heating, Refrigerating and Air-Conditioning Engineers) и OSHA (Occupational Safety & Health Administration).
— 1000 — 2500 ppm: Общая вялость, снижение концентрации внимания, возможна головная боль.
— 2500 — 5000 ppm: Возможны нежелательные эффекты на здоровье.

Переключаем датчик в диапазон 0 — 5000ppm. В режиме PWM у той же форточки во двор получаем 478ppm, что гораздо больше похоже на правду. Но вот в режиме UART наш датчик снова выдаёт совершенно неправдоподобное значение 1213ppm.

Десять раз перепроверив формулы, по близости показаний начинаю догадываться, что датчик считает с ошибками в арифметике. Модифицирую код, чтобы формула расчёта концентрации CO2 по данным PWM рассчитывалась с подстановкой всех вариантов верхнего предела значений. В момент какого-то озарения также дополнительно модифицирую код, чтобы значение, полученное по UART, дополнительно выводилось домноженным на 2000/5000:

диапазон 0 — 2000ppm

Range was set! (bytes 6 and 7) 1227 <- ppm (UART) 490 <- two fifths of it 606 <- Milliseconds PWM is HIGH 1208 <- ppm2 (PWM) with 2000ppm as limit 3020 <- ppm3 (PWM) with 5000ppm as limit

диапазон 0 — 5000ppm

Range was set! (bytes 6 and 7) 1213 <- ppm (UART) 484 <- two fifths of it 241 <- Milliseconds PWM is HIGH 478 <- ppm2 (PWM) with 2000ppm as limit 1195 <- ppm3 (PWM) with 5000ppm as limit

Делаем выводы:

  • в качестве рабочего диапазона работы датчика надо задавать 0 — 5000ppm
  • несмотря на это, для расчёта значений, полученных через PWM, надо в формулу подставлять константу 2000, а не 5000
  • для получения правдивых показаний от UART надо полученное значение умножать на 2/5
  • китайским даташитам, даже на вид добротным, верить нельзя
  • готовые скетчи для Ардуино из интернета брать нельзя
  • показания всех китайских «показометров» надо проверять хотя бы на соответствие здравому смыслу и внутреннюю непротиворечивость

Разбираемся с датчиками CO и метана MQ-4 и MQ-7

 Arduino  Комментарии к записи Разбираемся с датчиками CO и метана MQ-4 и MQ-7 отключены
Авг 062019
 

Разбираемся с датчиками CO и метана MQ-4 и MQ-7

20160814_100333В бытность появления у меня набора Arduino, в поисках объекта для автоматизации, я как-то сам собой задумался над тем, что неплохо бы получать информацию о том, не является ли опасным уровень CO (угарный газ) в зимнее время в котельной загородного дома. В холодные зимние деньки и особенно ночи, газовое оборудование работает в интенсивном режиме и жжет природный газ для поддержания теплоты в доме. А вдруг у меня плохая вентиляция? Или в трубе застрял валенок? И каждый раз входя в котельную и находясь там некоторое время, я подвергаю свою драгоценную жизнь опасности. Да и от утечек природного газа тоже никто не застрахован. Тут вообще можно полдома взорвать, просто включив свет. Их хорошо бы тоже контролировать и как-то отслеживать.

Поэтому было решено собрать систему по мониторингу уровня CO и метана в воздухе котельной на основе Arduino или совместимой платы. Помимо простой сигнализации, хотелось бы собирать еще и статистику, например, о том, как связаны концентрации опасных газов с работой газового оборудования. В принципе, задача реализуется на современном уровне культуры и техники, причем за очень небольшие деньги. В качестве источника расхода природного газа я использовал импульсы со встроенного в газовый счетчик датчика, а для анализа воздуха применил два чрезвычайно популярных в среде разработчиков Arduino датчика MQ-4 и MQ-7. MQ4 «нюхает» воздух на предмет содержания метана, а MQ7 проводит измерения в отношении CO.

Но для того чтобы пойти дальше, оказалось, что нужно конкретно углубиться в детали. Поскольку мало кто из пользователей Arduino и аналогов понимает, что это за датчики такие MQ-4 и MQ-7, и как ими вообще пользоваться. Ну так, приступим потихоньку к увлекательному повествованию.

Что такое ppm

Чтобы как следует оперировать со значениями, которые я буду приводить ниже, нужно для себя уяснить единицы измерений. У нас, на территории бывшего Советского Союза, показатели принято измерять в процентах (%) или же непосредственно в массе к объему (мг/м3). А вот в некоторых зарубежных странах применяет такой показатель как ppm.

Сокращение ppm расшифровывается как parts per million или в вольном переводе «частей на миллион» (хорошо, что тут не используют фунты на галлоны и империалы к саженям). В принципе, от процента показатель не сильно отличается, вернее, отличается только размерность. 1 ppm = 0,0001%, соответственно 3% = 30.000 ppm.

Перевод из процентов или ppm в мг/м3 уже сложнее, тут нужно учитывать молярную массу газа, давление и температуру. В целом формула для пересчета выглядит следующим образом P x VM=R x T, где P – давление, VM – молярный объем, R – универсальная газовая постоянная, T – абсолютная температура в Кельвинах (не Цельсиях и не Фаренгейтах). Но дабы не мучить читателя школьным курсом химии, сразу приведу несколько значений. А самые опытные бурители интернетов могут найти на просторах великой паутины онлайн-калькуляторы для самостоятельного расчета.

CO: 3% = 30.000 ppm = 34695.52 мг/м3
CO2: 3% = 30.000 ppm = 54513.22 мг/м3

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

Различие СО и CO2

Для начала стоит разобраться что же такое есть CO и в чем его отличие от CO2. Во-первых, CO это монооксид углерода, который также называют угарным газом, окисью углерода или оксидом углерода (II). СО газ весьма коварный. Он чрезвычайно ядовит, но при этом не обладает ни цветом, ни запахом. Попав в помещение с угарным газом, вы только по косвенным симптомам поймете, что подвергаетесь воздействию яда. Сначала головная боль, головокружение, одышка, сердцебиение, потом посинение трупа. Угарный газ соединяется с гемоглобином крови, отчего последний перестает переносить кислород тканям вашего организма, и первым страдает головной мозг и нервная система.

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

Основным источником выделения СО, как ни странно, является сгорание углеродного топлива при недостаточном количестве кислорода. Углерод «не догорает» и вместо углекислого газа CO2, в атмосферу выбрасывается угарный газ CO. В бытовом понимании отличным источником СО, при неправильной эксплуатации, могут выступать дровяные печи, газовые конфорки, газовые котлы и прочая отопительная техника, работающая на углеродном топливе. Не стоит забывать и про автомобили, в выхлопе бензинового двигателя СО может быть до 3%, а по гигиеническим нормам его должно быть не более 20 мг/м³ (около 0,0017%).

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

Оборотная сторона датчиков MQ-4 и MQ-7 от RobotDyn (цифровые и аналоговые).

Оборотная сторона датчиков MQ-4 и MQ-7 от RobotDyn (цифровые и аналоговые).

CO2, он же диоксид углерода, углекислый газ, двуокись углерода, оксид углерода (IV) или просто угольный ангидрид, не менее интересный газ. С углекислым газом мы встречаемся гораздо чаще в повседневной жизни, нежели с угарным газом. Мы пьем газированную воду, в которой растворяют диоксид углерода. Мы пользуемся сухим льдом для сохранения мороженого в парке жарким летним полднем, мы, наконец, выдыхаем двуокись углерода в сумасшедших объемах. Да и природные объекты, типа вулканов, болот или свалок способны генерировать изрядное количество углекислого газа.

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

И тот и другой газы состоят всего из двух видов элементов. Из кислорода (О) и углерода (С), вопрос только в количестве атомов кислорода. Знающий читатель может догадаться, что один газ в другой может превращаться с легкостью необыкновенной. Да, может, но не совсем с легкостью и не совсем обыкновенной. Нужно прилагать усилия. Так, например, в каталитических нейтрализаторах современных бензиновых автомобилей происходит процесс дожигания (превращения) CO в CO2. Процесс проходит при высокой температуре и в присутствии катализаторов (например, платины). Возможен и обратный процесс, но опять же непростой.

Кстати, в интернет есть сайт CO2.Earth отображающий динамику и текущую концентрацию углекислого газа в атмосфере Земли. Да, концентрация не такая уж и низкая. Ведь при скоплении углекислого газа в районе 2-4% человек теряет работоспособность, чувствует сонливость и слабость. А при концентрациях около 10% начинает ощущаться удушье.

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

Конструкция электрохимических датчиков

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

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

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

Схема электрохимического датчика

Схема электрохимического датчика

В сети можно насчитать пару десятков производителей плат с электрохимическими датчиками серии MQ. Но производитель у всех датчиков (не плат) один – китайская компания HANWEI. Компания выпускает весомый ассортимент различных устройств для детектирования газов и всего с ними связанного. Но сенсоров серии MQ среди номенклатуры нет, возможно, что продукция слишком уж мелкая, чтобы вывешивать ее на сайт.

Будучи по натуре любопытным персонажем, я покопался в спецификациях HANWEI и свел все доступные датчики серии MQ, материал подложки и тип детектирования в единую таблицу.

Датчик Газ Подложка
MQ-2 LPG SnO2
MQ-3 Alcohol SnO2
MQ-4 CH4 SnO2
MQ-5 LPG, natural gas SnO2
MQ-6 LPG, propane SnO2
MQ-7 CO SnO2
MQ-9 CH4, LPG SnO2
MQ-131 O3 SnO2
MQ-135 Air Quality SnO2
MQ-136 Air Quality SnO2
MQ-137 Air Quality SnO2
MQ-138 Multi-purpose SnO2
MQ-303A Alcohol ???
MQ-306 LPG, LNG ???

За исключением 300-й серии датчиков MQ все они используют один и тот же материал для подложки. Именно для той самой подложки которая и определяет концентрацию газа в атмосфере, именно для той подложки, которая меняет свое сопротивление. Во всех датчиках она используется одна и та же. У 300-й серии информация о чувствительном материале скромно опущена.

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

Прошу заметить, что все датчики имеют определенный и весьма небольшой срок жизни, который составляет порядка 5 лет. Причем 5 лет — это не только непосредственно работа, но и хранение. А если ваш датчик хранится без соответствующей упаковки, то срок его годности еще меньше. Дело в том, что чувствительный химический элемент, без нагрева, будет насыщаться углеродом, который постепенно его весь и разрушит. Именно по этой причине новые датчики рекомендуется «прокаливать» держа в рабочем состоянии на протяжении суток, а еще лучше двух. Тот углерод, что успел въесться в оксид олова (IV) «выгорит» и датчик сможет определять показания с более высокой точностью.

Если приглядеться к списку измеряемых газов или назначению датчиков, то видно, что все они, так или иначе, завязаны на углерод (метан, природный газ, пропан, угарный газ, сжиженный газ, алкоголь и даже датчики качества воздуха измеряют наличие углерода в соединениях в воздухе). И только датчик озона (MQ-131) стоит особняком, хотя и использует тот же самый чувствительный элемент с SnO2. Дело в том, что все датчики серии MQ рассчитаны на работу в атмосфере со стабильным уровнем кислорода. Спецификация говорит нам, что содержание кислорода должно быть 21%, что есть некая усредненная норма. А если кислорода меньше или больше, то показания будут плавать, вплоть до полной неспособности датчика выдавать вразумительные результаты при содержании кислорода на уровне 2% и ниже. Еще бы, в этом случае углерод совсем никак выгорать на подложке не будет, окислителя-то недостаточно. Видимо, на этом эффекте и рассчитано измерение озона электрохимическим датчиком.

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

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

Но точность показаний датчиков серии MQ зависит не только от кислорода. Показания хорошо меняются в зависимости от влажности воздуха и от его температуры. Расчетные показатели даны для влажности в 65% и температуры 20 градусов Цельсия. А при влажности выше 95% датчик перестанет адекватно выдавать показания. Жалко, что вот только не указана в спецификации какая влажность используется: относительная или абсолютная. Интуиция подсказывает, что все же относительная.

Помимо показателей окружающей среды на точность показаний датчиков MQ не хуже остальных параметров влияет еще и срок службы самих датчиков. Со временем их показания плывут. «Засоряется» продуктами измерения чувствительный слой, изменяются характеристики нагревателя и изменяется сопротивление при эталонных показателях. В какую сторону оно изменяется непонятно, но производитель рекомендует, во-первых, проводить калибровку датчика после покупки и первичного «отжига», а затем проводить регулярные перекалибровки на протяжении всего срока службы датчика. А единственный нормальный способ калибровки — сравнение результатов показания датчика с уже откалиброванным прибором. Понятное дело, что такого прибора нет ни у конечного потребителя-частника (а профи будут использовать несколько другие датчики, подороже), ни у многих производителей плат. Некоторые производители об этом заявляют честно прямо на своем сайте:

Заявление о невозможности нормальной калибровки датчиков

Заявление о невозможности нормальной калибровки датчиков

«И как же мне узнать, какова концентрация того или иного газа при помощи сенсора MQ?» — вопросит нетерпеливый читатель? Поскольку в большинстве случаев потребитель использует измеритель напряжения, впрочем с сопротивлением все аналогично, но меньше на один шаг, то у потребителя существует потребность в том, как вольты или кванты ЦАПа Arduino перевести в заветные ppm или хотя б проценты. Проделать сию операцию можно исключительно при помощи невнятных графиков из спецификации на датчик.

График: сопротивление в зависимости от концентрации газов.

График: сопротивление в зависимости от концентрации газов.

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

График зависимости сопротивления датчика MQ-7 от концентрации исследуемых газов.

График зависимости сопротивления датчика MQ-7 от концентрации исследуемых газов.

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

  • Фактически идентичные датчики использующие один и тот же чувствительный элемент и различающиеся используемым номиналом подстроечных резисторов.
  • Зависимость результатов измерения от множества факторов: температуры, влажности, концентрации кислорода.
  • Отсутствие заявляемой селективности по измеряемым газам, реагирует на все с углеродом (а, вполне возможно, и на другие элементы вступающие в реакцию с подложкой).
  • Высокое энергопотребление (нагреватель).
  • Необходимость в первичном «отжиге» датчика.
  • Нестабильность показаний по времени.
  • Необходимость первичной и повторяющейся калибровки.
  • Практическая невозможность получения осмысленных значений в виде ppm или %.

Ну что же, пойдем дальше.

Цифровой или аналоговый?

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

Чистый датчик

Самый простой и самый дешевый вариант. В поставке присутствует только сам электрохимический датчик и больше ничего. Подключать его к системе с измерением напряжения (например, к аналоговому порту Arduino) нужно через нагрузочный резистор. Резистор лучше всего использовать с возможностью подстройки при калибровке. Номиналы резистора указываются в спецификации (DataSheet) на датчик.

Датчик MQ-4

Датчик MQ-4

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

Аналоговый датчик

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

Аналоговый датчик

Аналоговый датчик

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

Цифровой датчик

Казалось бы, если датчик цифровой, то он должен выдавать информацию в цифровом виде. Однако, все цифровые датчики с сенсорами MQ, что мне попадались, не имели такой возможности. «Цифровой» в их названии означает только то, что датчик имеет цифровой выход, который переключается в режим HIGH при превышении некоего порога концентрации измеряемого газа. А основной съем значений пользователь осуществляет тем же самым аналоговым способом, как и с обыкновенным аналоговым датчиком.

Датчик с цифровым и аналоговым интерфейсом

Датчик с цифровым и аналоговым интерфейсом

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

Цифровой датчик с цифровой шиной

Пожалуй, это самый Hi End среди подобных датчиков. Подключение и передача данных осуществляется посредством цифровой шины I2C. И к одному устройству съема информации (например, Arduino) можно подключить аж сотню таких датчиков. Только нужно иметь в виду, что датчики потребляют весьма много тока и его необходимо подавать отдельно. Настроечный резистор, само собой, присутствует.

Цифровой датчик с цифровым интерфейсом

Цифровой датчик с цифровым интерфейсом

Судя по коду примера, предлагаемого производителем датчиков, сам датчик посылает данные в сыром виде и уже программно они переводятся в значения ppm. В целом от аналогового варианта датчик отличается только наличием цифровой шины.

Питание

Выше я уже упоминал, что для работы нагревателя датчиков MQ требуется подводить к нему качественное питание и в достаточно объеме. По спецификации датчики потребляют около 150 мА. В реальности потребление может плавать в весьма широком пределе. В принципе, 150 мА не такой уж и большой ток до тех пор, пока устройство (или несколько) с таким потреблением не пытаются скрестить с чем-то вроде Arduino. Подключив даже один такой датчик к питанию на плате, уже рискуешь получит неработоспособное устройство, которому не будет хватать напряжения для нормальной работы. При работе сами сенсоры нагреваются, не существенно, но градусов до сорока вполне могут раскочегариться. Если сравнить эту температуру с 60-70 градусами на стабилизаторе, питающем эти датчики, то температуру сенсоров можно считать сносной.

Для обеспечения нормальной работоспособности нагревателя и как следствие самого датчика необходимо подавать питание отдельно для этих датчиков. Например, использовать независимый источник питания на 1 или 2 А и 5V для питания датчиков (не все датчики потребляют 5V). Либо использовать специальную плату, преобразующую напряжение 9-12V в требуемое для питания датчиков.

Дишманский пульт мониторинга CO из платы Arduino, датчика MQ7 и планшета.

Дишманский пульт мониторинга CO из платы Arduino, датчика MQ7 и планшета.

В любом случае с источником тока, обладающим нужной мощностью, придется повозиться. Хотя возможен вариант, когда датчик подключается напрямую к плате (например, Arduino). Но в этом случае ничего большего к ней подключать не рекомендуется.

Вариант калибровки датчика и преобразования показаний в ppm

Блуждая по сети в поисках решения по калибровке и получения достоверных результатов с датчика, я наткнулся на весьма любопытный пост от некоего Davide Gironi, который столкнулся с точно такой же проблемой, как и я. Davide попытался разобраться, каким образом можно получить с его датчика MQ-135 (Air Quality) показания в виде ppm.

Согласно исследованиям, проведенным блоггером для калибровки, достаточно иметь представление о концентрации какого-то газа в атмосфере и опираясь на эти данные попробовать подобрать резистор для попадания в нужный сектор по графику. Davide использовал датчик MQ-135 который предназначен для определения качества воздуха, среди контролируемых газов которого есть и CO2. И именно углекислый газ больше всего интересовал блоггера. Используя информацию с сайта co2now.org, он смог вычислить требуемый номинал резистора. Согласитесь, что метод весьма далек от идеала, но все равно лучше, чем ничего.

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

float ppm = ((10000.0 / 4096.0) * raw_adc) + 200;

Приведенный выше код, между прочим, из примера для датчика MQ-4 с цифровым интерфейсом I2C. Заметьте, что это лучше, чем ничего. Ведь многие просто не в состоянии дойти и до такого преобразования и ограничиваются лишь просто некими пороговыми значениями. Например, при значении 750 (единица измерений отсутствует, это квант), нужно врубать красный светодиод, в диапазоне 350-750 достаточно желтого, а когда ниже 350 пускай горит зеленый светодиод.

Альтернативы?

Если датчики MQ так уж плохи, то есть ли какая альтернатива для использования в домашних проектах? На самом деле есть. Даже много. Методов измерения концентрации газов не один и не два. Только вот датчики, обладающие высокой точностью, стоят приличных денег. И порой от такой стоимости наступает амфибиотропная асфиксия. Разница в стоимости может достигать тысячи и десятки тысяч раз. Тут невольно призадумаешься.

Один из вариантов миниатюрного датчика CO2 с инфракрасным методом измерения. Датчик MH-Z19.

Один из вариантов миниатюрного датчика CO2 с инфракрасным методом измерения. Датчик MH-Z19.

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

Если же требуется детектирование других газов, но с применением недорогих устройств, то доступных вариантов на текущий момент (лето 2016 года) не так много, если не сказать прямо, что их совсем мало. Альтернативой можно считать использование серии MQ, правда обходиться придется только порогами значений (о точности перевода в ppm я уже высказался выше).

Сигнализатор CO. Применяется электрохимичский датчик и измерение в ppm.

Сигнализатор CO. Применяется электрохимичский датчик и измерение в ppm.

Многие сразу же возразят, дескать, я лично использовал такой датчик, и он работает. В качестве примеров приводят опыты сродни «подышать на датчик», подержать вокруг него руку, пустить облачко сигаретного дыма. Да, показания датчика сразу же изменятся, значения поползут вверх. Да, датчик отразит то, что он нагрелся, то что увеличилась влажность, то, что в атмосфере стало больше углерода и меньше кислорода. Но насколько больше, какое количество исследуемого газа сейчас в атмосфере и самое важное какого именно газа? Вот на этот вопрос ответ при помощи датчиков серии MQ дать уже нельзя. Лучше уж приобрести обыкновенный бытовой сигнализатор опасных газов, того же СО. За вполне сопоставимые деньги вы получите устройство заводского исполнения, с громкой сигнализацией и низким потреблением энергии.

Датчики близнецы

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

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

Графики показаний с датчиков MQ-4 и MQ-7 лежащих рядом друг с другом на столе

Графики показаний с датчиков MQ-4 и MQ-7 лежащих рядом друг с другом на столе

А ведь все началось с того, что я подключил два датчика (MQ-4 и MQ-7) к одному устройству и начал заливать результаты их работы на ThingSpeak. Один из датчиков должен измерять уровень ядовитого СО, а второй показывать сколько есть в воздухе метана. Меня очень заинтересовали графики, которые повторяли друг друга больше чем почти полностью. Да, один датчик выдавал показания на уровне 100-150 единиц, а второй на уровне 350-400. Пики и плато совпадали по времени от разных датчиков, а всплески лишь оттеняли неминуемую закономерность.

График корреляции показаний датчиков MQ-4 и MQ-7 лежащих на одном столе

График корреляции показаний датчиков MQ-4 и MQ-7 лежащих на одном столе

Я свел показания обоих датчиков в единый график корреляции и понял, что они показывают одни и те же результаты, правда в разных диапазонах. И задался вопросом – зачем мне датчик метана, который реагирует на все? Начиная от угарного газа и заканчивая алкоголем. Зачем мне датчик СО, который помимо самого СО еще больше реагирует на LPG и водород? Вот именно – незачем.

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

датчик, газ, Mq, mq4, mq-4, спиралька

Внутренности датчика MQ-4

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

mq7, датчик, mq-7, mq, газ, анализатор, ардуино

Внутренности датчика MQ-7

Несмотря на другой внешний вид, внутренности MQ-7 идентичны внутренностям MQ-4. А нагреваемая бобышка сероватого цвета, есть ни что иное, как искомый оксид олова, который при нагревании и присутствии углерода или водорода (как раз те самые газы) частично восстанавливается, стремясь стать металлическим оловом, и соответственно изменяет свое сопротивление.

Пример простой программы на Си для микроконтрол лера AVR

 Arduino  Комментарии к записи Пример простой программы на Си для микроконтрол лера AVR отключены
Июл 172019
 

Язык Си (без ++) — один из основных языков для программирования микроконтроллеров, поскольку здесь требуется высокая скорость, а оперативной памяти не бывает много.

Пример простой программы на Си для микроконтроллера AVR

Это текст программы компиляторов типа AvrStudio, CodeVisionAVR и т.п.

 #include // заголовочный файл для ввода-вывода #include #define BV(x) (1 << x) int main(void) { DDRC=0xFF; // порт PORTC настроен на выход PORTC=0xFF; // установка уровней на порте PORTC while(1) // начало цикла { PORTC=~(BV(5)); // переключение 5-го бита порта PORTC _delay_ms(1000); // задержка 1 секунда PORTC=BV(5); // переключение 5-го бита порта PORTC обратно _delay_ms(1000); } return 0; }  

Функция main — это точка входа в программу, с которой компьютер начинает выполнение программы.

Допускается из main возвращать void, хотя это не по стандарту, так что лучше int.

В функцию main можно передавать аргументы командной строки:

int main(int argc, char* argv[]) { }  

Вообще говоря, мы можем писать программу для MK AVR также на языке Processing/Wiring. Это тот же Си, но упрощенный. Но компилироваться это будет только в Arduino IDE или т.п., а потом можно загружать полученный hex в наш микроконтроллер. При этом не обязательно, чтобы МК стоял на плате Arduino. Разницы то нет.

Вот так выглядит аналогичная программа на Processing/Wiring:

int ledPin = 13; void setup() { pinMode(ledPin, OUTPUT); } void loop() { digitalWrite(ledPin, HIGH); delay(1000); digitalWrite(ledPin, LOW); delay(1000); }  

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

http://ar.com/basic/uno

а пока мы вернемся к языку Си.

Общая структура памяти программы на Си

— куча — для динамического выделения памяти

— стек — локальные переменные класса памяти auto (включая аргументы функций)

— DATA — константы

— CODE — исполняемый код, инструкции процессора

Типы данных в Си

-Базовые типы данных: char, int, float, double.

-Модификаторы знака: signed, unsigned.

-Модификаторы знака: long, short.

void — тип без значения

При этом следущие типы равны:

int = signed int = signed // 16 или 32 бит (зависит от платформы ) unsigned = unsigned int char = signed char	// 8 бит (от -128 до 127) (ASCII) unsigned char // 8 бит (от 0 до 255) wchar_t // UNICODE  

В Си логический тип реализован неявно (с помощью int): false = нуль, true = не нуль.

Введение псевдонимов для ранее описанных типов данных:

typedef тип имя

где тип — любой существующий тип данных, имя — новое имя для этого типа.

Пример: typedef unsigned char byte;

Преобразование типов:

Если операнды операции имеют разные типы, то происходит неявное приведение типов:

double a = 1.222; int i = a; // дробная часть отсекается! double x = 2/5;	// результат будет 0 !  

(чтобы здесь получить 0.4 нужно было бы написать x=2.0/5 или 2/5.0)

Явное приведение типов:

int a=2, b=5; double b = (double)a / b;	// результат будет b=0.4  

Принудительное преобразование типов:

(тип) выражение;

(желательно вообще избегать преобразования типов)

Переменные и константы

Переменная представляет собой блок памяти, на который мы ссылаемся по её имени (идентификатору).

Декларация переменных (вместе с инициализацией):

[класс памяти] [квалификаторы] [модификаторы] тип идентификатор = инициатор;

Например,

static const unsigned char x = 100;  

Здесь «;» — составляющая часть конструкции, завершающая часть.

Допустима (хотя и редко используется) запись: const x = 100; (по умолчанию int).

Квалификаторы (или «модификаторы доступа»): const, volatile.

const — означает, что переменные не могут изменяться во время выполнения программы; инициалиировать можно только при декларации;

volatile — содержимое переменной может измениться само собой (используется в многопоточных программах при взаимодействии процессов)

Возможен вариант const volatile, когда писать могут только снаружи.

Спецификторы хранения (описатель класса памяти): auto, register, extern, static.

auto — локальные переменных (по умолчанию) — программный стек.

register — просьба компилятору положить переменную в регистр ЦПУ (но он эту просьбу редко выполняет);

extern — объявление (declaration) переменных, но не определение (definition) (определение где-то в другом месте); определение может идти ниже по файлу (но как глобальная) или в другом файле.

static — статические локальные переменные, которые хранят своё значение между вызовами функций (они предпочтильнее, чем глобальные переменные). Статические глобальные переменные видны только в пределах данного файла.

Внешние и статические объекты существуют и сохраняют свои значения на протяжении всего времени выполнения программы.

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

Описание области действия идентификаторов (имен):

— внутреннее (локальное) — внутри блока {…}

— внешнее (глобальное) — вне всех блоков

Идентификатор, описанный внутри блока, известен только в этом блоке (локальный идентификатор).

Идентификатор, описанный на самом внешнем уровне, известен от места появления этого описания до конца входного файла, в котором он описан (глобальный идентификатор).

Стоит избегать использования глобальных имен.

Переменные с классом памяти static видны только в пределах текущего блока (для локальных) или в пределах файла (для объявленных глобально).

Статические переменные хранятся в сегменте данных (data) и по умолчанию инициализируются нулем. Т.е. память под static-переменные выделяется при старте программы и существует до конца программы.

Замечание: Инициализация выполняется одни раз при выделении памяти!

void f(void) { static int a = 1; /* - это инициализация (но не присваивание!), т. е. переменная инициализурется единицей только один раз при старте программы! (или 0 по умолчанию, т.е. если бы было просто static int a;) */ a++; }  

Статическими могут быть также функции. Такая ф-ция может исп-ся только внутри данного файла.

Следует различать присваивание и инициализацию:

— Присваивание: имя_переменной = выражение;

— Многочисленное присваивание: x = y = z = 0;

— Инициализация переменных: тип имя_переменной = константа;

Константы

Константы являются частью машинных команд и под них память не выделяется.

Константы бывают:

— целые:

10-я система: 127; -127; +127;

8-я система: 0127; (начинается с нуля — значит 8-ричная!)

16-я система: 0x7F; (x или X, f или F — регистр не влияет)

— вещественные: 3.14; 2. ; .25 (0 можно опускать); 2E3; 2e3; 2E-3; 2.0E+3;

— символьные: 8-битные ASCII: ‘A’, ‘=’, ‘\n’, ‘\t’, ‘\370’, ‘\xF8’ (символ градуса);

— строковые литералы (в двойных кавычках): «Hello, world!\n». Строки заканчиваются нулевым байтом — ‘\0’.

Макроопределения:

 #define WIDTH 80	//(подробнее ниже)  

Операции и операторы

Оператор (инструкция, англ. statement) — это единица выполнения программы.

В языке Си любое выражение, заканчивающееся символом «точка с запятой» (;), является оператором.

Фигурные скобки { } — это составной оператор.

Например,

{y = x; x++;}  

Кроме того { } является отдельным блоком и в нем можно определять локальные переменные.

; — пустой оператор.

Операции:

— Арифметические операторы: — + * / %

— Инкрименты и декрименты: ++a, —a, a++, a— (могут выполняться быстрее)

— Операторы сравнения (отн-ний): > >= < <= == != (возвращают 1 или 0)

— Логические операторы: && || ! (возвращают 1 или 0)

— Битовые операторы: & | ^ ~ >> <<

— Оператор ?: x ? y : z, напр.: r = 10>9 ? 100 : 200

sizeof — унарный оператор для вычисления размера переменной или типа

, — оператор запятая (последовательное вычисление): a = (b=3, b+2);

Порядок выполнения операторов:

— Унарные операторы выполняются справа-налево.

— Бинарные выполняются слева-направо.

— Присваивание выполняется справа-налево.

Порядок можно менять с помощью скобок!

Примеры:

a=10; r=!!a==a; // результат будет 0, т. к. !!a вернет 1;  

Выражение а + b + c интерпретируется как (а + b) + с.

r = (2==2==2); // результат будет 0, т. к. 2==2 вернет 1 и сравнит с 2; - и вычисляется слева направо. 5 < 3 < 2;	// результат будет 1, т. к. 5<3 вернет 0; a = b = c = 2;	// сначала c=2, потом b=c, потом a = b;  

sizeof() — возвращает длину в байтах переменной или типа; sizeof(int); sizeof(a);

sizeof выражение; — само выражение не вычисляется.

Оператор запятая:

x = (y = 3, y+1);  

левая сторона оператора вычисляется как void и не выдаёт значения, переменной x присвается значение выражения в правой стороне, т.е. y+1.

Указатели и ссылки в Си

& — оператор «получение адреса» объекта;

* — доступ к значению объекта по указанному адресу;

p = &number; // - получение адреса переменной number; q = *p; // - получение значения переменной по указанному адресу: st.a; // - обращение к полю структуры st; pst->a;	// - обращение к полю структуры по её указателю;  

Указатели:

Указатель