Умный дом на stm32 своими руками

Добавил пользователь Владимир З.
Обновлено: 18.09.2024

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

Что такое STM32

STM32 – это платформа, в основе которой лежат микроконтроллеры STMicroelectronics на базе ARM процессора, различные модули и периферия, а также программные решения (IDE) для работы с железом. Решения на базе stm активно используются благодаря производительности микроконтроллера, его удачной архитектуре, малом энергопотреблении, небольшой цене. В настоящее время STM32 состоит уже из нескольких линеек для самых разных предназначений.

История появления

Серия STM32 была выпущена в 2010 году. До этого компанией STMicroelectronics уже выпускались 4 семейства микроконтроллеров на базе ARM, но они были хуже по своим характеристикам. Контроллеры STM32 получились оптимальными по свойствам и цене. Изначально они выпускались в 14 вариантах, которые были разделены на 2 группы – с тактовой частотой до 2 МГц и с частотой до 36 МГц. Программное обеспечение у обеих групп одинаковое, как и расположение контактов. Первые изделия выпускались со встроенной флеш-памятью 128 кбайт и ОЗУ 20 кбайт. Сейчас линейка существенно расширилась, появились новые представители с повышенными значениями ОЗУ и Flash памяти.

Достоинства и недостатки STM32

  • Низкая стоимость;
  • Удобство использования;
  • Большой выбор сред разработки;
  • Чипы взаимозаменяемы – если не хватает ресурсов одного микроконтроллера, его можно заменить на более мощной, не меняя самой схемы и платы;
  • Высокая производительность;
  • Удобная отладка микроконтроллера.
  • Высокий порог вхождения;
  • На данный момент не так много литературы по STM32;
  • Большинство созданных библиотек уже устарели, проще создавать свои собственные.

Минусы STM32 не дают пока микроконтроллеру стать заменой Ардуино.

Сравнение STM32 с Arduino

Сравнение STM32 с Arduino

По техническим характеристикам Ардуино проигрывает STM32. Тактовая частота микроконтроллеров Ардуино ниже – 16 МГц против 72 МГц STM32. Количество выводов GRIO у STM32 больше. Объем памяти у STM32 также выше. Нельзя не отметить pin-to-pin совместимость STM32 – для замены одного изделия на другое не нужно менять плату. Но полностью заменить ардуино конкуренты не могут. В первую очередь это связано с высоким порогом вхождения – для работы с STM32 нужно иметь базис. Платы Ардуино более распространены, и, если у пользователя возникает проблема, найти решение можно на форумах. Также для Ардуино созданы различные шилды и модули, расширяющие функционал. Несмотря на преимущества, по соотношению цена/качество выигрывает STM32.

Семейство микроконтроллеров STM32 отличается от своих конкурентов отличным поведением при температурах от -40С до +80 С. Высокая производительность не уменьшается, в отличие от Ардуино. Также можно найти изделия, работающие при температурах до 105С.

Обзор продуктовых линеек

STM32L

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

Серии STM32F-1, STM32F-2 и STM32L полностью совместимы. Каждая из серий имеет десятки микросхем, которые можно без труда поменять на другие изделия. STM32F-1 была первой линейкой, ее производительность была ограничена. Из-за этого по характеристикам контроллеры быстро догнали изделия семейства Stellaris и LPC17. Позднее была выпущена STM32F-2 с улучшенными характеристиками – тактовая частота достигала 120 МГц. Отличается высокой процессорной мощностью, которая достигнута благодаря новой технологии производства 90 нм. Линейка STM32L представлена моделями, которые изготовлены по специальному технологическому процессу. Утечки транзисторов минимальны, благодаря чему приборы показывают лучшие значения.

Важно отметить, что контроллеры линейки STM32W не имеют pin-to-pin совместимости с STM32F-1, STM32F-2 и STM32L. Причина заключается в том, что линейку разрабатывала компания, которая предоставила радиочастотную часть. Это наложило ограничения на разработку для компании ST.

STM32F100R4

Микросхема STM32F100R4 имеет минимальный набор функций. Объем флэш памяти составляет 16 Кбайт, ОЗУ – 4 Кбайт, тактовая частота составляет 12 МГц. Если требуется более быстрое устройство с увеличенным объемом флэш-памяти до 128 Кбайт, подойдет STM32F101RB. USB интерфейс имеется у изделия STM32F103RE. Существует аналогичное устройство, но с более низким потреблением – это STM32L151RB.

Программное обеспечение для работы с контроллером

Keil Uvision 4

Для ARM архитектуры разработано множество сред разработки. К самым известным и дорогостоящим относятся инструменты фирм Keil и IAR System. Программы этих компаний предлагают самые продвинутые инструментарии для оптимизации кода. Также дополнительно существуют различные системы – USB стеки, TCP/IP-стеки и прочие. Применяя системы Keil, пользователь получает хороший уровень технической поддержки.

Также для STM32 используется среда разработки Eclipse и построенные на ней системы Atollic TrueStudio (платная) и CooCox IDE (CoIDE) (бесплатная). Обычно используется последняя. Ее преимущества перед другими средами разработки:

  • Свободно распространяемое программное обеспечение;
  • Удобство использования;
  • Имеется много примеров, которые можно загрузить.

Единственный недостаток среды разработки CooCox IDE – сборка есть только под Windows.

STM32 Discovery

STM32 Discovery

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

Что потребуется для подключения STM32 к компьютеру

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

  • Сама плата STM32 Discovery;
  • Datasheet на выбранную модель;
  • Reference manual на микроконтроллер;
  • Установленная на компьютер среда разработки.

В качестве примера первая программа будет рассмотрена в среде CooCox IDE.

Первая программа

CooCox IDE

Обучение следует начинать с простейшего – с Hello World. Для начала нужно установить CooCox IDE на компьютер. Установка стандартная:

  • Скачивается программа с официального сайта;
  • Там нужно ввести адрес своей электронной почты и начать загрузку файла с расширением .exe;
  • Нужно открыть CooCox IDE вкладку Project, Select Toolchain Path;
  • Указать путь к файлу;
  • Снова открыть среду разработки и нажать View -> Configuration на вкладку Debugger;
  • Теперь можно записывать программу.

Когда программа установлена, ее нужно открыть. Следует перейти во вкладку Browse in Repository и выбрать ST – свой микроконтроллер.

Далее на экране появится список библиотек, которые можно подключить. Для первой программы потребуются системные CMSIS core и CMSIS Boot, библиотека для работы с системой тактирования RCC, GPIO для работами с пинами.

Сама программа пишется как и для Ардуино, нужно знать основы языка Си.

В окошке Project следует открыть main.c. В коде в самом начале следует подключить библиотеки кроме CMSIS (они уже автоматически подключены). Добавляются они следующим образом:

Затем добавляется тактирование порта в главной функции main. Какой контакт за что ответственен, можно просмотреть в даташите к микроконтроллеру.

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

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

Когда программа написана, ее можно загружать в контроллер. Если есть отладочная плата, ее нужно подключить через USB кабель и нажать Download Code To Flash. Если плата отсутствует, потребуется переходник, который нужно подключить к порту компьютера. Контакт BOOT 0 подключается к плюсу питания контроллера, а затем включается само питание МК. После этого начнется прошивка.

После этого нужно отключить питание контроллера STM32, закрыть Flash Loader Demonstrator, выключить переходник. Теперь можно снова включить микроконтроллер в обычном режиме. Когда программа будет загружена, светодиод начнет мигать.

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

Умный дом
Собираю систему "Умный дом",который управляет светом в доме.Всего три типа датчика:Датчик света на.

Умный дом на Arduino
Здравствуйте. Хочу сделать систему умный дом у себя в квартире. Она находится в стадии.

Система "умный дом"
Салют! Собираю систему "Умный дом" для дачи. Цель - управление отопительной и некоторой другой.

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

Alexey652, по ресурс/цена stm32 однозначно выигрывает

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

Дабы "подлить" интересностей в тему - рекомендую посмотреть в сторону

У нее нет Ethernet, но есть Wifi. Ну, и "нормальный" линукс со всеми преимуществами Python, Java, Web'а и т.д. станет вполне доступнее, чем допиливание ядра под вашу плату (это в случае, если вы остановитесь на Cortex M4 или M7). Ну, и стоимость платы (мне обошлась в 12 евро из Нидерландов) - вполне себе адекватна. Корпуса под нее тоже продаются.

Если же всё-таки выбирать Cortex, сложно ли будет реализовать обработку более 200 датчиков с использованием драйверов типа RS-232, RS-485? Как на этом контроллере прикрутить ethernet? Ещё на алике видел wi-fi и всякие RC модули , можно и их прикрутить ведь? Главное потом опрашивать все эти порты и получать с них сигналы.

сложно ли будет реализовать обработку более 200 датчиков с использованием драйверов типа RS-232, RS-485

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

Предложенная "малинка" - это тоже Cortex, только A7. Разница ее в отношении к предложенным STM32 - это энергопотребление и относительная сложность основной платы - ведь припаять LQFP64 по ЛУТ еще можно (жуб даю, лично делал), а вот собрать в домашних условиях 4х слойку и запаять BGA будет сложнее . Но. вы ведь не будете собираться умный дом "на коленке", верно?

Строго говоря, ни в каких STM32 он не встроенный. Встроенный он разве что в очень не многих моделях МК от TI, но возможно, выносной PHY не так уж дорог.

Выносной PHY не дорог, однако корпус в случае STM32 требуется как минимум LQFP64 и довольно много ног уйдет на реализацию интерфейса MII/RMII. Причем у STM на этих ногах сидит довольно много различной альтернативной периферии.
Такие контроллеры (STM32F107/207 и т.д.) довольно дороги, есть куда более дешевые STM32F105 скажем или вовсе STM32F030, однако Ethernet там нет. Решить проблему можно отдельным устройством Ethernet-COM или Ethernet-SPI. Второй случай сравнительно просто реализуется на W5500. На aliexpress готовый модуль на нем можно купить рублей за 300.

Для коммутации столь большого числа интерфейсов RS-232/RS-485, как и любых других я бы использовал FPGA/CPLD, причем даже их скорее всего потребуется несколько штук. Так что кроме работы на C понадобятся также навыки работы на VHDL/Verilog, программатор для этих микросхем и работа в ISE/Vivado/Quartus.

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

Для коммутации столь большого числа интерфейсов RS-232/RS-485, как и любых других я бы использовал FPGA/CPLD, причем даже их скорее всего потребуется несколько штук. Так что кроме работы на C понадобятся также навыки работы на VHDL/Verilog, программатор для этих микросхем и работа в ISE/Vivado/Quartus.

я не думаю, что ТС нужно 200 интерфейсов уарт. Речь скорее идет о двухстах устройствах - а это можно сделать на одной шине RS485 с репитерами. Проблема скорее заключается в том, что некоторые девайсы на RS232 понимают только p2p протокол, без адресов. Тогда да, для таких придется выделять отдельный интерфейс ( и то, есть варианты ).

лучше STM32F103. 105я отличается с ним только USB, вторым CANом и вторым АЦП, если не считать разных, удобных для этой периферии клоков и их делителей. Ну, и мелочевки, типа доп. таймеров. 103й намного дешевое 105го, а все преимущества 105го, судя по всему, не интересны ТС.

Поддержу. Кортекса М0 за гланды хватит этой задаче.
Хотя, какой "задаче"? Если задача опрашивать 200 датчиков, пусть даже асинхронно, пусть даже на скорости 19200, пусть даже по 3м-4м каналам UART и отдавать эти данные на стервер через Веб-запросы - M0 не хватит, но M1 справится. Ну, и конфиг STM32 + внешний Ethernet (можно даже с простеньким Веб-сервачком) мне нравится больше.

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

промышленные протоколы и интерфейсы (вроде RS485, это токовая петля) для такого и предназначены. Линия на 9600 кбод работает по витой паре до 1200м. Это по спецификации. Можно еще пробовать CAN, но у него расстояния по-меньше. Да и ТС подходит меньше.

Про наводки я имел в виду как раз RS-232. RS-485 к наводкам относится проще. Кстати, сколько приемников RS-485 можно объединить в одну ветвь при топологии "звезда", если заниматься терминированием? -))
А вот петли по питанию никак от интерфейса не зависят (кроме случая беспроводного/оптического, конечно). Одно дело соединить два устройства на расстоянии 500м с независимыми источниками питания, другое - соединить вместе 100 устройств, находящихся рядом, многие из которых как минимум по ВЧ (сеть - фильтр источника питания 1 - интерфейс - фильтр источника питания 2 - сеть. И так 100 раз в разных конфигурациях) будут давать контура-антенны. И что там наведется.
Выходов здесь - либо и питание, и интерфейс на все исполнительные устройства вести от центрального, соединяя все звездой (проблемы с терминированием RS-485), либо какие-то гальванические развязки, причем не конденсаторные - по ВЧ они не спасают. Если только колечки на провода.
Соединение всех устройств последовательно, чтобы можно было корректно использовать возможности RS-485 по использованию многоточечного соединения с точки зрения терминирования, может потребовать (а может и не потребовать, если все рядом) весьма внушительной длины не только сигнальных, но и питательных проводов - ведь их тоже нужно будет вести последовательно, от устройства к устройству, иначе опять замкнутые контура, уже по постоянному току (питание-интерфейс-питание). А на длинных проводах падает напряжение, значит нужно брать провода толще.

Тут вообще есть над чем подумать. С одной стороны, действительно, вариант 3-4 RS-485 на все исполнительные устройства оказывается весьма прост схемотехнически, но неудачный отказ хотя бы одного устройства (такой, при котором работа всей ветки RS-485 становится ненадежной - самый простой пример вылет приемопередатчика RS-485) приводит к отказу целой ветки. Если же делать независимый интерфейс на каждое устройство, то надо городить схему мультиплексирования/демультиплексирования и набор приемопередатчиков, зато надежность (точнее - работоспособность при частичном отказе) потенциально будет выше.

ИМХО: Два минуса вижу
1. Провода для питания все равно тащить.
2. При количестве модулей более 5 начинаются проблемы с работой (сеть тормозит)

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

Согласен, думать надо над реализацией, над топологией.

1. Датчики по любому питать, провода никуда не деть, но либо одна сеть 220, либо к ней еще плюсом сети 485, 232.
Тут кстати и над бестрансформаторными БП от 220 поразмыслить можно, потому как гальваноразвязка в принципе действия Wifi.


2. Сети на сотнях wi-fi точек строят, в инете есть прецеденты и описание решений. Главное у датчиков трафик не большой, им 1 Мбит/сек не нужен, да и опрашивать их по кругу можно, а не все разом, и не думаю, что они все о состоянии своем каждые 0,1 сек должны отчитываться.

В общем если подойти со смыслом, то вариант, не хуже 485 сети.

Ну а главное умный дом на базе Wi fi это красиво! можно отработать на себе и реализовать стартап.

Да, идейно я тоже подходил бы к этому скорее со стороны беспроводных решений. Каких именно - дело в общем-то десятое.
Требуется лишь обеспечить требуемую "дальнобойность". Я не знаю точно, но думаю, что "табличные" данные по дальности связи любого устройства "в идеальных" условиях (а в рекламе именно такие и даются) в случае применения их в условиях квартиры-дома нужно делить по крайней мере на 10, если не на 100.

он мне первым на ум пришел.
А вообще мы ушли от темы то. ТС по сути не интересует периферия, он за центральный МК голову ломает..

Я бы концептуально делал как предложил уважаемый Voland_ центральная управляющая плата на малинке с остальными датчиками связываемся по Wi-Fi, модули ESP могут работать и без дополнительного МК, к тому же есть ESP32 которые уже не так жестко работает с сетью.

Я бы концептуально делал как предложил уважаемый Voland_ центральная управляющая плата на малинке с остальными датчиками связываемся по Wi-Fi

Стоп-стоп! Я предлагал использовать малинку только в качестве трасфера к ближайшему wifi-роутеру . Я не говорил - что при этом надо строить сеть вифи на ней, и в конечном счете, считаю это бесполезной затеей. И вот почему.

Во-первых, в общем случае в многоквартирных домах случаются варианты "перегруза". Допустим, у меня в окружении сейчас 64-67(!) точек доступа, и это ж только открытые - вы меня понимаете. Перекрытие каналов составляет до 30ти девайсов на даже узкую полосу.
В частных домах это число конечно будет в разы меньше (думаю, штук 10-15 максимум и все слабые), но и строить на этом управление чего-либо я бы не стал. Сигналы управления должны работать "моментально", ну, то есть нажал "включить свет" и "да будет свет", в течение 50мс - иначе задержка будет видна. В перегруженном канале WiFi это может быть затруднено.

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

3) по поводу RS-485 и "звезд". Ну.. если честно - сложно сказать, что за каша получится в таком соединении. Я себе по квартире развел витую пару вдоль электропроводки (с коробками), но так и не дошло рук до реализации умного дома. Все что получилось - это была "умная розетка" на tiny2313, которой я смог по-управлять из другой комнаты. На 9600 не было ни одной ошибки команд. Что касается количества, то думаю, передатчики ограничены нагрузочной способностью. То есть 16 девайсов в одном сегменте. Есть драйверы и мощнее, но я такие не использовал.

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


Умный дом для себя
Добрый вечер всем. Появилось немного времени и решил я соорудить умный дом. То бишь АСУ ресурсами -.

Умный дом. Мои мысли
Всем привет! Должна была быть тема дипломной работы у меня "Умный дом", но так как специальность.


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

Дипломная работа "Умный дом"
Всем привет. Затеял я диплом под название "умный дом". Такие функции хочу реализовать: 1).

STM32H7

Концепция умного дома

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

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

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

Думаю, хватит нам на сегодняшний день теории, пора плавно переходить к проекту.

Проект мы создадим новый. Для этого запустим проектогенератов Cube MX и выберем наш контроллер


Подключим кварцевый резонатор и отладчик


Включим таймер в режиме PWM на 2 канал, так как первый у нас подключен к ножке PA0, которая всегда может пригодиться и лучше её не занимать


Как видим, у нас включилась ножка PA1


Вот её мы и подключим к сигнальному проводу ленты.

Переходим в Clock Configuration и настроим там всё следующим образом (нажмите на картинку для увеличения изображения)


Переходим в Configuration и настроим таймер


Почему именно 89? А это легко объяснимо. Во-первых к значению предделителя и периода мы всегда прибавляем 1. Поэтому предделитель у нас 1, то есть он не учитывается. А 89 + 1 = 90. Делим частоту тактирования шины таймера 72 на 90 и получаем ровно 0,8 МГц, что составляет 800 килогерц. Это то, что нам и надо!

Прерывания на таймер не включаем, они нам не потребуются. Переходим в закладку DMA и добавим канал DMA, настройки оставляем все по умолчанию (проверьте, что они именно такие). Переключаем только направление работы DMA — Memory To Peripheral


А прерывания на DMA включатся сами.

Вроде пока всё. Заполним настройки проекта


Сохраним настройки. сгенерируем проект для Keil, откроем его, настроим программатор на авторезет и настроим уровень оптимизации 1.

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

Чтобы применить DMA в PWM, да и вообще в любых режимах таймера, мы должны будем при старте таймера передавать некие данные, причём с применением DMA мы можем передавать целые массивы.

В случае с PWM в массиве, указатель на который мы передадим функции старта, будут находиться данные со скважностью, а точнее с периодом, в течение которого ножка, управляемая таймером, будет находиться в высоком состоянии. В нашем случае у нас общий период 90 (в настройках 89). Если мы передадим таймеру число 44 (что составляет 45 — 1, а это ровно половина периода), то мы получим период нахождения ножки в высоком состоянии — 45, следовательно, остальную часть периода, что будет тоже 45, ножка будет в низком состоянии. Таким образом мы получим ровные импульсы со скважностью 50 процентов. Но нам нужны не такие импульсы. Поэтому рассчитаем сначала значение нашего периода для передачи бита 0 в нашу шину. Оно по технической документации составляет 0,35 микросекунды. Общий период бита у нас составляет 1,25 микросекунды. Поэтому мы получим пропорцию: при периоде 1,25 — 0,35 мкс, а при 90 — X. Отсюда X = 90 * 0.35 / 1.25, что составит примерно 25. Но мы всегда вычитаем единицу, поэтому в массив для передачи бита 0 мы будем в соответствующую ячейку заносить число 24.

Давайте сразу создадим библиотеку под наши умные светодиоды. Состоять она будет из пары файлов ws2812.c и ws2812.h следующего содержания

ws2812.c:

extern TIM_HandleTypeDef htim2;

ws2812.h:

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


Давайте сразу создадим буфер для хранения периодов PWM. Буфер потребуется немаленький. Сейчас посчитаем. Во-первых, лучше сразу переждать больше 50 микросекунд, чтобы лента поняла, что это уже новые данные. Это можно сделать с помощью серии нулей. Период таймера у нас 1,25 микросекунд, я думаю 48 таких периодов будет вполне предостаточно. Поэтому, прежде чем организовывать буфер, мы в файле ws2812.h это пропишем в качестве макроса

Также добавим макрос количества управляемых светодиодов. У нас их 144

А теперь макрос длины нашего буфера, так как мы помним, что для каждого светодиода требуется по 24 бита, следовательно, в буфере должно быть 24 полуслова, так как одно полуслово — это настройки для передачи одного бита. А полуслово потому, что у нас 16-битный таймер

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

extern TIM_HandleTypeDef htim2;

uint16_t BUF_DMA [ARRAY_LEN] = < 0 >;

Перейдём в файл main.c и подключим там нашу библиотеку

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

Также подключим здесь наш глобальный буфер

extern uint16_t BUF_DMA [ARRAY_LEN];

/* USER CODE END PV */

Только весь он нам сейчас не потребуется. Мы пока хотим понять, как вообще работает PWM с применением DMA. Поэтому давайте пока передадим только один элемент буфера.

Для этого мы в самое начало буфера запишем какое-нибудь число. А давайте не какое-нибудь, а сразу число 26. Хотя мы для нуля рассчитали и 24, но правильнее работает именно 26.

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

/* USER CODE BEGIN 2 */

BUF_DMA[ 0 ] = 26 ;

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


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

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

/* USER CODE BEGIN 0 */

extern TIM_HandleTypeDef htim2;

/* USER CODE END 0 */

А затем в соответствующем месте в обработчике прерывания от DMA остановим таймер

void DMA1_Channel7_IRQHandler( void )

/* USER CODE BEGIN DMA1_Channel7_IRQn 0 */

HAL_TIM_PWM_Stop_DMA(&htim2,TIM_CHANNEL_2);

Вернёмся в файл main.c и в функции main() изменим количество элементов на 2. С одним не сработает

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


Соберём код, прошьём контроллер, и увидим, что у нас теперь уходит на информационный контакт только один импульс


Удалим строку с инициализацией первого элемента буфера

Теперь перейдём опять в заголовочный файл ws2812.h и напишем там макросы для настроек PWM для передачи нуля и единицы. Для единицы экспериментальным путём получено число 65

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

void ws2812_init( void )

int i;

for (i=DELAY_LEN;i

Напишем для данной функции прототип и вызовем её в файле main.c в функции main()

/* USER CODE BEGIN 2 */

ws2812_init();

В файле ws2812.h добавим макрос установки бита в каком-либо числе

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

void ws2812_pixel_rgb_to_buf_dma( uint8_t Rpixel , uint8_t Gpixel, uint8_t Bpixel, uint16_t posX)

volatile uint16_t i;

for (i= 0 ;i 8 ;i++)

if (BitIsSet(Rpixel,( 7 -i)) == 1 )

BUF_DMA[DELAY_LEN+posX* 24 +i +8 ] = HIGH;

> else

BUF_DMA[DELAY_LEN+posX* 24 +i +8 ] = LOW;

if (BitIsSet(Gpixel,( 7 -i)) == 1 )

BUF_DMA[DELAY_LEN+posX* 24 +i +0 ] = HIGH;

> else

BUF_DMA[DELAY_LEN+posX* 24 +i +0 ] = LOW;

if (BitIsSet(Bpixel,( 7 -i)) == 1 )

BUF_DMA[DELAY_LEN+posX* 24 +i +16 ] = HIGH;

> else

BUF_DMA[DELAY_LEN+posX* 24 +i +16 ] = LOW;

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

Напишем для данной функции прототип и вызовем её в файле main.c в функции main(), тем самым попробовав окрасить в какой-нибудь цвет самый первый светодиод нашей ленты, например, в зелёный. В вызове функции старта таймера, мы можем уже передавать в качестве аргумента весь наш буфер, так как он забит уровнями нуля

ws2812_pixel_rgb_to_buf_dma( 0 , 128 , 0 , 0 );

Подключим питание ленты, соберём код, прошьём контроллер и посмотрим результат


Давайте зажжём данный светодиод другим цветом, например красным (опять используем только половину свечения — 128)

ws2812_pixel_rgb_to_buf_dma( 128 , 0 , 0 , 0 );


Теперь попробуем окрасить синим цветом, и причём не этот, а например четвёртый светодиод

ws2812_pixel_rgb_to_buf_dma( 0 , 0 , 128 , 3 );


Давайте зажжём теперь разными цветами первые 4 светодиода, не забывая о нашем золотом правиле — общая сумма единиц свечения всех цветов светодиода не должна превышать 128, что составит 1/6 от интенсивности свечения полным белым цветом

ws2812_pixel_rgb_to_buf_dma( 128 , 0 , 0 , 0 );

ws2812_pixel_rgb_to_buf_dma( 0 , 128 , 0 , 1 );

ws2812_pixel_rgb_to_buf_dma( 0 , 0 , 128 , 2 );

ws2812_pixel_rgb_to_buf_dma( 64 , 64 , 0 , 3 );


Отлично! Значит мы движемся в правильном направлении.

Инициализировать каждый раз каждый светодиод не очень удобно. Поэтому давайте расширять функционал нашей библиотеки.

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

В файле ws2812.c добавим такой временный буфер, который будет двумерным, первым его размером будет количество светодиодов, а вторым — количество цветов

uint16_t BUF_DMA [ARRAY_LEN] = < 0 >;

uint8_t rgb_temp[ 12 ][ 3 ];

После функции ws2812_pixel_rgb_to_buf_dma напишем функцию подготовки временного буфера

void ws2812_prepareValue ( uint8_t r00, uint8_t g00, uint8_t b00,

uint8_t r01, uint8_t g01, uint8_t b01,

uint8_t r02, uint8_t g02, uint8_t b02,

uint8_t r03, uint8_t g03, uint8_t b03,

uint8_t r04, uint8_t g04, uint8_t b04,

uint8_t r05, uint8_t g05, uint8_t b05,

uint8_t r06, uint8_t g06, uint8_t b06,

uint8_t r07, uint8_t g07, uint8_t b07,

uint8_t r08, uint8_t g08, uint8_t b08,

uint8_t r09, uint8_t g09, uint8_t b09,

uint8_t r10, uint8_t g10, uint8_t b10,

uint8_t r11, uint8_t g11, uint8_t b11)

rgb_temp[ 0 ][ 0 ]=r00; rgb_temp[ 0 ][ 1 ]=g00; rgb_temp[ 0 ][ 2 ]=b00;

rgb_temp[ 1 ][ 0 ]=r01; rgb_temp[ 1 ][ 1 ]=g01; rgb_temp[ 1 ][ 2 ]=b01;

rgb_temp[ 2 ][ 0 ]=r02; rgb_temp[ 2 ][ 1 ]=g02; rgb_temp[ 2 ][ 2 ]=b02;

rgb_temp[ 3 ][ 0 ]=r03; rgb_temp[ 3 ][ 1 ]=g03; rgb_temp[ 3 ][ 2 ]=b03;

rgb_temp[ 4 ][ 0 ]=r04; rgb_temp[ 4 ][ 1 ]=g04; rgb_temp[ 4 ][ 2 ]=b04;

rgb_temp[ 5 ][ 0 ]=r05; rgb_temp[ 5 ][ 1 ]=g05; rgb_temp[ 5 ][ 2 ]=b05;

rgb_temp[ 6 ][ 0 ]=r06; rgb_temp[ 6 ][ 1 ]=g06; rgb_temp[ 6 ][ 2 ]=b06;

rgb_temp[ 7 ][ 0 ]=r07; rgb_temp[ 7 ][ 1 ]=g07; rgb_temp[ 7 ][ 2 ]=b07;

rgb_temp[ 8 ][ 0 ]=r08; rgb_temp[ 8 ][ 1 ]=g08; rgb_temp[ 8 ][ 2 ]=b08;

rgb_temp[ 9 ][ 0 ]=r09; rgb_temp[ 9 ][ 1 ]=g09; rgb_temp[ 9 ][ 2 ]=b09;

rgb_temp[ 10 ][ 0 ]=r10;rgb_temp[ 10 ][ 1 ]=g10;rgb_temp[ 10 ][ 2 ]=b10;

rgb_temp[ 11 ][ 0 ]=r11;rgb_temp[ 11 ][ 1 ]=g11;rgb_temp[ 11 ][ 2 ]=b11;

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

void ws2812_setValue( void )

uint8_t n= 0 ;

for (n= 0 ;n 12 ;n++)

ws2812_pixel_rgb_to_buf_dma( rgb_temp[ 0 ][ 0 ], rgb_temp[ 0 ][ 1 ], rgb_temp[ 0 ][ 2 ], n* 12 );

ws2812_pixel_rgb_to_buf_dma( rgb_temp[ 1 ][ 0 ], rgb_temp[ 1 ][ 1 ], rgb_temp[ 1 ][ 2 ], n* 12+1 );

ws2812_pixel_rgb_to_buf_dma( rgb_temp[ 2 ][ 0 ], rgb_temp[ 2 ][ 1 ], rgb_temp[ 2 ][ 2 ], n* 12+2 );

ws2812_pixel_rgb_to_buf_dma( rgb_temp[ 3 ][ 0 ], rgb_temp[ 3 ][ 1 ], rgb_temp[ 3 ][ 2 ], n* 12+3 );

ws2812_pixel_rgb_to_buf_dma( rgb_temp[ 4 ][ 0 ], rgb_temp[ 4 ][ 1 ], rgb_temp[ 4 ][ 2 ], n* 12+4 );

ws2812_pixel_rgb_to_buf_dma( rgb_temp[ 5 ][ 0 ], rgb_temp[ 5 ][ 1 ], rgb_temp[ 5 ][ 2 ], n* 12+5 );

ws2812_pixel_rgb_to_buf_dma( rgb_temp[ 6 ][ 0 ], rgb_temp[ 6 ][ 1 ], rgb_temp[ 6 ][ 2 ], n* 12+6 );

ws2812_pixel_rgb_to_buf_dma( rgb_temp[ 8 ][ 0 ], rgb_temp[ 8 ][ 1 ], rgb_temp[ 8 ][ 2 ], n* 12+8 );

ws2812_pixel_rgb_to_buf_dma( rgb_temp[ 9 ][ 0 ], rgb_temp[ 9 ][ 1 ], rgb_temp[ 9 ][ 2 ], n* 12+9 );

ws2812_pixel_rgb_to_buf_dma(rgb_temp[ 10 ][ 0 ],rgb_temp[ 10 ][ 1 ],rgb_temp[ 10 ][ 2 ],n* 12+10 );

ws2812_pixel_rgb_to_buf_dma(rgb_temp[ 11 ][ 0 ],rgb_temp[ 11 ][ 1 ],rgb_temp[ 11 ][ 2 ],n* 12+11 );

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

void ws2812_light( void )

Добавим на эти 3 функции прототипы и попробуем их применить в функции main() файла main.c.

Старый код, кроме инициализации, во второй пользовательской секции удалим и добавим новый, останется там теперь вот это

/* USER CODE BEGIN 2 */

ws2812_prepareValue( 128 , 0 , 0 ,

0 , 128 , 0 ,

0 , 0 , 128 ,

64 , 64 , 0 ,

0 , 64 , 64 ,

64 , 0 , 64 ,

96 , 32 , 0 ,

96 , 0 , 32 ,

32 , 96 , 0 ,

0 , 96 , 32 ,

0 , 32 , 96 ,

32 , 0 , 96 );

ws2812_setValue();

ws2812_light();

/* USER CODE END 2 */

В принципе, логический анализатор мы можем отключить. У нас всё правильно работает.

Соберём код, прошьём контроллер и получим следующий результат (нажмите на картинку для увеличения изображения)


Всё отлично работает и все блоки правильно повторяются.

Только вот смотреть картинку — это всё же не то. Поэтому в конце урока есть ссылка на видеоурок на Youtube, там уже будет гораздо красивее.

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

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

Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6

Программатор недорогой можно купить здесь ST-Link V2

Ленты светодиодные WS2812B разные можно приобрести здесь WS2812B

Читайте также: