Приборы http://myowndevice.ru Wed, 28 Aug 2024 12:10:33 +0000 Joomla! - Open Source Content Management ru-ru USB UART адаптер /index.php/pribory/item/7-usb-uart-konverter /index.php/pribory/item/7-usb-uart-konverter USB UART адаптер

Очень полезный прибор для работы с Serial портом через USB с помощью компьютера. Пригодится для получения данных с наших приборов, программирования микроконтроллеров, общения с GSM и GPS датчками.

{autotoc}

Зачем нужен USB UART адаптер

Как следует из названия данный прибор организует мост между компьютером через USB порт и вашим устройством по Serial протоколу. Можно сказать что он является USB COM портом для логики TTL (уровни 1.8v-5v).

С помощью данного прибор можно программировать различные микроконтроллеры, получать информацию на компьютер со прибора по serial порту. Кроме этого применений ему масса:

  • управление устройством

  • отладка программы

  • передача небольших объёмов данных

  • прошивка различных приборов —разработчики часто делают выход serial для возможности перепрошивки своего устройства

  • прошивка микроконтроллеров — многие микроконтроллеры имеют Bootloader (специальная программа для загрузки прошивки по serial) загруженный на заводе, и для загрузки прошивки не нужен специальный программатор — достаточно данного устройства.

Нам он будет необходим в первую очередь для прошивки ST-Link. Ну и собственно так как тут нечего программировать — прибор состоит из одной микросхемы — то на этом приборе мы поучимся паять и работать в Kicad. В этой статье подробно рассмотрим как трассировать печатную плату вручную.

Как сделать USB UART адаптер

1. Прочитать эту статью внимательно и до конца!

2. Подготовить или приобрести необходимые инструменты: все для пайки

3. Внимательно прочитать статьи из раздела Обязательная теория.

4. Скачать необходимые файлы по данному прибору с github.

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

6. Приобрести все необходимые комплектующие в виде готового радиоконструктора можно в нашем магазине.

{product id=26}

7. Запаять все компоненты на плату, смотри наше видео.

ПРИБОР ГОТОВ, можно пользоваться!

Как работает USB UART адаптер

Для реализации данного моста обычно используется специализированная микросхема, которая с одной стороны имеет usb выход, а с другой — serial выход. Обычно эти микросхемы имеют драйвера для Windows \ Linux и определяются системой как COM — порт. Дальше используется специальная программа для работы через COM порт. Это может быть и программа прошивки микроконтроллера или программа для получения данных от прибора и т. д.

Выбираем микросхему для прибора

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

Итак, самые распространённые микросхемы для данного девайса:

  • cp2102 (cp2103) — дешевая отличная микросхема, но имеет корпус QFN28 — то есть безвыводный корпус — паять такую в самом начале пути не очень легко — поэтому мы ее не будем использовать

  • pl2303 — отличная микросхемы фирмы Prolific — существует очень много вариантов этой микросхемы (в том числе китайские подделки). У нее корпус TSOP28 — отлично подходит для пайки. И старые модификации стоят недорого и отлично работают. Мы будем использовать ее — модификацiия pl2303TA — самый недорогой вариант. Есть модификация Rev. D которая не требует внешний кварц — но она стоит в 2 раза дороже.

  • CH340 — китайский вариант (оригинал) моста — микросхема хорошая — но ее трудно купить где-либо кроме как в Китае.

  • FT232R — микросхема от FTDI — отлично подходит и работает — но стоит почти в 2 раза дороже. Ее плюс также в том что не требуется внешний кварц.

Несколько слов о том как подобрать микросхему для своего проекта. Есть очень простой путь. Сначала необходимо найти одну микросхему которая подходит под данную задачу. Набираем в интернете — USB — serial chip и сразу находим — FT232R. Отлично. Далее идет на сайт крупного поставщика микросхем — например — mouser.com. Там в поиске набираем — FT232R. И в разделе интегральных схем видим нашу микросхему.

Самое главное для нас здесь — ЭТО КАТЕГОРИЯ в которую входит микросхема. Здесь это «ИС интерфейс USB». Также смотрим тип «Bridge, USB to UART». Идем в эту категорию и смотрим какие бывают микросхемы. Далее проверяем по datasheets подходит ли она нам.

 

Итак, наш выбор PL2303TA.

Составляем схему на базе PL2303

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


тут приведена полная схема с трансивером (преобразователь уровня до 9v) для получения полного COM порта. Нам эта часть не нужна. Также схема не содержит кварца, а нам он необходим. Дополнительно можно отметить, что еще не хватает светодидов для сигнализации процесса обмена данными. В итоге поискав различные варианты схемы на данной микросхеме (pl2303 schematic) нашли самую простую схему со светодиодами и кварцев — ее и возьмем.


По сути на этой схеме сокращена обвязка USB порта (убраны высокочастотные фильтры L1 L2), убран трансивер. В остальном схема совпадает. Мы же дополнительно ещё добавим разводку всех сигнальных выводов DTR и т. д. - они могут быть полезны. Также следует отметить, что на вывод согласования уровней в нашей версии чипа нельзя подавать 5v, поэтому на разъеме уберем подальше этот вывод. Сам вывод для согласования уровней оставим — вдруг необходимо будет пользоваться UART на 1.8v. Таким образом, по умолчанию у нас будет стоять джампер соединяющий вывод 4 и 3.3v и на выходе всех сигналов UART у нас будет 3.3v. Данного напряжения уверенно хватает для определения логической 1 в 5v схеме, согласно datasheet все сигнальные ножки толерантны 5v ( то есть на них можно подавать 5v смело). Так что при таком подключении схема будет работать с напряжением от 3.3в до 5в. Дополнительно оставим выводы 5v и 3.3v для питания например прошиваемого контроллера. Имейте ввиду, что без внешнего EEPROM usb порт будет отдавать только 100ma! Соответственно питать что-то существенное не получится.

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

Разрабатываем плату в Kicad

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

Прежде чем разрабатывать плату необходимо определится какие у нас будут использоваться разъемы и определить посадочные места. Мы будем делать плату переходник которая втыкается в usb порт и на конце имеет угловые разъемы PIN 2.54mm — это самый распространяенный формат. На конечный разъем мы выведем только наиболее нужные выводы — остальное просто разведем на плате и оставим как дырки на будущее. Основные выводы: RX, TX, 5V, 3.3v, DTR (часто используется как reset схемы микроконтроллера при прошивке). Остальные выводы разведем в самом конце.

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


На данном этапе лучше скрыть лишнюю информацию. Убираем отображение слоев Связи, Скрытый текст, Значения, Обозначения.

Далее начинаем располагаем на будущей плате основные компоненты — разъемы и чип. Так чтобы выводы чипа располагались согласно подключению разъемов. Особенно важно в этом случае чтобы выводы подключения USB были напротив разъема. Наводим мышку на нужный компонент — жмем M — и переносим его чуть ниже на пустое место — формируем будущую плату. Так как плата у нас двух стороняя — то надо сразу определить нужную сторону компонент. Самый просто вариант — все DIP элементы (под которые надо сверлить сквозные отверстия) располагаем с обратной стороны, а все smd элементы с основной стороны — так проще будет подводить дорожки. Для смены стороны используем кнопку F. Так как Kicad умеет подсвечивать связи при переносе элемента, то очень удобно все резисторы связанные с разъемами размещать сразу. Это позволит быстро увидеть связи при переносе микросхемы. Итак, размещаем USB разъем, потом резисторы с ним связанные на сигнальных линиях и потом разъем на другом краю платы:


дальше размещаем чип — так чтобы было как можно меньше пересечений.

Далее размещаем кварц (тоже с обратной стороны — он у нас выводной). Он должен быть как можно ближе к выводам чипа.


После этого размещаем кондецаторы по цепям питания — они должны быть как можно ближе к выводам питания.

После этого соединяем дорожками обязательные выводы — это usb сигнальные — кварц, кондецаторы по питанию. Прикидываем линии питания. Если что-то не удобно — то компоненты двигаем — переносим.

Например кондецатор C3 удобнее перенести вниз чтобы не делать переходное отверстие. Конечно это не очень хорошо — но в данном случае дорожка будет очень небольшая.

После размещения основных элементов размещаем оставшиеся — ориентируясь на подсказки по связям и стараясь не пересекать дорожки.


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

Осталось выводы на разъеме расположить в порядке следования выходов чипа. И финально все соединить. На этом этапе плату можно сделать более компактной. Финальный вариант который получился. Можно сделать еще лучше .. но вариант удовлетворительный.

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

Как пользоваться USB UART конвертером

Для пользования данных приборов в Windows необходимо установить драйвера. Свежие драйвера можно взять на сайте производителя. Если они не подходят, то можно установить более старые драйвера 1.15 — который можно найти в интернет.

После установки драйверов устройство должно определиться как COM порт.

Для Windows самая лучшая программа для работы с COM портом — это Terminal 1.9b (приложена к статье)

Для тестирования нашего устройства необходимо проводами соединить выходы TX — RX. В этом случае мы получим режим эхо — все что будет передано в порт должно тут же возвращаться назад. Скорость при это может быть любая.

Работать с программой очень просто — выбираем порт — можно автоматически по кнопке ReScan или вручную. Задаем скорость и параметры порта. Далее в окне видим все что пришло по терминалу, а в строке SEND можно передать любую информацию. Чтобы передать спецсимволы необходимо использовать запись виды «$1a» в шестнадцетиричном формате.

Для linux устройство должно определится само (драйвера входят в ядро). Неплохая программа — minicom.

Для понимая остальных сигналов данного устройства — DTR, DSR и другие — вот тут есть очень хорошая статья.

Как собирать прибор

Собираем прибор по общим правилам описанным в нашей статье.

Для более быстрой сборки, вы можете приобрести полный набор для пайки, радиоконструтор USB UART адаптер в нашем магазине.

Самостоятельная работа

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

 

]]>
(Super User) Приборы Sun, 01 Jan 2017 18:21:00 +0000
Квадрокоптер /index.php/pribory/item/14-kvadrokopter /index.php/pribory/item/14-kvadrokopter Квадрокоптер

Будем делать современный квадрокоптер со складной рамой 450 размера для съёмки с воздуха FULLHD видео. 

Будем делать современный квадрокоптер со складной рамой 450 размера для съёмки с воздуха FULLHD видео. Квадрокоптер состоит из различных модулей.Мы будем максимально делать сами все модули, но часть придется купить. Наши модули:

  • Регуляторы
  • Полетный компьютер
  • Плата питания BEC с датчиком тока
  • ГПС модуль с магнетометром
  • Плата контроля разряда аккмулятора
  • Плата OSD для видео
  • Балансировочное зарядное устройство
  • GPS + GSM маячок

Надо будет купить:

  • Бесколлекторные двигатели и пропеллеры
  • Камера RunCam  для съемки видео и как курсовая камера
  • Радио аппаратура - передатчик, аппаратура управления, видео передатчик и приемник
  • Аккумулятор

К сожалению описать квадракоптер не простая задача. Это займет не мало времени. Также сейчас мы тестируем новые сенсоры от ST. Вы можете потихоньку ознакомится с полетным компьютером. Мы будет делать квадракоптер на базе Paparazzi UAV - очень мощный компьютер, отличный софт, великолепное документирование.

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

А пока вы можете посмотреть фото и видео как он летает.

 

]]>
(Super User) Приборы Thu, 07 Sep 2017 12:29:18 +0000
ST-Link v2 /index.php/pribory/item/16-st-link-v2 /index.php/pribory/item/16-st-link-v2 ST-Link v2

Программатор-отладчик для программирования и отладки микроконтроллеров STM8 STM32, а также многих микроконтроллеров Cortex M0-M4 по SWD выходу.

{autotoc}

Зачем нужен ST-Link v2

ST-Link/V2 специальное устройство разработанное компанией ST для отладки и программирования микроконтроллеров серии STM8 и STM32. Про сам прибор можно прочитать на сайте компании ST.

Основные его возможности:

  • Выход 5В для питания устройства

  • USB 2.0 высокоскоростной интерфейс

  • SWIM, JTAG/serial wire debugging (SWD) интерфейсы

  • SWIM поддержка низкоскоростного и высокоскоростного режимов

  • SWD and serial wire viewer (SWV)

  • Возможность Обновление прошивки

Так как микроконтроллеры STM32 построены на ядре ARM Cortex, которое имеет интерфейс отладки SWD, то ST-Link позволяет программировать и отлаживать и другие 32-битные микроконтроллеры на базе ARM-Cortex.

Это, можно сказать, единственный программатор микроконтроллеров STM8. Для программирования STM32 существуют и другие универсальные программаторы.

Где можно купить программатор STM8 STM32 ST-Link

На текущий момент интерес к микроконтроллерам ST очень большой. Поэтому программатор ST link довольно широко распространен на рынке. Существует несколько версий, отличающихся по цене.

Оригинальный ST Link от компании ST, как всегда, самый дорогой вариант. Стоит больше 2 000 руб.

Мини ST link (очень похож на наш вариант этого программатора) стоит около 600 руб. Купить его можно у крупных поставщиков электроники - Компэл, Терра электроника и другие.

Ali express (Китай) - тут предлагается большое количество самых простых вариантов Программатора, но в общем, они все рабочие, ими вполе можно пользоваться. Как правило они годятся для программирования STM8 и STM32. Единственное, они не имеют SWO выхода, но он нужен не так часто. Пожалуй, единственный минус тут, это ожидание покупки. Стоимость около 150-200 руб.

Если вам не нужен программатор STM8, а нужна только серия STM32, то хорошим вариантом будут платы Discovery от ST, они имеют на бору и программатор ST link. Однако, как правило, разъем для программирования STM8 там не разведен.

Ну и конечно, можно просто купить детали и сделать данное устройство самостоятельно. В основе лежит не самый дешевый микроконтроллер STM32, да и купить детали дешево не так просто, так что, стоимость будет от 300 до 400 рублей. В данной статье мы будем рассказывать, как собрать данный прибор самостоятельно из набора необходимых SMD компонент. Конечно же мы рекомендуем пойти этим путем. Только так вы сможете научится трассировке плат, их изготовлению и паянию.

{product id=30}

Как изготовить программатор ST-LINK V2

1. Прочитать эту статью внимательно и до конца!

2. Подготовить или приобрести необходимые инструменты: все для пайки, USB UART адаптер (будет нужен для программирования МК)

3. Внимательно прочитать статьи из раздела Обязательная теория.

4. Скачать необходимые файлы по данному прибору с github.

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

6. Приобрести все необходимые комплектующие можно в нашем магазине за 300 руб.

7. Запаять все компоненты на плату, смотри наше видео.

ПРИБОР ГОТОВ, можно пользоваться!

Поиск схемы для ST Link программатора, отладчика

Сама компания ST не дает нам схему данного прибора, однако есть схемы ее ознакомительных плат серии DISCOVERY, в которых приводится и схема отладчика. Например документ UM0919. Но она не полная, там присутсвует только SWD интерфейс. В основе микроконтроллер STM32F103C8T6.


Вторая схема, которая есть в документе UM1670, содержит выводы SWIM выходов, но это уже версия V2.2 на другом микроконтролере STM32F103CBT6.


Также в интернет удалось найти схему ST-LINK v2, восстановленную по оригинальному прибору:

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

Требования к нашему ST-LINK

Мы будем делать приборы на базе STM8, а также STM32, процессоров NUVOTON Cortex-M0, ATMEL. Все они будут питаться от 3.3В или 5В. Так что, нам не нужна возможность работать с микроконтроллерами на напряжении 1.8В. Но сама возможность программировать STM8 нужна обязательно.

Мы делаем прибор для своих задач, поэтому у нас нет необходимости в стандартных разъемах SWIM и JTAG. Будет делать такой разъем, который удобнее для трассировки платы.

Версия 2.2 на микроконтролере STM32F103CBT6 добавляет второе USB устройство — COM порт UART, но он уже у нас есть, так что, нет смысла переплачивать, микроконтроллер там дороже. Правда у него есть хорошая возможность - прошивка через интерфейс DFU, то есть микроконтроллер видится как флешка при подключении по USB, и прошивку просто надо скопировать на диск. Но прошить надо будет один раз, и для этого у нас есть USB UART адаптер, прошивать первый раз будет через него. Дальнейшее обновление прошивки идет уже через программу от ST по USB. Мы будем делать версию 2.0 на базе STM32F103C8T6.

Оригинальная версия ST-Link содержит микросхему преобразования уровней, что удобно для отладки и прошивки готового устройства, и необходимо для работы с напряжением ниже 3.3В. У нас таких не будет, а для работы с 5В и 3.3В — преобразование уровней не нужно.

Прибор будем делать в формате USB dongle, соответсвенно будет использоваться разъем USB-A male.

На защите выходов можно сэкономить, так что не будем использовать защитные диоды. Достаточно будет сопротивлений на всех выходах разъемов на случай, если вдруг мы их подключим на 5В или землю. Надо обязательно иметь в виду, что пользоваться данным прибором надо аккуратно! Все выходы при подключении проверять несколько раз! Выход 3.3В больше защищен, он идет через регулятор напряжения, защищающий от КЗ. Так что, лучше питать тестовые схемы от него!

Теперь можно составить финальную схему нашего ST-Link.

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

Финальная схема

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

Основная часть:


Питание и разъемы:

Небольшие комментарии.

В качестве регулятора питания на 3.3в используем NCP603 — очень хороший LDO, выдает ток до 300ма с падением 300mv и точностью +-3%. Светодиоды индикации - обычные smd светодиоды двух цветов. Для программирования по UART необходимо вывод BOOT0 соединить с +3В, для этого выведем его на разъем. Также необходимо вывести сам UART — ножки RX TX. Все остальные выводы без защиты выведем на разъем. Пользуюсь этим программатором уже больше года, и кз были и помехи — ничего не сгорело ни разу.

В некоторых схемах ставится самовостанавливающийся предохранитель на питание от USB для защиты самого порта. Современные компьютеры имеют защиту на портах USB, в том числе предохранители и токовые ограничивающие ключи, так что он не нужен. Но лучше конечно не проверять это, и не ошибаться! Напряжение 3.3в идет с нашего LDO, который имеет защиту от КЗ и от перегрева, и не выдает больше 600ма, там тоже защищать нечего.

Очень удобно подключать STM8 для программирования с помощью ST-Link, нужно всего 3 провода - питание, земля и SWIM выход. Это так же удобно при разводке плат, можно разводить только SWIM выход, землю и питание всегда можно найти на плате.

Трассировка платы в Kicad с помощью автотрассировщика Topor

В приборе USB UART адаптер мы уже тренировались трассировать плату в Kicad вручную. Данный прибор чуть сложнее. На нем можно поучиться разводить плату в автотрассировщике TOPOR. Весь процесс лучше просмотреть на видео в конце статьи, здесь будут лишь небольшие комментарии к видео.

Подготовка платы к автотрассировке

Для того, чтобы работать с Topor, надо сначала подготовить плату в Kicad. Необходимо определить границы платы, импортировать все компоненты и предварительно их расположить. У нас нет требований к разъемам, поэтому на первом этапе лучше сам разъем удалить с платы. Так как каждый вывод разъема соединен через резистор, то резисторы и будут ориентиром выводов разъема. Также для расстановки компонент можно удалить все конденсаторы питания, кварцы, микросхемы питания (их лучше располагать на обратной стороне — там обычно много места) — это все можно расставить потом.

Теперь необходимо определить сторону кажого копонента. И примерно расположить их как необходимо, разъемы расположить у края. И на этом этапе можно все это перебросить в Topor и там продолжить размещение копонентов. USB разъем, светодиоды сразу располагаем на обратной стороне, все остальное на лицевой.

Размещение компонентов с помощью Topor

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

Покрутив и подвигав компоненты в Topor мы пришли к такому расположению:


Теперь необходимо этот результат перекинуть в Kicad обратно и добавить остальные компоненты. Перед финальной трассировкой необходимо:

  • расположить микросхемы питания

  • развести вручную цепи питания

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

  • переопределить выводы разъема на схеме.

Автотрассировка

Перебрасываем нашу полутрассировку в Topor.

Необходимо сразу установить правила трассировки — ширину зазоров, дорожек, размеры переходных отверстий. При первом импорте из Kicad надо выделить все компоненты и зафиксировать их, чтобы можно было легко удалить кнопкой del и заново перепроложить трассировку, оставляя наш полуручной вариант. В параметрах автотрассировки обязательно необходимо установить галку «Использовать имеющуюся разводку в качестве начального варианта», иначе наши ручные трассы будут перепроложены (Сам процесс работы в Topor смотри на видео).

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

Финальный вариант платы

Лицевая сторона


Обратная сторона

 

Прошивка ST Link, установка драйверов

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

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

Все микроконтроллеры STM32 имеют bootloader и прошиваются по UART. Для прошивки необходимо:

  • скачать с сайта ST программу «STM32 Flash loader demonstrator» по ссылке (необходимо зарегистрироваться у них на сайте).

  • установить ее, все как обычно — далее далее далее — готово.

  • подключить наш ST link для программирования временными проводками:

    • Соединяем выводы программирования PROG_RX и PROG_TX (см. схему в Kickad на github) и USB/UART модуль — наш RX на TX модуля, наш TX на RX модуля.

    • В USB ST Link не включаем, подключаем 5В с UART модуля и GND на любой наш разъем (например на разъеме SWIM есть 5В и GND) — то есть запитаем от нашего модуля (если у вас свой модуль без питания, то можно сразу подключить ST-Link в USB разъем, тогда надо будет только соединить TX и RX, только не забудьте на вашем модуле необходимо выбрать 3.3в)

    • Подключем BOOT0 на выход 3.3В (можно просто держать проводок при подключении питания) — это необходимо для перехода в bootloader

  • включаем USB/UART модуль в компьютер, указываем в программе Flash Loader наш COM порт, жмем далее — программа должна найти наш микроконтроллер, далее, выбираем download и загружаем прошивку STLinkV2.J16.S4.bin, выложенную на github прибора. Вот такие это выглядит в картинках:

    Тут выбираем 64К.

    а тут ставим переключатель на download и выбираем файл прошивки (маска файлов на *.bin)

Теперь у нас есть ST LINK, но со старой прошивкой. Убираем все провода. Скачиваем с сайта ST программу обновления прошивки STSW-LINK007 и драйвера STSW-LINK009 для windows. Вставляем новоиспеченный ST-Link в USB порт компьютера, и запускаем программу обновления прошивки, в ней жмем CONNECT и потом обновить прошивку до последней версии. Прибор ГОТОВ! Теперь у вас есть программатор-отладчик и можно перейти к программированию.

Готовое устройство

Радиоконструктор ST-Link в сборе. Так будет выглядеть твой самодельный ST Link - программатор STM8 и STM32

Набор для пайки в деле. Запаянный ST-Link. Готов к работе. Теперь вы готовы к программированию микроконтроллеров STM8

Самостоятельная работа

Потренируйтесь разводить плату. Сделайте это вручную, с помощью программы Topor и без. Вы должны уметь быстро делать любую несложную плату.

 

]]>
(Super User) Приборы Mon, 02 Jan 2017 12:36:00 +0000
Bluetooth велокомпьютер /index.php/pribory/item/1-velokompyuter /index.php/pribory/item/1-velokompyuter Bluetooth велокомпьютер

Управление по bluetooth. Питание от li-ion аккумулятора. 2 датчика — на колесо и педали. Более 18 поездок по 3часа на одном заряде. Автоматическое фиксирование поездки. Расчёт и хранение за 3 последние поездки основных показателей — скорость, расход калорий, каденс. И самое главное звуковой контроль параметров — заданной скорости и каденса. Компактный размер 30х50х35мм

{autotoc}

Прежде чем начать

Прежде чем читать эту статью, рекомендуем вам ознакомится со следующей теорией:

Что такое и зачем нужен велокомпьютер

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

Учёт каких параметров может вести велокомпьютер:

  • скорость и её производные (средняя скорость, максимальная, основная скорость движения и т. д.)

  • пройденное расстояние

  • время в пути — активное (то есть когда именно ехали), все время поездки (с учётом перерывов)

  • пульс — средний, максимальный и т. д.

  • Потраченные калории за поездку

  • Частота вращения педалей - оптимальная или нет

Основные компоненты

  • Основной блок (компьютер) — мозг всей системы

  • Датчики скорости — в основном крепится на колесо

  • Датчик каденса — крепится на педали

  • Датчик пульса — одевается на руку или крепится на теле

Анализ рынка, какой будет наш прибор

Прежде чем делать прибор изучим немного рынок, что продаётся и примерно почём. Все модели можно поделить на 3 категории:

  • дешевые модели — один проводной датчик, небольшой размер, жк экранчик, работа от батареек около 1года. Функции очень простые — средняя скорость, текущая скорость, часы, пробег. Цена — около 800 руб.

  • средние модели — два датчика, проводные или беспроводные, жк экран, работа от батареек. Функции — каденс, скорость, средняя скорость, пробег, часы, автоматический старт и стоп. Цена — около 1500 руб.

  • дорогие модели — наличие bluetooth, два датчика, плюс возможность подключения различных датчиков (сила нажима на педали, пульс, скорость насыщения организма кислородом и другие). Функции — каденс, калории, скорость, пробег, и в зависимости от датчиков — около 5000 руб.

Будем ориентироваться на средний или даже дорогой сегмент по функциям, а по цене не дороже дешёвых моделей — дешевле 700 руб. Так как мы сами будем паять прибор, то будет проще, если мы исключим экран (это прибор для новичков, и начинать сразу работать с дисплеем — это плохое начало) и заменим его на bluetooth модуль. От этого мы только выиграем. Это даст нам возможность не только выводить любую информацию, но и программировать прибор с телефона по bluetooth. Также это сильно снизит габариты прибора. Добавим возможность вести историю поездок, и звуковой контроль каденса — это очень полезная функция, позволяет не перегружать суставы на многоскоростных велосипедах. Также в случае, например, тренировки на скорость — добавим звуковой контроль минимальной скорости. Ну и естественно, так как у нас большой экран смартфона, то будем выводить всю возможную статистику. Средняя скорость - не очень информативный показатель, если мы делаем частые остановки. Гораздо интереснее знать скорость, с которой мы ехали большую часть времени. Обязательно будем считать калории, и только в тот момент, когда мы крутим педали. Часы есть на телефоне, и нам не нужны. А вот возможность автоматически определять поездки и фиксировать по ним информацию — очень.

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

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

{product id=1}

Постановка задачи

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

Параметр

Требования

Питание

Аккумулятор, зарядка по miniusb, одного заряда должно хватать на 10-20 поездок по 3 часа.

Измеряемые показатели

Пройденное расстояние, скорость, потраченные калории, каденс

Особенности

Контроль каденса — с помощью звука, экрана у нас нет, так что максимально будем использовать звук.

Интерфейс

Bluetooth serial port 2.0

Корпус

Небольшой корпус с удобным креплением к велосипеду

Подбор компонентов

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

Датчики

Для измерения скорости велосипеда и пройденного расстояния можно использовать:

  • gps модуль — спутники дают данную информацию

  • инерциальная система позиционирования

  • счётчик оборотов колеса

Для измерения каденса — нужен счётчик оборотов педалей.

Мы выберем самый простой вариант — счётчик оборотов колеса и педалей. Для подсчёта оборотов удобнее всего использовать магнит закрепленный на колесе и датчик магнитного поля закрепленный на раме и такой же вариант для педалей. Возможные датчики магнитного поля:

Датчик

Преимущества - недостатки

Датчик холла

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


Основной недостаток — энергопотребление от 2ма. Что не годится для спящего режима.

Геркон

Относительно небольшой, нет энергопотребления (по сути кнопка).


Невысокая чувствительность, дребезг контактов — ограничение по частоте срабатывания 400гц.



Чтобы рассчитать подойдёт ли нам геркон, нужно посмотреть не превысили ли мы его максимальную частоту срабатывания на максимальной скорости движения велосипеда. Допустим диаметр колеса у нас 50см, максимальная скорость велосипедиста 100 км\ч. За один оборот колесо проходит, по известной формуле длины окружности:

π D = 3,14 * 50 = 157см = 1,57м.

Чтобы найти частоту срабатывания в секунду надо перевести максимальную скорость в метры в секунду

100 км\ч = 100000м / 3600с = 27,8 м\с.

Частота срабатывания геркона будет равна 27,8м\с / 1,57м = 17,7 оборотов\с = 17,7Гц. Геркон отлично подходит для данного прибора, его частота 400Гц.

Для прибора нам необходимо 2 геркона — один будет учитывать кол-во оборотов колеса — другой педалей. Можно оба датчика сделать выносными на проводе, но так как у нас нет необходимости в экране (интерфейс будет по bluetooth) — то для минимизации проводов — мы разместим прибор на задней вилке. При этом один геркон разместим в корпусе прибора — другой на небольшом удалении с помощью провода. Если вы эстет, то можете использовать черные стяжки. Для того чтобы прибор не скользил по вилке велосипеда, можно использовать специальную подложку сетку под ковры.




Интерфейс общения

Как мы видели ранее, в велокомпьютерах используется экран на который выводится нужная информация. Мы решили использовать bluetooth. Практически у всех сейчас есть смартфон, в котором он есть (к сожалению, iphone не работает с протоколом Bluetooth SPP). Учитывая тот факт, что критическую информацию можно передать звуком (пищалка), а все показатели снять по окончанию поездки или во время остановок — bluetooth отличная замена экрана (вы также можете легко модернизировать прибор на работу с экраном — далее разбираются приборы с ЖК экранами).

Будем использовать Bluetooth Serial Port для передачи данных — соответственно нужен протокол UART. Возьмём модуль Bluetooth SPP-C. Данный модуль обеспечивает двух стороннюю прозрачную связь между телефоном и велокомпьютером. Для отображения информации на экране телефона мы будем использовать простейшую программу bluetooth terminal (вы можете использовать другие более симпатичные программы или написать свою). Информацию будем передавать каждые 2 секунды в виде форматированной строки текста.

Что будем передавать:

Велокомпьютер будет передавать информацию:

  • Текущая скорость движения в км\ч

  • Каденс - скорость вращения педалей в об\мин

  • Макс скорость за поездку

  • Длительность поездки полная и активная

  • Основная скорость — та скорость с которой едем большую часть поездки

  • Время проезда со скоростью в определённом диапазоне— интервалы по 4км\ч до 40км\ч

Что будем получать:

Настройку прибора будем производить с телефона. Можно будет задать следующие параметры:

  • диаметр колеса для проведения всех расчетов — в см.

  • вес человека (для расчёта калорий) в кг

  • настройка контроля каденса — минимальный каденс при котором необходимо подать звуковой сигнал (при езде на велосипеде необходимо так выбирать скоростной режим, чтобы каденс был больше 80 об\мин — вот это и будем отслеживать)

  • Запрос на получение итоговых данных - подробные за 3 последние поездки и итоговые за все время пользования прибором

Использование пищалки:

  • при включении

  • при переходе в спящий режим

  • при нарушении скорости каденса на 10 об\с в течение 2 мин

Микроконтроллер

Выберем микроконтроллер. Какие требования к микроконтроллеру в нашем проекте?

  • считывать показания 3 кнопок (наши датчики — герконы и еще одна кнопка)

  • иметь интерфейс UART для общения с bluetooth модулем

  • наличие спящего режима для энергосбережения

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

  • удобный корпус для пайки

  • точный подсчёт интервалов времени, работа от кварца

  • EEPROM память для хранения настроек

Выберем серию STM8. Она имеет отличный отладчик ST-Link по 2-ум проводам, симулятор и всю необходимую периферию. Программа будет небольшая, выберем самый дешёвую модель - наш выбор STM8S003F3P6. Можно выбрать линейку STM8L — но они дороже, а энергопотребление у нас будет минимальное.




Аккумулятор

Для выбора аккумулятора рассчитаем примерный расход энергии. Основные потребители энергии:

Модуль

Потребление

Микроконтроллер

1мА на частоте 1мгц (нам больше не надо)

4мкА в спящем режиме

Bluetooth модуль

8мА в режиме активного соединения

30мА в режиме поиска соединения

Прочая утечка — LDO в режиме отключения и прочие утечки

3мкА



Таким образом, максимальный расход энергии — 40мА. Рассчитаем сколько миллиампер будет тратиться на одну поездку длительностью 3ч при следующем профиле работы прибора:

  • 1 поездка 3часа

  • bluetooth работает за время поездки 2мин поиск, 30мин активное соединение

  • во время поездки 1ч спим

получается 2ч потребление 1ма, 1ч потребление 7мкА, 30мин потребление 8мА, 2мин потребление 30мА. Если все привести к мА\ч то получается:

2 мА\ч + 0,007мА\ч + 4 мА\ч + 1ма\ч = 7,007 мА\ч.

Надо необходимо, чтобы заряда хватало минимум на 10 поездок. Значит нужен аккумулятор ёмкостью более 70 мА\ч. Будем использовать Li-ion аккумулятор LIR-2450 ёмкостью 120мА\ч.




Рассчитаем расход в спящем режиме. Расход 7 мкА\ч. Значит прибор может проработать на оставшихся 50 мА\ч около 7143 часов = 300 дней.

Составляем схему

Начнём с питания. Аккумулятор мы выбрали. Соответственно нужна схема его заряда. Заряжать наш прибор будем через разъем micro-usb, микросхему для заряда возьмём самую дешёвую — TP4056. Ток заряда установим 100 мА (примерно 1C для выбранного аккумулятора).

Bluetooth модуль — самый простой UART slave модуль на базе BK3231




По datasheet на модуль ему необходимо питание от 2 до 3.6в. У нас аккумулятор выдаёт от 3 до 4.2В. Соответственно нужен LDO для понижения напряжения до 3.3В. Возьмём серию NCP603 на 3.3в.




Микроконтроллер мы выбрали — STM8S003F3 — его питание от 3 до 5В. Ему LDO не нужен. Таким образом, МК будет питаться сразу от аккумулятора, LDO будет питать bluetooth модуль, включать LDO будем только на время работы модуля.

Герконы — подключаем стандартно, как кнопки, сразу на вывод и на GND. Будет использовать встроенный в МК PULL-UP резистор. Точно также подключим тактовую кнопку.

UART — так как у нас разное напряжение питание модулей то нужно согласование напряжения. Разница между уровнями 4.2В — 3.6В = 0.6В. Проблема будет только в канале TX, когда передаём сигнал с МК на модуль. Так как в модуле стоят защитные диоды на всех входах, то достаточно использовать простой резистор на 10 кОм.

Пищалка. Возьмём очень громкую пищалку — HC0903A, на 3В — но будет работать и на 4В. Ток работы — 100ма.




Соответственно нужен будет транзистор для управления пищалкой. Возьмём маломощный N-Mosfet 2N7002 (до 300ма ток), так можно сэкономить на резисторе на базе транзистора.

Для МК нужна стандартная обвязка плюс кварцевый резонатор на 8МГц.

Схема определена. Теперь нарисуем ее в Kicad.


И вторая часть




Размещение велокомпьютера, Корпус и плата

Подберём корпус для нашего прибора. Для этого прикинем размер платы. Размещение будет такое — сверху на плате — МК, micro-usb, микросхемы заряда и все прочее, снизу — кварц и bluetooth модуль. На краю платы угловая тактовая кнопка:


Получаются примерные размеры 50х30 мм. Мне понравился корпус фирмы GAINTA — NUB503522BK:


Внутренние размеры платы под корпус — 45х30мм, что вполне подходит. Корпус имеет 2 крепёжных отверстия для платы, что очень удобно, а также ушки — за них можно крепить к велосипеду. Так как у нас нет экрана и смотреть нам не надо, то удобнее разместить велокомпьютер на задней вилке велосипеда. При таком размещении один геркон можно разместить прямо на плате, а второй на коротком проводе — педали рядом. Кнопка должна быть на противоположном боку от геркона. Второй геркон можно просто припаять внутри прибора или использовать любой разъем в разрыв провода.


Платы мы уже научились разводить на приборах ST-Link и UART, так что готовая плата находится на github проекта папке Kicad.

Математика

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

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

C (длина окружности) = π (константа ПИ = 3,1415926535) * D (диаметр колеса).

Далее нам необходимо переводить единицы времени — миллисекунды в часы. Ну тут просто используем тот факт, что в одной минуте 60 секунд, а в одном часе 60 минут.

Для расчёта потраченных калорий будем использовать простую формулу

(Калории в ккал) = (Скорость в км\ч) * (Время в ч) * (Вес в кг).

Считать калории мы будем только тогда, когда крутим педали.

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

Также мы будем считать, что диапазон скоростей у нас от 0 до 60 км\ч, конечно велосипед может развивать большую скорость, но только если он в руках спортсмена.

Программа

Программа написана в среде ST Visual develop IDE. Полный проект вы можете скачать с github данного прибора, папка velo. В статье мы разберём ключевые моменты работы программы.

Структура файлов проекта

Проект создан на основе библиотеки SPL для STM8 от ST. Подробное описание как развернуть проект вы найдёте в этой статье. Основная программа содержится в файле main.c, работа с прерываниями в файле stm8s_it.c, частота кварца задана в файле stm8s.h. Остальные файлы остались без изменений.

Общее описание программы

Упрощённый алгоритм работы программы.

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

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

  3. Из EEPROM считываются записанные настройки, если они равны 0, то туда записываются типовые настройки, обнуляются все данные о поездках, идет подготовка EEPROM

  4. Фиксируется начало поездки, обнуляются все переменные по поездке

  5. Включается bluetooth модуль для экономии энергии на 2мин, включение и выключение модуля фиксируется звуковым сигналом

  6. Через прерывания фиксируются показания датчиков и рассчитываются все необходимые параметры

  7. Каждые 2с на bluetooth передаётся текущая информация о поездке, если он включён

  8. Если в течение 2мин не было прерываний от датчиков, то МК переходит в спящий режим, выход по прерыванию от датчиков или кнопки

  9. Кнопка включает\выключает bluetooth модуль, а также будит МК

  10. Если МК находится в спящем режиме больше 2часов, то считается, что поездка завершилась. Идёт анализ данных поездки, если расстояние меньше 500метров, то данные по поездке обнуляются и не сохраняются, иначе данные о поездке сохраняются в EEPROM

  11. При получении данных от bluetooth модуля, идёт их анализ и разбор фраз настройки МК, данные записываются в EEPROM

  12. Во время активного режима работы МК идёт анализ скорости и каденса и в случае превышения заданных параметров идёт оповещение звуковым сигналом

Инициализация, прерывания

Рассмотрим более подробно исходный текст программы. Основная программа находится в функции main(). Первым делом необходимо произвести все настройки периферии.

[code]CLK->PCKENR1 = 0;
CLK->PCKENR1 |= CLK_PCKENR1_UART2|CLK_PCKENR1_TIM4;
CLK->PCKENR2 = 0xFF & 0b01110111;
[/code]

Данный регистр отвечает за использование необходимой периферии, каждая периферия потребляет энергию, если она включена, даже если мы ей не пользуемся. Для экономии энергии отключим все, кроме UART(используется для обмена с bluetooth модулем) и TIM4 (таймер 4 используется как миллисекундный таймер).

[code]CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE,DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV8);
[/code]

Задаём работу от внешнего кварца. Кварц у нас в проекте — 8Мгц, делитель CPU устанавливаем на 8, чтобы МК работал на частоте 1Мгц для экономии энергии. В STM8 все настройки частоты производятся прямо в коде программе, необходимости в прошивке фьзов, как например, в AVR, нет. Это очень удобно. Автоматический (CLK_SWITCHMODE_AUTO) режим переключения кварца означает, что система сама дождётся корректного запуска внешнего кварца и потом перейдёт на него.

[code]GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_IN_PU_IT);//knopka
GPIO_Init(GPIOC,GPIO_PIN_7,GPIO_MODE_IN_PU_IT);//H1
GPIO_Init(GPIOC,GPIO_PIN_6,GPIO_MODE_IN_PU_IT);//H2

//прерывания по падающему фронту
EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOD,EXTI_SENSITIVITY_FALL_ONLY);
EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOC,EXTI_SENSITIVITY_FALL_ONLY);
[/code]

Настройка работы выводов МК датчиков и кнопки. Используется режим PULL UP и включаются внешние прерывания на этих выводах (GPIO_MODE_IN_PU_IT). Принцип срабатывания внешних прерываний на выводах задается в целом для порта. EXTI_SENSITIVITY_FALL_ONLY — означает прерывание по падающего сигналу, когда на выводе сигнал меняется с HIGH на LOW, для нас это будет соответствовать нажатию кнопки или срабатыванию геркона.

[code]UART1_DeInit();
UART1_Init((uint32_t)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1,UART1_PARITY_NO,
UART1_SYNCMODE_CLOCK_DISABLE,UART1_MODE_TXRX_ENABLE);

UART1_ITConfig(UART1_IT_RXNE_OR,ENABLE);
[/code]

Настраиваем UART для связи с bluetooth модулем. Вся работа будет вестись на прерываниях. Здесь задаем скорость порта — 9600, работу TX и RX, контроль четности, асинхронный режим, передачу данных по 8 бит. То есть так, как этого требует bluetooth модуль. Последней командой включаем работу прерываний по UART событиям.

[code]TIM4_TimeBaseInit(TIM4_PRESCALER_64, 125);
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
enableInterrupts();
TIM4_Cmd(ENABLE);
[/code]

Запускаем миллисекундный таймер. Обратите внимание, что частота кварца 8Мгц, не смотря на установленный делитель для CPU, вся периферия работает на 8Мгц, в том числе и все таймеры. Поэтому устанавливаем предделитель 64, а счетчик — 125 (8 000 000/64/125 = 1000 = 1мс). Включаем прерывания на таймере 4 и запускаем работу прерываний. После этого включаем сам таймер 4.

[code]GPIO_Init(GPIOC,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5,GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOB,GPIO_PIN_5|GPIO_PIN_4,GPIO_MODE_OUT_OD_HIZ_SLOW);

GPIO_Init(GPIOD,GPIO_PIN_4,GPIO_MODE_OUT_PP_LOW_SLOW);//speaker
GPIO_Init(GPIOD,GPIO_PIN_2,GPIO_MODE_OUT_PP_LOW_SLOW);//blue onoff
[/code]

Настраиваем работу выводов как LOW, для энергосбережения. Если их оставить в неопределённом состоянии, триггеры Шмита на входах будут тратить энергию. Ножки 4,5 порта B не имеют триггеров Шмита, оставим их в неопределённом режиме. Динамик выключаем. Bluetooth модуль выключаем.

Переводим МК в спящий режим по команде halt(). Это сделано для того, чтобы в случае разряда аккумулятора при включении зарядного устройства не было попыток проиграть музыку, это требует много энергии, а зарядное устройство на столько не рассчитано, аккумулятор еще слабый и это вызывает перегрузку МК, мешая заряду аккумулятора.

После выхода из спящего режима по прерыванию, программа продолжает выполнение после инструкции halt().

[code]playmusic(1);

GPIO_WriteHigh(GPIOD,GPIO_PIN_2);
blueen = TRUE;
kn = FALSE;

timeblueoff = 120;
timehalt=120;
[/code]

Проигрываем музыку, включаем bluetooth на 2 минуты. Запускаем счетчик перехода в спящий режим.

На этом настройка выполнена, программа переходит в основной цикл.

Миллисекундный таймер, события по временным интервалам

Обработка всех временных событий ведётся в прерывании таймера 4. Сам обработчик прерывания проще перенести в файл main.c, потому что, в нем будет много общих переменных. Предопределённая процедура INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23). Разберём обработку этого прерывания. Данное прерывание срабатывает каждую миллисекунду, согласно настройкам таймера 4.

[code]TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
[/code]

Первым делом при входе в прерывание оповещаем МК, что мы его обработали. Без этой команды вызов прерывания будет продолжаться бесконечно и МК зависнет. Далее идёт обработка событий по времени. Для того чтобы посчитать прошедшее время используется очень простая методика. Если нам необходимо выполнить какое действие по прошествую времени Х мс, то заводим глобальную переменную timeX, и в момент начала события записываем в эту переменную нужное количество миллисекунд. В обработке прерывания таймера необходимо написать следующий код:

[code]if (timeX) timeX--;
[/code]

Уменьшаем на 1 значение переменной пока там не станет 0. В глобальном цикле, в основной программе далее проверяем данную переменную на 0 и когда она станет равной 0 выполняем нужное действие. Например, так мы выключаем bluetooth через 2 минуты.

[code]//В основной программе:
if (timeblueoff==0 && blueen==TRUE)
{
//через 2 мин выключаем блютус!
blueen=FALSE;
GPIO_WriteHigh(GPIOD,GPIO_PIN_2);
playmusic(3);
}

//в прерывании
if (timeblueoff) timeblueoff--;
[/code]

Дополнительно для удобства вводим секундные события

[code]if (nextsec==0) {
//раз в секунду!
Nextsec = 1000;
//обработка секундных событий
}
[/code]

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

[code]//в прерывании обработки датчика, присрабатывании датчика
h2time = 1; //начинаем замер с 1, для того,чтобы можно было отследить, что замервообще начат, если будет 0 — то замер неидет.

//в прервании таймера
if (h2time)
{
h2time++; //если замер начат, то добавляем1
}

if (h2time > 3000) { //обязательно необходимоограничение, если больше 3000, то замеростановили
scor2 = 0;
h2time=0;
}
[/code]

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

Работы пищалки, звуковое оповещение

Для звукового оповещения мы используем мини пищалку. Для воспроизведения звука необходимо подать меняющийся сигнал 0 — 1 с нужной частотой. Наша пищалка имеет самую большую громкость в районе частоты 3Кгц. Но в принципе будет пищать с любой частотой. Для создания на выводе МК меняющего сигнала можно использовать таймер. Например, для частоты 3Кгц нам необходимо иметь таймер срабатывающий 6тыс раз в сек. И каждое срабатывание менять состояние вывода МК. STM8 специальную периферию для работы пищалок. Ей мы и воспользуемся. Звук может выводится только на вывод №1 и с частотой только 1, 2 или 4 Кгц. Нам этого хватит, чтобы издавать различные несложные мелодии. В стандартной библиотеке в примерах есть специальная функция, которая может калибровать данный генератор звука по кварцу, но можно ей не пользоваться.

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

[code]void playmusic(int t)
{
if (t==1)
{
//turn on
BEEP_Init(BEEP_FREQUENCY_1KHZ);
BEEP_Cmd(ENABLE);
Delay(100);
BEEP_Init(BEEP_FREQUENCY_2KHZ);
Delay(200);
BEEP_Init(BEEP_FREQUENCY_4KHZ);
Delay(100);
BEEP_Cmd(DISABLE);
}
[/code]

Все очень просто. Задаем нужную частоту и запускаем генератор. Через определённую в миллисекундах задержку выключаем, включаем опять с другой частотой и т. д. Получается простая мелодия — два писка, три писка разной тональности. Нам этого вполне достаточно.

Обработка кнопок и датчиков, дребезг контактов

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

[code]INTERRUPT_HANDLER(EXTI_PORTD_IRQHandler, 6)
{
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the followinginstruction.
*/
if ((BitStatus)(GPIO_ReadInputPin(GPIOD,GPIO_PIN_3)) == RESET) {
//защита от дребезга контактов -отключим прервание на 50мс
if( haltstart==0)GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_IN_PU_NO_IT);
kn = TRUE;
kntime = 200;
}
}
[/code]

Так как обработчик прерывания у нас один на весь порт, то необходимо проверить наш ли вывод его вызвал. Для этого считываем состояние нужного нам вывода и есть там LOW, то кнопка нажата. Далее мы отключаем прерывание на выводе D3 и устанавливаем флажок kn в TRUE, для обработки события в основном цикле. Тут же запускаем таймер защиты от дребезга контакта. Заметим, что отключать прерывание мы будем только тогда, когда переменная haltstart у нас равна 0. Это нам необходимо для того, чтобы случайно не выключить прерывания прямо перед уходом в спящий режим, а то мы не сможем разбудить наш МК.

По прошествию этого времени, включаем прерывание обратно в обработчике прерываний таймера 4.

[code]	if (kntime)	
{
kntime--;
if (kntime==0)
GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_IN_PU_IT);
}
[/code]

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

[code]		if ((BitStatus)(GPIO_ReadInputPin(GPIOC,GPIO_PIN_7)) == RESET) {
//защита от дребезга контактов -отключим прервание на 50мс
if (haltstart==0)
GPIO_Init(GPIOC,GPIO_PIN_7,GPIO_MODE_IN_PU_NO_IT);

if (h1time>1) {
//скорость будем считать толькокогда прошло больше одной миллисекундыс прошлого замера
scor1 = 60000/(h1time - 1);//в оборотах в мин
} else scor1 = 0;

h1time = 1;
hall[0]++;
timehalt=120;
}
[/code]

В обработчике таймера делаем аналогично, но h1time растет, а не уменьшается

[code]		if (h1time)	
{
h1time++;
if (h1time==30)
{
GPIO_ReadInputPin(GPIOC,GPIO_PIN_7);
GPIO_Init(GPIOC,GPIO_PIN_7,GPIO_MODE_IN_PU_IT);
}
}
[/code]

Дополнительно в той же процедуре обнуляем скорость и показания h1time в случае превышения 3сек

[code]	if (h1time > 5000) {
scor1 = 0;
h1time=0;
}
[/code]

Вычисления, расчёт показателей

Основой всех вычислений у нас является показатель скорости вращения педалей и скорости велосипеда. Переменные scor1 и scor2. Для расчёта скорости вращения педалей в обработчике прерывания, при обработке соответствующего датчика, вычисляем scor1 по формуле

[code]	if (h1time>1) {
scor1 = 60000/(h1time - 1);//в оборотах в мин
} else scor1 = 0;
[/code]

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

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

[code]	if (h2time>1) {
scor2 = 36*(uint32_t)dkoles*314/100/(h2time - 1);//в км/ч
//1/ms * dkol * 314/10 * 36 / 10
} else scor2 = 0;
[/code]

Так как мы работаем с целыми числами, то необходимо использовать большие форматы uint32_t, для помещения результата всех умножений перед делением, а потом поделить. В целочисленной математике порядок операций имеет очень большое значение. Например, 2*100/4 = 50, а вот 2/4*100 = 0. Изначально полная формула у нас такая:

=

таким образом получается наша формула. Можно использовать большую точность числа PI, но в общем принцип понятен. Дополнительно в массиве hall[] мы считаем количество оборотов педалей и оборотов колеса.

Дополнительно раз в секунду мы считаем скорость велосипеда по границам 0-4км\ч, 4-8км\ч и т.д. В отдельном массиве obs[] мы получаем количество секунд, которое мы ехали с определёнными интервалами скорости, а также общее количество секунд, которое мы ехали - activetime. Конечно это не совсем хорошо, ведь скорость может меняться чаще чем раз в секунду. Но велосипед очень инертен, мы не можем очень быстро тормозить и разгоняться, так что этим можно пренебречь. Делаем это в обработчике таймера 4.

[code]if (scor2)
{
uint32_t ind = scor2/4; //по 4 км\ч
if (ind>9) ind=9; //все что больше 40км\ч пишемв последнюю градацию скорости
obs[ind]++; //добавляем одну секунду

activetime++;
}
[/code]

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

[code]	if (scor1)
power += (float)ves * (float)scor2 / 3600;
[/code]

Расстояние, которое мы проехали, считаем уже в основном цикле исходя из массива hall[] , при форматировании конечного результата. Её мы передаём на bluetooth, если он включён каждые 2сек. См раздел по работе с bluetooth.

Работа с EEPROM, хранение значений в энергонезависимой памяти

STM8 позволяет работать с EEPROM в нескольких режимах. Первый — автоматическая перезапись — вы записываете новое значение во флеш, старое автоматически стирается. Второй — вы сначала стираете ячейку, а потом записываете новое значение. Во втором случае, скорость записи выше, а обнулить значения можно заранее. Когда работаете с EEPROM необходимо внимательно читать Datasheet, у каждого МК своя методика, а также свой минимальный размер записываемой информации. В STM8 минимальный объем это 1 байт, например, в STM32 — это страница — 256 байт. Объем EEPROM очень небольшой, поэтому надо экономить этот вид памяти — у нас всего 128 байт.

Для упрощения работы с EEPROM в СИ удобно использовать структуры, которые будут описывать записываемые параметры. Компилятор размещает структуру в оперативной памяти последовательно, как она заявлена в СИ. Таким образом, чтобы записать или прочитать структуру в EEPROM, достаточно записать\прочитать нужное количество байт, начиная с адреса структуры. Напишем вспомогательные функции для чтения и записи во флеш из оперативной памяти.

[code]void saveflash(u32 addrf,u32 addr,u8 nbyte)
{
FLASH_Unlock(FLASH_MEMTYPE_DATA);

while (nbyte--)
{
FLASH_ProgramByte(addrf, *((u8 *)addr));
addr++;
addrf++;
}

FLASH_Lock(FLASH_MEMTYPE_DATA);
}

void readflash(u32 addrf,u32 addr,u8 nbyte)
{
FLASH_Unlock(FLASH_MEMTYPE_DATA);

while (nbyte--)
{
*((u8 *)addr) = FLASH_ReadByte(addrf);
addr++;
addrf++;
}

FLASH_Lock(FLASH_MEMTYPE_DATA);
}
[/code]

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

[code]saveflash(0x4000,(u32)¶m,14);
[/code]

Записать во флеш 14 байт, начиная с адреса 0x4000h, данные из памяти по адресу структуры param.

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

[code]struct s_param {
u8 ves;
u8 dkoles;
u32 probeg;//пробег в метрах за все времяпользования прибором
u32 power;//потраченные калории за всевремя пользования прибором
u8 numpoezdki;//номер последней поездки
int ks;//контроль скорости
int kk;//контроль каденса
//итого 14байт!
} param;

struct s_poezdka {
u8 fix;//0 — пустая поездка, 1 — частичнозаписанная, 2 - фиксированная
u32 nump;//номер поездки по порядку
u32 probeg;//пробег за поездку
u32 power;//калории за поездку
u8 obs[10];//время в процентах от активноговремени на каждой скорости для экономииместа!
u8 maxspeed;//максимальная скорость в км\чза время поездки
u32 activetime;//активное время поездки вминутах, когда скорость была больше 4км\ч
//итого 28 байта! получается 4 поездки!!!
} poezdka;
[/code]

Мы храним вес, диаметр колеса, общий пробег, общие потраченные калории, номер поездки для записи во флеш, настройки контроля. А по каждой поездке — номер поездки по порядку, чтобы видеть сколько вообще раз ездили, пробег за поездку, калории, активное время в секундах, проценты времени (для экономии места в памяти 100% занимает 1 байт) с определённым диапазоном скорости от активного времени.

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

[code]	readflash(0x4000,(u32)¶m,14);

if (param.ves==255 || param.ves==0)
{
cleareeprom(1);
}
[/code]

Для хранения последних поездок мы организуем во флеше кольцевой буфер данных поездок. Данные пишутся в память следующим образом — 1 2 3 4 1 2 3 4, это самый удобный формат хранения данных во флеше, для минимизации циклов перезаписи флеша. Мы помним, что количество этих циклов ограничено.

С данными о поездках мы работаем следующим образом, если МК переходит в спящий режим, то мы записываем во флеш текущие данные о поездке, признак fix в таких данных выставляем в 1. Это гарантирует нам, что если вдруг сядет аккумулятор или произойдёт какое-то ЧП, то данные о поездке останутся в памяти и при следующем включении они зафиксируются в памяти. В случае выхода из спящего режима до окончания поездке, мы продолжаем накапливать данные, если же поездка закончилась, то сдвигаем номер поездки на следующий. Как мы будем определять поездки - разберём в следующем разделе.

Спящий режим, фиксирование одной поездки

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

STM8 имеет несколько режимов сна, они подробно описаны, в datasheet и отличаются скоростью выхода из спящего режима и энергопотреблением. Мы будем использовать два режима: halt, active halt. В первом режиме МК полностью спит, выход из режима только по внешнему прерыванию. Во втором режиме работает специальный таймер, который будет будить МК, а также внешние прерывания.

Алгоритм работы у нас такой с поездками такой:

  1. после двух минут бездействия, переводим МК в activehalt, интервал пробуждения 30 секунд

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

  3. если внешних прерываний нет, то каждые 30 секунд мы просыпаемся и считаем пока не пройдёт 3 часа

  4. если в течение 3 часов нас никто не разбудил, то поездка закончилась, и велосипед стоит в гараже.

Для экономии энергии перед переходом в спящий режим мы переключаем МК на работу от внутреннего генератора LSI 128 кГц и включаем AWU (auto wake up — пробуждающий) таймер на 30 секунд.

[code]	if (timehalt==0) {
haltstart=1;
timehalt=120;
GPIO_WriteLow(GPIOD,GPIO_PIN_2);//выкл блютус
blueen=FALSE;

//пришло время спать запишем данныепоездки во флеш на всякий случай!!
if (activetime>1200) //маленькие поездки нефиксируем!
{
int u;
poezdka.activetime = activetime;
poezdka.power = (u32)power;//оставим целую частьот калорий
for (u=0;u<10;u++)
{
poezdka.obs[u]=0;
if(obs[u])
poezdka.obs[u] = obs[u]*100/activetime;//переведемв проценты от общего активного времени!

}
poezdka.maxspeed = maxspeed;
poezdka.fix= 1;
poezdka.probeg = (long)hall[1] * param.dkoles * 314 / 10000;

saveflash(ADDRP+param.numpoezdki*NUMBYTEP,(u32)&poezdka,NUMBYTEP);
}


playmusic(4);

//на всякий случай включим прерывания!вдруг отключили!
GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_IN_PU_IT);//knopka
GPIO_Init(GPIOC,GPIO_PIN_7,GPIO_MODE_IN_PU_IT);//H1
GPIO_Init(GPIOC,GPIO_PIN_6,GPIO_MODE_IN_PU_IT);//H2

current_millis=0;
[/code]

Устанавливаем флажок haltstart, чтобы случайно перед сном не отключить прерывания, при работе с дребезгом контактов. Выключаем bluetooth. Если поездка длилась более 1200 секунд, то запишем данные во флеш, маленькие поездки не фиксируем. Проиграем музыку. На всякий случай включим прерывания. Мы готовы ко сну. Теперь переходим на LSI генератор.

[code]CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_LSI,DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
AWU_Init(AWU_TIMEBASE_30S);

timeawu=255;//255 * 30 = 7600 сек = 2часа

halt();
while (isawu)
{
int i=0;
isawu = i;
halt();
}
isawu=0;
[/code]

И активируем AWU таймер, специальная переменная isawu будет говорить нам, что мы проснулись от AWU, в этом случае будем опять засыпать. Разберём обработчик прерывания AWU.

[code]INTERRUPT_HANDLER(AWU_IRQHandler, 1)
{
AWU_GetFlagStatus();
isawu=1;
if (timeawu) timeawu--;
else {
if (poezdka.fix) { //если есть поездка!
poezdka.fix=2;
saveflash(ADDRP+param.numpoezdki*NUMBYTEP,(u32)&poezdka,NUMBYTEP);

nextp();
param.power += poezdka.power;
param.probeg += poezdka.probeg;
saveflash(0x4000,(u32)¶m,14);

poezdka.fix = 0;
poezdka.nump++;
saveflash(ADDRP+param.numpoezdki*NUMBYTEP,(u32)&poezdka,NUMBYTEP);
}
//обнулим все данные по текущей поездке
clearlocal();

AWU_DeInit();
}
}
[/code]

Сначала сбросим флаг, чтобы оповестить МК, что мы обработали прерывание, не забываем это делать. В обработчике прерывания AWU таймера проверим закончилась поездка или нет. Если нет, то спим дальше — признак isawu стоит. Если поездка закончилась, то фиксируем ее в памяти, fix = 2, и начинаем следующую пустую поездку, обнуляем все данные, отключаем AWU таймер и спим дальше.

При включении МК проверим не было ли сбоя, в тек поездке стоит признак fix=1, в этом случае зафиксируем поездку и начнём следующую.

[code]	readflash(ADDRP+param.numpoezdki*NUMBYTEP,(u32)&poezdka,NUMBYTEP);
if (poezdka.fix==1)
{
param.power+=poezdka.power;
param.probeg+=poezdka.probeg;
nextp();
saveflash(0x4000,(u32)¶m,14);
//начнем новую поездку
poezdka.fix = 0;
poezdka.nump++;
saveflash(ADDRP+param.numpoezdki*NUMBYTEP,(u32)&poezdka,NUMBYTEP);
}
[/code]

Работа с bluetooth - получение данных

По bluetooth мы можем получать различные команды, для управления нашим прибором. Для их обработки создаем специальный массив Rxbuff[], в нем будет хранится строка для обработки. Также будет необходим специальный флажок — Rxready, который мы будем выставлять, когда строка получена. Заполнение буфера реализовано в прерывании в файле stm8s_it.c, а обработка буфера в основном цикле, чтобы не загружать прерывания.

[code] INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
char c=0;
if (UART1_GetFlagStatus(UART1_FLAG_RXNE) != RESET )
c = UART1_ReceiveData8();

if (RXready==FALSE) {
if (c == '\n' || c == '\r') {
RXready=TRUE;
}
else
RXbuff[RXtek] = c;
RXtek++;
if (RXtek==5) RXready=TRUE;
}
}
[/code]

Прерывание срабатывает в тот момент, когда периферия получила один байт информации. Проверяем, что байт получен и считываем его в переменную «c». В момент считывания байта происходит автоматическое снятие флага сработавшего прерывания, так что выставлять какой-то флажок, чтобы сбросить прерывание, нам нет необходимости. Далее мы предполагаем, что любая команда состоит из 4 байт и заканчивается символом перевод строки. Если мы еще не успели обработать буфер, то новые данные не получаем. Если получили конец строки, то выставим RXready в истину. Если буфер заполнен весь, то будем считать, что строку получили, иначе запишем очередной байт в буфер. На этом работа с прерываниями закончена. Теперь в основном цикле осталось разобрать строку.

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

  • clr — обнулить все данные в памяти, полный сброс. Чтобы случай не стереть все, запросим подтверждение этой команды.

  • yes — подтверждение команды clr

  • v256 — установка веса в кг, например, для веса 65 кг, команда будет такой — «v65\n», далее аналогично

  • d256 — установка диаметра колеса в см

  • s127 — установка контроля скорости, не меньше заданной, 0 — нет контроля

  • s-127 — установка контроля скорости не больше заданной, 0 — нет контроля

  • k127 — установка контроля каденса, не меньше заданной, 0 — нет контроля

  • k-127 — установка контроля каденса, не больше заданной , 0 — нет контроля

  • info — вывод информации о предыдущих поездках из памяти.

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

[code]	if (RXready) {
if (flagclr==1 && RXbuff[0]=='y' &&RXbuff[1]=='e' && RXbuff[2]=='s')
{
//сотрем все поездки
cleareeprom(0);
}
flagclr=0;

switch (RXbuff[0]) {
case 'c':
flagclr = 1;
break;
case 'i':
//..//
case 'v':
//..//
default:
break;
}

if (cmd)
{
int ind = RXtek-2;

for(u=start;u<RXtek-1;u++)
{
//v256 start = 2 Rxtek = 5
if (RXbuff[ind] < 0x30 || RXbuff[ind] > 0x39)
{
//ошибка тут должно быть толькочисло!
noerr=0;
break;
}

rez = rez + (RXbuff[ind] - 0x30) * r;
r *= 10;
ind--;
}
if (noerr)
{
//установим параметр и выведемсообщение о всех параметрах!
if (znak>0) *pp = rez;
else *(int *)pp = (int)rez * (-1);

saveflash(0x4000,(u32)¶m,11);

printf("(ves-kg)%i (d-cm)%li (ks)%i(kk)%i\n\r",(int)param.ves,(long)param.dkoles,param.ks,param.kk);
}
}
RXtek = 0;
RXready = FALSE;
}
[/code]

Процедура начинается тогда, когда флаг RXready выставлен. Flagclr — используется для подтверждения получения предыдущей команды «clr», и если все подтверждено, введена команда «yes», то очищаем данные о поездках во флеш. После получения «clr» выведем, что мы ждем подтверждения.

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

В самом конце снимаем признак RXready и готовимся принять следующую команду.

Работа с bluetooth - вывод данных

Для передачи данных по bluetooth мы будем использовать стандартную функцию printf. Стандартная библиотека проекта на STM8 (на других МК это работает похожим образом) позволяет настроить вывод данную функции на любую периферию. Для этого созданы специальные макросы PUTCHAR_PROTOTYPE и GETCHAR_PROTOTYPE, в которых необходимо написать, как МК будет передавать или получать один байт с периферии. Для получения данных мы самостоятельно обрабатывали прерывания, а вот для вывода данных, воспользуемся этим механизмом.

[code]PUTCHAR_PROTOTYPE
{
/* Write a character to the UART1 */
UART1_SendData8(c);
/* Loop until the end of transmission */
while (UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);

return (c);
}
[/code]

Так выглядит функция передачи одного байта по UART. Записываем байт в специальный регистры данных UART и ждем окончания передачи — флаг TXE сброшен.

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

[code]		if (timeblue==0 && blueen) {
//каждые 2 сек будем выводить на экранчто-то и считать все подряд
timeblue = 2;

printf("(cad)%i (SCOR)%i (all)%li (ob)%li (m)%li\n\r",(int)scor1,(int)scor2,(long)(hall[0]+hall[1]),(long)(hall[0]),(long)(hall[1]*(long)param.dkoles*PI/100/100));

printf("t");
{
int j;
for (j=0;j<10;j++)
{
printf(":(%li)%li",(long)(j+1)*4,(long)obs[j]);
}
printf("\n\r");
}
}
[/code]

Если bluetooth включен, и время 2 секунды вышло, то запускаем заново таймер и передаем данные. Сначала передаем одной строкой основные параметры — скорость, каденс, общее расстояние и т. д. Потом в цикле передаем данные по интервалам скорости. В данной функции важно использовать приведение типов, то есть если используется форматный символ %li — long — то при передаче параметра, необходимо его привести к типу long. Вот так просто осуществляется вывод информации.

Контроль скорости и каденса

Скорость мы будем контролировать следующим образом. В течение 30 секунд мы будем проверять каждую секунду нарушение режима. Если оно было 80%, то выставляем флаг нарушения. Для этого воспользуемся функцию СИ по сдвигу битов в переменной. Каждый бит кодировать было нарушение или нет. 32 битного числа достаточно, чтобы вести историю за 30 секунд.

[code]		if (param.ks)
{
int bit=0;
if ((param.ks > 0) ? (scor2 < (u8)param.ks) : (scor2 >(u8) (-param.ks)) )
{
errspeed++;//есть нарушение скорости!
bit=1;
}
errspeed = errspeed - (u8)((errspeed32 & (1L <<31))?1:0);

errspeed32 <<= 1;
errspeed32 |= bit;
}
[/code]

Если задан контроль скорости, то для случая положительного параметра, нарушением является скорость меньшая чем параметр, для отрицательного, нарушением является большая чем параметр скорость. Если есть нарушение, то добавляем один к переменной errspeed, в итоге в ней имеем сколько было нарушений за последние 32 секунды. Далее уменьшаем на один количество нарушений, если 31 секунду назад оно было, сдвигаем влево весь результат и правый бит устанавливаем в один, если было нарушение. Так мы в итоге реализуем скользящее окно в 32 секунды. Тоже самое для каденса. Далее в основном цикле остаётся только следить за errspeed, и когда значение больше 20, то пищать нужную мелодию каждые 30 секунд.

[code]if (errspeed > 20 && time_errspeed == 0)
{
time_errspeed = 30;
playmusic(5);
}
[/code]

Работа с симулятором

На данном проекте вы можете испытать в работе симулятор. Для работы с симулятором вам необходимо в модуле main.с раскомментировать строку

[code]#define SIMUL
[/code]

В итоге будут отключены вызовы функций, не работающие в симуляторе. Для начала работы в симуляторе запускаем отладчик, предварительно установив средства отладки — симулятор. В симуляторе не работают таймеры, прерывания, но их тоже можно симулировать. Делается через специальное окно — View — I\O Simulation. В данном окне можно симулировать любое прерывание по номеру, номер можно найти в функции обработчике прерывания. Например, для таймера TIM4 — это 23. Также для симуляции прерывания можно задать периодическое событие, делается это по двойному нажатию на поле «Current Value». В окне необходимо задать нужную периодичность в тактах МК.


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

Как изготовить велокомпьютер

Делаем плату и все запаиваем

  1. Подготовить или приобрести необходимые инструменты: все для пайки, ST-LINK (будет нужен для программирования и отладки МК)

  2. Внимательно прочитать статьи из раздела Обязательная теория.

  3. Скачать необходимые файлы по данному прибору с github.

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

  5. Приобрести все необходимые комплектующие.

  6. Запаять все компоненты на плату, смотри наше видео.

  7. Плата готова!

Для программирования лучше припаять (на специальную площадку PRG) провод с разъемом пин терминал, запаянный в термоусадочную трубку — получится удобный разъем для программирования. Программировать удобнее сразу подключив прибор через USB разъем и ST LINK в другой USB разъем, тогда достаточно только подключить SWIM в разъему программирования.

Установка в корпус

Для установки в корпус вам понадобятся 2 небольших шурупа, чтобы прикрутить плату (в комплекте они не идут). Также для исключения вибраций будет необходим кусочек поролона или другой уплотнитель. Необходимо сделать бутерброд — нижняя часть корпуса - плата — поролон — аккумулятор — верхняя часть корпуса. Под провод для датчика необходимо просверлить отверстие в корпусе. Под usb разъем вырезать паз ножом и доработать надфилем. Под кнопку необходимо просверлить отверстие. Кнопка занимает чуть больше места, чем высота стоек в корпусе, поэтому лучше подложить шайбочки под плату до получения нужной высоты. Шайбы можно сделать из оставшегося текстолита или ненужных пластиковых карточек. Если у вас есть желание, кнопку можно разместить сверху платы, но так она будет мешать аккумулятору. Под провод для подключения аккумулятора можно сделать пропил в плате.

Делаем датчик

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

Для того, чтобы сделать датчик на проводе, лучше всего воспользоваться термоклеевым пистолетом. Берём ненужную прозрачную пластиковую ручку, отрезаем носик, припаиваем к проводу датчик, откусываем лишние ножки. (ВНИМАНИЕ! Когда будете паять герконы не гните его ножки, лучше припаять провод параллельно ножкам и их просто откусить. Гнуть их строго придерживая пинцетом, иначе можно разбить стеклянную колбу и сломать геркон.!). Далее вставляем геркон и часть провода в ручку и заливаем под давлением термоклей, так чтобы он заполнил все внутренности. Это сделать наш датчик влагостойким и защитит от повреждений. В принципе вы можете сделать оба датчика на проводах, такая конструкция проще.




Для работы датчика необходим сильный магнит. Можно купить магнит для велокомпьютера (100-200руб), а можно взять магнит из детского магнитного конструктора Geomag. Там очень сильные магниты и их можно прикрепить к спице велосипеда обычной стяжкой. Также бывают очень сильные магниты шайбы. Магнит надо подобрать так, чтобы датчик срабатывал на расстоянии 3-5 см, и проверить при вращении колеса и педалей.

Переходим к программированию

Данный прибор достаточно простой в программировании. В этой статье подробно разобрана вся программа. Мы настоятельно рекомендуем написать программу САМОСТОЯТЕЛЬНО. Пройти полный путь от скачивания библиотеки с сайта ST, до финальной программы. Только так вы сможете изучить программирование микронтроллеров. Если вы не можете справиться самостоятельно, или хотите просто сделать прибор и просто пользоваться им, на github есть все исходные текст. Обязательно поработайте с симулятором и отладчиком. Выполните задания для развития. И самое главное не сдавайтесь. В начале будет тяжело, но интересно!

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

Вариант с индикатором

Данный велокомпьютер можно дополнить индикатором. Плату и описание как его подключить можно скачать в этой статье.

На индикаторе можно отображать скорость - шкала из 8-ми красных светодиодов, каденс - вторая шкала из 8-ми зеленых светодиодов, 4 информационных светодиода - отображение статуса bluetooth (синий светодиод), отображение нарушение контроля скорости и каденса (красные светодиоды).

На плате специально выделены площадки для подключения провода управления - J7 или J8.

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

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

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

Приобретённые навыки

Пайка: пайка модулей, пайка корпуса TTSOP, пайка корпуса SOT-23-5, пайка micro USB разъема.

Схемотехника: LDO, схема зарядки Liion аккумулятора, подключение модуля bluetooth, типовая схема подключения STM8, подключение пищалки, работа с кнопками.

Программирование: обработка кнопок по прерываниям, миллисекундный таймер, спящий режим, AWU таймер, работа с EEPROM, UART

Самостоятельная работа

Вы дополнительно можете доработать функции велокомпьютера. Идеи для доработки:

  • Дописать функцию контроля скорости, аналогично контролю каденса.

  • Реализовать различные режимы передачи информации — при движении — передавать только скорость, при остановке передавать итоговые параметры.

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

  • Расширьте диапазон хранимых скоростей до 120км\ч.

  • Оповещать звуком каждый км.

  • Сделайте хранение скорости не по интервалам, а в абсолютном значении, 4 скорости, с которыми вы ехали наибольшее время.

]]>
(Super User) Приборы Sat, 01 Jul 2017 21:04:00 +0000
Кухонный таймер /index.php/pribory/item/33-kukhonnyj-timer /index.php/pribory/item/33-kukhonnyj-timer Кухонный таймер

Прямой и обратный отсчёт времени до 10 часов. Три предустановленных интервала таймера, с возможностью настройки. Громкий сигнал различной тональности. Встроенный литиевый аккумулятор и схема зарядки по micro usb. Игры — игральная кость, лото, бомба. Учёт рабочего времени с подтверждением. Компактный размер 40x40x16мм. Красивый пластиковый корпус.

{autotoc}

Прежде чем начать

Прежде чем читать эту статью, рекомендуем вам ознакомится со следующей теорией:

Кухонный таймер. Что это? сколько стоит?

На рынке существует очень много различных видов кухонных таймеров. Мы будем рассматривать только электронные варианты (еще есть механические). Основное применение данный прибор нашёл на кухне. Отсюда идёт и его название — кухонный таймер. Допустим, вы готовите какое-то блюдо, варите картошку. Через 20 минут после закипания, надо ее выключить — она готова. Можно, конечно запомнить по часам этот промежуток времени, но делать это с помощью таймера гораздо удобнее. Установили нужный интервал времени — нажали кнопку, начался обратный отсчёт времени. Через 20 минут кухонный таймер громко просигналит, обычно в течение 1 минуты. Вот такой простой прибор.

Купить электронный кухонный таймер на рынке можно по цене от 200 до 2000 рублей. Как правило, они отличаются дизайном, размерами и функциями. Все они умеют выполнять основную функцию — таймер обратного отсчёта. Интервал времени почти у всех моделей ограничен 99 минутами (4 разряда цифр — 2 на минуты и 2 на секунды). Дополнительные функции, которые можно встретить:

  • магнитное крепление, крепление на ремень

  • секундомер

  • быстрая установка времени (покрути корпус)

Все рыночные приборы, питаются от батареек, имеют, как правило, ЖК дисплей. Батареек хватает больше чем на 2-3 месяца регулярного использования.

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

{product id=32}

Постановка задачи, требования к прибору

Основные требования к нашему кухонному таймеру.

  • Компактный размер

  • Питание от аккумулятора, длительная работа от одного заряда

  • Зарядка от micro usb

  • Индикатор как минимум на 3 разряда, лучше 4-е

  • Низкая стоимость

  • Громкий сигнал

  • Широкий набор функций — Таймер, Секундомер, Игры: игральная кость, лото, бомба, возможность программирования.

Подбор компонентов

Компоненты будем подбирать самые простые, недорогие, и доступные на рынке.

Индикатор

Это самый сложный вопрос. На рынке есть следующие виды индикаторов:

  • LCD, TFT дисплей — дорого, большой размер




  • ЖК сегментный индикатор — на 3-4 цифры — вполне подойдёт, но тяжело купить (больше распространён китае), большой плюс — низкое энергопотребление.


  • Светодиодный сегментный индикатор — отличный, недорогой вариант, минусом является высокое энергопотребление, но с аккумулятором это не так страшно. За счет яркости, можно снизить энергопотребление до 2ма. Его несложно купить. Наш таймер будем делать на данном виде индикатора.


Данные индикаторы могут иметь прямое управление каждым светодиодом, но в этом случае у них будет много выводов. Мы выберем 3-х сегментный светодиодный индикатор красного цвета с общим анодом. У каждой цифры аноды светодиодов соединены вместе и выведены на один вывод. На таком индикаторе можно в одном время показать только одну цифру! Как же задействовать все три? Очень просто. Будем использовать динамическую индикацию, то есть очень быстро показывать первую цифру, потом вторую, потом третью. Глаз не успеет заметить этого подвоха, и будет складываться впечатление, что горят одновременно все три цифры! Такая схема очень часто используется в индикаторах, в том числе и в ЖК. Поэтому вам просто необходимо освоить модель программирования таких индикаторов.

Интерфейс общения

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

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

  • Таймер

  • Секундомер, с возможностью учета рабочего времени

  • Игры

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

В режиме таймера:

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

  • Вторая кнопка начинает Отсчет, при окончании раздаётся сигнал

  • Долгое нажатие второй кнопки позволяет поменять значение и запрограммировать новое предустановленное значение

В режиме Секундомера

  • Вторая кнопка старт/пауза

  • Первая кнопка выбор режима — простой секундомер или с подтверждением. В режиме с подтверждением, каждые 5 минут необходимо нажимать кнопку, если не нажали, то секундомер пищит и встаёт на паузу. Так можно измерять рабочее время, когда вы часто отвлекаетесь от рабочего процесса.

В режиме игр

  • Первая кнопка выбор игры

  • Вторая кнопка ход в игре

Конечно, вы можете сами написать свою программу, и сделать совершенно другие комбинации и режимы — это же ваш кухонный таймер — вы его создатель!

Микроконтроллер

Выберем микроконтроллер. Какие требования к микроконтроллеру в нашем проекте?

  • считывать показания 2 кнопок

  • наличие спящего режима для энергосбережения

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

  • удобный корпус для пайки

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

  • EEPROM память для хранения настроек

  • достаточное количество выводов для управления индикатором — нужно 11 выводов.

Выберем уже знакомую серию STM8, исключительно по цене. Дополнительно она имеет отличный отладчик ST-Link по 2-ум проводам, симулятор и всю необходимую периферию. Программа будет небольшая, выберем самый дешёвую модель - наш выбор STM8S003F3P6. Можно выбрать серию STM8L — с низким энергопотреблением, но на выбранном микроконтроллере прибор будет работать больше месяца. Этого вполне достаточно.

Аккумулятор

В этот раз будем использовать литиевый аккумулятор меньшего размера — LIR2032, ёмкостью 45 mAh, для того чтобы прибор поместился в небольшой корпус. Схема заряда аналогично велокомпьютеру. Дополнительно будем использовать схему защиты аккумулятора от глубокого разряда из данной статьи.

Составляем схему

Схема зарядки аккумулятора и обвязки МК будет очень похожа на велокомпьютер, так что, не будем повторяться. Для защиты аккумулятора от разряда добавим схему аналогично данной статьи. Для отображения информации добавим ещё светодиодный индикатор — это по сути просто набор светодиодов. При управлении индикатором будем использовать посегментное сканирование — одновременно может светиться только один сегмент из цифры. В этом случае управление сегментом напрямую можно подключить к выводу МК. Резисторы нужны только на общих выводах анода. Резисторы можно использовать 200 Ом, при этом ток свечения одного светодиода будет около 6мА, яркости будет достаточно. Дополнительно ее можно будет снизить за счет динамической индикации для уменьшения потребления. Итак, вот финальная схема.


Вторая часть схемы — зарядка и защита аккумулятора от разряда. Отметим, что резистор R7 здесь не нужен!! При его установке будет только увеличено потребление тока во сне до 50 мкА. Запаивать его не надо!!




Корпус

Подберём небольшой корпус для нашего прибора. Компания SANHE выпускает много универсальных корпусов. Нам подойдет корпус 20-31 размером 30х40мм. Данный корпус очень приятный на ощупь и совсем небольшой.


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




Стойки крепления платы необходимо будет убрать — это можно сделать пассатижами. Чтобы отделить аккумулятор от платы необходимо вырезать прокладку из толстого полиэтилена или плотной изоленты.

Программа

Программа, как обычно, для STM8, написана в среде ST Visual develop IDE. Заготовку проекта вы можете скачать с github данного прибора, папка timer. Мы специально не выкладываем полную программу! В этом приборе вы должны сделать ее сами! Только так вы научитесь программировать МК. В заготовке проекта мы сделали самую сложную часть — инициализация, динамическая индикация, спящий режим, обработка кнопок. Вот это мы и разберём в этой статье. В кухонном таймере будем использовать все виды нажатий кнопки — одиночное, двойное, долгое. Такие режимы обработки кнопок очень часто используются в различных устройствах. Читайте внимательно!

Если вы делаете подарок, то вы можете запрограммировать при включении какую-то небольшую мелодию. Это не сложно. В интернет есть много примеров. Заодно поработаете со звуком.

Структура файлов проекта

Проект создан на основе библиотеки SPL для STM8 от ST. Подробное описание, как развернуть проект, вы найдёте в этой статье. Вся программа содержится в файле main.c, обработка прерываний перенесена в этот файл.

Общее описание программы

Упрощённый алгоритм работы программы.

  1. При включении производится настройка всей периферии, тактирование от внутреннего генератора на частоте 2 МГц. Читаем данные из EEPROM. Сразу переходим в спящий режим.

  2. Прибор может находится в одном из трёх режимов — Игры, Таймер, Секундомер, перебор по долгому нажатию первой кнопки. Выбор подрежимов, по обычному нажатию первой кнопки. Запуск и остановка второй кнопкой.

  3. Индикация

    1. Если прибор в режиме игры — то левый сегмент индикация игры — L — лото, Б — бомба, Н — игральная кость. Остальные два разряда для игры.

    2. В режиме таймера. Таймер запущен — мигает точка в такт секундам. Таймер остановлен точка не горит. Таймер может отображать от 999 минут до 0. На экране всегда отображаем значащие разряды, точка разделитель секунд и минут. Например, 900 минут = 900. , 10 минут 15 секунд = 10.1, 1 минута 25 секунд = 1.25.

    3. В режиме секундомера. Запущен — мигает точка в такт секундам. Отображение как в таймере. При остановке секундомера, например на 10 мин 35 сек, показывает целую часть 10. 1сек потом дробную часть .35 1сек и так попеременно.

  4. Таймер

    1. Когда таймер не запущен. Первая кнопка выбираем предустановленные значения.

    2. Вторая кнопка старт таймера из предустановленного значения. Таймер в минутах.

    3. Долгое нажатие второй кнопки переходит в режим настройки значения. В этом режиме вторая кнопка и первая кнопка работают как плюс минус 1 минута. Долгое нажатие Второй кнопки записывает значение в настройку. Быстрое нажатие на кнопки прибавляет по 5 минут.

    4. При достижении конца таймера играем мелодию каждые 60с в течение 5 мин. Пока не остановим кнопкой.

    5. Когда таймер запущен — вторая кнопка долгое нажатие — сброс, первая кнопка - пауза

  5. Секундомер

    1. Когда запущен — мигает точка

    2. Вторая кнопка старт/пауза секундомера

    3. Первая кнопка выбор режима — с подтверждением или без. Когда выбран режим с подтверждением, то горит дополнительно первая точка

    4. Вторая кнопка долгое нажатие сброс

  6. Лото

    1. Игра не началась. Отображаем две тире

    2. Вторая кнопка следующее значение и выдаем звуковой сигнал

    3. Вторая кнопка долгое нажатие начать сначала

    4. в конце игры выдаем мелодию переливы и начинаем сначала

  7. Бомба

    1. Игра не началась — две тире

    2. Вторая кнопка — начать игру. Засекаем случайное время

    3. Игра идет — каждую секунду мигают нули и идет звук как часы пикают. Звук ускоряется каждые 10% оставшегося времени

    4. Когда время вышло — то звучит звук низкого тона — взрыв. У кого в руками остался прибор — тот проиграл. Игра начинается сначала.

  8. Спящий режим

    1. Если ничего не запущено, то через 30с неактивности — глубокий сон

    2. Если запущен таймер или секундомер — то через 30с гасим экран — остаётся только точка мигать каждую сек на 200мс. По кнопке показываем время. Когда осталось 30 сек. Кнопки работают как обычно. Но сначала будят как бы. То есть пробуждение не срабатывает как нажатие кнопки. Будить можно любой кнопкой.

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

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

Инициализация, прерывания

Первоначальная инициализация довольно простая.

[code]CLK->PCKENR1 = CLK_PCKENR1_TIM4+CLK_PCKENR1_TIM2;
CLK->PCKENR2 = 0b01110111;

CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8);
[/code]

Выключаем лишнюю периферию, оставляем только таймер 4 и 2. Тактирование от внутреннего генератора 16 МГц, с делителем 8, для пониженного энергопотребления. В итоге, работаем на частоте 2 МГц. При тактировании от внутреннего генератора, периферия работает на частоте центрального процессора — то есть таймеры будут работать тоже на частоте 2Мгц, имейте это ввиду при настройке счетчиков таймеров.

[code]TIM4_TimeBaseInit(TIM4_PRESCALER_8, 249);
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
TIM4->IER |= (uint8_t)TIM4_IT_UPDATE;

TIM2_TimeBaseInit(TIM2_PRESCALER_32, 50);
TIM2_ClearFlag(TIM2_FLAG_UPDATE);
TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);
TIM2->IER |= (uint8_t)TIM2_IT_UPDATE;
[/code]

TIM4 будем использовать для миллисекундного отсчета, а TIM2 для динамической индикации. Для TIM2 частота нужна повыше, чтобы не было заметно мерцания, также она не должна быть пропорциональна 50 Гц (частота мерцания лампочек в сети 220В). С другой стороны слишком высокая частота будет больше тратить энергии.

[code]EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOA,EXTI_SENSITIVITY_FALL_ONLY);	
EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB,EXTI_SENSITIVITY_RISE_ONLY);
[/code]

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

[code] GPIO_Init(GPIOA,GPIO_PIN_2,GPIO_MODE_IN_PU_IT);//кнопки
GPIO_Init(GPIOB,GPIO_PIN_5,GPIO_MODE_IN_FL_IT);//кнопки

GPIO_Init(GPIOD,GPIO_PIN_4,GPIO_MODE_OUT_PP_LOW_SLOW);//пищалка

GPIO_Init(GPIOD,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_OUT_PP_HIGH_SLOW);//индикатор
GPIO_Init(GPIOA,GPIO_PIN_1,GPIO_MODE_OUT_PP_HIGH_SLOW);//
GPIO_Init(GPIOB,GPIO_PIN_4,GPIO_MODE_OUT_PP_HIGH_SLOW);//
GPIO_Init(GPIOC,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_OUT_PP_HIGH_SLOW);

halt();
[/code]

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

Динамическая индикация

Настройка динамической индикации не очень сложная. Для удобства, необходимо сделать несколько дефайнов:

[code]#define ON1 GPIO_WriteHigh(GPIOC,GPIO_PIN_3)
#define ON2 GPIO_WriteHigh(GPIOD,GPIO_PIN_5)
#define ON3 GPIO_WriteHigh(GPIOD,GPIO_PIN_6)

#define OFF1 GPIO_WriteLow(GPIOC,GPIO_PIN_3)
#define OFF2 GPIO_WriteLow(GPIOD,GPIO_PIN_5)
#define OFF3 GPIO_WriteLow(GPIOD,GPIO_PIN_6)

#define AON GPIO_WriteLow(GPIOB,GPIO_PIN_4)
#define BON GPIO_WriteLow(GPIOA,GPIO_PIN_1)
#define CON GPIO_WriteLow(GPIOC,GPIO_PIN_6)
#define DON GPIO_WriteLow(GPIOD,GPIO_PIN_3)
#define EON GPIO_WriteLow(GPIOD,GPIO_PIN_2)
#define FON GPIO_WriteLow(GPIOC,GPIO_PIN_4)
#define GON GPIO_WriteLow(GPIOC,GPIO_PIN_5)
#define TON GPIO_WriteLow(GPIOC,GPIO_PIN_7)

#define ALLOFFGPIO_WriteHigh(GPIOC,GPIO_PIN_6|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7);GPIO_WriteHigh(GPIOD,GPIO_PIN_2|GPIO_PIN_3);GPIO_WriteHigh(GPIOA,GPIO_PIN_1|GPIO_PIN_3);GPIO_WriteHigh(GPIOB,GPIO_PIN_4);
[/code]

ONx.. OFFx — позволяют включить и выключить 1 цифру. AON..TON — один сегмент в цифре. ALLOFF — выключить все сегменты. Далее, нам нужна вспомогательная функция — cifraS(), которая будет отображать в одной цифре нужный сегмент для выбранного символа (например буквы L, прочерка и т. д.). В функцию передаем нужный сегмент. Информация о том, что необходимо выводить содержится в массиве ind[] и tchk[] для символов и точек.

[code]void cifraS(u8 seg){
u8 j=0;

if(seg==0) AON;
if(seg==1) BON;
if(seg==2) CON;
if(seg==3) DON;
if(seg==4) EON;
if(seg==5) FON;
if(seg==6) GON;
if(seg==7) TON;

for (j=0;j<3;j++) {
u8 num;
u8 flag=0;

if (seg==7) {
if (tchk[j] * tchkmig) flag = 1;
} else {

num = ind[j];


if (num==0) {
//AON;BON;CON;DON;EON;FON;
if(seg==0) flag=1;
if(seg==1) flag=1;
if(seg==2) flag=1;
if(seg==3) flag=1;
if(seg==4) flag=1;
if(seg==5) flag=1;
}
if (num==1) {
//BON;CON;
if(seg==1) flag=1;
if(seg==2) flag=1;

}
if (num==2) {
//AON;BON;GON;EON;DON;
if(seg==0) flag=1;
if(seg==1) flag=1;
if(seg==3) flag=1;
if(seg==4) flag=1;
if(seg==6) flag=1;
}
if (num==3) {
//AON;BON;CON;DON;GON;
if(seg==0) flag=1;
if(seg==1) flag=1;
if(seg==2) flag=1;
if(seg==3) flag=1;
if(seg==6) flag=1;
}
if (num==4) {
//FON;GON;BON;CON;
if(seg==1) flag=1;
if(seg==2) flag=1;
if(seg==5) flag=1;
if(seg==6) flag=1;

}
if (num==5) {
//AON;FON;GON;CON;DON;
if(seg==0) flag=1;
if(seg==2) flag=1;
if(seg==3) flag=1;
if(seg==5) flag=1;
if(seg==6) flag=1;
}
if (num==6) {
//AON;EON;FON;GON;CON;DON;
if(seg==0) flag=1;
if(seg==2) flag=1;
if(seg==3) flag=1;
if(seg==4) flag=1;
if(seg==5) flag=1;
if(seg==6) flag=1;
}
if (num==7) {
//AON;BON;CON;
if(seg==0) flag=1;
if(seg==1) flag=1;
if(seg==2) flag=1;
}
if (num==8) {
//AON;BON;CON;GON;DON;EON;FON;
if(seg==0) flag=1;
if(seg==1) flag=1;
if(seg==2) flag=1;
if(seg==3) flag=1;
if(seg==4) flag=1;
if(seg==5) flag=1;
if(seg==6) flag=1;
}
if (num==9) {
//AON;BON;CON;GON;DON;FON;
if(seg==0) flag=1;
if(seg==1) flag=1;
if(seg==2) flag=1;
if(seg==3) flag=1;
if(seg==5) flag=1;
if(seg==6) flag=1;
}

if (num==14) {
//-
if(seg==6) flag=1;
}

if (num==11) {
//L
if(seg==3) flag=1;
if(seg==4) flag=1;
if(seg==5) flag=1;
}

if (num==12) {
//K
if(seg==0) flag=1;
if(seg==3) flag=1;
if(seg==4) flag=1;
if(seg==5) flag=1;
}

if (num==15) {
//K
if(seg==0) flag=1;
if(seg==3) flag=1;
if(seg==4) flag=1;
if(seg==5) flag=1;
}
}

if (flag==1 && j==0 ) ON1;
if (flag==1 && j==1 ) ON2;
if (flag==1 && j==2 ) ON3;


}
}
[/code]

С дефайнами она выглядит симпатично. Активируем нужный сегмент и проверем в каких из трех цифр он активен. Там где активен — включаем общий анод. Если вам нужны другие символы на индикаторе, то надо добавить еще условия, например, (num==11) — вывести на индикатор L.

Для того, чтобы вывести что-то на индикатор, достаточно положить в массивы ind[] и tchk[] нужные нам значения, остальное будет сделано в прерываниях. Вот так можно вывести число от 0 до 999.

[code]void shownumber(u16 num){
ind[0]=num/100;
ind[1]=num/10-ind[0]*10;
ind[2]=num - ind[0]*100 - ind[1]*10;
}
[/code]

Теперь, собственно сам вывод на индикатор. Вся работа ведётся в обработчике прерывания TIM2. Введём переменную numind, которая будет обозначать, какой сегмент показывать в данный вызов прерывания.

[code] INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)
{
TIM2_ClearITPendingBit(TIM2_IT_UPDATE);

OFF1;
OFF2;
OFF3;
ALLOFF

if (numind<8) {
cifraS(numind);
}

numind++;

if (numind==16) numind=0;
}
[/code]

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

Первый Сегмент, Второй Сегмент, Третий Сегмент, Ничего не горит …. Ничего не горит, Первый сегмент и т.д….

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

Обработка кнопок

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

Для настройки процедуры обработки кнопок есть несколько дефайнов:

[code]#define KNNUM  2  //колво кнопок
#define KNONE 4 //обычное нажатие
#define KNLONG 5 //долгое
#define KNTWO 6 //двойное

#define KNDTIME 50 //время в мс дребезга контактов
#define KNTIMETWO 300 //время в мс двойногонажатия
#define KNTIMELONG 1000 //время в мс долгогонажатия
[/code]

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

Сама процедура обработки кнопок вызывается из миллисекундного таймера каждые 50 мс (время нужное для устранения дребезга), так сразу решается проблема с дребезгом контактов.

[code]		u8 i,pd;

if(kndtime) kndtime--;
if (kndtime==0) {
//опрос кнопок редко для избежаниядребезга
kndtime = KNDTIME;

pa = GPIOA->IDR;//GPIO_ReadInputData(GPIOA);
pb = ~(GPIOB->IDR);//_ReadInputData(GPIOB);
knint(0, pa, GPIO_PIN_2);
knint(1, pb, GPIO_PIN_5);
}
for (i=0;i<KNNUM;i++) if(kntime[i]) kntime[i]--;
[/code]

Предварительно считываем состояние порта, на котором висят кнопки. Далее, передаем это значение, номер кнопки, номер вывода кнопки в функцию, в которой будет вся обработка — knint(). Так как кнопка на порту B нажата когда там будет значение 0, то используем операцию инверсии битов.

В конце уменьшаем на единицу переменные таймеры кнопок.

Рассмотрим саму функцию обработки кнопок.

[code]	if (knstatus[knum] && ((zn&pin) == 0)) {//кнопкунажали
knstatus[knum] = zn&pin;
if (kn[knum]>=KNONE) return; //еще не обработалипредыдущее нажатие в основном циклепропустим это нажатие

kn[knum]++;//колво нажатий плюс один
if (kn[knum]==1) kntime[knum] = KNTIMELONG;//первый разначнм замер времени

if (kn[knum]==2) {
if (kntime[knum] > (KNTIMELONG-KNTIMETWO) ) kn[knum] =KNTWO;
else kn[knum] = KNONE;
}
}

if ((kn[knum]==1) && (kntime[knum]==0)) kn[knum]=KNLONG;
if ((kn[knum]==1) &&(kntime[knum]<(KNTIMELONG-KNTIMETWO)) && zn&pin)kn[knum]=KNONE;

knstatus[knum] = zn&pin;
[/code]

Чтобы определить, что мы нажали кнопку, сравним предыдущее состояние кнопки и состояние вывода. Если кнопка нажата, но мы еще не обработали в основном цикле значение кнопки, то делать ничего не будем. Каждое нажатие увеличиваем на один счётчик нажатий, он будет у нас хранится в элементе массива результата кнопки kn[]. Таким образом, пока мы не знаем точно, какой вид нажатия, то будем там хранить количество нажатий. Если это первое нажатие, то засекаем время определения долгого нажатия. Если это второе нажатие, то проверим уложились ли мы во время двойного нажатия — если да, то фиксируем двойное нажатие, если нет — то обычное.

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

Все! Так несложно можно определить все нужные нам виды нажатия. В основном цикле вы можете обработать их

[code]		if (kn[0] == KNONE) {
secundomer = 0;
sleeptime=30;
kn[0]=0;
}
if (kn[0] == KNTWO) {
secundomer = 100;
sleeptime=30;
kn[0]=0;
}
if (kn[0] == KNLONG) {
secundomer = 200;
sleeptime=30;
kn[0]=0;
}
[/code]

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

Начало положено, остальной код программы мы не приводим, так как это ваше творчество!

Как изготовить кухонный таймер самостоятельно

Делаем плату и все запаиваем

  1. Подготовить или приобрести необходимые инструменты: все для пайки, ST-LINK (будет нужен для программирования и отладки МК)

  2. Внимательно прочитать статьи из раздела Обязательная теория.

  3. Скачать необходимые файлы по данному прибору с github.

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

  5. Приобрести все необходимые комплектующие.

  6. Запаять все компоненты на плату, смотри наше видео.

  7. Плата готова!

Для программирования вам понадобятся временно припаять провод выводу J3 (PRG). Питание можно подключить сразу с ST-Link в разъем аккумулятора.

Переходим к программированию

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

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

Приобретённые навыки

Пайка: пайка корпуса TTSOP, пайка корпуса SOT-23-5, пайка micro USB разъёма

Корпус: самодельный корпус из короба

Схемотехника: LDO, схема зарядки Liion аккумулятора, типовая схема подключения STM8, подключение пищалки, работа с кнопками.

Программирование: сложная обработка кнопок, миллисекундный таймер, динамическая индикация, спящий режим, работа с EEPROM

Самостоятельная работа

Прибор очень простой, но интересный и полезный. На github мы выкладываем только шаблон проекта. В данном шаблоне настроено энергопотребление, прерывания, таймеры, обработка кнопок, динамическая индикация с выводом трёх символов и точек. Остальное мы рекомендуем сделать самостоятельно. У вас получится отличный кухонный таймер, для себя или в подарок.

]]>
(Super User) Приборы Tue, 01 Aug 2017 09:02:00 +0000
Цифровая паяльная станция /index.php/pribory/item/19-payalnaya-stantsiya /index.php/pribory/item/19-payalnaya-stantsiya Цифровая паяльная станция

Специальный прибор для автоматической регулировки температуры жала обычного паяльника на 220в или для управления паяльным термофеном. Полностью цифровой вариант. Для измерения термопары используется самый современный метод - внешний 18-ти битный сигма-дельта ADC. Для управления вентилятором фена - ШИМ модуляция и MOSFET. PID регулятор температуры с возможностью различных настроек для фена и паяльника.

{autotoc}

Прежде чем начать

Прежде чем читать эту статью, рекомендуем вам ознакомится со следующей теорией:

Что такое паяльная станция

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

Максимальная температура паяльника без терморегулирования составляет около 400 градусов. Для пайки SMD компонент это слишком много. Есть риск перегреть компоненты. Рекомендуемая температура составляет 250-300 градусов. Снизить температуру паяльника можно с помощью регулятора мощности — обычного диммера на 220В. Но при этом, вы снизите максимальную температуру паяльника, а в момент пайки, паяльник начнёт остывать и температура может упасть ниже 200 градусов. Олово перестанет плавиться, и пайка станет некачественной.

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

По-большому счёту, прибор может управлять не только паяльником, а также термофеном, со встроенным вентилятором. Купить такой можно на aliexpress.

Hot Air Desolder Gun


Он уже содержит внутри термопару К типа, а также вентилятор. Перейдём к требованиям к прибору.

{product id=40}

Постановка задачи и требования к паяльной станции

Основные требования к прибору.

  • Компактный размер

  • Встроенный блок питания на 220В

  • Возможность определения типа нагревателя (2 прибора, паяльник и фен)

  • Цифровая регулировка мощности нагревателя на основе PID регулятора

  • Возможность управления паяльником постоянного напряжения до 24В

  • Возможность управления вентилятором термофена (4 скорости)

  • Управление нагрузкой целыми полуволнами, с учётом перехода через ноль (меньше помех)

  • Программная защита от перегрева нагревателя

  • Индикатор температуры и скорости вентилятора

  • Управление тактовыми кнопками

  • Защита от ложных срабатываний управляющего симистора

  • Максимальный ток нагрузки 3 А, что составляет 600 вт

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

Компоненты для управления нагрузкой 220В

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

Подберём симистор для управления нагрузкой. Максимальная средняя мощность нагрузки составляет для паяльника около 100Вт, а для паяльного фена на 500 градусах около 400Вт (максимальная мощность около 700Вт, при этом фен достигает 800 градусов). Выберем обычный симистор (не логический), так как он более защищён от самопроизвольного открытия. BT139-800 — выбранный ключ. Из datasheet видно, что он может без радиатора управлять нагрузкой до 400Вт.

Так как мы выбрали не логический симистор, то для управления будем использовать оптосимистор со схемой перехода через ноль - MOC3041. Схему будем использовать из datasheet. Также установим снаббер согласно datasheet. Итоговая схема управления.

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

Блок питания микроконтроллера

Паяльная станция будет управлять приборами 220В и логично было бы сделать сразу встроенный блок питания. Вся электроника управления, микроконтроллер, индикатор, оптосимистор суммарно будут потреблять меньше 100 мА. Такой маломощный, компактный блок питания несложно найти.

Отлично подходят готовые блоки питания светодиодных лент на 12В. На выходе они выдают стабилизированное напряжение 12В. Возьмем B2M003ESB мощностью 3Вт (до 250мА) от компании Ecola. Без защитного кожуха его размер составляет всего 18х25х38 мм.

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

Индикатор

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

Цепь измерения температуры с помощью термопары

Для измерения температуры с помощью термопары используем схему аналогичную прибору измеритель уф индекса и температуры. В основе очень точный внешний ADC mcp3421. В дополнение к нему датчик измерения температуры воздуха NCT75 (можно обойтись и без него, в комнате в основном всегда 22-25 градусов, но стоит он недорого, пусть будет).

Управление этими датчиками идёт по шине I2C.

Микроконтроллер

Подойдёт самый простой и дешёвый микроконтроллер — STM8S003F3. Шина I2C — есть, остальные выводы стандартные.

Регулятор питания микроконтроллера

Питание микроконтроллера и датчиков составляет до 5В. Поэтому нужен понижающий регулятор питания с 12В (а лучше с 24В до 5В). Падение напряжение здесь большое, но ток маленький, поэтому отлично подойдёт регулятор серии L78M05. Корпус лучше взять DPAK для лучшего рассеивания тепла.

Максимальное входное напряжение у него составляет до 35В. Но при это значении на нем будет теряться (35В — 5В) * 100 мА = 3Вт тепла. Что конечно очень много. Надо или снижать потребляемый ток или снижать напряжение. Снизим напряжение до 24В — для случая питания всей схемы от блока питания паяльника постоянного тока. 2Вт он выдержит при большой медной площади на плате. Но лучше ещё побороться за потребляемый ток (за счёт динамической индикации).

Силовые разъёмы

Так как мы работаем с 220В, то будем использовать мощные разъёмы серии minifit. Рабочее напряжение до 600В.

MINIFIT R8


Эти разъёмы очень удобны — их нельзя неправильно соединить, перепутать полярность, что очень важно при работе с высоким напряжением.

Корпус

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

Sanhe 20-11




Составляем схему паяльной станции

Все основные компоненты определены. Можно составлять схему прибора. Как во всех цифровых приборах, делать это совсем не сложно. По сути соединяем модули согласно datasheet на каждую микросхему.

Schema Indicator
Индикатор подключаем также как в приборе кухонный таймер. Чтобы он поярче светился, поставим резисторы 300 Ом. Таким образом, максимальный ток при одном светящемся сегменте в цифре составит около 15мА при 5В питании. На три цифры 45мА. Средний ток можно сильно снизить за счёт программного снижения яркости.

Schema mcp3421 ADC


Датчики подключаем, как обычно, к питанию и к шине I2C. Шина I2C подтянута к питанию через резисторы 10кОм. На цепях питания, как можно ближе к выводам микросхем, керамические конденсаторы.

Schema ADC switchs
Выводов у МК не хватает, поэтому кнопки «повесим» на вход ADC. Тогда все кнопки можно обслужить одним выводом. 4-х кнопок хватит. Резисторы в 10 кОм подойдут.

Schema MOC3041
Управление 220В идёт через оптосимистор, по схеме согласно datasheet. С точки зрения МК это обычный светодиод, ток необходимый для надёжного открытия составляем 15мА, подойдёт резистор 220 Ом.

Schema L78m05


Регулятор питания на 5В подключаем по типовой схеме.


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

Паяльный фен может иметь обычный мотор постоянного тока в качестве надува воздуха, а может иметь маломощный моторчик (как в выбранном варианте) на 12В, который управляется низкочастотным ШИМ ом (до 100Гц). В случае обычного мотора дополнительно нужен диод D2. Для выбранного варианта фена он не нужен.


Так как прибор работает с напряжением 220В, то необходим предохранитель. Прибор может питаться от сети 220в, от встроенного блока питания, а также от внешнего БП постоянного тока паяльника постоянного тока напряжением до 24В. Поэтому необходим диод D1, чтобы в случае питания от БП паяльника ток не уходил в цепи внутреннего блока питания.


На внешний разъем, дополнительно выведем два вывода которые позволят МК определить, что подключено — фен или паяльник. Если выводы mark1 и mark2 замкнуты, то на выводе mark при включённой внутренней подтяжке будет 0, иначе 1. На разъем также выведем питание вентилятора (или паяльника постоянного тока), термопару, и ten1 ten2 — управление 220В.


На отдельный маленький разъем выведем внешнее питание — или 220В или 24В от БП паяльника.

Schema STM8S003F3P
Ну и сам МК. С ним все просто. Цепи питания, резистор 10 кОм на цепь сброса для большей надёжности, для определения типа оборудования будем использовать вывод программирования SWIM. Кнопки выведены на ADC — вывод PC4. ШИМ сигнал и управление симистором на выводы таймеров TIM2 TIM1.

Особенности трассировки печатной платы

Трассировка платы проходит без особенностей, за исключением части 220В.

PCB HomeMade
При трассировке необходимо помнить про расстояния между проводниками. На печатной плате оно должно быть больше 1мм. Рассчитывается оно по пиковому напряжению в сети - 220 * 1,4 = 310В, по следующей таблице:

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

Программа для микроконтроллера

Структура файлов проекта

Программа написана в среде ST Visual develop IDE. Полный проект вы можете скачать с github данного прибора, папка solderstation. В статье мы разберём ключевые моменты работы программы.

Проект создан на основе библиотеки SPL для STM8 от ST. Подробное описание как развернуть проект вы найдёте в этой статье. Вся программа содержится в файле main.c. Остальные файлы остались без изменений.

Общее описание программы

Алгоритм работы программы.

  1. При включении производится настройка всей периферии. На индикаторе отображается подключённое оборудование FFF(фен) или PPP (паяльник), и система переходит в рабочий режим.

  2. Основной цикл. Обработка кнопок

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

    2. Нижний ряд кнопок - регулировка скорости фена

    3. Верхний ряд кнопок — короткое нажатие +\- 10 градусов, долгое нажатие +\- 100 градусов

    4. После изменения режима отображаем 2 сек выбранный режим (заданную температуру или скорость фена от 1 до 4)

  3. Основной цикл. Каждые 300мс. Получаем данные температуры. Вызываем функцию ПИ регулятора и он рассчитывает мощность нагревателя.

  4. Прерывание миллисекундного таймера 4. Управляем нагревателем.

  5. Прерывание таймера 2. Управление индикатором.

  6. Прерывание таймера 1. Управление ШИМ вентилятора.

Инициализация

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

[code]CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8);//2mghэнергосбережение
//индикатор
GPIO_Init(GPIOD,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_OUT_PP_HIGH_SLOW);
GPIO_Init(GPIOA,GPIO_PIN_1|GPIO_PIN_2,GPIO_MODE_OUT_PP_HIGH_SLOW);
GPIO_Init(GPIOC,GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_OUT_PP_HIGH_SLOW);

GPIO_WriteHigh(GPIOC,GPIO_PIN_1);
GPIO_WriteLow(GPIOA,GPIO_PIN_2);

GPIO_Init(GPIOC,GPIO_PIN_3,GPIO_MODE_OUT_PP_LOW_FAST);//PWM FAN
GPIO_Init(GPIOA,GPIO_PIN_3,GPIO_MODE_OUT_PP_LOW_FAST);//Spiral
[/code]

Кнопки опрашиваются с помощью ADC. Настроим его работу. Вывод как обычный вход. Конвертация в ручном режиме по команде.

[code]GPIO_Init(GPIOC,GPIO_PIN_4,GPIO_MODE_IN_FL_NO_IT);//кнопка!
ADC1_DeInit();
ADC1_Init(ADC1_CONVERSIONMODE_SINGLE, ADC1_CHANNEL_2,ADC1_PRESSEL_FCPU_D2, \
ADC1_EXTTRIG_TIM, DISABLE, ADC1_ALIGN_RIGHT,ADC1_SCHMITTTRIG_CHANNEL2,\
DISABLE);
ADC1_Cmd(ENABLE);
[/code]

Таймер 4 — миллисекундный.

[code]TIM4_TimeBaseInit(TIM4_PRESCALER_8, 249);
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
TIM4->IER |= (uint8_t)TIM4_IT_UPDATE;
[/code]

Таймер 2 тоже миллисекундный для управления индикатором.

[code]TIM2_TimeBaseInit(TIM2_PRESCALER_8, 249);
TIM2_ClearFlag(TIM2_FLAG_UPDATE);
TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);
TIM2->IER |= (uint8_t)TIM2_IT_UPDATE;
[/code]

Таймер 1 — для ШИМ сигнала управления вентилятором. Для управления вентилятором нужен ШИМ низкой частоты. 55Гц вполне подойдет.

[code]	TIM1_DeInit();
TIM1_TimeBaseInit(36000, TIM1_COUNTERMODE_UP, MAXPWM, 0);
TIM1_CCPreloadControl(DISABLE);

TIM1_BDTRConfig(TIM1_OSSISTATE_DISABLE,
TIM1_LOCKLEVEL_OFF,
0,
TIM1_BREAK_DISABLE,
TIM1_BREAKPOLARITY_LOW,TIM1_AUTOMATICOUTPUT_DISABLE);
TIM1_OC1Init(TIM1_OCMODE_PWM2, TIM1_OUTPUTSTATE_DISABLE,TIM1_OUTPUTNSTATE_DISABLE, 0, TIM1_OCPOLARITY_LOW,TIM1_OCNPOLARITY_HIGH, TIM1_OCIDLESTATE_SET,TIM1_OCNIDLESTATE_RESET);
/* TIM1 counter enable */
TIM1_CtrlPWMOutputs(DISABLE); //выводы будемпереключать в прерывании
TIM1_Cmd(ENABLE);
TIM1_ITConfig(TIM1_IT_UPDATE|TIM1_IT_CC1, ENABLE);
[/code]

Стандартная настройка для I2C.

[code]I2C_Cmd( ENABLE);
I2C_Init(I2C_MAX_STANDARD_FREQ, (uint8_t)0xA0, I2C_DUTYCYCLE_2,I2C_ACK_CURR, I2C_ADDMODE_7BIT, 7);
[/code]

Инициализируем датчики температуры.

[code]mcpinit();
nctinit();
[/code]

Внешний ADC для термопары настраиваем на максимально точный режим 18 бит 3.75 измерения в секунду и усиление в 8 раз.

[code]	buff[0] = (uint8_t) 0b00011111;
if( ! I2C_writenbyte((uint8_t)MCPaddr, buff, 2,0) )
[/code]

Если подключён фен паяльный — то выводим на индикатор FFF иначе выводим PPP

[code]	if (fan==0) {
ind[0] = 10;//P
ind[1] = 10;//P
ind[2] = 10;//P
} else {
ind[0] = 11;//F
ind[1] = 11;//F
ind[2] = 11;//F
}
[/code]

На этом инициализация заканчивается.

ПИ регулятор

Температура паяльника (или фена) регулируется ПИ регулятором. Более подробно о том, что это такое можно прочитать в этой статье. Здесь разберём конкретную реализацию для этого прибора.

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

[code]s16 PI_Regulator(s16 hReference, s16 hPresentFeedback)
{
s32 wError, wProportional_Term,wIntegral_Term, houtput_32;
s32 wIntegral_sum_temp;

// error computation
wError= (s32)(hReference - hPresentFeedback);

// Proportional term computation
wProportional_Term = hKp_Gain * wError;

// Integral term compuztation
if (hKi_Gain == 0)
{
wIntegral = 0;
}
else
{
wIntegral_Term = hKi_Gain * wError;
wIntegral_sum_temp = wIntegral + wIntegral_Term;

if (wIntegral_sum_temp > 0)
{
if (wIntegral < 0)
{
if (wIntegral_Term < 0)
{
wIntegral_sum_temp = S32_MIN;
}
}
}
else
{
if (wIntegral > 0)
{
if (wIntegral_Term > 0)
{
wIntegral_sum_temp = S32_MAX;
}
}
}

if (wIntegral_sum_temp > wUpper_Limit_Integral)
{
wIntegral = wUpper_Limit_Integral;
}
else if (wIntegral_sum_temp < wLower_Limit_Integral)
{
wIntegral = wLower_Limit_Integral;
}
else
{
wIntegral = wIntegral_sum_temp;
}
}

houtput_32 =(wProportional_Term/hKp_Divisor+wIntegral/hKi_Divisor);

if (houtput_32 > hUpper_Limit_Output)
{
houtput_32 = hUpper_Limit_Output;
}
else if (houtput_32 < hLower_Limit_Output)
{
houtput_32 = hLower_Limit_Output;
}
return((s16)(houtput_32));
}
[/code]

В результате опытной настройки регулятора для паяльного фена мощностью 700Вт получились следующие коэффициенты:

[code]#define hKp_Divisor 512
#define hKi_Divisor 2000

s16 hKp_Gain=230;
s16 hKi_Gain=20;

#define hUpper_Limit_Output (s32)70
#define hLower_Limit_Output (s32)0
[/code]

Регулятор возвращает мощность в интервале от 0 до 70. При максимальной мощности фен паяльный нагревается до 700 градусов (установлено опытным путём). Все эти коэффициенты вы обязательно должны настроить под свой управляемый прибор. Начинать нужно с нулевого iGain и небольшого pGain. Предварительно установив небольшую максимальную мощность.

Управление индикатором

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

Часто, бывает удобно после смены режима, что-то показать на индикаторе длительное время. В этом приборе как раз используется такой режим. Разберём как он работает.

[code]	if ((kn[3] == KNONE) || (kn[3] == KNLONG)) {
kn[3]=0;
speedfan++;
if (speedfan>4) speedfan=4;

//hKi_Gain +=1;

timeshownext=2;
showinfo(0);
}
[/code]

При нажатии третьей кнопки увеличиваем скорость вентилятора, устанавливаем время показа информации 2 секунды (переменная timeshownext) и вызываем функцию, которая отображает нужную информацию showinfo().

По прошествию этого времени переводим индикатор в обычный режим — отображение текущей температуры нагревателя каждую секунду.

[code]	if (timeshownext==0) {
timeshownext= 1;

showinfo(10);
}
[/code]

Идентификация вида нагревателя — паяльник или паяльный фен

Как проводится идентификация вида нагревателя? На силовом разъёме, которым подключается управляемый прибор, есть два вывода, которые можно замкнуть на стороне паяльника в кабеле (mark1 mark2) и таким образом сообщить прибору, что подключено устройство другого типа.

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

Вывод SWIM по умолчанию имеет подтяжку к HIGH (к линии питании) по datasheet через встроенный резистор номиналом около 40кОм. Поэтому для идентификации используется резистор 10кОм. Есть два варианта:

  1. подтяжка — будет 1 на этом выводе

  2. замыкание вывода на землю через резистор 10 кОм (когда mark1 и mark2 замкнуты), будет гарантированный 0 на выводе.

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

Управление мощностью нагревателя

Прибор управляет очень инерционным устройством — нагревателем. Управление осуществляется с помощью полных полуциклов. Минимальный интервал регулирования — 50мс. ПИ регулятор на выходе выдаёт дискретную мощность, и чем большее количество различных значений будет доступно, тем более плавная и точная регулировка температуры будет получена. Опытным путём установлено, что для паяльного фена необходимо минимум 20 градаций мощности. При меньшем количестве регулирование получается дёрганым. Одна градация будет соответствовать 100 мс работы нагревателя. Получается, что при максимальной мощности нагреватель должен работать 2 сек. Получается какое-то несоответствие: ПИ регулятор вызывается каждые 300мс (когда мы получаем новое измерение температуры), мощность нагревателя мы регулируем интервалами по 100 мс и аж до 2 сек. Как же это все работает? Разберём часть программы ответственную за управление мощностью нагревателя.

Управление нагревателем осуществляется в прерывании основного миллисекундного таймера.

[code]if (spiralpower==0) {
//выключаем спираль или паяльник
GPIOA->ODR &= (uint8_t)(~GPIO_PIN_3);
spiraltime=0;
spiralon=0;
[/code]

Если вдруг мощность спирали стала равна нулю, то выключим нагреватель.

[code]	} else {
u16 timeon;
u16 timeoff;

spiraltime++;
[/code]

Переменная spiraltime отражает количество миллисекунд, которое нагреватель был включён или выключен. Поэтому каждое прерывание увеличиваем её на единицу.

[code]		timeon = 2000 * spiralpower/100;
timeoff = 2000 - timeon;
[/code]

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

[code]		if (spiralon) {
//ждем выключения! и если насталовремя выключаем!
if (spiraltime > timeon) {
spiraltime = 0;
GPIOA->ODR &= (uint8_t)(~GPIO_PIN_3);
spiralon = 0;
}
[/code]

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

[code]	} else if (spiraltime > timeoff) {
spiraltime = 0;
GPIOA->ODR |= GPIO_PIN_3;
spiralon = 1;
}
[/code]

Если же, нагреватель выключен, то проверяем, что время выключения вышло, и когда это произойдёт, то включим нагреватель.

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

Как же ПИ регулятор, который вызывается раз в 300 мс, может задать такое малое значение включение нагревателя в 100мс? Очень просто, прямой связи между частотой вызова регулятора и частотой управления нагревателем нет! Но эти параметры влияют на скорость реакции регулятора. Конечно, если у нас есть задача получить быстро реагирующий регулятор, то необходимо, чтобы частота управления мощностью была равна или больше частоты самого регулятора. Здесь же в паяльнике или фене в этом нет необходимости. Реакции в рамках двух секунд вполне достаточно.

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

Опрос 4-х кнопок по одному выводу с помощью ADC

Так как в этом приборе все выводы микроконтроллера заняты, а одной кнопки явно мало, то используется приём опроса кнопок с помощью ADC (вольтметра). Кнопки подключены через резисторный делитель и в зависимости от того, какая кнопка нажата на выводе МК будет различное напряжение. Это напряжение будем считывать модулем ADC и сверять с фиксированными значениями.

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

[code]	if (kndtime==0) {
u8 knall=0;
//u16 adcval;
//опрос кнопок редко для избежаниядребезга
kndtime = KNDTIME;
//кнопки на ADC - прочитаем и выяснимкакая кнопка нажата
ADC1_StartConversion();
while( ADC1_GetFlagStatus(ADC1_FLAG_EOC) == RESET);
adcval = ADC1_GetConversionValue();
[/code]

Когда пришло время опросить кнопки, стартуем измерение ADC и ждём пока оно будет завершено. Одно измерение занимает около 5 мкс, так что не влияет на таймер.

[code]		if (adcval < 10 )  {knall |= GPIO_PIN_0;}
else if (adcval < 550 ) {knall |= GPIO_PIN_1;}
else if (adcval < 700 ) {knall |= GPIO_PIN_2;}
else if (adcval < 800 ) {knall |= GPIO_PIN_3;}

knall = ~knall;

knint(0, knall, GPIO_PIN_0);
knint(1, knall, GPIO_PIN_1);
knint(2, knall, GPIO_PIN_2);
knint(3, knall, GPIO_PIN_3);
[/code]

После измерения проверяем какая кнопка нажата и устанавливаем нужный бит в переменной knall (аналог регистра GPIO). И это значение отдаём в процедуру расчёта нажатий кнопок. В итоге опрос ADC сведён к анализу состояния обычного порта.

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

Как сделать цифровую паяльную станцию своими руками

Делаем плату и все запаиваем

  1. Подготовить или приобрести необходимые инструменты: все для пайки, ST-LINK (будет нужен для программирования и отладки МК)

  2. Внимательно прочитать статьи из раздела Обязательная теория.

  3. Скачать необходимые файлы по данному прибору с github.

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

  5. Приобрести все необходимые комплектующие.

  6. Запаять все компоненты на плату, смотри наше видео.

  7. Плата готова!

Для программирования лучше припаять (на специальную площадку PRG) провод с разъёмом пин терминал, запаянный в термоусадочную трубку — получится удобный разъем для программирования.

Отладка и настройка прибора

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

На этапе настройки и тестирования лучше не работать с питанием 220В, а все проверить при питании от ST-Link напрямую. Что можно протестировать в этом режиме:

  • работу измерителя термопары

  • работу индикатора

  • работу кнопок

  • работу управляющего оптосимистора — наличие нужного напряжения на управляющих выводах

  • работу аварийного режима — сброс управления в случае превышения температуры

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

220В — ОПАСНОЕ ДЛЯ ЖИЗНИ НАПРЯЖЕНИЕ!

ВСЕ РАБОТЫ ПРОВОДИТЬ ПОД ПРИСМОТРОМ ВЗРОСЛЫХ!

Для начала необходимо проверить вольтметром работу блока питания — он должен выдавать 12В постоянного напряжения. Только после проверки его работоспособности можно припаивать его к плате и устанавливать в корпус!

Далее можно переходить к проверке схемы управления нагревателем. На первом этапе следует подключить вместо нагревателя лампочку. Термопару можно оставить в свободном состоянии — она будет показывать около 25 градусов. При таком режиме работы любая заданная температура больше 30 градусов вызовет работу лампочки на полную мощность, а ниже 20 градусов — её выключение. Если в таком режиме все работает. То можно переходить к управлению нагревателем.

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

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

Настройка работы с паяльным феном нужно начинать с управления вентилятором — он должен всегда работать. Включать паяльный фен без работающего вентилятора нельзя! После работы вентилятора необходимо в программе поставить ограничение максимальной мощности и проверить что фен не перегревается в этом режиме. После этого можно уже более точно настраивать ПИ регулятор с помощью кнопок (дописав программу) или в отладчике.

Если у вас есть желание управлять более мощной нагрузкой — обязательно использовать радиатор на симисторе!

Установка в корпус

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


Рядом просверлить 4 отверстия под кнопки. Так как сами кнопки находятся ниже крышки корпуса, то необходимо их удлинить. Это не сложно сделать с помощью пластмассовых прутиков. Соединить их с кнопками можно с помощью изоленты или термоусадки. Дополнительно можно посадить на суперклей. Если будете это делать, то обязательно кнопку переворачивайте ножками вверх, чтобы клей не затёк в механизм кнопки!




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

Прибор готов. На нашем канале вы можете посмотреть его в работе. Удачной пайки!

Приобретённые навыки

Пайка: пайка корпуса TTSOP, пайка корпуса SOT-23-5, пайка выводных компонент, пайка силовых разъёмов minifit.

Схемотехника: светодиодный индикатор, подключение нескольких кнопок одним проводом, управление приборами 220В, измерение температуры термопары.

Программирование: считывание состояния нескольких кнопок с помощью ADC, миллисекундный таймер, ПИД регулятор

Самостоятельная работа

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

  • Дописать работу прибор с двумя нагревателями — феном и паяльником (в прилагаемых исходных файлах реализовано только управление паяльным феном)

  • Дописать работу прибора в случае управления паяльником постоянного тока 24В с помощью ШИМ модуляции.

]]>
(Super User) Приборы Mon, 11 Sep 2017 09:45:10 +0000
Умный индикатор /index.php/pribory/item/35-umnyj-indikator /index.php/pribory/item/35-umnyj-indikator Умный индикатор

Будем делать свой индикатор, произвольной формы из smd светодиодов. Компактный — минимальный размер 20х20 мм при толщине всего 2 мм. Низкое энергопотребление — 1-10 мА в работе, 5мкА в спящем режиме. Независимое управление каждым светодиодом по одному проводу. Управление яркостью — более 100 градаций яркости. До 100 светодиодов в индикаторе, с произвольным расположением на плате. Возможные конструкции — две шкалы по 8 светодиодов и 4 служебных светодиода; индикация сторон света - 8 светодиодов по кругу и 4 служебных; часы - 12 светодиодов по кругу; матрица 8х8 светодиодов.

{autotoc}

Прежде чем начать

Прежде чем читать эту статью, рекомендуем вам ознакомится со следующей теорией:

Постановка задачи, требования к самодельному индикатору

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

  • низкое энергопотребление в спящем режиме

  • управление одним МК большим количеством светодиодов

  • управление каждым светодиодом независимо

  • управление яркостью

  • минимальное количество компонент — в идеале МК и светодиоды

  • одностороннее размещение на плате — для более тонкого исполнения

  • управление индикатором по одному проводу

  • диапазон питания 3-5в

Таким образом, вы сами сможете расположить светодиоды на плате как вам необходимо. Например, в форме сердечка или ёлочки. Для управления достаточно подключить 3 провода — GND, VDD, и управляющий вывод. Управлять можно будет каждым светодиодом независимо.

{product id=33}

Подбор компонентов

Светодиоды

Будем использовать обычные smd светодиоды различных цветов формата 0603. Его легко паять, он ярко светит, легко купить.

Интерфейс общения

Нам нужно минимизировать количество проводов от данного индикатора. Для передачи информации нашему индикатору будем использовать совместимый с широко распространённым протоколом 1-wire. Таким образом, нужно всего 3 провода — питание, GND и управляющий провод. Почти для всех типов МК есть примеры для работы по данному протоколу, так что проблем с подключением данного индикатора к проекту не будет.

Начинается посылка с сигнала RESET. Первый байт — служебный, перевод в спящий режим или задает яркость светодиодов. Далее нужное количество байт, по одному биту на каждый светодиод. Например, для 24 светодиодов, одна посылка занимает 400 мкс + 60мкс * 32 = 2 мс, что вполне достаточно даже для мигания светодиодами.

Микроконтроллер

Продолжаем эксплуатировать STM8. Выбираем исключительно по цене. Индикатор должен быть не дорогим. Конечно хотелось бы больше ног, но в этом случае получается дороже цена. Ну и потом, разместить большое количество светодиодов компактно, на одной стороне — не так просто. Так что, хватит самого простого МК stm8s003. Данный МК дает широкий диапазон питания от 3 до 5В.

Если бороться за энергопотребление, то лучше взять серию stm8l, но цена МК будет в два раза дороже. Также снизится напряжение питания, нельзя будет подключить напрямую от 5В.

Составляем схему

Обвязка МК стандартная. Сам МК, пару конденсаторов и все. А вот со светодиодами будем использовать чуть модернизированную методику чарлиплексинга. Выделим несколько выводов МК как управляющие. Минимум один. Остальные выводы МК рабочие, не больше 20, иначе будет низкая яркость. Каждый управляющий вывод снабдим резистором, рассчитанными на максимальную яркость светодиода из расчёта 5 вольтового питания 220Ом. Между каждым управляющим выводом, после резистора, и рабочим выводом МК разместим по 2 светодиода, навстречу друг другу разной полярностью. Получится такая схема.


Как управлять светодиодами в такой схеме? Чтобы зажечь один светодиод, необходимо на управляющем выводе подать 0, а на рабочем 1. Чтобы зажечь другой светодиод из пары, надо на управляющем подать 1, а на рабочем 0. Чтобы оба погасить, на управляющем может быть любой сигнал, а рабочий надо перевести в такое же состояние или в режим входа. Выводы PB4 и PB5 не могут иметь 1, поэтому там может быть только по одному светодиоду. Вывод PA1 во время сна переводится в input pull-up, это надо иметь ввиду. Одновременно можно зажигать только один светодиод на один управляющий вывод, иначе они могут выйти из строя. У нас 14 выводов. Итого, например, если будет 4 управляющих и 10 рабочих — то будет 80 светодиодов, а если 6 управляющих и 8 рабочих — то 96. Так что, можно считать, что ограничение — это ваше желание паять столько светодиодов и возможность разместить их на плате. Для реальных проектов хватит 20-30 светодиодов.

Вывод PRG будем использовать для управления. Он будет находится в режиме input pull-up. А общаться будем по протоколу 1-wire. Так что, это не будет мешать программированию. При такой схеме — у нас всего 1 резистор на 20 светодиодов. Очень удобно!

Примеры готовых индикаторов

Велокомпьютер

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


А так в корпусе. Под каждый светодиод сверлим отверстие 1.5 - 2 мм. Это очень легко сделать, если к корпусу приклеить распечатку платы, она будет шаблоном для сверления. Можно расточить эти отверстия в одну общую щель. На внутреннюю часть корпуса можно приклеить прозрачный пластик (например от DVD диска). Можно залить щель прозрачной эпоксидкой.

В таком формате можно разместить его на руле и будет отлично видно текущую скорость и каденс. Потребление такого индикатора в дороге будет около 2 мА. В спящем режиме добавит еще 5 мкА.

GPS трекер

Для GPS трекера индикатор будет состоять из 8 ми светодиодов красного цвета по кругу — для обозначения направления. Четыре светодиода сверху будут отображать записанные в память точки и активную точку. Размер 2х2 см. Толщина 2мм. Отлично разместится в таком небольшом корпусе.


А так он будет выглядеть в собранном приборе.

 

Ваш индикатор

Вы можете сделать любой индикатор и использовать в своих проектах. У вас будет не только уникальный прибор, но и уникальный индикатор к нему!

Примеры индикатора:

  • шкала по кругу для роторного энкодера

  • часы и минуты — два круга светодиодов 24 светодиода

  • несколько шкал громкости на разные каналы

  • отображение уровня жидкости в процентах и различные статусные светодиоды

  • компактное отображение количества подключенных датчиков

  • матрица 8 х 8 из светодиодов — отображаем динамические картинки

  • ваш логотип из светодиодов

Программа

Программу как обычно пишем в среде ST Visual Develop, на основе стандартной библиотеки.

Общая логика работы программы

Для работы программы будем использовать два таймера — один для протокола 1-wire, с минимальной градацией 8 мкс, и второй для динамической индикации, с частотой 1000 Гц и PWM режимом. Сам МК будет работать на частоте 2МГц, от внутреннего генератора.

Для управления светодиодами будем использовать механизм динамической индикации. Каждый рабочий вывод по сути будет сегментом. Итого максимальная яркость, которую мы можем получить, будет равна яркости одного светодиода поделённой на количество всех светодиодов и умноженное на количество управляющих выводов. Например, если у нас 10 светодиодов и один управляющий вывод с резистором, то яркость будет 1/10 от максимальной. Светодиоды светятся довольно ярко, так что для индикатора это вполне достаточная яркость.

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

Инициализация

Как обычно, отключим всю периферию и перейдем на частоту 2 МГц. Таймер TIM2 будем использовать для динамической индикации.

[code]	CLK->PCKENR1 = CLK_PCKENR1_TIM4+CLK_PCKENR1_TIM2;
CLK->PCKENR2 = 0b01110011;

CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8);

TIM2_TimeBaseInit(TIM2_PRESCALER_16, 124);//1000Гц.
TIM2_ClearFlag(TIM2_FLAG_UPDATE);
TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);
TIM2->IER |= (uint8_t)TIM2_IT_UPDATE | TIM2_IT_CC1;

TIM2_OC1Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_DISABLE,124,TIM2_OCPOLARITY_HIGH);
TIM2_OC1PreloadConfig(ENABLE);
TIM2_ARRPreloadConfig(ENABLE);
[/code]

Для регулирования яркости будем использовать PWM режим таймера TIM2. Разрешение PWM нам высокое не нужно, сделаем 124 градации яркости. В начале яркость максимальная. Частота таймера 1000 Гц. Прерывания будут задействованы по обновлению таймера и по сравнению со значением PWM скважности.

Для приёма команд по протоколу 1-wire будем использовать таймер TIM4. Его задача будет отсчитать таймаут и определить первый стартовый сигнал RESET. Настраиваем его в одиночный режим, то есть по окончанию отсчёта он остановится и все. Прерывания на нем нам не нужны.

[code]	TIM4_Cmd(DISABLE);//для приема 1-wire
TIM4_TimeBaseInit(TIM4_PRESCALER_16, 200);//8 микросекунды один тик до 1600мкс - как таймаут!
TIM4_SelectOnePulseMode(TIM4_OPMODE_SINGLE);//одиночныйрежим
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
TIM4->CNTR=0;
[/code]

Сам таймер пока остановлен, значение счётчика обнулено. Максимальное значение 1600 мкс. Для корректной работы протокола 1-wire необходимо установить срабатывания прерывания на управляющем выводе на FALL_ONLY (по падению сигнала) и установить максимальный приоритет данному прерыванию, чтобы нас ничего не отвлекало при декодировании сигнала.

[code]	EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOD,EXTI_SENSITIVITY_FALL_ONLY);//самыйвысокий приоритет имеет
ITC_SetSoftwarePriority(ITC_IRQ_TIM2_OVF, ITC_PRIORITYLEVEL_2);
ITC_SetSoftwarePriority(ITC_IRQ_TIM4_OVF, ITC_PRIORITYLEVEL_2);
ITC_SetSoftwarePriority(ITC_IRQ_PORTD, ITC_PRIORITYLEVEL_3);
[/code]

Дальше инициализируем все выводы. Ставим их как PUSH PULL и значение 0. Это самый лучший вариант для сна, наименьшее энергопотребление. Вывод для управления индикатором ставим как PULL_UP с прерываниями (этот вывод SWIM).

[code]	//GPIO_Init(GPIOC,GPIO_PIN_7,GPIO_MODE_IN_PU_IT);//приемсигнала! для тестирования!
GPIO_Init(GPIOD,GPIO_PIN_1,GPIO_MODE_IN_PU_IT);//приемсигнала!

sleep();
[/code]

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

[code]void sleep(void) {
stoptim = 1;//чтобы не менять индикацию
//переключаем все выводы на GND
//переходим в спящий режим
GPIO_Init(GPIOA,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOD,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOC,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOB,GPIO_PIN_4|GPIO_PIN_5,GPIO_MODE_OUT_OD_LOW_SLOW);

halt();
stoptim = 0;
}
[/code]

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

Динамическая индикация

С динамической индикацией вы уже умеете работать. Подробно мы её рассматривали в приборе Кухонный таймер. Обработка ведётся в обработчике прерывания TIM2. В данном приборе мы будем использовать возможность данного таймера работать в PWM режиме. Это позволит нам удобно управлять яркостью светодиодов.

Давайте немного посчитаем. Допустим мы решили управлять одним управляющим выводом сразу 20 светодиодами. В случае динамической индикации нам придётся последовательно включать каждый светодиод и так пока не переберём все 20. Если частота таймера у нас будет 1000 Гц, то итоговая частота мигания одного светодиода будет 1000 / 20 = 50 Гц. Этого вполне достаточно, но ниже опускать не стоит — будет заметно мерцание. Если в этом случае поступить как мы делали в кухонном таймере, то есть добавлять пустых циклов, то для управления яркостью надо будет поднять частоту таймера до 10 000 Гц и выше. При нашей частоте процессора в 2 МГц, это становится проблемой. Поэтому самый правильный вариант использовать PWM режим. В этом случае все относительно просто. С частотой в 1000Гц мы перебираем каждый светодиод и включаем его, а потом по прерыванию Capture and Compare, мы выключаем все светодиоды. В таком выбранное максимальное число в таймере ARR = 124 будет служить нам градациями яркости. Стоит отметить, что при нашей не высокой частоте процессора, мы должны успеть обработать логику включения нужного светодиода. Минимальная яркость у нас должна быть больше чем процедура обработки. Можно подобрать опытным путем — для 20 светодиодов, например, это 8 единиц при такой настройке таймера.

Теперь перейдем к обзору самой процедуры.

[code]INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)
{
if (stoptim)
{
TIM2->SR1 = (uint8_t)(~TIM2_IT_UPDATE);
return;
}

//милисекунды
if (timedelay) timedelay--;

//все выкл!
GPIOA->DDR &= (u8) (~ (GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3));
//GPIO_Init(GPIOA,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,GPIO_MODE_IN_FL_NO_IT);
GPIOD->DDR &= (u8) (~(GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6) );
//GPIO_Init(GPIOD,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_IN_FL_NO_IT);
GPIOC->DDR &= (u8) (~(GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7) );
//GPIO_Init(GPIOC,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_IN_FL_NO_IT);
GPIOB->DDR &= (u8) (~ (GPIO_PIN_4|GPIO_PIN_5) );
//GPIO_Init(GPIOB,GPIO_PIN_4|GPIO_PIN_5,GPIO_MODE_IN_FL_NO_IT);
}
[/code]

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

Все будет зависеть от вашей схемы подключения светодиодов. Разберём на примере схемы, приведённой выше (см. раздел Схема). Согласно схеме у нас 2 управляющий вывода и 3 рабочих. Значит одновременно мы можем зажечь 2 светодиода. Таким образом, наши выводы можно разбить на пары (lx_uprx) - (l1_upr1 + l2_upr2), (l1_upr2 + l2_upr1), (l3_upr1+l3_upr2). Каждую пару надо задействовать по два раза меняя полярность. Итого получается общее количество светодиодов поделить на количество управляющих выводов состояний = 6 состояний.

Необходимо в конструкции switch case перебрать их все. Получится такой код.

[code]switch (numind) {	
case 0:
if (ind[0] ) GPIO_Init(GPIOD,GPIO_PIN_2,GPIO_MODE_OUT_PP_LOW_SLOW);
if (ind[6]) GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOD,GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_OUT_PP_HIGH_SLOW);//все управляющие включили на HIGH
break;

case 1:
if (ind[1] ) GPIO_Init(GPIOD,GPIO_PIN_2,GPIO_MODE_OUT_PP_HIGH_SLOW);
if (ind[7]) GPIO_Init(GPIOD,GPIO_PIN_3,GPIO_MODE_OUT_PP_HIGH_SLOW);

GPIO_Init(GPIOD,GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_OUT_PP_LOW_SLOW);//все управляющие включили на GND
break;

….. и так далее
}

numind++;
if (numind==6) numind=0;
[/code]

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

Для управления яркостью, просто будем выключать все светодиоды в прерывании TIM2_CAP_COM.

[code]INTERRUPT_HANDLER(TIM2_CAP_COM_IRQHandler, 14)
{
GPIOA->DDR &= (u8) (~ (GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3));
//GPIO_Init(GPIOA,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,GPIO_MODE_IN_FL_NO_IT);
GPIOD->DDR &= (u8) (~(GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6) );
//GPIO_Init(GPIOD,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6,GPIO_MODE_IN_FL_NO_IT);
GPIOC->DDR &= (u8) (~(GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7) );
//GPIO_Init(GPIOC,GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_IN_FL_NO_IT);
GPIOB->DDR &= (u8) (~ (GPIO_PIN_4|GPIO_PIN_5) );

TIM2->SR1 = (uint8_t)(~TIM2_IT_CC1);
}
[/code]

Вот и все. Важно не запутаться и получается отличная динамическая индикация. Как нумеровать светодиоды вы можете выбрать сами. Например, если это две шкалы по 8 светодиодов, то удобнее одну шкалу с 0 до 7, потом другую с 8 до 15, потом оставшиеся 4 светодиода. Так будет проще управлять. Если у вас часы, то опять же проще 0 1 2 3 — по часовой стрелке с первого часа. Если стороны света, то как часы, по часовой стрелке.

Приём команд по протоколу 1-wire

Протокол 1-wire очень популярен. Он часто используется в приборах. Практически на всех платформах вы можете найти реализацию кода обмена по данному протоколу. Чтобы понять как он работает приведем простую диаграмму из datasheet на датчик температуры DS18B20. Протокол работает на PULL UP линии, которая поднята к VDD. Для общения, управляющий микроконтроллер (мастер) опускает линию на GND.

Для начала работы по данному протоколу требуется специальный сигнал RESET.

Мастер опускает линию на 480 мкс, а потом освобождает и она возвращается на HIGH. Датчик отвечает, что он есть, опуская линию на 240 мкс и ждёт до окончания 480 мкс. Далее идет обмен данными. Каждый бит передаётся используя тайм слот длиной в 70 мкс. Чтобы передать 1, почти весь слот должна быть 1, а чтобы передать 0, то почти весь слот должен быть 0.

Перевод линии в 0 служит начало передачи бита. Если считывать линию в середине тайм слота, то состоянии линии и будет означать 0 или 1. Биты в байте передаются от младшего к старшему. Сам протокол поддерживает адресацию и много различных функций, но мы будем использовать простой режим — один мастер, один индикатор.

Итак в начале обмена, мастер передаёт сигнал RESET. Далее 1 байт операции и далее нужное количество байт состояния светодиодов. Для реализации будем использовать прерывание по переходу в 0 состояния управляющего вывода. Сам вывод будет находится в состоянии PULL UP, так что со стороны управляющего МК можно использовать OPEN DRAIN режим вывода.

[code]INTERRUPT_HANDLER(EXTI_PORTD_IRQHandler, 6)
{
u8 zn;
u8 time;

time = TIM4->CNTR;
TIM4->CNTR=0;//сразу начинаем отсчётсначала!
TIM4->CR1 |= (uint8_t)TIM4_CR1_CEN;

if (dataok) return;

if(time > 190) {//190*8 = 1520мкс таймаут и стартпосле прошлого пакета //тут либо 0 либо200 с прошлого раза
waitreset=1;//какая то ошибка
} else if (waitreset==1) {
if (time > 50) {//50*8 = 400мкс //старт!
numbuffind=0;
waitreset=0;
}
}

if (waitreset==0) {
//10мкс - около 20 тактов до этого местаот срабатывания прервания
_delay_us(20);
if (GPIOC->IDR & GPIO_PIN_7) buffind[numbuffind]=1;
else buffind[numbuffind]=0;

if (numbuffind>(NUMIND)) dataok=1;
numbuffind++;
}
}
[/code]

Считываем значение счётчика таймера 4. Обнуляем его и запускаем заново. Если dataok не нулевая, значит мы еще не обработали предыдующие полученные данные, в этом случае ничего не делаем. Если счетчик больше 190 — 1500 мкс, то что- то не так, сбрасываем все в начало — устанавливаем переменную waitreset. Если мы ждем ресет и счетчик меньше 1520 мкс, но больше 400мкс, то дождались — начинаем работать. Так как прерывание у нас срабатывает только по переходу в 0, то мы его получим когда уже пойдет первый бит, поэтому сразу начинаем считывать состояние линии. Необходимо немного подождать — 20 мкс и считать состояние линии. Будет примерно половина тайм слота. МК у нас работает не очень быстро и это время по сути будет немного больше, вместо 20 мкс мы получим около 30мкс, нам это и надо. Далее записываем полученный бит в массив и ждем пока пока не получим команду плюс все данные. После этого ставим в единицу флажок dataok. Дальнейшяя обработка полученных данных идет в основном цикле.

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

[code]#define US(us) ( 2000000.0 / 3000000.0 * us ) //FCPU / 3000
#define MS(ms) US(ms * 1000) // maximum 10ms

#define _delay( loops ) _asm("$N: \n decw X \n jrne $L \nnop", (u16)loops);
#define _delay_us(us) _delay(US(us))
[/code]

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

[code]	if (dataok) {
//обработка данных
u8 i=0;
for (i=0;i<10;i++) {
ind[i] = buffind[i+8];
};

command = 0;
for (i=0;i<8;i++) {
command |= (buffind[i] << i);
}

if (command) {
//первые 7 бит яркость
u8 tyar;

tyar = command & 0b1111111;
if (tyar) TIM2->CCR1L = tyar;

//идем спать!
if (command & 0b1000000) sleep();
}

waitreset=1;
dataok=0;
numbuffind=0;
}
[/code]

Записываем полученные данные в массив индикации. Собираем команду, и если пора спать, то идём спать, а если это яркость — то меняем CCR значение таймера. В конце все готовим к следующей посылке. Вот так можно передавать данные по одному проводу.

Управление индикатором со стороны прибора

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

 

[code]#define IND_WIRE_1 GPIOC->ODR |=(uint8_t)GPIO_PIN_6//GPIO_WriteHigh(GPIOC,GPIO_PIN_6)
#define IND_WIRE_0 GPIOC->ODR &= (uint8_t)(~GPIO_PIN_6) //GPIO_WriteLow(GPIOC,GPIO_PIN_6)

void sendindicator(void) {
//reset
u32 dd = indicator;

stoptim=1;

IND_WIRE_0;
_delay_us(10);
IND_WIRE_1;
_delay_us(480);

{
u8 i;

for (i=0;i<32;i++) {
if (dd & 1) {
disableInterrupts();
IND_WIRE_0;
_delay_us(10);
IND_WIRE_1;
enableInterrupts();
_delay_us(55);
} else {
IND_WIRE_0;
_delay_us(65);
IND_WIRE_1;
_delay_us(5);
}
dd >>= 1;
}
}

stoptim=0;
}
[/code]

Узкое место передача 1, обязательно надо чтобы в этом момент ничто нас не прерывало. Лучше отключить прерывания. Остальное не так требовательно к точности таймера.

Как изготовить индикатор

Разработка схемы в Kicad и трассировка

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

Делаем плату и все запаиваем

  1. Подготовить или приобрести необходимые инструменты: все для пайки, ST-LINK (будет нужен для программирования и отладки МК)

  2. Внимательно прочитать статьи из раздела Обязательная теория.

  3. Скачать необходимые файлы по данному прибору с github.

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

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

  6. Приобрести все необходимые комплектующие вы можете самостоятельно, или у нас в виде набора из 20 светодиодов, если вам мало 20 светодиодов — то можете заказать больше.

  7. Запаять все компоненты на плату, смотри наше видео. При пайке светодиодов старайтесь сильно их не греть!

  8. Плата готова!

Для программирования, можно сразу подключить питание к ST-Link и SWIM вывод.

Переходим к программированию

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

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

Приобретённые навыки

Пайка: пайка паяльником светодиодов! пайка корпуса TTSOP.

Схемотехника: управление светодиодами.

Программирование: 1-wire протокол в master и slave режимах, динамическая индикация с помощью PWM таймера, спящий режим.

Самостоятельная работа

На github мы выкладываем образец индикатора. На его основе вы можете самостоятельно разработать свой индикатор и использовать его в ваших приборах.

 

]]>
(Super User) Приборы Tue, 28 Nov 2017 09:20:56 +0000
Самодельный сверлильный станок /index.php/pribory/item/43-samodelnyj-sverlilnyj-stanok /index.php/pribory/item/43-samodelnyj-sverlilnyj-stanok Самодельный сверлильный станок

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

{autotoc}

Что вам понадобится

Надо будет купить (или найти на чердаке) следующие детали

  1. Длинный болт 15 см, с неполной резьбой от края 3-4 см. Диаметр болта — 10мм, диаметр гладкой части 8мм (лучше конечно тоже 10мм — но таких нет в продаже). И две гайки к нему, одна или две большие шайбы.


  2. Уголки 2шт с отверстием 10мм (должен плотно входить наш болт) и отверстиями 3-4мм под болт (проушина для замка). Размером 25 х 25 мм. Толщина стали около 2мм.


  3. Стальную пластину — 40 х 100 мм.


  4. Доска 120 х 18 мм


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

  6. Моторчик и мини патрон (см статью про изготовление плат)


Рассчитываем смещение уголков в программе QCAD

Если уголки имеют отверстие большее чем диаметр гладкой части болта, то надо будет расположить уголки под углом, чтобы не было люфта. Сделать это очень легко в программе QCAD. Надо будет рассчитать угол поворота уголков относительно центра отверстий. Программа бесплатная, скачать можно с офф сайта.




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

Крепим двигатель

Двигатель можно прикрепить стяжками (просто, но не надёжно — двигатель не будет жёстко прикреплён к пластине):




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







Электрическая часть

Остаётся припаять провода, разъем и светодиоды для подсветки. Если питание будет 12в — то можно взять 3 белых светодиода и резистор 400 ом. Если будет 5в, то 3 светодиода просто без резистора, если будет не ярко — то 2 светодиода без резистора. Один светодиод требует около 2 В.

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

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




Само питание подаём на пластину и на второй вывод мотора. С таким расположением очень удобно быстро включать\выключать мотор. И работает он только при сверлении.

Финальный вид станка

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




На болт одеваем уголки, их крепим к пластине и к ней же двигатель. Болт прикручиваем к доскам.


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

Результат работы на станке. Все отверстия сверлятся за 5 минут.




Как работает станок смотрите на небольшом видео. Одной рукой держим плату, другой нажимаем на провод — кнопку и давим на пластину. На таком станке точность сверления отверстий очень высокая, и сверлить плату получается быстро и удобно.



]]>
(Super User) Приборы Mon, 03 Dec 2018 16:33:36 +0000
Плата управления моторами постоянного тока /index.php/pribory/item/44-plata-upravleniya-motorami-postoyannogo-toka /index.php/pribory/item/44-plata-upravleniya-motorami-postoyannogo-toka Плата управления моторами постоянного тока

Любой робот или машина на радиоуправлении содержит моторы, и ими надо управлять. Данная плата управления моторами может управлять 4-мя моторами постоянного тока напряжением от 7 до 12В и максимальным током до 1.5А каждый. Управление осуществляется по протоколу UART по одному проводу RX.

{autotoc}

Прежде чем начать

Прежде чем читать эту статью, рекомендуем вам ознакомится со следующей теорией:

Зачем нужен этот прибор?

Если вы собрались делать робота или машину на радиоуправлении, то вам обязательно понадобится управлять моторами постоянного тока. Рассмотрим классическую платформу управляемого робота на базе Arduino UNO (отладочная плата микроконтроллера ATMEGA).




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

Большая часть, продаваемых плат на рынке, не содержит логики управления моторами, а только предоставляет интерфейс для микроконтроллера. Например, так работает известная плата управления моторами — Arduino motor shield, стоимостью около 600 рублей.


Основной минус данной платы состоит в том, что для управления 4-мя моторами необходимо задействовать много выводов микроконтроллера (почти все выводы Arduino UNO), а также в том, что на микроконтроллер возлагается вся логика управления моторами. В итоге, ресурсов не такого уж мощного микроконтроллера, не хватает на другие задачи — обработку датчиков и основную программу.

Мы будем делать плату управления 4-мя моторами, которая содержит свой собственный микроконтроллер. Он будет управлять всеми моторами, а общение с основным мозгом робота будет производиться по протоколу UART — всего по одному проводу.

Такая технология в настоящее время набирает обороты. В модуль ставится недорогой микроконтроллер, который берет на себя рутинные операции, а основной мозг, освобождается от них. Например, вы можете все чаще встретить LCD экраны на базе встроенного микроконтроллера (драйвера), со своей памятью, что позволяет «свалить» на него формирование текста, графических примитив и даже операций 2D графики (масштабирование и другие). Также устроен SPP bluetooth модуль. В компьютере различные модули периферии (видео карта, wifi карта) тоже имеют свой микроконтроллер или процессор.

Постановка задачи, требования к прибору

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

Основные требования к плате моторов

  • Небольшой размер

  • Управление 4-мя моторами постоянного тока одновременно

  • Рабочий ток каждого мотора не более 1.5А, напряжение не более 12В

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

  • Напряжение питания от 7 до 12В

  • Выход 5В для питания Arduino

  • Управление по одному проводу — протокол UART

  • Независимое управление скоростью и направлением вращения каждого мотора

  • Низкая стоимость

  • Возможность расширения функционала — управление по шине I2C, подключение 2-х датчиков оборотов колес для контроля скорости и пройденного расстояния.

{product id=34}

Подбор компонентов

Так как у нас стоит задача управлять скоростью и направлением вращения каждого мотора, то нам понадобится четыре полноценных H-моста. В качестве электронных ключей будем использовать полевые транзисторы (MOSFET). Так как у нас невысокие требования по силе тока и напряжению, то в качестве верхних транзисторов будем использовать P-MOSFET, а в качестве нижних N-MOSFET. Для возможности реализации любой схемы управления будем стараться сделать так, чтобы скорость управления транзисторами была как можно выше, и чтобы оба транзистора были максимально близкие по параметрам. В итоге мы должны иметь возможность подавать ШИМ сигнал на все четыре транзистора каждого H-моста.

Подробно прочитать теорию про управление можно тут.

Подбираем ключевые транзисторы — MOSFET

Выбирать полевой транзистор мы будем по ключевым параметрам, которые обычно указаны в datasheet. Разберём подробно каждый параметр, чтобы научиться подбирать транзисторы. Руководствоваться будем документом Understanding-Modern-Power-MOSFETs.pdf

Rθja — коэффициент зависимости нагрева транзистора от выделяемой им мощности

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




В нашем приборе будет много транзисторов, поэтому выберем минимальный корпус — SOT-23 (u-3). Коэффициент тепловой передачи, при модифицированной площади припаивания, согласно данной таблице, для него составляет 308 градусов на ватт. Запомним данную цифру, она нам будет нужна позже.

Дополнительно стоит отметить, что данная таблица приводится для ОДНОГО транзистора на плате! По сути, часть тепла уходит в воздух через медную площадку, а часть тепла, медная площадка передаёт стеклотекстолиту, и он уже в свою очередь отдаёт тепло воздуху. Если у нас на одну площадку припаяно несколько транзисторов, то нужно считать одновременную выделяемую мощность и общую площадь меди. Например, у нас четыре H-моста. В самой плохой ситуации у нас будет открыто по 2 транзистора на каждый мост. А это значит, что всего у нас будет открыто 8 транзисторов! Если общая площадь меди будет в разы больше 1 дюйма, то все равно надо считать коэффициент не ниже 30 К / Ватт и выбирать максимальное значение нагрева между двумя расчётами. Также, надо учитывать выделяемую мощность при прохождении тока по меди (калькулятор есть в Kicad). И если мощность большая, то требуется напаять шины на дорожки (толстой медной жилой). Мы проведём все эти расчёты когда будем рассматривать финальную плату.

Rds(on) — сопротивление в открытом состоянии

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

  1. Максимальный ток равен 1.5А

  2. Температура где будет работать прибор не будет превышать 40 градусов. Максимальный нагрев транзистора — 150 градусов. Значит нагреться транзистор может максимум на 110 градусов (150 — 40 градусов)

  3. При выбранном корпусе, максимальная мощность составляет 110 / Rθja = 110 / 308 = 357 мВт

  4. Теперь можно рассчитать Rds(on) =

  5. Дополнительно надо сделать запас около 30%, таким образом нам подойдёт транзистор с сопротивлением в открытом состоянии меньше 110 мОм

  6. При подборе транзистора, необходимо брать сопротивление Rds(on) при температуре 150градусов!! как правило оно в 1.5 раза выше максимального, приводимого в datasheet для 25 градусов (обычно есть график зависимости сопротивления от температуры).



Vsd - максимальное падение напряжения на внутреннем диоде

Мы будем использовать самый простой вариант ШИМ управления H-мостом — ШИМ сигнал прилагать к нижнему левому (или правому) транзистору, а верхний правый будет постоянно открыт. В этом случае, когда нижний левый транзистор закрывается, то ток ЭДС мотора течет через ВЕРХНИЙ ЛЕВЫЙ транзистор, его паразитный диод. При этом на нем выделяется мощность Pdiode = I * Vsd. Как правило, падение напряжения на диоде MOSFET транзистора составляет 1.2В.

Ток мотора будет пропорционален ШИМ сигналу и самым большим он будет, когда коэффициент заполнения будет больше 90%. При этом диод будет открыт менее 10% всего времени, а значит мощность выделяемая на нем не будет превышать P = 1.2В * 1.5А * 0,1 = 180 мВт. Тем не менее в реальной схеме следует обязательно проверить нагрев верхнего левого транзистора на разных режимах работы мотора. И если он будет перегреваться, то необходимо добавить внешние диоды или сменить схему управления H-мостом. В нашей схеме, мы можем применять ШИМ сигнал к любому из четырёх транзисторов, в том числе реализовать комплементарную схему управления. Применение такой схемы не сильно усложнит код, зато существенно снизит нагрев транзисторов.

Vdss — максимальное напряжение

Мотор является индуктивной нагрузкой. Для индуктивной нагрузки напряжение необходимо брать с запасом - в два раза больше номинального напряжения питания мотора. У нас моторы ограничены 12В, так что, транзистор надо выбирать на напряжение около 20-30В.

VGS(th) — пороговое напряжение открытия транзистора

Так как мы планируем управлять нижними транзисторами напрямую МК, а его питание составляет 5В, то необходимо выбирать логические полевые транзисторы. У них, значение порогового напряжения ниже 2В.

Исходя из этих параметров, уже можно сделать выбор. В качестве N-канального транзистора мы выберем IRLML6244TRPbF (Rds(on) = 21мОм * 1.5 = 31.5), а в качестве P-канального IRLML6402TRPbF (Rds(on)=65мОм * 1.5 = 97.5 мОм).

Схема управления MOSFET

Ещё одна существенная составляющая нагрева транзистора в схемах с управлением ШИМ сигналом - это затраты на его переключение. Они прямо зависят от скорости открытия и закрытия транзистора, а также от частоты переключения. Так как у нас H-мост, то при управлении мостом, надо учитывать время закрытия и открытия, чтобы оба левых транзистора (или правых) не оказались включёнными одновременно (время ожидания окончания переключения называется dead-time). При разработке схемы управления надо не забывать и про время задержки включения и выключения транзистора, которое влияет на время dead-time.

В данном разделе, разберёмся как из параметров, указанных в datasheet, можно получить всю эту информацию, и правильно подобрать драйвер полевых транзисторов. Заметим, что при разработке устройства, лучше дополнительно проверять подобранные значения на симуляторе (например, LTSpice), а потом ещё и на практике с помощью осциллографа!

Практически во всех datasheet на полевые транзисторы приводятся скоростные параметры транзисторах при определённых условиях. К сожалению, их нельзя прямо пересчитать к нужным нам значениям, но можно грубо посчитать то, что необходимо и проверить в симуляторе. Это мы и сделаем. Возьмем один транзистор IRLML6244TRPbF для примера. В datasheet мы имеем следующие значения:


Наиболее полезные:

  • Qg — заряд, который необходимо передать транзистора для полного заряда затвора транзистора

  • td(on) - Время задержки открытия транзистора при указанных условиях

  • tr — Время открытия транзистора при указанных условиях

  • td(off) — Время задержки выключения транзистора

  • tf — Время выключения транзистора

  • Ciss — входная ёмкость затвора транзистора

В идеале, драйвер (схема управления транзистором) должен обеспечивать расчётные условия, указанные в datasheet — производитель указывает оптимальные условия управления. В нашем случае - это Rg = 6.8Ом и Vgs = 4.5В. Затвор полевого транзистора представляет собой конденсатор, и скорость заряда линейно зависит от тока заряда, который в свою очередь зависит от сопротивления перед затвором транзистора. Поэтому, если мы знаем сопротивление, то можно по нему пересчитать приведённые значения. А как же рассчитать данное сопротивление?

Так как мы планируем управлять транзистором напрямую от МК, то один вывод МК не может выдать больше 20мА тока. Исходя из этого ограничения можно рассчитать требуемое сопротивление — 250 Ом. Также надо учесть, что сопротивление внутреннего транзистора в МК в открытом состоянии около 50 Ом. Таким образом внешнее сопротивление необходимо в районе 200 Ом. Ожидаемое время открытия транзистора при таком резисторе будет составлять . Полное время открытия с учётом задержки составит 370 нс, а закрытия ещё больше - 911 нс. Полное время будет необходимо при расчёте времени dead-time. А время открытия и закрытия необходимо для расчёта нагрева транзистора. Для расчёта мощности, которая будет выделяться при переключении используется формула:


её удобнее использовать в виде (с использованием длительности открытия и закрытия транзистора)

В случае с верхним транзистором, необходимо использовать ещё один маломощный транзистор для смещения уровня управления — так как для его закрытия на затворе должно быть напряжение питания двигателей — до 12В, а МК может выдать только 5В. Также необходимо понизить напряжение на базе полевого транзистора через делитель (R3,R5), для его защиты. Можно было бы использовать выход МК в режиме Open Drain, но при напряжении более 5В ток управления составляет менее 1 мА, что приведёт к очень низкой скорости открытия транзистора и большему нагреву. Мы будем использовать для управления N-канальный полевой транзистор 2N7002. Им можно управлять напрямую, без резистора.

В итоге у нас получается вот такая схема управления транзисторами:




Резистор R9 необходим для того, чтобы полевой транзистор был закрыт при подаче питания, когда МК ещё не начал работать. При такой схеме время dead time надо брать около 1-2мкс.

Мы подобрали силовые транзисторы и разобрались со схемой управления ими. Наша плата управления должна замечательно работать с токами до 1.5А на каждый мотор, без всякого радиатора охлаждения. При этом плата должна находится на открытом воздухе, а не в коробке. Стоит также отметить, что силовые элементы платы нельзя покрывать лаком, заматывать изолентой — это сильно снижает теплоотдачу и нарушает все приведённые выше формулы.

Интерфейс общения

Для управления платой моторов будем использовать UART RX — только один провод. Посылка будет очень простая. Будем использовать один байт для скорости, как знаковое число от -127 до +127:

  • от 0 до 127 — скорость вперед

  • от 0 до -127 - скорость назад

Начинаться посылка будет с двух байтов 0x1 и 0x2. В конце посылки передаётся контрольная сумма всех 4 байтов скорости. Такой механизм необходим для контроля посылки, чтобы случайно не получить неверные данные. Если вы используете Arduino, то это позволит не отключать плату моторов на время прошивки Arduino по Serial порту. Для дополнительного контроля, будем считать, что если повторной посылки нет в течение 1 секунды, то требуется остановить все моторы.

Таким образом, у нас будет надёжный протокол управления 4-мя моторами по одному проводу.

Микроконтроллер

Для управления 4-мя моторами нужно много выводов. Возьмём микроконтроллер из серии STM8S с 32 выводами. Выберем серию, которая содержит загрузчик для прошивки по UART, в этом случае нам не понадобится ST-Link. Прошить микроконтроллер вы сможете используя любой COM порт (например наш USB UART адаптер, или плату Arduino, или любой другой). Нам подойдёт любой микроконтроллер в корпусе LQFP-32. Это может быть STM8S003Kx, STM8S005Kx, STM8S105Kx, STM8S207Kx, STM8S903Kx. Все эти микроконтроллеры имеют почти одинаковые выводы, так что проект легко можно мигрировать на любой из них. Схему будем составлять так, чтобы работать можно было с любым перечисленным микроконтроллером. Возможность прошивки по UART имеют все эти микроконтроллеры, кроме STMSx03Kx.

Конденсаторы

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

Чтобы разобраться в этом вопросе нам понадобится наглядное пособие — симулятор электрических схем LTSpice. Данная программа разрабатывается компанией Linear Technology и ее бесплатно можно скачать по приведённой ссылке. Программа очень удобная, занимает мало места, работает в Windows и linux под wine. Для понимания необходимости конденсатора составим простую схему. Для упрощения, заменим мотор катушкой индуктивности, а вместо H-моста возьмём один N канальный транзистор. Когда вы моделируете любую схему в симуляторе необходимо обязательно учитывать все паразитные элементы схемы, иначе получится модель далёкая от реальности. Составим следующую схему (её можно скачать с github):


Небольшие пояснения к схеме:

  • V1 — основной источник питания 12В, внутреннее сопротивление 500 мОм

  • L1, L3 — индуктивность проводов, от источника питания до схемы управления мотором

  • V2 — схема управления MOSFET, частота управления 4кГц.

  • M1 — произвольный N канальный MOSFET

  • R1 — сопротивление дорожек платы

  • L2 — наш мотор, небольшие моторы имеют индуктивность в районе 100 мГн, внутреннее сопротивление ставим так, чтобы ток при максимальном ШИМ сигнале ток был около 1.5А * 4 = 6А

  • D1 — любой диод, обязательно необходим для управления двигателем, без него схема будет работать не верно

  • C1,C2 — конденсаторы, в которых нам и надо разобраться

Для максимального приближения к реальности, рассчитаем с помощью данного калькулятора индуктивность проводов. Допустим в качестве источника питания у нас аккумулятор и он подключён многожильными проводами МГТФ-0.14 кв.мм длиной 20см. Индуктивность проводов будет составлять 0.6 нГн — в модели возьмём 1нГн. Теперь уберём конденсаторы, сделаем ШИМ сигнал 99%, для максимального тока и посмотрим график напряжения в точке bat, от которой питается вся схема.




В течение всего лишь 15 нс мы видим высоковольтные всплески — до 72В! Вся проблема в индуктивности проводов. Основное назначение конденсатора - не допустить таких всплесков на линии питания. Данное напряжение, даже на таком коротком интервале может привести к сбою в работе микроконтроллера или вообще вывести его из строя. Чтобы подобрать ёмкость конденсатора, рассмотрим данную схему при 50% ШИМ сигнале и посмотрим на амплитуду напряжения в цепи питания (при 50% ШИМ сигнале она будет максимальная), без конденсатора — 10В:




с конденсатором 1000 мкФ — 300мВ.




Ёмкость конденсатора влияет на колебания напряжения на линии питания — чем они меньше, тем лучше. Соответственно, подбираем ёмкость так, чтобы колебания были в пределах 1 В (лучше 500мВ). Получилось около 100 мкФ. Заметим, что ёмкость зависит от частоты ШИМ, чем она выше, тем меньшая ёмкость нам нужна. Теперь посмотрим, какой ток проходит через конденсатор (около 5А — максимальный и 2.5А средний ток). Максимальный средний ток через конденсатор будет примерно равен половине максимального среднего тока мотора. Так что, нам надо рассчитывать на ток где-то около 4А.


У конденсатора есть такой параметр как ESR — сопротивление на определённой частоте. Это сопротивление основной источник потерь в конденсаторе. Чем оно меньше, тем лучше. Соответственно подбирать сам конденсатор надо по этому параметру. Самое маленькое значение ESR имеют керамические конденсаторы — несколько мОм. Есть специальные алюминиевые LOW ESR конденсаторы — до 100 мОм, есть танталовые конденсаторы LOW ESR — 150 мОм, есть полимерные около 40 мОм. В datasheet на конденсаторы есть параметр Max Ripple Current — можно ориентироваться по этому значению, оно должно быть меньше среднего расчётного тока через конденсатор. Если его превысить, то конденсатор будет перегреваться. Также надо учитывать, что при ШИМ управлении в колебаниях обязательно присутствуют высшие частоты. Алюминиевые конденсаторы имеют высокое сопротивление на этих частотах, так что параллельно им обязательно нужен керамический или плёночный конденсатор небольшой ёмкости. Также надо учитывать, что керамические конденсаторы сильно теряют ёмкость (до 80%) при повышении напряжения. Если у вас напряжение не превышает 20В, то можно использовать керамику, при более высоком напряжении — керамика + алюминиевые конденсаторы. Вы также можете попробовать в модели поменять ESR конденсатора, и посмотреть как оно влияет на схему.

У нас напряжение 12В и нам нужен конденсатор небольшого размера в SMD исполнении и не дорогой. Подойдёт танталовый LOW ESR (85 мОм) конденсатор на 20В 100мкф.

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

Подведём итоги, как подбирать конденсатор:

  1. Максимально реально, с запасом учитываем индуктивность проводов

  2. Подбираем ёмкость конденсатора при 50% ШИМ, чтобы колебания напряжения были 5-10%.

  3. Подбираем конденсатор по ESR и Max Ripple Current, чтобы выдержать нужный ток при 50% ШИМ

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

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

  6. Размещать конденсатор надо как можно ближе к силовому контуру «питание плюс - MOSFET — MOTOR — питание минус».

Мотор

Нам подойдёт любой мотор постоянного тока рассчитанный на напряжение от 7 до 12 В. Максимальный потребляемый ток мотора должен не превышать 1.5А.

Надо не забывать, что если у вас может быть ситуация стопора мотора, то надо выбирать мотор по току останова. Как правило, в этом случае, потребляемый ток мотором возрастает в разы. Например, мотор R380-2580 имеет максимальный ток под нагрузкой — 1.5А, но ток останова 9А!!! Если такая ситуация не возможна, то по максимальному рабочему току.

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

Регулятор питания МК

Для питания МК нам необходимо 5В, так как токи здесь небольшие, то можно использовать линейный регулятор питания. На входе у нас может быть до 12В, плюс возможны помехи — лучше всего использовать автомобильную версию регулятора NCV1117. Он работает до 20В входного напряжения и может выдать ток до 1А. В качестве альтернативы можно использовать регуляторы типа L78, LM78.

Составляем схему

Основные компоненты подобраны, составляем схему.

Каждым мотором управляет полный H-мост, который состоит из 4 силовых полевых транзисторов, а также схемы управления. Схему управления мы разбирали выше, приведём полную схему одного моста.


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

Так как мы будем использовать программное управление H-мостами, то управляющие выводы можно подключить к любым выводам МК. Выберем наиболее удобные с точки зрения трассировки платы. Для связи платы с внешним миром оставим шины UART, I2C, а также вывод программирования. Все это выведем на внешний разъем.


Линейный регулятор подключаем по схеме из datasheet. В качестве блокирующих конденсаторов у регулятора будем использовать керамические конденсаторы на 10 мкФ на 25В. Для повышения помехоустойчивости МК вывод RESET подключим через резистор 10 кОм на линию питания.

Трассировка платы — силовая часть

Плата в данном приборе совсем несложная, однако, имеет особенности — большие токи управления моторами. В данном разделе разберём подробно трассировку силовой части данного прибора. Большие рабочие токи порождают помехи на линии питании. А вместе с высокой частотой ШИМ они могут вызывать радиочастотные помехи. Все это в итоге может привести к неправильной работе приборе или и вовсе выходу его из строя. Поэтому когда вы разрабатываете плату с импульсным управлением большими токами, то должны строго следовать как минимум этим правилам:

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

  • силовая часть вместе с областью земли должна максимально не пересекаться с зоной МК

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

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

  • силовой контур питания должен обязательно иметь на входе LOW ESR конденсаторы, а также керамические конденсаторы 0.1 мкф. При этом рабочее напряжение таких конденсаторов должно быть как минимум 1.5 * Напряжение питания моторов. Например, у нас это будет 18В.

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

Посмотрим что у нас получилось.




Красным выделен силовой контур в одном из вариантов прохождения тока через силовые транзисторы. На входе стоит LOW ESR танталовый конденсатор. Силовые дорожки должны рассчитаны на общий максимальный общий ток всех 4-ех моторов. Питание МК подключено в одной точке через узкие дорожки. Земля МК не пересекается с силовой землей.




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

Особенности трассировки более мощных регуляторов моторов будут рассмотрены на примере регулятора бесколлекторного двигателя () для квадрокоптера с токами до 30А.

Программа

Общее описание программы

Всю программу можно поделить на две части:

  • общение по протоколу UART

  • управление моторами.

Протокол очень простой, в одну сторону, задействована только линия RX. Заголовок пакета данных состоит из двух байт — 0x01 и 0x02, далее следуют 4 байта скорости каждого мотора в формате знакового числа от -127 до 127. Завершает пакет данных контрольная сумма — сумма четырёх байт скорости в виде одного байта. Данный пакет будет защищён от помех, а также позволит передавать прочие данные по тому же UART параллельно, вряд ли встретится такая же последовательность данных. Таким образом UART можно будет использовать например в ARDUINO для прошивки МК не отключая плату моторов. Дополнительно добавим защиту от зависания управляющего МК - если нового пакета не будет получено в течение 3 сек, то все моторы будут остановлены.

Так как у нас 4 полных H-моста, то получить «железный» PWM сигнал на данном типе МК не получится, поэтому будем использовать программный метод генерации PWM. Задействуем таймер TIM1 и его все 4 канала в режиме PWM генерации. А в обработчике прерывания данного таймера будем переключать ножки как нам это необходимо. Для управления моторами будем использовать самую простую схему — верхний транзистор все время открыт, а нижний переключается согласно PWM сигналу. В момент переключения направления вращения мотора будем отключать все транзисторы, выжидать паузу 100мс и потом включать нужный режим. В момент перехода скорости через 0, достаточно выждать 2мс — dead time с запасом. Такая схема решит все вопросы связанные с dead time, а также даст время мотору остановиться в случае смены направления вращения.

Вы можете самостоятельно изменить программу, добавить режим активного торможения, попробовать различные варианты PWM управления H-мостом и другие функции. Также можно возложить на эту плату задачу подсчёта скорости вращения колес, ресурсов МК и свободных выводов для этого достаточно. На плате специально выведен порт I2C — можно настроить управление платой по этому протоколу. В итоге данная плата может полностью закрыть вопрос управления движением 2-4 моторного робота, освободив ресурсы основного «мозга». Также за счёт наличия выводов UART возможно использовать плату сразу как «мозг» простого робота, подключив по UART плату радиоуправления, а по I2C необходимые датчики.

Выбор микроконтроллера

Нам необходимо иметь возможность скомпилировать проект под любой микроконтроллер из серии STM8S. В среде ST VD 8 это делается очень легко. Шаблон проекта содержит настройки под любой МК из серии STM8S. Остаётся только выбрать нужную серию, указать конкретный МК и скомпилировать код под него.




В настройках проекта выбрать конкретный МК и скомпилировать проект.




В коде учтены возможные отличия периферии. Для нашего проекта отличается только номер UART периферии — это может быть UART1 или UART2 или UART3. Делается это с помощью условий препроцессора вида:

[code]#ifdef STM8S003
UART1_DeInit();
UART1_Init((uint32_t)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1,UART1_PARITY_NO,
UART1_SYNCMODE_CLOCK_DISABLE,UART1_MODE_TX_DISABLE|UART1_MODE_RX_ENABLE);

UART1_ITConfig(UART1_IT_RXNE_OR,ENABLE);
#else
UART2_DeInit();
UART2_Init((uint32_t)9600, UART2_WORDLENGTH_8D, UART2_STOPBITS_1,UART2_PARITY_NO,
UART2_SYNCMODE_CLOCK_DISABLE,UART2_MODE_TX_DISABLE|UART2_MODE_RX_ENABLE);

UART2_ITConfig(UART2_IT_RXNE_OR,ENABLE);
#endif
[/code]

Инициализация

Частоту работы микроконтроллера устанавливаем в 16 МГц. Кварцевый резонатор не используем, в данном случае в нем нет необходимости. Высокая точность PWM сигнала нам не нужна.

[code]CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);//16mhg
[/code]

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

[code]TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124);//Используемпредделитель 128, в этом случае значениетаймера 125 будет соответсвовать 1 мс.
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
[/code]

Далее необходимо все выводы управления моторами перевести в LOW состояние.

[code]GPIO_Init(GPIOB,GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3,GPIO_MODE_OUT_PP_LOW_FAST);
GPIO_Init(GPIOC,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_MODE_OUT_PP_LOW_FAST);
GPIO_Init(GPIOD,GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4,GPIO_MODE_OUT_PP_LOW_FAST);
GPIO_Init(GPIOE,GPIO_PIN_5,GPIO_MODE_OUT_PP_LOW_FAST);
[/code]

Для организации PWM сигнала мы будем использовать таймер 1 и его 4 канала, а управлять выводами будет в прерывании данного таймера. Такой метод более универсальный и позволяет задействовать любые выводы под управление моторами. Но если требуется более быстрое управление моторами то необходимо использовать специальную периферию таймеров. Она позволяет автоматически учесть dead-time и имеет ряд других преимуществ. Настроим сам таймер и все его каналы на 0 скорость.

[code]TIM1_DeInit();
TIM1_TimeBaseInit(0, TIM1_COUNTERMODE_UP, MAXPWM, 0);
[/code]

Используем значение MAXPWM = 4095 для получения частоты PWM сигнала 4 кГц. Использование 16 битного таймера позволяет плавно изменять скорость мотора. Но мы будем использовать более грубую настройку скорости — 127 значений в одну сторону и столько же в другую.

[code]TIM1_CCPreloadControl(DISABLE);
TIM1_BDTRConfig(TIM1_OSSISTATE_DISABLE,
TIM1_LOCKLEVEL_OFF,0,
TIM1_BREAK_DISABLE,
TIM1_BREAKPOLARITY_LOW,TIM1_AUTOMATICOUTPUT_DISABLE);

TIM1_OC1Init(TIM1_OCMODE_PWM2, TIM1_OUTPUTSTATE_DISABLE,TIM1_OUTPUTNSTATE_DISABLE,
0, TIM1_OCPOLARITY_LOW, TIM1_OCNPOLARITY_HIGH,TIM1_OCIDLESTATE_SET,
TIM1_OCNIDLESTATE_RESET);

TIM1_OC2Init(TIM1_OCMODE_PWM2, TIM1_OUTPUTSTATE_DISABLE,TIM1_OUTPUTNSTATE_DISABLE,
0, TIM1_OCPOLARITY_LOW, TIM1_OCNPOLARITY_HIGH,TIM1_OCIDLESTATE_SET,
TIM1_OCNIDLESTATE_RESET);

TIM1_CtrlPWMOutputs(DISABLE);

TIM1_Cmd(ENABLE);
TIM1_ITConfig(TIM1_IT_UPDATE|TIM1_IT_CC1|TIM1_IT_CC2|TIM1_IT_CC3|TIM1_IT_CC4,ENABLE);
[/code]

Таким образом таймер используется только для генерации прерываний. Наличие 4-х каналов позволяет удобно управлять скоростью каждого мотора независимо. Активируем необходимые прерывания — По переполнению таймера и по сравнению с заданным уровнем PWM сигнала (capture and compare).

В конце блока инициализации настроим UART для управления нашим модулем моторов. Используем только вывод RX и прерывания разрешаем только по приёму данных(наш модуль ничего не передаёт).

[code]UART1_Init((uint32_t)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1,UART1_PARITY_NO,
UART1_SYNCMODE_CLOCK_DISABLE,UART1_MODE_TX_DISABLE|UART1_MODE_RX_ENABLE);
UART1_ITConfig(UART1_IT_RXNE_OR,ENABLE);
[/code]

Управление по UART

Для управления всеми 4-мя моторами используется протокол UART. Получение данных выполняется в прерывании модуля UART.

[code]INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
char c=0;
#ifdef STM8S003
if (UART1_GetFlagStatus(UART1_FLAG_RXNE) != RESET )
c = UART1_ReceiveData8();
#else
if (UART2_GetFlagStatus(UART2_FLAG_RXNE) != RESET )
c = UART2_ReceiveData8();
#endif
[/code]

Если байт получен, то запишем его в переменную «c» и начнем обработку.

[code]	//ждем 1 2 с1 с2 с3 с4 (с1+с2+с3+с4)
if (RXready==5) return;
[/code]

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

[code]	if (RXready==2) {
if (RXtek>=4) {
u8 tmp=0;
u8 i;

for (i=0;i<4;i++) {
tmp += mot_newscor[i];
}

if (tmp == c) RXready = 5;
else RXready = 0;
}

mot_newscor[RXtek] = c;
RXtek++;
} else {
if ((RXready==0) && (c==1) ) {
RXready = 1;
}
else if ((RXready==1) && (c==2) ) {
RXready = 2;
RXtek=0;
}
else RXready=0;
}
}
[/code]

После получения двух байт проверим, что это начало посылки — последовательность 0x01 и 0x02. Если да, то следующие 4 байта — это новые значения скоростей моторов. Последний байт — контрольная сумма (просто сумма всех скоростей с переполнением — то есть один байт). Если все хорошо — пакет получен, то выставляем флаг получения новой порции скоростей и обрабатываем его в основном цикле.

[code]if (RXready==5) {
u8 i;
timetest = 3;
changespeed();
RXready=0;
}
[/code]

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

[code]if (timetest==0) {
//все выключаем!
u8 i;
RXready=5;
for (i=0;i<4;i++)
mot_newscor[i]=0;
changespeed();
RXready=0;
timetest = 3;
}
[code]Если в течение 3 секунд не было пакета— то останавливаем моторы.
[/code]

ШИМ управление моторами

Для генерации PWM сигнала управления моторами используется таймер 1 и его 4-е канала. Каждый канал отвечает за свой мотор. Обработка ведется в прерывании таймера. В каждом H-мосте мы управляем только одним нижним транзистором.Соответственно, при обнулении таймера— включаем данный транзистор (устанавливаемнужный вывод в HIGH), а при достижении установленного значения Capture and Compare выключаем его (устанавливаем вывод в LOW). Используем специальный массив mot_time[i] для блокировки управления моторамина время dead time или время смены направления вращения мотора. Значение в этом массиве уменьшается каждую миллисекунду, и пока оно не равно нулю, обработка выводов не осуществляется.
[code]INTERRUPT_HANDLER(TIM1_UPD_OVF_TRG_BRK_IRQHandler, 11)
{
TIM1_ClearITPendingBit(TIM1_IT_UPDATE); //очищаем битобработки прерывания
//надо включить все нужные нижниевыводы!
//но только если скорость не нулевая!и нет блокировки!
{
u8 i;
for (i=0;i<4;i++) {
if (mot_scor[i] && mot_time[i]==0) {
switch (i) {
case 0:
if (mot_scor[i] > 0) GPIO_WriteHigh(GPIOD,GPIO_PIN_0);//1NL
else GPIO_WriteHigh(GPIOD,GPIO_PIN_2);//1NR
break;
case 1:
if (mot_scor[i] > 0) GPIO_WriteHigh(GPIOC,GPIO_PIN_4);//2NL
else GPIO_WriteHigh(GPIOC,GPIO_PIN_5);//2NR
break;
case 2:
if (mot_scor[i] > 0) GPIO_WriteHigh(GPIOC,GPIO_PIN_6);//3NL
else GPIO_WriteHigh(GPIOC,GPIO_PIN_7);//3NR
break;
case 3:
if (mot_scor[i] > 0) GPIO_WriteHigh(GPIOD,GPIO_PIN_3);//4NL
else GPIO_WriteHigh(GPIOD,GPIO_PIN_4);//4NR
break;
}
}
}
}
}
[/code]

Сами значения скоростей устанавливаются в регистр таймера в процедуре changespeed(). Разберём ее поподробнее.

[code]void changespeed(void)
{
u8 i;

for (i=0;i<4;i++) {
if ( mot_scor[i] == mot_newscor[i]) {
//скорость не изменилась, ничего неделаем
continue;
}else if (mot_scor[i]*mot_newscor[i] > 0) {
//тот же знак, просто скорость другая!
//тут ничего не делаем = сделаем ниже
[/code]

Если скорость не поменялась, то ничего не делаем. Если изменилась скорость, но не изменилось направление, то достаточно поменять значение регистра таймера. Сделаем это позже.

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

[code]		}else {
//знак разный
//тут надо сначала мотор остановить!
//сменить знаки
//а только потом уже поменять скорости!
if (mot_scor[i]*mot_newscor[i] < 0) {
mot_time[i]=100;//в случае смены направлениявращения заблокируем на 100мс управлениевыводами!
} else mot_time[i]=2;//а здесь достаточнотолько 2мс — dead time.
//выключим нижние транзисторы иверхние!
//нижние сами включаться дальше впрерывании таймера!
//подготовим сразу верхние как надо!!

//выключаем нижние транзисторы
switch (i) {
case 0:
GPIO_WriteLow(GPIOD,GPIO_PIN_0|GPIO_PIN_2);
GPIO_WriteLow(GPIOE,GPIO_PIN_5);
GPIO_WriteLow(GPIOC,GPIO_PIN_1);
break;
case 1:
GPIO_WriteLow(GPIOC,GPIO_PIN_4|GPIO_PIN_5);
GPIO_WriteLow(GPIOB,GPIO_PIN_2|GPIO_PIN_3);
break;
case 2:
GPIO_WriteLow(GPIOB,GPIO_PIN_0|GPIO_PIN_1);
GPIO_WriteLow(GPIOC,GPIO_PIN_6|GPIO_PIN_7);
break;
case 3:
GPIO_WriteLow(GPIOD,GPIO_PIN_3|GPIO_PIN_4);
GPIO_WriteLow(GPIOC,GPIO_PIN_2|GPIO_PIN_3);
break;
}
Delay(1);//чтобы исключить deadtime
//теперь включим верхние как нужно!
if (mot_scor[i]>0) {
//xHR правые в случае положительнойскорости
switch (i) {
case 0:
GPIO_WriteHigh(GPIOC,GPIO_PIN_1);
break;
case 1:
GPIO_WriteHigh(GPIOB,GPIO_PIN_2);
break;
case 2:
GPIO_WriteHigh(GPIOB,GPIO_PIN_0);
break;
case 3:
GPIO_WriteHigh(GPIOC,GPIO_PIN_3);
break;
}
} else {
//xHL левые в случае отрицательнойскорости
switch (i) {
case 0:
GPIO_WriteHigh(GPIOE,GPIO_PIN_5);
break;
case 1:
GPIO_WriteHigh(GPIOB,GPIO_PIN_3);
break;
case 2:
GPIO_WriteHigh(GPIOB,GPIO_PIN_1);
break;
case 3:
GPIO_WriteHigh(GPIOC,GPIO_PIN_2);
break;
}
}
}
[/code]

Теперь установим нужные значения в регистр таймера CCRx.

[code]		ccrval = (u32)((mot_newscor[i]>0) ? mot_newscor[i] :(-mot_newscor[i]))*MAXPWM/127;

switch (i) {
case 0:
TIM1->CCR1H = (uint8_t)(ccrval>> 8);
TIM1->CCR1L = (uint8_t)(ccrval);
break;
case 1:
TIM1->CCR2H = (uint8_t)(ccrval>> 8);
TIM1->CCR2L = (uint8_t)(ccrval);
break;
case 2:
TIM1->CCR3H = (uint8_t)(ccrval>> 8);
TIM1->CCR3L = (uint8_t)(ccrval);
break;
case 3:
TIM1->CCR4H = (uint8_t)(ccrval>> 8);
TIM1->CCR4L = (uint8_t)(ccrval);
break;
}

}
[/code]

Сохраним установленные значения скоростей в массив текущих скоростей.

[code]	for (i=0;i<4;i++) {
mot_scor[i]=mot_newscor[i];
}
}
[/code]

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

Как изготовить данный прибор самостоятельно

Делаем плату и все запаиваем

  1. Подготовить все необходимые инструменты: все для пайки, ST-LINK (будет нужен для программирования и отладки МК) или USB-UART адаптер (можно загрузить прошивку по UART).

  2. Внимательно прочитать статьи из раздела Обязательная теория.

  3. Скачать необходимые файлы проекта по данному прибору с github.

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

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

  6. Плата готова!

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

Особенности тестирования платы

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

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

  • токи, большие чем рабочие для данного транзистора, например при коротком замыкании

  • неправильная схема управления — слишком долгое открытие и закрытие транзистора

Вот эти два момента и нужно будет дополнительно протестировать. Короткое замыкание возможно при одновременном открытии верхнего и нижнего парного транзистора, например по ошибке в программе. Для тестирования этой ситуации можно воспользоваться лампочкой или специальным блоком питания с защитой от КЗ. В случае с лампочкой все просто — питание к плате подаётся через последовательно включённую лампочку. Далее без мотора пробуем управлять скоростью его вращения (для этого проще в основном цикле программы сделать тестовое изменение скорости от 0 до 100), и если в программе есть ошибки — то лампочка будет загораться!

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

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

Прошивка по UART

Используемый в данном приборе микроконтроллер содержит загрузчик (bootloader), который позволяет загрузить прошивку по UART протоколу. Для этого необходимо использовать специальную программу от ST и обычный USB-UART модуль. Скачать прошивальщик STM8 Flash loader demonstrator (UM0462) можно отсюда.

Приобретённые навыки

Трассировка платы: трассировка силовых плат

Схемотехника: LDO, схема управления MOSFET транзисторами, H-мост

Программирование: программирование PWM сигнала, управление микроконтроллером по UART

Самостоятельная работа

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

Если добавить SPP bluetooth модуль, то на данной плате можно сделать машину на радиоуправлении без дополнительной платы центрального процессора.

]]>
(Super User) Приборы Mon, 03 Dec 2018 16:40:14 +0000
Измеритель УФ-индекса и температуры /index.php/pribory/item/46-izmeritel-uf-indeksa-i-temperatury /index.php/pribory/item/46-izmeritel-uf-indeksa-i-temperatury Измеритель УФ-индекса и температуры

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

{autotoc}

Прежде чем начать

Прежде чем читать эту статью, рекомендуем вам ознакомится со следующей теорией:

Индекс ультрафиолетового излучения или как правильно загорать

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




В небольших дозах УФ излучение полезно — под его воздействием в организме вырабатывается витамин Д. Однако в больших дозах оно приводит к ожогам кожи, эритеме(подробнее про вред и пользу УФ излучения можно прочитать в этой статье).

Уровень УФ излучения на поверхности нашей планеты принято измерять УФ индексом (UV Index). Этот показатель отражает степень ультрафиолетового излучения, он варьируется от 0 до 11. Чем выше его величина, тем больше потенциальная угроза для кожных покровов и глаз человека, и, соответственно, тем меньше времени можно находиться на солнце. Чтобы рассчитать данный индекс необходимы знания об интенсивности УФ излучения. Причём для корректного подсчёта нужно учитывать весь спектр УФ излучения - от 100 до 400 нм.


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

Учёными была установлена максимальная суточная доза УФ излучения (1 МЭД — минимальная эритемная доза), которая не приводит к отрицательным последствиям. Она зависит от типа кожи. Данные приведены в следующей таблице.

Тип кожи

Загар

Солнечный ожог

Цвет волос

Цвет глаз

1 МЭД, Дж/м2

I

никогда

всегда

рыжий / соломенный

голубой

200

II

иногда

иногда

светло русый

голубой / зелёный

250

III

всегда

редко

тёмно русый / каштановый

серый / карий

300

IV

всегда

никогда

чёрный

карий / чёрный

450



Индекс УФ напрямую влияет на время проведения на солнце. На следующем графике видна зависимость времени пребывания на солнце до покраснения кожи от индекса УФ и типа кожи.


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



Вид деятельности

Коэффициент C

Плавание:

море

2

пресноводные водоёмы

4

Спортивные игры

4

Пешеходные прогулки

3

Гребля, прогулки на лодке

3

Работа на приусадебном участке

6



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

Измеряем температуру воды и воздуха

Как правило, все едут в отпуск на море — понежиться на солнце и поплавать в ласковом теплом море. Чтобы рассчитать сколько времени можно находится в воде нужно знать её температуру. Наиболее комфортной считается температура 24-28 градусов. Вторая полезная функция прибора для отдыха — точное и быстрое измерение температуры воды.

В качестве датчика температуры воды идеально подходит термопара, например К типа (она самая распространённая). Во первых, такой датчик является достаточно точным, а во вторых он не боится влаги. Ну и самое главное — термопара имеет очень маленькую теплоёмкость, а это значит, что значения температуры воды вы получите практически мгновенно — 1-2 секунды достаточно для замера. Длина датчика может быть больше 1 метра, что позволит измерить температуру воды не только на поверхности, но и на глубине.

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

Вот теперь можно смело переходить к требованиям к прибору «отпускника».

Прочие полезные функции

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

Для работы с датчиками используется протокол I2C, а это значит, что если вывести выводы SDA SCL на внешний разъем, то можно будет подключать дополнительные датчики по этой шине, а также может сделать I2C сканер.

{product id=35}

Постановка задачи, требования к прибору

Основные требования к прибору.

  • Компактный размер

  • Питание от аккумулятора, длительная работа от одного заряда

  • Измерения индекса УФ излучения в двух диапазонах UVA и UVB

  • Измерение температуры с помощью термопары К типа, подключение ее через разъем

  • Измерение температуры воздуха

  • Индикация измеренных данных — миниатюрный ЖК (на солнце он читается лучше других индикаторов) дисплей

  • Возможность индикации звуком о различных событиях

  • Широкий набор функций и возможность доработки.

Подбор компонентов

Выбираем датчик УФ излучения

В качестве датчика УФ излучения будем использовать один из самых современных и миниатюрных датчиков уф излучения — VEML6075 от компании Vishay.




Данный датчик имеет очень маленький размер 2х2 мм, низкое энергопотребление 500 мкА в режиме работы и 800 нА в режиме сна. И самое главное - он умеет измерять UVA и UVB излучение одновременно. К датчику идёт подробный datasheet, а также дополнительная документация, в которой подробно рассмотрено как его калибровать и использовать в проектах. Датчик подключается по шине I2C, поэтому микроконтроллер должен уметь работать с этой шиной.

Датчик измерения термопары

Термопара — датчик температуры, принцип работы которого основывается на термоэлектрическом эффекте. Точность такого датчика очень высока — до 0.01 градуса, он имеет очень большой диапазон измерения — от -250 до 2000 градусов. Однако получить данные с него не так-то просто. Основным показателем температуры является напряжение на концах термопары (ТЭДС), по специальным формулам по нему можно определить температуру спая.

На показания датчика оказывают влияние:

  • Температура свободных концов (которые подключаются к разъему). Ее необходимо добавить к вычисленной температуре спая.

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

  • Зависимость ТЭДС от температуры существенно не линейна. Это требует сложных вычислений значения температуры по ТЭДС.

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

  • На один градус температуры для термопары типа К — ТЭДС составляет всего лишь 40 мкВ. Нужен очень точный ADC, чтобы измерить такое напряжение, или малошумящий операционный усилитель для усиления данного сигнала.

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

Самый современный путь для измерения температуры термопары - использовать внешний очень точный сигма дельта ADC — mcp3421. Данный ADC умеет измерять напряжение с разрешением до 2 мкВ (что дает разрешение в 0.05 градусов), при этом для его работы практически не нужны внешние компоненты. И что более важно, он не требует никакой калибровки, настройки и т. д. Таким образом, мы сразу получим очень точные данные с термопары. Такой подход сильно упрощает схему. Все вычисления произведёт микроконтроллер с помощью таблицы коэффициентов для многочленов. Скорость вычислений тут не нужна, поэтому даже слабый микроконтроллер справится с данной задачей. Датчик подключается также по шине I2C.

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

  • напряжение

  • ток

  • сопротивление в диапазоне от 1 мОм и выше

  • ESR аккумуляторов

  • емкости конденсаторов

Датчик измерения температуры воздуха

К сожалению, ТЭДС отражает разницу температуры между точкой подключения датчика и спаем. Поэтому для получения реальной температуры в месте спая необходимо знать температуру разъёма, куда подключена термопара. Будем использовать цифровой интегральный датчик температуры NCT75. Он имеет разрешение до 0.06 градусов и погрешность в один градус. Так что возможная погрешность всего измерения составит 1 градус. В настоящее время есть интегральные датчики с погрешностью до 0.1 градуса, но применение такого датчика здесь не оправдано.

Этот датчик опять же работает по шине I2C, что очень удобно.

Индикатор

Индекс УФ излучения имеет смысл измерять в погожий солнечный день. А это означает, что индикатор должно быть хорошо видно на ярком солнце. Лучше всего для этого подойдёт LCD индикатор, например Gdc0209 — 4 цифры.


Он имеет всего 13 выводов на все сегменты. Используется динамическая индикация. Управляющее напряжение 2.5В. Сегменты подключены следующим образом.




Управление таким индикатором без специализированной периферии довольно сложное. Но в этом приборе микроконтроллеру будет скучно — пусть им и управляет.

Пищалка

Чтобы иметь возможность предупредить о высоком уровне излучения или низкой температуре нужна пищалка. Используем традиционно — HC0903A.

Микроконтроллер

Нам обязательно нужна периферия I2C, но она есть практически везде. Так что подойдёт относительно любой микроконтроллер. Возьмём уже знакомый по другим приборам — STM8S003F3.

Аккумулятор

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

Регулятор питания

Так как на аккумуляторе максимально может быть 4.2В, а для датчиков максимальное напряжение составляет 3.6В, то необходим регулятор питания. Козьмем серию NCP551. Эти недорогие регуляторы имеют очень низкий ток собственного потребления — всего 4мкА, что позволяет питать устройства, которые будут большую часть времени спать.

Подбираем корпус и разъёмы

Корпус возьмём аналогично кухонному таймеру «Sanhe 20-31». В качестве разъёма используем самые дешёвые угловые PIN, сделаем так, чтобы они были утоплены в корпус и не торчали наружу. На разъем выведем:

  • 2 вывода для подключения термопары

  • 2 вывода — контакты батарейки для подключения внешней зарядки

  • I2C и 3.3в - для подключения внешних датчиков (в случае расширения функционала)

  • SWIM — для программирования

Наличие разъёма позволит подключать к прибору внешние датчики, что позволит расширить его функционал.

Составляем схему

Общая часть - питание, МК, пищалка, разъемы.




И датчики.


Все подключения согласно datasheet, ничего особенного нет. Печатную платы вы сможете найти в проекте на github.

Программа

Программа для STM8 написана в среде ST Visual develop IDE. Полный проект вы можете скачать с github данного прибора, папка uv. В статье мы разберём ключевые моменты работы программы.

Общая логика работы программы

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

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

  3. После смены режима работы в течение 2с отображается текущий режим в виде символов режима

  4. Предусмотрены следующие режимы работы:

    1. Измерение температуры (символ 1хх)

      1. воздуха, с помощью цифрового датчика (символ режима 101)

      2. с датчика термопары (символ режима 102)

    2. измерение UV индекса (символ режима 201)

  5. На экране отображаются измеряемые значения

  6. Через 30с неактивности прибор переходит в спящий режим

Инициализация

Установим частоту работы микроконтроллера в 2 МГц и отключим всю периферию, кроме I2C и TIM2 и TIM4.

[code]	CLK->PCKENR1 = CLK_PCKENR1_TIM2+CLK_PCKENR1_I2C; 	CLK->PCKENR2= 0b11110011; 
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8);//2mgh
//internal clock
GPIO_Init(GPIOD,ALL_PORTD,GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOA,ALL_PORTA,GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOC,ALL_PORTC,GPIO_MODE_OUT_PP_LOW_SLOW);
[/code]

Настроим внешние прерывания для возможности выхода из сна по кнопке.

[code]	EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOA,EXTI_SENSITIVITY_FALL_ONLY);
GPIO_Init(GPIOA,GPIO_PIN_2,GPIO_MODE_IN_PU_IT);
[/code]

Инициализируем I2C.

[code] I2C_Init(I2C_MAX_STANDARD_FREQ, (uint8_t)0xA0, I2C_DUTYCYCLE_2,I2C_ACK_CURR, I2C_ADDMODE_7BIT, 7);
[/code]

Настроим таймеры на 1000 Гц (основной миллисекундный таймер) и 2000 Гц (для индикатора).

[code]	TIM2_TimeBaseInit(TIM2_PRESCALER_8, 124);//2000Hz
TIM2_ClearFlag(TIM2_FLAG_UPDATE);
TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);
TIM2->IER |= (uint8_t)TIM2_IT_UPDATE;
TIM2_Cmd(ENABLE);

TIM4_TimeBaseInit(TIM4_PRESCALER_8, 249);//1000Hz
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
TIM4->IER |= (uint8_t)TIM4_IT_UPDATE;
TIM4_Cmd(ENABLE);
[/code]

Дальше переходим к запуску периферии и инициализации датчиков.

[code]	enableInterrupts();
Delay(100);
bmeT=0;
I2C_Cmd( ENABLE);
mcpinit();
uvinit();
nctinit();
[/code]

На этом все. Процедуры инициализации датчиков рассмотрим ниже.

I2C драйвер

Компания ST не предоставляет готовой библиотеки для работы с I2C, только низкоуровневые функции для настройки периферии и доступа к регистрам. В их примерах есть куски кода обмена данными по шине I2C. На их основе напишем необходимые функции передачи и получения данных по шине I2C. Обмен будет работать без использования прерываний. Для записи данных используется функция I2C_writenbyte, а для чтения I2C_readnbyte. Начнём с первой, она проще.

[code]int I2C_writenbyte(uint8_t addr, uint8_t* buff, int nbyte, intnostop)
{
uint32_t timeout;
timeout = current_millis + 1000;

while (I2C_GetFlagStatus(I2C_FLAG_BUSBUSY))
{
if (current_millis>timeout) return 0;
}

I2C->CR2 |= I2C_CR2_START;//I2C_GenerateSTART(ENABLE);
while (!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT))
{
if (current_millis>timeout) return 0;
}
[/code]

Перед записью необходимо убедиться, что шина I2C не занята, за это отвечает флаг I2C_FLAG_BUSBUSY в регистре I2C. Подождём пока шина не освободиться. Если этого не произойдёт за разумное время, то вернём состояние ошибки. Далее сгенерируем событие START, запишем соответствующий бит в регистр CR2. Проверим, что шина перешла в режим мастер. Можно передавать данные. В функцию передаётся адрес массива с байтами buff и количество байт для передачи, а также флаг — nostop, который отвечает за передачу в конце сообщения сигнала STOP. Некоторые датчики требуют, чтобы за командой записи следовала сразу команда чтения, без передачи сигнала STOP.

[code]	I2C_Send7bitAddress((uint8_t)addr << 1, I2C_DIRECTION_TX);
while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if (current_millis>timeout) return 0;
}

while (nbyte>0)
{
I2C->DR =(uint8_t)*buff;//I2C_SendData((uint8_t)*buff);//ctrl meas
while(!I2C_GetFlagStatus( I2C_FLAG_TRANSFERFINISHED))
{
if (current_millis>timeout) return 0;
}
*buff++;
nbyte--;
}

if(nostop==0)
{
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP(ENABLE);
}

return 1;
[/code]

Передаём адрес датчика, с которым будет производиться общение, и признак записи — первый бит. Ожидаем подтверждения, что режим мастера никто не отобрал. Далее, пока не закончатся все байты, записываем их в регистр DR периферии I2C и ждём пока очередной байт будет передан (I2C_FLAG_TRANSFERFINISHED). Остаётся только передать сигнал STOP, если он необходим. В случае возникновения ошибки, байт не будет считаться переданным, и через таймаут будет возвращён статус ошибки. Как видно, процедура совсем несложная.

Разберём теперь процедуру чтения данных.

[code]int I2C_readnbyte(uint8_t addr, uint8_t * buff, int nbyte,intnocheckbusy)
{
uint32_t timeout;
timeout = current_millis + 1000;

if (nocheckbusy==0)
{
while (I2C_GetFlagStatus(I2C_FLAG_BUSBUSY))
{
if (current_millis>timeout) return 0;
}
}

I2C->CR2 |= I2C_CR2_START;//I2C_GenerateSTART(ENABLE);
while (!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT))
{
if (current_millis>timeout) return 0;
}

I2C_Send7bitAddress((uint8_t)addr << 1, I2C_DIRECTION_RX);
[/code]

Начало примерно такое же. Ожидаем освобождения линии (если это необходимо). Далее передаём команду START, и ждём подтверждения перехода в мастер режим. Передаём адрес с битом чтения и начинаем передавать данные. И вот тут необходимо разобрать три варианта чтения данных. Первый - когда байт для чтения больше трёх. Второй - когда всего два байта и третий когда один. В каждом случае необходимо по-разному отслеживать события чтения, потому, что шина I2C имеет теневой регистр, в котором могут уже находиться данные, когда заполнен основной регистра данных. То есть, когда мы разбираемся с полученным байтом, периферия может получить уже второй байт. Случай больше трёх байт.

[code]	if (nbyte >= 3) 
{
while (I2C_GetFlagStatus( I2C_FLAG_ADDRESSSENTMATCHED) == RESET)
{
if (current_millis>timeout) return 0;
}
disableInterrupts();
(void)I2C->SR3;
enableInterrupts();

while (nbyte > 3) {

while (I2C_GetFlagStatus( I2C_FLAG_TRANSFERFINISHED) == RESET)
{
if (current_millis>timeout) return 0;
}

*buff = ((uint8_t)I2C->DR);//I2C_ReceiveData();
*buff++;
nbyte--;
}
while (I2C_GetFlagStatus( I2C_FLAG_TRANSFERFINISHED) == RESET)
{
if (current_millis>timeout) return 0;
}
I2C->CR2 &=(uint8_t)(~I2C_CR2_ACK);//I2C_AcknowledgeConfig(I2C_ACK_NONE);
disableInterrupts();
*buff = ((uint8_t)I2C->DR);//I2C_ReceiveData();
*buff++;
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP(ENABLE);
*buff = ((uint8_t)I2C->DR);//I2C_ReceiveData();
enableInterrupts();
*buff++;
while (I2C_GetFlagStatus( I2C_FLAG_RXNOTEMPTY) == RESET)
{
if (current_millis>timeout) return 0;
}

*buff = ((uint8_t)I2C->DR);//I2C_ReceiveData();
nbyte=0;

while(I2C->CR2 & I2C_CR2_STOP)
{
if (current_millis>timeout) return 0;
}

/* Re-Enable Acknowledgement to be ready for another reception*/
I2C->CR2 |= I2C_CR2_ACK;
I2C->CR2 &=(uint8_t)(~I2C_CR2_POS);//I2C_AcknowledgeConfig( I2C_ACK_CURR);
}
[/code]

Проверяем, что датчик откликнулся на свой адрес. Теперь необходимо прочитать регистр SR3, и сделать это нужно так, чтобы нас никто не прервал. Запрещаем прерывания и читаем регистр. В этот момент периферия получает байт данных. Ждем окончания получения байта и записываем его в буфер. Так делаем, пока количество оставшихся байт не станет равно 3. Отключаем автоматическое подтверждение ACK при получении байте, чтобы обработать байт. Запрещаем прерывания и получаем байт. Далее сразу генерируем STOP сигнал. Ждем пока придет еще один байт и записываем его в буфер. Ждём пока будет передан стоп сигнал и генерируем ACK сигнал. Таким хитрым образом получаем все оставшиеся три байта.

Когда надо получить два байта.

[code]	if (nbyte == 2) 
{
I2C_AcknowledgeConfig(I2C_ACK_NEXT);
while (I2C_GetFlagStatus( I2C_FLAG_ADDRESSSENTMATCHED) == RESET)
{
if (current_millis>timeout) return 0;
}
(void)I2C->SR3;
I2C_AcknowledgeConfig(I2C_ACK_NONE);

while (I2C_GetFlagStatus( I2C_FLAG_TRANSFERFINISHED) == RESET)
{
if (current_millis>timeout) return 0;
}

disableInterrupts();
I2C_GenerateSTOP(ENABLE);
*buff= I2C_ReceiveData();
enableInterrupts();
// Point to the next location where the byte read will be saved
*buff++;
*buff= I2C_ReceiveData();
nbyte=0;

while(I2C->CR2 & I2C_CR2_STOP)
{
if (current_millis>timeout) return 0;
}

// Re-Enable Acknowledgement to be ready for another reception
I2C_AcknowledgeConfig( I2C_ACK_CURR);
}
[/code]

Включаем автогенерацию ACK бита, проверяем что адрес опознан. Читаем регистр SR3. Отключаем генерацию ACK. Ждем флага байт получен. Запрещаем прерывания. И уже генерируем STOP сигнал. Байт уже получен. Быстро его читаем. И периферия получает в теневой регистр еще один байт. Записываем его в буфер и ждём пока выставится STOP на линии. Возвращаем назад автогенерацию ACK сигнала. Остался случай одного байта.

[code]	if (nbyte == 1) 
{
I2C->CR2 &=(uint8_t)(~I2C_CR2_ACK);//I2C_AcknowledgeConfig(I2C_ACK_NONE);
while(I2C_GetFlagStatus( I2C_FLAG_ADDRESSSENTMATCHED) == RESET)
{
if (current_millis>timeout) return 0;
}
disableInterrupts();
(void)I2C->SR3;
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP( ENABLE);
enableInterrupts();
while(I2C_GetFlagStatus( I2C_FLAG_RXNOTEMPTY) == RESET)
{
if (current_millis>timeout) return 0;
}
*buff = ((uint8_t)I2C->DR);//I2C_ReceiveData();
nbyte=0;
while(I2C->CR2 & I2C_CR2_STOP)
{
if (current_millis>timeout) return 0;
}
I2C->CR2 |= I2C_CR2_ACK;
I2C->CR2 &=(uint8_t)(~I2C_CR2_POS);//I2C_AcknowledgeConfig( I2C_ACK_CURR);
}
[/code]

Сразу отключаем генерацию ACK. Ждем подтверждения адреса. Запрещаем прерывания и сразу генерируем STOP сигнал. Ждем получения байта и передачи STOP сигнала. Включаем обратно автогенерацию ACK.

Вот так хитро работает получение данных по шине I2C.

Управление LCD индикатором с 4-мя общими выводами

Для управления индикатором будет использоваться метод цифровой корреляции. Чтобы понять как работает этот метод, рассмотрим как нужно управлять ЖК индикаторами.

Во первых, ЖК индикатором необходимо управлять строго переменным напряжением. Чтобы сегмент стал чёрным (то есть видимым) необходимо приложить переменное напряжение больше рабочего (у нас это 2.5В), в случае если переменное напряжение будет меньше заданного, то сегмент будет невидим (или слабо видим). Это свойство ЖК и используется для управления. В простых индикаторах каждый сегмент выведен на свои выводы. Управлять одним сегментом легко, но нужно очень много выводов у микроконтроллера. Для уменьшения количества выводов, так же как и в светодиодных индикаторах, в выбранном ЖК индикаторе используются общие выводы, которые подключены ко всем сегментам. Их в данной модели четыре. В таком режиме управлять уже сложнее. Нужен ступенчатый аналоговый сигнал. На момент показа одного сегмента необходимо на другие подать переменное напряжение меньше 2.5В. Вот диаграмма управления выбранным индикатором в аналоговом режиме.




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

Для полностью цифрового управления индикатором данные ступеньки необходимо эмулировать ШИМ сигналом. Такая методика гораздо проще для МК без специализированной периферии. Вот её график.


Для управления используется ШИМ сигнал с 50% наполнением. Активный общий вывод задаётся ШИМ сигналом с вдвое меньшей частой, а не активный с вдвое большей. Для управления сегментами используется ШИМ сигнал меньшей частоты, при этом полярность ШИМ сигнала меняется для сегментов которые видимы — сигнал начинается с 0 и заканчивается 1, а для невидимых наоборот. Данная схема должна работать на довольно высокой частоте и с самым высоким приоритетом, иначе могут быть отклонения от схемы и будут появляться участки времени с постоянным напряжением, что будет приводить к деградации индикатора.

К сожалению, традиционным путём, расчётом и вычислением состояния выводов в прерывании, пойти не получится. У микроконтроллера не хватает скорости. Тем более, желательно работать на самой низкой частоте 2МГц для снижения энергопотребления.

Для управления показываемой информацией служит массив ind[]. Там находятся данные, которые необходимо отобразить на месте первой, второй, третьей цифры. А массив tchk[] содержит отображаемые точки. После изменения данных в этих массивах необходимо вызвать функцию calсlcd, которая рассчитает необходимое состояние выводов согласно схеме. Рассмотрим эту функцию построчно.

[code]	if (timeshowrezhim) {
//0- temp 1-termopara 2 - uv
if (rezhim==0) {
ind[0]=1;
ind[1]=0;
ind[2]=1;
}
[/code]

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

Рассмотрим предварительно логику вывода информации на экран (ориентируемся на предыдущую картинку). Вся информация на экран выводится фреймами. Каждый фрейм состоит из сегментов активных в общем выводе com1, потом в выводе com2, com3 и com4, а потом несколько пустых состояний (для управления яркостью свечения сегментов). Выводятся фреймы в прерывании таймера по кругу. В каждый момент срабатывания таймера выводится одна часть фрейма, которая в свою очередь состоит из четырёх возможных комбинаций общих битов и битов сегментов. В итоге на один фрейм нужен массив из 4*4 возможных состояний общих выводов и выводов сегментов. Так как сегменты цифр разбросаны по общим выводам не очень удобно, то для начала заполним отдельный массив, отражающий какие биты сегментов должны быть активированы в каждом общем выводе.

[code]	for (i=0;i<4;i++) com[i]=0;
//7-8
addnum(0, GPIO_PIN_1,GPIO_PIN_2);
//9-10
addnum(1, GPIO_PIN_3,GPIO_PIN_4);
//11-12
addnum(2, GPIO_PIN_5,GPIO_PIN_6);
[/code]

Массив com содержит 4 байта, каждый бит которого отвечает за светящийся сегмент в соответствующем общем выводе. Всего сегментов в одном общем выводе у нас не более 8, так как у нас светиться могут не все сегменты (мало выводов у выбранного микроконтроллера). Очистим массив с общим выводами, а потом добавим три цифры. Заметим, что на одну любую цифру приходится два каких то вывода и 4 общих вывода. Например на цифру 1 — это выводы 5 и 6, на цифру 2 — выводы 7,8 и так далее. Передаём в процедуру номера сегментов и включаем нужные биты в массиве com в зависимости от выводимого символа.


[code]void addnum(u8 index, u8 pin1,u8 pin2) {
u8 num;
num = ind[index];

if (tchk[index]) {
com[3] |= pin2;
}

switch (num) {
case 0:
//p1 - com0 com2 com3
//p2 - com0 com2 com1

com[0] |= pin1|pin2;
com[1] |= pin2;
com[2] |= pin1|pin2;
com[3] |= pin1;
break;
case 1:
//p2 - com1 com2
com[1] |= pin2;
com[2] |= pin2;
break;
[/code]

И так делаем для всех возможных символов. В итоге получаем в массиве com для каждого общего вывода какие сегменты должны светится. Осталось все это перевести в 0 и 1 на нужных выводах МК.

[code]	for (i=0;i<16;i++) {
lcdm[16+i].porta_odr = GPIOA->ODR & (~(ALL_PORTA));
lcdm[16+i].portd_odr = GPIOD->ODR & (~(ALL_PORTD));
lcdm[16+i].portc_odr = GPIOC->ODR & (~(ALL_PORTC));
}
[/code]

Так как выводы разбросаны по трём портам A, D, C, храним состояние ODR регистра каждого порта. При этом, используем режим двойного буфера, так как эти вычисления занимают много процессорного времени. Все расчёты сначала ведём в последних 16 значениях массива, а потом быстро копируем их в первые 16 элементов массива. Готовим состояния портов — все биты выводов индикатора равны 0.

[code]	for (i=0;i<4;i++) {
lcdm[16+i*4].porta_odr |= lcdpins[i].porta;
lcdm[16+i*4].portd_odr |= lcdpins[i].portd;
lcdm[16+i*4].portc_odr |= lcdpins[i].portc;

lcdm[16+i*4+1].porta_odr |= lcdpins[i].porta;
lcdm[16+i*4+1].portd_odr |= lcdpins[i].portd;
lcdm[16+i*4+1].portc_odr |= lcdpins[i].portc;

for (j=0;j<4;j++) {
if (i==j) continue;

lcdm[16+i*4].porta_odr |= lcdpins[j].porta;
lcdm[16+i*4].portd_odr |= lcdpins[j].portd;
lcdm[16+i*4].portc_odr |= lcdpins[j].portc;

lcdm[16+i*4+2].porta_odr |= lcdpins[j].porta;
lcdm[16+i*4+2].portd_odr |= lcdpins[j].portd;
lcdm[16+i*4+2].portc_odr |= lcdpins[j].portc;
}

for (j=4;j<11;j++) {
//1100 //all seg off
lcdm[16+i*4].porta_odr |= lcdpins[j].porta;
lcdm[16+i*4].portd_odr |= lcdpins[j].portd;
lcdm[16+i*4].portc_odr |= lcdpins[j].portc;

lcdm[16+i*4+1].porta_odr |= lcdpins[j].porta;
lcdm[16+i*4+1].portd_odr |= lcdpins[j].portd;
lcdm[16+i*4+1].portc_odr |= lcdpins[j].portc;
}
}
[/code]

Предварительно установим все выводы по com сигналам. Например, для com0 будет так «1100 1010 1010 1010».


А потом установим выводы сегментов согласно массиву com[].

[code]	for (i=0;i<4;i++) {
if (com[i]) {
u8 j,pin;
pin = 1;

for (j=0;j<7;j++) {
if (com[i] & pin) {
lcdm[16+i*4+0].porta_odr &= ~lcdpins[j+4].porta;
lcdm[16+i*4+1].porta_odr &= ~lcdpins[j+4].porta;
lcdm[16+i*4+2].porta_odr |= lcdpins[j+4].porta;
lcdm[16+i*4+3].porta_odr |= lcdpins[j+4].porta;

lcdm[16+i*4+0].portd_odr &= ~lcdpins[j+4].portd;
lcdm[16+i*4+1].portd_odr &= ~lcdpins[j+4].portd;
lcdm[16+i*4+2].portd_odr |= lcdpins[j+4].portd;
lcdm[16+i*4+3].portd_odr |= lcdpins[j+4].portd;

lcdm[16+i*4+0].portc_odr &= ~lcdpins[j+4].portc;
lcdm[16+i*4+1].portc_odr &= ~lcdpins[j+4].portc;
lcdm[16+i*4+2].portc_odr |= lcdpins[j+4].portc;
lcdm[16+i*4+3].portc_odr |= lcdpins[j+4].portc;
}
pin = pin << 1;
}
}
}
[/code]

В переменной pin сдвигаем 1 бит влево, пока не пройдём по всем битам. В самом конце скопируем данные в первые ячейки массива.

[code]	blockcopylcd=1;
for (i=0;i<16;i++) {
lcdm[i].porta_odr = lcdm[16+i].porta_odr;
lcdm[i].portd_odr = lcdm[16+i].portd_odr;
lcdm[i].portc_odr = lcdm[16+i].portc_odr;
}
blockcopylcd=0;
[/code]

При этом, в момент копирования не будем выводим ничего на индикатор. При установленной переменной blockcopylcd на все выводы индикатора выводится 0.

Все данные готовы для вывода, осталось в прерывании вывести всю эту последовательность.

[code]	lcdframe++;
if (lcdframe==75) lcdframe = 0;
ind = lcdframe;

//blockcopylcd=1;

if (readytosleep==0) {
if ((ind < 16) && (blockcopylcd==0)) {

GPIOA->ODR = lcdm[ind].porta_odr;
GPIOD->ODR = lcdm[ind].portd_odr;
GPIOC->ODR = lcdm[ind].portc_odr;
}
else {
GPIOA->ODR &= ~(ALL_PORTA);
GPIOD->ODR &= ~(ALL_PORTD);
GPIOC->ODR &= ~(ALL_PORTC);
}
}
[/code]

Таймер срабатывает 2000 раз в секунду. 16 мс выводим все общие выводы, которые программировали в массиве, потом 59мс не выводим ничего. В итоге 75мс на один проход. То есть обновление индикатора происходит с частотой около 100 Гц. Это более чем достаточно.

Обработка кнопок

Обработку кнопок возьмём из проекта кухонный таймер.

Обработка датчиков

Ntc75 — датчик температуры

Для работы с датчиком используются две процедуры: nctinit() - используется один раз и настраивает режим работы датчика, nctdata() - вызывается регулярно, считывает температуру и записывает ее в глобальную переменную bmeT.

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

[code]#define NCTaddr  (0x48)
int nctinit(void) {
buff[0] = (uint8_t) 0b1;
buff[1] = (uint8_t) 0b100000;
if( ! I2C_writenbyte((uint8_t)NCTaddr, buff, 2,0) )
{
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP(ENABLE);
return 0;
};
}
[/code]

Адрес датчика задаётся с помощью команды #define — это общая практика использования констант в Си. Регистр настройки имеет адрес 0x01. Датчик может работать в непрерывном режиме или однокаратном. Для меньшего потребления тока и меньшего нагрева датчика лучше использовать однократный режим, это повысит точность измерений. За этот режим отвечает 7-ой бит. Первый бит отвечает за рабочий режим (когда передаём 0, то включаем датчик). Записываем в регистр настроек 0b100000. На этом инициализация датчика завершена.

Обработка показаний датчика выполняется также несложно.

[code]int nctdata(void)
{
long tmcpT;

buff[0] = (uint8_t) 0x4;
buff[1] = (uint8_t) 0;
if( ! I2C_writenbyte((uint8_t)NCTaddr, buff, 2,0) )
{
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP(ENABLE);
return 0;
};
Delay(90);
[/code]

Активируем разовое измерения. В регистр 0x04 записываем любые данные, например 0. Одно измерение занимает 60мс, на всякий случай подождём 90мс. После этого прочитаем данные.

[code]	buff[0] = (uint8_t) 0x00;
if( ! I2C_writenbyte((uint8_t)NCTaddr, buff, 1,0) )
{
I2C_GenerateSTOP(ENABLE);
return 0;
};

if (! I2C_readnbyte((uint8_t)NCTaddr, buff, 2,0) )
{
return 0;
};
[/code]

Данные находятся по регистру 0x00. Для чтения используем две команды. Сначала в режиме записи передаём номер регистра, который будем читать. А потом в режиме чтения получаем нужное количество байт в буфер. Данные о температуре состоят из двух байт. Старший байт передаётся первым.

[code]	tmcpT = (u32) (buff[0]<<8) | buff[1]; 
[/code]

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

[code]	bmeT = (tmcpT>>4) * 625 / 100; 
[/code]

В переменной получаем температуру в формате целого числа градусов умноженного на 100. То есть температура 25.65 градусов представлена числом 2565. На данном микроконтроллере в вычислениях лучше использовать целочисленную математику для меньшего расхода памяти и более быстрого выполнения вычислений.

Veml6075 — датчик УФ излучения

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

[code]	buff[0] = (uint8_t) 0b0;//config reg
buff[1] = (uint8_t) 0b01000000;//low byte 400ms
buff[2] = (uint8_t) 0b0;//high byte
if( ! I2C_writenbyte((uint8_t)UVaddr, buff, 3,0) )
{
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP(ENABLE);
return 0;
};
[/code]

Передаем адрес регистра настройки — 0x0, и значение настроек в виде двух байт.


Включаем датчик (бит 0), используем нормальный режим работы, нормальные установки динамического режима, задаем режим интеграции 800ms — в этом режиме датчик менее подвержен боковой засветке, которую трудно убрать без тефлонового фильтра.

Для более удобного получения данных с датчика напишем функцию readUVword(u8 addr). Функция читает сразу по два байта по переданному адресу и собирает из них беззнаковое целое размером 16 бит.

[code]	u16 readUVword(u8 addr) {
buff[0] = addr;
if( ! I2C_writenbyte((uint8_t)UVaddr, buff, 1,1) )
{
I2C_GenerateSTOP(ENABLE);
return 0;
};

if (! I2C_readnbyte((uint8_t)UVaddr, buff, 2,1) )
{
return 0;
};
return (u16) ((buff[1]<<8) | buff[0]);
}
[/code]

Отметим, что в данном датчике первым передаётся младший байт! Разберем процедуру uvdata(), в которой производятся все вычисления.

[code]int uvdata(void)
{
float uvia,uvib;
int i;
long tmcpT;

uva = readUVword(0x07);
uvb = readUVword(0x09);
uvcomp1 = readUVword(0x0A);
uvcomp2 = readUVword(0x0B);
[/code]

Для работы с данным датчиком необходимо использовать вычисления с плавающей точкой. Точности float будет достаточно. Получаем с датчика основные данные — uva (интенсивность уф излучения А типа), uvb (интенсивность уф излучения B типа), uvcomp1 (коэффициент компенсации 1), uvcomp2 (коэффициент компенсации 2). Используя эти коэффициенты, а также шесть констант можно вычислить необходимый индекс УФ излучения. К датчику идёт документ «Designing the VEML6075 into an Application», в котором подробно рассмотрена методика рассчета констант и проведения вычислений.

[code]	uvia = ((uva-UKa*uvcomp1-UKb*uvcomp2)*0.001461);//for 100ms
uvib = ((uvb-Ukc*uvcomp1-Ukd*uvcomp2)*0.002591);

if (uvia<0 || uvib<0) uindex=0;
else uindex = (uvia+uvib)*100/2/6;//800ms!!
[/code]

VEML6075 — как правильно вычислить индекс УФ излучения

Чтобы корректно рассчитать индекс УФ излучения по показаниям датчика необходимо использовать несколько констант. Как их вычислить не имея специального оборудования? Разберёмся в этом вопросе. Вот полная формула вычисления индекса:


Константы k1 и k2 без оборудования вычислить не получится. Но они необходимы для максимально точного расчёта, так что их можно принять за единицу. Константы чувствительности датчика можно взять из таблицы:


Нам нужны константы из первой строки, так как датчик у нас не закрыт тефлоном. UVAresp и UVBresp. А вот константы a, b, c, d необходимо вычислить. Для этого проще всего использовать отладчик. Необходимо получить данные uva, uvb, uvcomp1, uvcomp2, и в Excel рассчитать константы. Показывать их на дисплее неудобно — слишком мало разрядов. Можно использовать отладчик. Поставить точку останова после получения данных и посмотреть вычисленные значения. Также можно использовать возможность отключения ST-link от STM8 в процессе отладки и обратного подключения. При этом сеанс отладки не прерывается! Ещё один вариант — использовать STM8 STUDIO. Это специальная программа позволяет получить переменные в любой момент времени. Придётся немного модифицировать программу, например по кнопке записывать данные в отдельные переменные и в STUDIO или отладчике их уже прочитать.

Солнечный свет в своём спектре имеет УФ излучение, ИК излучение и видимое излучение. Чтобы рассчитать интенсивность УФ излучения, необходимо вычесть лишние данные про ИК излучение и видимое излучение. Для этого служат данные uvcomp1 (отвечает за видимое излучение) и uvcomp2 (отвечает за ИК излучение). Чтобы рассчитать константы в используемой формуле необходимы два искусственных источника света:

  • обычная лампа накаливания — она излучает в ИК спектре и видимом излучении;

  • светодиодная лампа — она излучает только в видимом излучении.

Начинаем со светодиодной лампы. Так как УФ излучение отсутствует, то соответствующий индекс будет равен нулю.


У светодиодной лампы нет ИК излучения, поэтому UVcomp2 будет равен 0. И в этом случае можно найти коэффициенты

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

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

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

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

Mcp3231 — измерение температуры термопары

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

[code]		buff[0] = (uint8_t) 0b00011100;
if( ! I2C_writenbyte((uint8_t)MCPaddr, buff, 2,0) )
{
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP(ENABLE);
return 0;
};


return 1;
[/code]

Передавать можно один байт или два. Учитывается только первый — байт конфигурации. Первые два бита задают использование режима усиления до 8 раз. Для измерения термопары нам такой точности не нужно, поэтому не будем использовать усиление. Следующие два бита задают разрядность, используем максимальную 18бит. И следующий бит включает непрерывный режим измерений. Скорость в таком режиме составляет 270 мс на одно измерение.

Данный ADC на своем борту имеет источник референсного напряжения и имеет очень высокую стабильность результата. Можно сказать он отдаёт результат до последнего бита. При использовании 18 битного разрешения можно измерить напряжение с точностью до 15мкВ. Этого более чем достаточно для термопары.

Чтобы прочитать данные с датчика необходимо просто получить от него 3 байта.

[code]	long tmcpT;

tmcpT = ((long)buff[0]<<24) + ((long)buff[1]<<16) +((long)buff[2]<<8);
tmcpT/=256;

e = (double) tmcpT/64;//512; //* 15.625/8000;
[/code]

18 бит данных содержит знак результата. Датчик дублирует этот бит до 24 бита, чтобы получить 24битное знаковое число. Однако в Си нет формата знакового числа 24 бита, а есть только 32 битное — long. Поэтому, все число необходимо сместить влево на 8бит, а потом поделить на 256.

Для вычисления температуры термопары необходимо провести вычисления с плавающей точкой. Поэтому переведём полученный результат в милливольты. Переменная «e» содержит нужное значение. В этой статье есть вся информация как посчитать температуру нужной термопары (у нас используется К типа) с помощью полиномов. ГОСТ Р. 8.585-2001 даёт нужные коэффициенты для разных диапазонов температур (стр. 71). В этом приборе будем использовать три диапазона температур: от -200 до 0 градусов, от 0 до 500 градусов и от 500 до 1372 градусов.

[code]const double cK[9]={
2.508355*10,
7.860106/100,
-2.503131/10,
8.315270/100,
-1.228034/100,
9.804036/10000,
-4.413030/100000,
1.057734/1000/1000,
-1.052755/10000/10000};
и т.д.
[/code]

Напишем свою функцию возведения в степень, типовая занимаем много места.

[code]double mypow(double a,int b) {
double x=a;
if (b==1) return a;
while (b--)
{
x *= a;
}

return x;
}
[/code]

И сами вычисления

[code]	t=0;
if (e>20)
{
t=t+cKf[0];
for (i=0;i<6;i++)
{
t=t + (cKf[i+1])*mypow(e,(i+1));
}
} else {
for (i=0;i<((e>0)? 9 : 8);i++)
{
t=t + ((e>0)?cK[i]:cKm[i])*mypow(e,i+1);
}
}
t*=100;
tmcpT = (long) t + bmeT;
mcpT = tmcpT;
[/code]

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

Спящий режим

В данном приборе используется много датчиков и ЖК экран. Все это нужно правильно «уложить» спать. Для этого используется функция sleep().

[code]u8 sleep(void) {
readytosleep = 1;

//off disp! need pullup PA1 !
GPIO_Init(GPIOD,ALL_PORTD,GPIO_MODE_IN_PU_NO_IT);
GPIO_Init(GPIOA,ALL_PORTA,GPIO_MODE_IN_PU_NO_IT);
GPIO_Init(GPIOC,ALL_PORTC,GPIO_MODE_IN_PU_NO_IT);
[/code]

Сначала выключим все выводы управления дисплеем. Переменная readytosleep нужна для того, чтобы выводы не были случайно включены в обработчике прерывания.

[code]	//nct datchik sleep
buff[0] = (uint8_t) 0b1;//config reg
buff[1] = (uint8_t) 0b1;//shutdown
if( ! I2C_writenbyte((uint8_t)NCTaddr, buff, 2,0) )
{
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP(ENABLE);
return 0;
};
[/code]

Усыпляем датчик температуры nct.

[code]	//uv datchik
buff[0] = (uint8_t) 0b0;//config reg
buff[1] = (uint8_t) 0b01000001;//low byte
buff[2] = (uint8_t) 0b0;//high byte - always 0
if( ! I2C_writenbyte((uint8_t)UVaddr, buff, 3,0) )
{
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP(ENABLE);
return 0;
};
[/code]

Следом УФ датчик. И потом внешний ADC.

[code]	//mcp adc
buff[0] = (uint8_t) 0b10001100;//one shot and sleep
if( ! I2C_writenbyte((uint8_t)MCPaddr, buff, 1,0) )
{
I2C->CR2 |= I2C_CR2_STOP;//I2C_GenerateSTOP(ENABLE);
return 0;
};

Delay(10);//need for end i2c!
[/code]

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

После выхода из сна, включаем все обратно.

[code]	halt();
Delay(100);

kn[0] = 0;

nctinit();
mcpinit();
uvinit();

GPIO_Init(GPIOD,ALL_PORTD,GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOA,ALL_PORTA,GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOC,ALL_PORTC,GPIO_MODE_OUT_PP_LOW_SLOW);

//on LCD
readytosleep = 0;
[/code]

Как изготовить наш прибор

Делаем плату и все запаиваем

  1. Подготовить или приобрести необходимые инструменты: все для пайки, ST-LINK (будет нужен для программирования и отладки МК)

  2. Внимательно прочитать статьи из раздела Обязательная теория.

  3. Скачать необходимые файлы по данному прибору с github.

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

  5. Приобрести все необходимые комплектующие.

  6. Запаять все компоненты на плату, смотри наше видео.

  7. Плата готова!

Для программирования вам понадобятся провода мама-мама. Вы можете их сделать сами из данного набора. Для программирования, можно сразу подключить питание с ST-Link, вместо аккумулятора и SWIM вывод.

Размещение УФ датчика в корпусе

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

Ширина отверстия надо датчиком должна быть строго рассчитана по формуле:


Можно использовать как круглое так и квадратное отверстие. Круглое сделать проще — просверлить. Также необходимо исключить проникновение света внутрь корпуса.

Сам датчик можно окружить ПВХ пластиком, стенки окрасить в черный цвет. В итоге у вас должно получиться примерно так:




Запаивание датчика УФ обычным паяльником

Если вы уже сделали себе паяльную станцию с паяльным феном, то лучше запаять этот датчик с ее помощью. Но если ее нет — то не беда, запаять этот датчик не сложно и обычным паяльником. При трассировке платы дорожки к данному датчику специально сделаны длиннее нужного размера. В этом случае остаётся много места для жала паяльника.


Начинать запаивание всей платы в этом случае надо с датчика. Тогда можно будет легко проверить, что все припаяно качественно. Для начала необходимо подготовить чистое рабочее место. Лучше взять чистый лист А4, аккуратно достать датчик и положить на лист ножками вверх. Намазать флюсом ЛТИ-120 и аккуратно залудить контактные площадки датчика — оставив небольшие бугорки олова. Делать это нужно быстро, чтобы не перегреть датчик. Остатки флюса необходимо смыть спиртом. Много олова оставлять не нужно, его должно быть совсем чуть-чуть. Точно также залуживаем посадочное место датчика на плате. Олово на посадочном месте совсем не оставляем, если оно лишнее — можно его разогнать по дорожкам в стороны.

Добавляем флюс на плату (лучше TR-RMA), кладем датчик на посадочное место, внимательно смотрим на лицевую сторону, чтобы не перепутать местами выводы (отпаять его будет сложно). У датчика сверху отлично видно с одной стороны 3 контактные площадки, а с другой 2-е. Вот по ним и ориентируемся. Проще всего совмещать вывод GND.




После того как вы спозиционировали датчик, не трогая сам датчик, прогреваем паяльником одну дорожку! Олово на датчике тоже в итоге расплавится и он припаяется. После припаивания одного контакта, можно проверить что все верно (не трогая датчик, можно оторвать контактную площадку, зрительно проверить как лежит датчик). В этот момент еще можно все вернуть назад. Если все хорошо, то точно также прогреваем остальные дорожки и все — датчик припаян. Проверить качество пайки очень легко. Достаточно взять обычный мультиметр в режиме проверки диода. Плюс поместить на GND и проверить все остальные выводы — должно быть 500-600 единиц (у датчика есть защитные диоды по всем входам). Далее нужно проверить что нет замыканий между близлежащими контактами.

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

Отладка программы

Если вы решили проводить отладку программы, то необходимо на момент отладки отключать ЖК дисплей, иначе в момент остановки МК на выводах может быть постоянное напряжение. Ориентироваться в этом случае можно по переменным в отладчике.

Если у вас есть желание освоить программирование микроконтроллеров, то рекомендуем написать программу «с нуля» самостоятельно.

Приобретённые навыки

Пайка: пайка паяльником LGA датчика микроразмера.

Схемотехника: LDO, I2C, типовая схема подключения STM8, подключение пищалки, работа с кнопками.

Программирование: I2C, изменение температуры термопары, интегральные датчики температуры, внешний ADC, датчик УФ излучения, расчёт индекса UVA UVB, сложная обработка кнопок, миллисекундный таймер, динамическая индикация ЖК индикатора, спящий режим.

Самостоятельная работа

Вы можете расширить функционал прибора в части измерения UV индекса:

  • реализовать измерение накопленного UV излучения и предупреждение о превышении норматива за день

  • рассчитать время пребывания на солнце с учётом типа кожи и крема от загара

  • сделать функцию I2C сканера — показывает с какими адресами есть датчики на шине I2C

  • сделать символьное отображение режимов

  • реализовать измерение и отображение отрицательной температуры

  • реализовать прочие расширенные функции данного прибора.

]]>
(Super User) Приборы Sat, 09 Feb 2019 15:19:15 +0000