Обвязка stm32 описание и инструкция по программированию. Ёмкостный датчик касаний без внешней обвязки на STM32 Discovery

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

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

Использовать достаточно мощный чип. Так как я длительное время использовал свою отладку на stm32f100, то по мере проектов я осознал, что хочу по максимуму использовать чипы. Так как возможностей последнего мне стало не хватать (мало ног и низкая частота 24МГц), то я решил пересесть на чуть больший чип: STM32F103 , на котором у меня уже была удачная отладка, но не получившая очень широкого применения.

Использовать аккумуляторы типоразмера 18650, которые мне так полюбились своим отношением ёмкость/цена.

Использовать встроенный контроллер питания от mini-usb на MCP73833 . Хотелось попробовать сделать заводскую плату с хорошим отведением тепла от микросхемы, и посмотреть на что получится разогнать данный контроллер заряда без внешнего радиатора.

Использовать так мною любимый TPS63000 для создания 3,3В линии. Это не очень эффективный контроллер питания с точки зрения тока холостого хода, но он работает как повышающий/понижающий преобразователь, что позволяет использовать весь заряд батареи при выходном высоком выходном токе(единицы ампер).

Сделать маркировку всех сигнальных выводов платы.

Ну и так по мелочи:

Кварцы 5032 (ни одного сбоя за всё время работы)

Smd0603+кондёры 0805 на самых маленьких футпринтах.

Разделение аналоговой и цифровой земель в устройстве

Разъёмы с шагом 2,54 тип мама(PBS20) для того, чтобы в моих макетках сделанных лутом уставлять имеющиеся у меня в большом количестве разъёмы тогоже типа, но папы(дешевле выходит).

Полностью одностороннюю пайку(за исключением разъёмов под аккумулятор).

Тестирование DC-DC преобразователя.

После этого я принялся за тестирование. Для этого специально купил резистор SQP5-4R7 чтобы протестировать контроллер DC-DC на ток ~1А. В результате тестов резистор прогревался до 110*С (узнавал по пирометру), что приводило к некоторой просадке сопротивления и росту тока до 1А.

В результате было установлено, что шумов дополнительных не появляется, а вся система работает как часы. При этом температура DC-DC преобразователя находится в диапазоне 35-40*С при температуре внешней среды +27*С. Конечно, я понимаю, что с ростом нагрузки будут рости и пульсации, но я думаю что когда будет от линии питания микроконтроллера работать и достаточная силовая нагрузка, то особая точность аналоговой части не потребуется.

Тестирование зарядного устройства.

Честно говоря это первый раз, когда я решил сделать промышленно изготовленную плату с MCP73833. В предыдущий раз я посмотрел то, что данный контроллер вообще заряжает и работать + ознакомился на практике с алгоритмом его работы. В данном случае, так как приближалась сдача диплома, а попробовать очень хотелось, я просто разобрал предыдущую плату и аккуратно перенёс все компоненты на новую. В результате, при заряде батарейки после предыдущего теста я зафиксировал, что при зарядном токе в 375мА температура контроллера заряда не достигает и 45*С. Это говорит о том, что можно смело перепаять резистор управляющий зарядом, чтобы увеличить зарядный ток. Я его подниму до 500мА, а вот дальше не пойду. Связано это не с теплом, которое будет выделятся на микросхеме, а с тем, что не все мои пяти вольтовые блоки питания для мобильников выдают более 500мА. Особых защит, в тех что я смотрел, нет, и это может привести к проблемам в электросети.

Недостатки разработанной платы.

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

У меня не хватило опыта в трассировке для того, чтобы установить в данной печатной плате выключатель on/off на батарейку. Конечно, я это отлично умею делать путём выдёргивания 18650 из разъёма или установкой специальной пластиковой пластины. Но это же костыль друзья мои. Хорошо бы было доделать выключатель.

Нет BMS у аккумулятора на плате, хотя он нужен. Чисто технически TPS63000 работает в диапазоне входных напряжений 1,8-6В. Это возможно при глубоком разряде аккумулятора будет приводить к его порче. Это проблема решается некоторой модификацией самой батарейки и установлением в неё дешёвого bms прямо на батарейку со впихиванием/подрезанием одного из контактов. Опять же не критично, но с костылями.

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

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

Недостаточная компактность платы. Текущие габариты платы 34х80 мм. Всегда хочется решение компактнее. Может и получится. Хотя с другой стороны, на обратной стороне печатной платы не так много и места.

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

Достаточно высокая цена устройства. Я делал прототипным производством в панели, по этому цена снижена, но один чёрт далека от китайской ардуинки/стмки за 200 руб.

Всем желающим такую штуку себе.

В настоящее время есть 2 таких платы, так что все желающие могу её приобрести за 1700 руб без доставки и аккумулятора 18650. Почему я не высылаю аккумулятор? – дело в почте России. Я был бы счастлив, если бы они пересылали аккумуляторы, хотя первому заказавшему я постараюсь отправить одну 18650 банку сразу с устройством бесплатно.

Связаться со мной можно по почте: [email protected]

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

Рисунок 1. Схема элементов STM32F103RC_board

Некоторая доработка. Версия 1.0.

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

С первого взгляда бросаются следующие вещи:

Нет «гребёнки» PBS-30 для вставки в печатную плату. К моему сожалению тут работает 2 фактора (они у меня закончились и заказчик попросил их не ставить.

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

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

Но дьявол часто кроется в деталях, так оказывается и тут. На данной плате я пробовал разные резисторы в управлении зарядным током. В итоге было выявлено, что микросхема MCP73833 на данной плате нормально держит ток в 800мА и при заряде с 2,5В Li-Ion батареек прогревается до 65-70*С. Конечно, по даташиту она работает с токами до 2А, но я честно пока не представляю как их реализовать на корпусе msop-10. Может быть в следующем корпусе, в котором эта проблема решается лучше, получится вытянуть 2А.

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

Предосторожность.

Во время проведения полной диагностической проверки я спалил один STM32F103RCT6. Как я это сделал:

Я взял обычный мультиметр и ткнулся им в резистор обратной связи. Пр этом TPS63000 видит просадку напряжения на обратной связи и начинает быстро повышать напряжение на своём выходе. В итоге, по проведённому тесту с отпаянным контроллером: напряжение в импульсе вырастало до 7В. При этом контроллер испытывал перенапряжение и умирал.

Забавно происходило потом: по входу на 3,6В контроллер начинал потреблять 0,6А. Это связано с тем, что в TPS63000 встроена защита по току в 2А, Именно данный ток и протекал через убитый микроконтроллер. При этом работоспособность всей оставшейся схемы сохранялась.

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

Упаковка отправленной платы

Отсылая данную плату моему коллеге , я решил её упаковать получше, чтобы Почта Р. не сломало всё. В итоге получилось так:





Казалось бы простая тема, а однако в комментах меня завалили вопросами как подключить микроконтроллер. Как подключить к нему светодиод, кнопку, питание. Что делать с AGND или AREF . Зачем нужен AVCC и все в таком духе. Итак, раз есть вопросы, значит тема не понятна и надо дать по возможности исчерпывающий ответ. Все описываю для контроллеров AVR, но для каких нибудь PIC все очень и очень похоже. Т.к. принципы тут едины.

Питание
Для работы микроконтроллеру нужна энергия — электричество. Для этого на него естественно нужно завести питалово. Напряжение питание у МК Atmel AVR разнится от 1.8 до 5 вольт, в зависимости от серии и модели. Все AVR могут работать от 5 вольт (если есть чисто низковольтные серии, то просьба уточнить в комментах, т.к. я таких не встречал). Так что будем считать что напряжение питания контроллера у нас всегда 5 вольт или около того. Плюс напряжения питания обычно обозначается как Vcc . Нулевой вывод (а также Земля, Корпус, да как только его не называют) обозначают GND . Если взять за пример комповый блок питания. То черный провод это GND (кстати, земляной провод традиционно окрашивают в черный цвет), а красный это +5, будет нашим Vcc . Если ты собираешься запитать микроконтроллер от батареек, то минус батареек примем за GND , а плюс за Vcc (главное чтобы напряжение питания с батарей было в заданных пределах для данного МК, позырь в даташите. Параметр обычно написан на первой странице в общем описании фич:

Operating Voltages
–1.8 — 5.5V (ATtiny2313V)
–2.7 — 5.5V (ATtiny2313)
Speed Grades
–ATtiny2313V: 0 — 4 MHz @ 1.8 — 5.5V, 0 — 10 MHz @ 2.7 — 5.5V
–ATtiny2313: 0 — 10 MHz @ 2.7 — 5.5V, 0 — 20 MHz @ 4.5 — 5.5V

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

Для работы контроллерам серии AVR достаточно только питания. На все входы Vcc надо подать наши 5 (или сколько там у тебя) вольт, а все входы GND надо посадить на землю. У микроконтроллера может быть много входов Vcc и много входов GND (особенно если он в квадратном TQFP корпусе. У которого питалово со всех сторон торчит). Много выводов сделано не для удобства монтажа, а с целью равномерной запитки кристалла со всех сторон, чтобы внутренние цепи питания не перегружались. А то представь, что подключил ты питалово только с одной стороны, а с другой стороны чипа навесил на каждую линию порта по светодиоду, да разом их зажег. Внутренняя тонкопленочная шина питания, офигев от такой токовой нагрузки, испарилась и проц взял ВНЕЗАПНО и без видимых, казалось бы, причин отбросил копыта. Так что ПОДКЛЮЧАТЬ НАДО ВСЕ ВЫВОДЫ Vcc и GND . Соединить их соответственно и запитать.

Отдельные вопросы вызвают AGND и AVCC — это аналоговая земля и питание для Аналого-Цифрового Преобразователя. АЦП это очень точный измеритель напряжения, поэтому его желательно запитать через дополнительные фильтры, чтобы помехи, которые не редки в обычной питающей цепи, не влияли на качество измерения. С этой целью в точных схемах проводят разделение земли на цифровую и аналоговую (они соединены должны быть только в одной точке), а на AVCC подается напряжение через фильтрующий дроссель. Если ты не планируешь использовать АЦП или не собираешься делать точные измерения, то вполне допустимо на AVCC подать те же 5 вольт, что и на Vcc , а AGND посадить на ту же землю что и все. Но подключать их надо обязательно!!! ЕМНИП от AVCC питается также порт А.

Warning!!!

В чипе Mega8 похоже есть ошибка на уровне топологии чипа — Vcc и AVcc связаны между собой внутри кристалла. Между ними сопротивление около (!!!) 5Ом Для сравнения, в ATmega16 и ATmega168 между Vcc и AVcc сопротивление в десятки МЕГА ом! В даташите на этот счет никаких указаний нет до сих пор, но в одном из топиков за 2004 год на AVRFreaks сказано, что люди бодались с цифровым шумом АЦП, потом написали в поддержку Atmel мол WTF??? А те, дескать, да в чипе есть бага и Vcc и AVcc соединены внутри кристалла. В свете этой инфы, думаю что ставить дроссель на AVcc для Mega8 практически бесполезно. Но AVcc запитывать надо в любом случае — кто знает насколько мощная эта внутренняя связь?

Простейшая схема подключения Микроконтроллера AVR приведена ниже:

Как видишь, добавился дроссель в цепь питания AVCC , а также конденсаторы. Хорошим тоном является ставить керамический конденсатор на сотню нанофарад между Vcc и GND у каждой микросхемы (а если у микрухи много вход питания и земель, то между каждым питанием и каждой землей) как можно ближе к выводам питания — он сгладит краткие импульсные помехи в шине питания вызыванные работой цифровых схем. Конденсатор на 47мКФ в цепи питания сгладит более глубокие броски напряжения. Кондесатор между AVcc и GND дополнительно успокоит питание на АЦП .

Вход AREF это вход опорного напряжения АЦП . Туда вообще можно подать напряжение относительно которого будет считать АЦП , но обычно используется либо внутренний источник опорного напряжения на 2.56 вольта, либо напряжение на AVCC , поэтому на AREF рекомендуется вешать конденсатор, что немного улучшит качество опорного напряжения АЦП (а от качества опоры зависит адекватность показаний на выходе АЦП ).

Схема сброса
Резистор на RESET . Вообще в AVR есть своя внутренняя схема сброса, а сигнал RESET изнутри уже подтянут резистором в 100кОм к Vcc . НО! Подтяжка это настолько дохлая, что микроконтроллер ловит сброс от каждого чиха. Например, от касания пальцем ножки RST , а то и просто от задевания пальцем за плату. Поэтому крайне рекомендуется RST подтянуть до питания резистором в 10к. Меньше не стоит, т.к. тогда есть вероятность, что внутрисхемный программатор не сможет эту подтяжку пересилить и прошить МК внутри схемы не удасться. 10к в самый раз.

Есть еще вот такая схема сброса:

Она замечательна чем — при включении схемы конденсатор разряжен и напряжение на RST близко к нулю — микроконтроллер не стартует, т.к. ему непрерывный сброс. Но со временем, через резистор, конденсатор зарядится и напряжение на RST достигнет лог1 — МК запустится. Ну, а кнопка позволяет принудительно сделать сброс если надо.

Задержка будет примерно T=R*C для данного примера — около секунды. Зачем эта задержка? Да хотя бы для того, чтобы МК не стартовал раньше чем все девайсы платы запитаются и выйдут на установившийся режим. В старых МК (АТ89С51 , например) без такой цепочки, обеспечивающей начальный сброс, МК мог вообще не стартануть.

В принципе, в AVR задержку старта, если нужно, можно сделать программно — потупить с пол секунды прежде чем приступать к активным действиям. Так что кондер можно выкинуть нафиг. А кнопку… как хочешь. Нужен тебе внешний RESET ? Тогда оставь. Я обычно оставляю.

Источник тактового сигнала
Тактовый генератор это сердце микроконтроллера. По каждому импульсу происходит какая нибудь операция внутри контроллера — гоняют данные по регистрам и шинам, переключаются выводы портов, щелкают таймеры. Чем быстрей тактовая частота тем шустрей МК выполняет свои действия и больше жрет энергии (на переключения логических вентилей нужна энергия, чем чаще они переключаются тем больше энергии надо).

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


Генератор может быть:

  • Внутренним с внутренней задающей RC цепочкой.
    В таком случае никакой обвязки не требуется вообще! А выводы XTAL1 и XTAL2 можно не подключать вовсе, либо использовать их как обычные порты ввода вывода (если МК это позволяет). Обычно можно выбрать одно из 4х значений внутренней частоты. Этот режим установлен по дефолту .
  • Внутренним с внешней задающей RC цепочкой.
    Тут потребуется подключить снаружи микроконтроллера конденсатор и резистор. Позволяет менять на ходу тактовую частоту, просто подстраивая значение резистора.
  • Внутренним с внешним задающим кварцем.
    Снаружи ставится кварцевый резонатор и пара конденсаторов. Если кварц взят низкочастотный (до 1МГц) то конденсаторы не ставят.
  • Внешним.
    С какого либо другого устройства идет прямоугольный сигнал на вход МК, который и задает такты. Полезен этот режим, например, если надо чтобы у нас несколько микроконтроллеров работали в жестком синхронизме от одного генератора.

У разных схем есть разные достоинства:
В случае внутренней RC цепи мы экономим место на плате, нам не нужно дополнительных деталек, но мы не можем развить максимальную частоту и частота немного зависит от температуры, может плавать.

У внешнего кварца отличные показатели точности, но он стоит лишних 15 рублей и требует дополнительных деталей и, что самое обидное, часто съедает пару ног I/O. Также на внешнем же кварце можно добиться максимальной производительности от МК. Частота МК определяется частотой на которую заточен выбранный кварц. Внешная RC цепь позволяет тикать генератору МК быстрей чем от внутренней, стоит дешевле кварца, но имеет те же проблемы со стабильностью частоты, что и внутренняя RC цепь.

Способы тактования МК описаны в даташите в разделе System Clock and Clock Options и всецело определяются конфигурацией Fuse Bit’s . Пока же я настоятельно рекомендую НЕ ТРОГАТЬ FUSE пока ты не будешь твердо знать что ты делаешь и зачем. Т.к. выставив что нибудь не то, можно очень быстро превратить МК в кусок бесполезного кремния, вернуть к жизни который будет уже очень непросто (но возможно!)

Подключение к микроконтроллеру светодиода и кнопки
Сам по себе, без взаимодействия с внешним миром, микроконтроллер не интересен — кому интересно что он там внутри себя тикает? А вот если можно как то это отобразить или на это повлиять…

Итак, кнопка и светодиод подключаются следующим образом:


Для кнопки надо выбраную ножку I/O подключить через кнопку на землю. Сам же вывод надо сконфигурировать как вход с подтяжкой (DDRxy=0 PORTxy=1). Тогда, когда кнопка не нажата, через подтягивающий резистор, на входе будет высокий уровень напряжения, а из бит PINху будет при чтении отдавать 1. Если кнопку нажать, то вход будет положен на землю, а напряжение на нем упадет до нуля, а значит из PINxy будет читаться 0. По нулям в битах регистра PINх мы узнаем что кнопки нажаты.

Пунктиром показан дополнительный подтягивающий резистор. Несмотря на то, что внутри AVR на порт можно подключить подтяжку, она слабоватая — 100кОм. А значит ее легко придавить к земле помехой или наводкой, что вызовет ложное срабатывание. А еще эти внутренние подтягивающие резисторы очень любят гореть от наводок. У меня уже с десяток микроконтроллеров с убитыми PullUp резисторами. Все работает, но только нет подтяжки — сгорела. Вешаешь снаружи резистор и работает как ни в чем ни бывало. Поэтому, для ответственных схем я настоятельно рекомендую добавить внешнюю подтяжку на 10кОм — даже если внутреннюю накроет, внешняя послужит. В процессе обучения на это можно забить.

Светодиод подключается на порт двумя способами. По схеме Порт-земля или Порт-Питание . В первом случае для зажигания диода надо выдать в порт лог1 — высокий уровень (примерно равен Vcc). Во втором случае для зажжения диода требуется выдать в порт лог0 — низкий уровень (около нуля). Для AVR разницы вроде бы нет, а вот многие старые серии микроконтроллеров вниз тянули куда лучше чем вверх, так что схема Порт-Питание распространена чаще. Я применяю и ту и другую схему исходя из удобства разводки печатной платы. Ну, а на программном уровне разницы особой нет.
Вывод порта для работы со светодиодом надо сконфигурировать на выход (DDRxy=1) и тогда в зависимости от значения в PORTxy на ножке будет либо высокий либо низкий уровень напряжения.

Светодиод надо подключать через резистор . Дело в том, что прямое сопротивление светодиода очень мало. И если не ограничивать ток через него, то он просто напросто может сгореть нафиг. Либо, что вероятней, пожечь вывод микроконтроллера, который, к слову, может тянуть что то около 20-30мА. А для нормального свечения обычному светодиоду (всякие мы не рассматриваем сейчас, эти монстры могут и ампер сожрать) надо около 3…15мА.

Так что, на вскидку, считаем:

  • Напряжение на выходе ноги МК около 5 вольт, падение напряжени на светодиоде обычно около 2.5 вольт (выше нельзя, иначе диод сожрет тока больше чем надо и подавится, испустив красивый дым)
  • Таким образом, напряжение которое должен взять на себя ограничительный резистор будет 5-2.5 = 2.5В.
  • Ток нам нужен 5мА — нефига светодиод зря кормить, нам индикация нужна, а не освещение:)
  • R=U/I= 2.5/5E-3 = 500Ом. Ближайший по ряду это 510 Ом. Вот его и возьмем. В принципе, можно ставить от 220 Ом до 680 Ом что под руку попадется — гореть будет нормально.

Если надо подключить много светодиодов, то на каждый мы вешаем по собственному резистору. Конечно, можно пожадничать и поставить на всех один резистор. Но тут будет западло — резистор то один, а диодов много! Соответственно чем больше диодов мы запалим тем меньше тока получит каждый — ток от одного резистора разделится между четырьмя. А поставить резистор поменьше нельзя — т.к. при зажигании одного диода он получит порцию тока на четверых и склеит ласты (либо пожгет порт).

Немного схемотехнических извратов или пара слов о экономии выводов

То что не удается запаять приходится программировать. (С) народная мудрость.

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

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

Главное, тут следовать двум правилам:

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

Приведу пример:

  • У есть у нас вывод на который повешан выход с некого датчика и кнопка. Выход с датчика может быть 0, 1 в активном режиме и Hi-Z когда на датчик не приходит сигнал Enable.
  • Кнопка же дает на линию жесткий 0, путем короткого замыкания.

Как это должно работать:
Скажем, основную часть времени у нас ввод микроконтроллера настроен на вход Hi-Z и мы снимаем показания с датчика на который подан еще и сигнал Enable. Когда нам надо опросить кнопку, то мы отбираем у датчика Enable и его выходы становятся в режим Hi-Z и нам не мешают. Вывод микроконтроллера мы переводим в режим Pull-Up и проверяем нет ли на входе нуля — сигнал нажатой кнопки. Проверили? Переводим вход МК в Hi-Z вход и подаем Enable на датчик снова. И так много раз в секунду.

Тут у нас возникает два противоречия:

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

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

  • Электрическое противоречие
    Если датчик выставит 1, а мы нажмем кнопку, то очевидно, что GND с Vcc в одном проводе не уживутся и кто нибудь умрет. В данном случае умрет выход датчика, как более слабый — куда там хилому транзистору тягаться с медной кнопкой.

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

    Если у нас, например, вывод датчика может дать не более 10мА, то резистор нужен такой, чтобы ток через него от Vcc до GND не превышал этой величины. При питании 5 вольт это будет 510Ом. Теперь, даже если на линии со стороны датчика будет лог1, высокий уровень, то нажатие на кнопку не вызовет даже искажения логического уровня т.к. резистор рассчитан с учетом максимальной нагрузки порта

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

Ну и несколько примеров нескольких функций на одной ноге:
Во-первых, ISP разьем . Я уже давным давно забыл что такое тыкать микроконтроллер вначале в колодку программатора, потом в плату, потом обратно и так по многу раз, пока прогу не отладишь. У меня на плате торчат 6 выводов ISP разьема и при отладке программатор вечно воткнут в плату, а программу я перешиваю порой по нескольку раз в 10 минут. Прошил — проверил. Не работает? Подправил, перепрошил еще раз… И так до тех пор пока не заработает. Ресурс у МК на перепрошивку исчисляется тысячами раз. Но ISP разьем сжирает выводы. Целых 3 штуки — MOSI, MISO, SCK.

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

На линии под ISP можно повесить и что нибудь другое, главное, чтобы при прошивке это ЧТОТО не начало ВНЕЗАПНО чудить . Например, управление стокилограммовым манипулятором висит на линии ISP и во время прошивки на него пошла куча бредовых данных — так он может свихнуться и кому нибудь бошку разнести. Думать надо, в общем. А вот с каким нибудь , который работает по шинному интерфейсу прокатит такая схема:

Переключаем выход с 0 на 1 и зажигаем то верхний то нижний диод. Если надо зажечь оба, то мы просто переводим вывод микроконтроллера в режим Hi-Z и словно нет его, а диоды будут гореть сквозным током. Либо быстро быстро переключать диоды между собой, в этом случае на глаз они будут оба гореть. Недостаток схемы очевиден — диоды нельзя погасить. Но если по задумке хотя бы один должен гореть, то почему бы и нет? UPD: Тут подумал, а ведь можно подобрать светодиоды и резисторы так, чтобы их суммарное падение напряжения было на уровне напряжения питания, а суммарные резисторы в таком случае загонят ток в такой мизер, что когда нога в Hi-Z то диоды вообще гореть не будут. По крайней мере на глаз это будет не заметно совсем. Разве что в кромешной тьме.

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

А применив сходную тактику к кнопкам можно либо упростить разводку, либо по трем ножкам развести 6 кнопок.
Тут тоже все просто — одна нога дает подтяг, вторая косит под землю. Нажатие кнопки дает просадку напряжения на подтягивающей ножке. Это чует программа, поочередно опрашивающая каждую кнопку. Потом роли ножек меняются и опрашивается следующая кнопка.

В шестикнопочном режиме ситуация схожая — одна ножка дает подтяг, другая землю, а третья прикидывается ветошью Hi-Z и не отсвечивает. Но тут есть один побочный эффект. Например, опрашиваем мы кнопку «В». Для этого у нас верхняя линия встает на вход с подтяжкой (PORTxy=1, DDRxy=0), средня дает низкий уровень на выходе (PORTxy=0, DDRxy=1), нижняя не участвует в процессе ибо стоит в Hi-Z (PORTxy=0, DDRxy=0). Если мы нажмем кнопку «В» то верхняя линия в этот момент просядет и программа поймет что нажата кнопка «В», но если мы не будем жать «В», а нажмем одновременно «Е» и «Б» то верхняя линия также просядет, а программа подумает что нажата «В», хотя она там и рядом не валялась. Минусы такой схемы — возможна неправильная обработка нажатий. Так что если девайсом будут пользоваться быдло-операторы, жмущие на все подряд без разбора, то от такой схемы лучше отказаться.

Ну и, напоследок, схема показывающая как можно обьединить кнопку и светодиод:


Работает тоже исключительно в динамике. То есть все время мы отображаем состояние светодиода — то есть выдаем в порт либо 0 (диод горит) либо Hi-Z (диод не горит). А когда надо опросить кнопку, то мы временно (на считанные микросекунды) переводим вывод в режим вход с подтягом (DDRxy=0 PORTxy=1) и слушаем кнопку. Режим когда на выводе сильный высокий уровень (DDRxy=1 PORTxy=1) включать ни в коем случае нельзя, т.к. при нажатии на кнопку можно пожечь порт.

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

Вот такие пироги. А теперь представьте себе прогу в которой реализованы все эти динамические фичи + куча своего алгоритма. Выходит либо бесконечная череда опросов, либо легион всяких флагов. В таких случаях простейшая диспетчеризация или кооперативная это то что доктор прописал — каждый опрос гонишь по циклу своей задачи и не паришься. Зато юзаешь везде какую-нибудь ATTiny2313 и ехидно глядишь на тех кто в ту же задачу пихает Mega8 или что пожирней:)

Я ничего не знаю и боюсь что либо сжечь, что мне делать???

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

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

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

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

То есть для того, что бы закрасить один пиксель по координате X=1 Y=5, нам будет нужно записать первый столбец нулевой страницы целиком X=1 Y=0-7. Для этого нужно или хранить видео буфер в контроллере; или перед записью считать блок, затем его модифицировать и только потом записать его; или хорошо представлять структуру экрана и учитывать её при выводе надписей, графиков, рисунков… В самом простом — текстовом — варианте работы с такими дисплеями, достаточно использовать шрифт кратный по высоте 8 точкам (1 странице) и выводить его кратно 8 точкам: 0,7,15…

Прошивка/библиотека

Библиотека для работы с дисплеями на контроллере ST7565R по параллельному интерфейсу 8080 в текстовом режиме была написана на основе даташита и исходника идущего с подобным дисплеем от другого производителя. Команды и были взяты и адаптированы из ранних моих проектов по дисплеям от и . Библиотека подходит для дисплеев на основе контроллера ST7565R. При её использование нужно учитывать особенности каждого отдельно взятого дисплея, например, то, какие линии управления у дисплея инвертированы, а какие нет. Так же она написана под
семейство контроллеров stm32f1xx, при использовании её на других контроллерах нужно изменить функцию инициализации выводов и define’ы отвечающие за управления выводами.

Библиотека содержит следующий функции:

lcd_init_pins (); Инициализация выводов дисплея
lcd_delay (unsigned long p ); Задержка
lcd_write_data (unsigned char dat ); отправка данных на дисплей
lcd_write_cmd (unsigned char cmd ); Отправка команд
lcd_Initial_Dispay_Line (unsigned char line ); Адрес первой строки дисплея
lcd_Set_Page_Address (unsigned char add ); Установка строки (заменена lcd_gotoxy)
lcd_Set_Column_Address (unsigned char add ); Установка столбца (заменена lcd_gotoxy)
lcd_Power_Control (unsigned char vol ); Управление питанием
lcd_Regulor_Resistor_Select (unsigned char r );
lcd_Set_Contrast_Control_Register (unsigned char mod ); Установка контрастности дисплея
lcd_init (void); Инициализация дисплея
lcd_clear (void); Очистка дисплея
lcd_gotoxy (unsigned char x ,unsigned char y ); Установка текстового курсора
x — столбец, y — строка (страница)
unsigned char lcd_symbol_decode (unsigned char c ); Декодирование сжатой ASCII таблицы
c — код символа в ASCII
lcd_putch (unsigned char c ); Вывод символа на дисплей
c — символ
lcd_putch_inv (unsigned char c ); Вывод инвертированного (закраска) символа
c — символ
lcd_puts (char *s ); Вывод строки
s — строка
lcd_puts_inv (char *s ); Вывод инвертированной строки
s — строка
void lcd_test (void); Тестовое заполнение дисплея подряд идущим символами
lcd_putch_big_prototype (unsigned char col ,unsigned char row ,char c , unsigned char inv ); Вывод символов х2 х4 х8 размера
col — ширина
row — высота
c — символ
inv — инверсия 0 — выкл, 1 -вкл
lcd_putch_big (char c ); Вывод символа размера х2
c — символ
lcd_puts_big (char *s ); Вывод строки х2
s — строка
lcd_puts_int2 (unsigned char v ); Вывод числа из двух цифр (простая функция)
v — число от 0 до 99
lcd_puts_int (int v ); Вывод числа.
v — число от -32768 до 32767
lcd_puts_long (unsigned long v ); Вывод длинного 4 Байтового числа (внимание! функция занимает много памяти)
v — число от -2147483648 до 2147483647

Инициализация выводов дисплея производиться путём настройки следующих define’ов в файле ST7565R.h , для stm32f1xx контроллеров.

#define INVERT_MODE 1 // перевернуть дисплей #define lcd_port_data GPIOB // порт линий данных #define lcd_port_data_rcc RCC_APB2Periph_GPIOB // тактирование порта линий данных #define lcd_port_data_offest 0 // смещение, если начальный вывод не 0 #define lcd_pins_data GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7; // линии данных, должны идти подряд по возрастающей #define lcd_port_control GPIOB // порт линий команд #define lcd_port_control_rcc RCC_APB2Periph_GPIOB // тактирование порта линий команд #define lcd_pin_RS GPIO_Pin_14 // линия выбора команды/данные #define lcd_pin_RW_WR GPIO_Pin_13 // линия чтение/запись #define lcd_pin_E_RD GPIO_Pin_12 // линия enable, разрешения #define lcd_pin_CS1 GPIO_Pin_11 // линия выбора кристала/дисплея #define lcd_pin_RST GPIO_Pin_15 // линия сброса

Если семейства контроллера отличается, то нужно будет подправить настройку выводов МК функция в файле ST7565R.c: lcd_init_pins, функции вывода данных и команд — lcd_write_data, lcd_write_cmd , а так же define управляющих линий в ST7565R.h .

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

Init(); // инициализация контроллера GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET); // включить светодиод delay_ms(100); // задержка 100 мс lcd_init_pins(); // инициализация выводв LCD delay_ms(100); lcd_init(); // инициализация LCD delay_ms(100); GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET); // выключить светодиод lcd_clear(); // очистка дисплея lcd_gotoxy(0,0); // установить курсора по координатам x=0 , y=0 lcd_puts("COG"); // вывод строки lcd_gotoxy(3,0); // установить курсора по координатам x=3 , y=0 lcd_puts_big("LCD128x64"); // вывод строки шрифтом x2 lcd_gotoxy(0,2); // установить курсора по координатам x=0 , y=2 lcd_puts("GS-GG1286456FFWJ-A-R"); lcd_gotoxy(0,3); lcd_puts("controller ST7565R on"); lcd_gotoxy(0,4); lcd_puts("mc stm32f103c8t6"); lcd_gotoxy(0,5); lcd_puts_big("Alex_EXE"); lcd_gotoxy(10,7); lcd_puts("сайт");

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

Статья обновлена 23.04.2016

18 комментариев на « Подключение COG LCD дисплея на ST7565R контроллере»

    Добрый день!
    Периодически посещаю ваш сайт и слежу за новыми обновлениями, т.к. сам начинал с pic-ов и в данный момент работаю с stm32.
    Очередная хорошая статья! Жаль, что чуть раньше не вышла)
    Пару месяцев назад тоже пришлось разбираться с контроллером ST7565 на экране w012864C2-TFH от WINSTAR и писать свою библиотеку под русские шрифты разной величины и стиля (подключение по spi).
    Очень помогла вот эта статья:
    http://edeca.net/wp/electronics/the-st7565-display-controller/
    и программа для генерации шрифтов на странице автора.
    Возможно вам тоже будет интересно.

    Удачи и успеха во всем.

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

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

    С Уважением, Юрий

    Сейчас использую CooCox, у него проблем с кириллицей не наблюдается. В Keil по началу библиотеку работы с дисплеем и все сообщения на русском писал в notepad++. Потом как то случайно, файл перевёлся, кажется, в юникод, из под него с кириллицей в Keil стало возможно работать. Точнее объяснить не смогу, т.к. уже забыл, по моему, на этот вопрос не раз давал ответ в комментариях к ранее описанным символьным дисплеям под stm32.
    Когда закончил изучение и перешел к проекту, над которым до сих пор работаю, то сразу оценил, что выйду за ограничение в 32КБ и перешел на другую IDE.

    Статью слегка дополнил.

    Владимир пишет 20.10.2016 в 20:15

    А нет ли у вас случайно конвертера изображений 128*64,чтобы на выходе получить массив,как в вашей программе Image generator 84*48 дисплея от нокиа.

    Как промню, у меня на сайте есть 2 программы image generator. Первая генерирует для нокии т.е. 84х48, это первая версия программы и та статья иметь пометку устарела. Вторая версия генерирует до 320х240.

    вряд ли есть что-то из паябельного дешевле дисплея от nokia 1202
    по цене 70! р.

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

    Алексей пишет 19.02.2017 в 00:40 Обвязка у подобных дисплеев примерно одинакова, но выводы могут располагаться по другому, название выводов одинаковы. Схема включения может немного различаться.
    Поэтому на выбранный дисплей в любом случае нужен даташит. Схемы включения всех дисплеев брал из официальной документации именно на конкретные марки.
    В статье видны 4 разные дисплея, у 3-х (на зеленой платке) схема включения и распиновка оказалась одинаковой и она отличается от GG1286456FFWJ-A-R.

    спасибо! очень помог

    Александр Д пишет 25.02.2018 в 18:34

    Добрый день!
    В моем устройстве был использован довольно редкий дисплейный модуль COG с матрицей 132×64 на контроллере Solomon SSD1815BZ. К сожалению ничего похожего в сети сейчас не обнаруживается. Максимально близкое это 132×64 на контроллере ST7567, где-то прочитал что у них система команд одинаковая. Однако по распиновке не у всех контактов есть прямое соответствие. Можете ли как-то помочь по данному вопросу? Т.е. имеется ли возможность один заменить другим? И что будет если установить дисплей на контроллере SSD1815BZ но с матрицей 128×64 — будет ли работать вообще?

    Данные дисплеи бывают с разными интерфейсами SPI, i2c, 8080. Некоторые поддерживают несколько, выбор производится соответствующими выводами.
    Для дисплеев с интересом 8080: идут 8 линий данных и 5 линий управления, у которых в разных источниках разные названия, даже у меня на сайте на принципиальной схеме название одно, а на pcb, которая была разработана много ранее, другое (использовались разные даташиты на разные дисплеи, а управление одинаковое); порядок у меня совпадает, ищите аналогию использую эти две картинки.
    CS — выбор кристалла
    Reset (RST) — сброс
    RS — выбор команд/данных
    E (A0) — разрешение
    RW/RD — запись/чтение
    При подключении подобных дисплеев так же нужно обратить внимание на линии подключения конденсаторного умножителя: CAP+- V1… Вот здесь нужен даташит. Но можно попробовать подобрать по аналогии, некоторая зависимость по названиям просматривается, но у таких дисплеев бывает несколько схем включения умножительных конденсаторов.
    По разрешению:
    отличие разрешения и смещение — не страшно, его можно настроить или во время инициализации (если есть соответствующие команды) или компенсировать при выводе данных на дисплей.
    В инициализации так же есть свои нюансы:
    Выбор напряжения умножителя и схемы включения конденсаторов умножителя, контрастность, начало вывода (угол), ориентация горизонтальная/вертикальная, развертка (чересстрочная, последовательная…)… Это уже будет зависеть от типа дисплея. Здесь критические могут быть только первые пункты, остальные можно будет без документации подобрать уже во время работы.

    Александр Д пишет 27.02.2018 в 18:54

    Спасибо за ответ!
    Вообще ситуация такова, что сильно ограничены в возможности внесения каких-либо программных изменений кода. Условно имеем «черный ящик» с 18-пиновым выходом и анод/катод для подсветки. В этот разъем был включен дисплей, который надо заменить. Даташиты, распиновка есть. На рынке нет ничего похожего… Максимально подходящий дисплей из доступных на ST6757 практически с аналогичной распиновкой (порядок пинов тот же, но обратный). Бустера (умножителя) на новом дисплее нет. Вопросы по соответствию контактов 1..5 SSD1815BZ и 10..12 ST6757 соответственно. Можно ли просто тупо включить другой дисплей в разъем через переходник и что подавать на контакты 10-12? Если у вас есть время и возможность помочь советом, напишите на email…

    Дисплей на SSD1815BZ
    1.V6 (This pin is the most negative LCD driving voltage)
    2.V5
    3.V4
    4.V3
    5.V2 (V2-V5 — These are the LCD driving voltage levels)
    6.C2P
    7.C2N
    8.C1N
    9.C1P
    10.C3N
    11.VEE
    12.VSS
    13.VDD
    14.SDA
    15.SCK
    16.D/C
    17./RES
    18./CS
    K
    A

    Дисплей на ST6757
    1.A
    2.K
    3./CS
    4./RES
    5. A0 (D/S)
    6.SCK
    7.SDA
    8.VDD
    9.VSS
    10.V0 (Positive LCD driver supply voltage)
    11.XV0 (Negative LCD driver supply voltage)
    12.VG (LCD driving voltage for segments)

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

Сами по себе микроконтроллеры работать не умеют. Им нужны всякие сопутствующие элементы. Вот к примеру, STM32L05 умеет работать с USB без всяких внешних кварцевых резонаторов, а STM32L152 - нет. Если мы планируем использовать более-менее точное время в наших проектах, то нам жизненно необходим внешний часовой кварцевый резонатор. Без него уход времени на 5-10 минут в сутки станет совершенно нормальным. И более того, он будет не постоянным и зависеть от температуры, напряжения питания и кучи других вещей.

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

Клоки, тайминги и шины

Одна из самых распространенных причин неработоспособности чего-либо - неправильная конфигурация частот и всего, что с этим связано. Наступило время раскрытия еще одной вкладки в кубе - Clock configuration. Я открыл новый проект, взял выбранный микроконтроллер, и включил rtc, usb и пару uart. Просто для примера. Открываем вкладку и видим примерно следующее

Слева «источники» тактовых сигналов, а справа - их «получатели». Пока сигнал дойдет с одного края до другого, он может пройти через умножители и делители, а может и напрямую. Для удобства красным подсвечивается то, что куб считает неправильным. Нет, вы можете нажать кнопку «сгенерировать код», скомпилировать полученное и залить (программист всегда прав!), но контроллер работать не будет.

Давайте начнем слева. У stm32 могут быть источники тактовых сигналов высокой (HS) и низкой (LS) частоты. Они могут быть внутренними (I) или внешними (E). Те, что сейчас в работе - подсвечиваются синим. Например, сейчас используется два источника - на 37 килогерц и на 16 мегагерц.

Теперь ваша задача пройти лабиринт, выставив все в нужных положениях. Задача осложняется тем, что можно выставить все в § «зеленое», но потом обнаружить, что частоту uart нельзя будет поднять больше 300бод. В общем, у программистов ST получилась этакая игрушка для взрослых. А теперь представьте, что раньше все это надо было рассчитывать руками, после неоднократного чтения документации и выяснить, будет ли это работать можно было только экспериментально.

В нашем случае все просто: изменив пару параметров в PLL (программируемый множитель), я легко добился исчезновения «красного». Почти.

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

Ок, идем на первую вкладку и около RCC видим такую картину

Disable - это понятно, выключено. Bypass - это прием тактового сигнала с внешнего источника. Ведь с stm можно сделать так, что бы куча микроконтроллеров работала в одном ритме, ибо это очень сильно облегчает вопросы взаимодействия чипов между собой. Например, так сделано на всех discovery платах, что я видел. Там в «программаторской» части стоит кварцевый резонатор, который «питает» чип программатора, а тот в свою очередь отдает тактовый сигнал чипу на плате. И ну последний пункт - это свой, так сказать, персональный кварцевый резонатор.

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

Как видно, частоту «часового» резонатора нам менять не дают, а вот частоту «быстрого» - сколько влезет. Опять придется идти в магазин и смотреть, какие есть, почем дают и подойдут ли нам.

Открываем даташит (я его на всякий случай положил в 02_switch) и ищем требования к кварцам. У кварцевых резонаторов, кроме частоты, есть еще два параметра – емкость и частота увода. Емкость в pF, нужна для расчета «запускающих» конденсаторов, а с ppm немного сложнее

Аббревиатура ppm означает parts per million или количество миллионных частей от основной частоты. Говоря иначе, погрешность 100 ppm для 100 МГц означает уход частоты на 100/1000000 часть от 100 МГц. Таким образом, частота может уйти на 100000000 * 100 / 1000000 = 10000 Гц (10 кГц, или 0.01 МГц), то есть финальная частота может быть любой в диапазоне 99.99 ... 100.01 МГц. Или говоря другими словами чем меньше ppm, тем лучше. Итак, смотрим в даташит и находим следующую табличку

Согласно ей у нас «высокоскоростной» кварц может быть от 0 до 32 мегагерц. Куб считает, что только до 24 можно (да и в других местах тоже идет речь про максимальную частоту в 24 мегагерца). Но я искренне рекомендую использовать параметры из Typ(ical) или «типичного» столбца. Как показывает моя практика, это наиболее беспроблемные цифры.

Говоря же про кварцы, то можно поиграться «соседними» по степени двойки частотами. То есть посмотреть на 2, 4, 8 и 16 мегагерц. Поиск осуществляем по уже описанной методике: дешевле, лучше и можно запаять руками.

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

Как видно, там нужны с нагрузочной емкостью 20pF. А вот мне попадались либо 16, либо 32. Чего делать? Как обычно, читать даташит и смотреть на строчку «AN2867 "Oscillator design guide for ST microcontrollers"» (можно взять там же, где и остальные дополнительные файлы к книге).

Если кратко, то там есть следующая схема

и вот такая вот сложная формула

Воспользовавшись знаниями математики за 5 класс среднеобразовательной школы (хотя могу и ошибаться), решим это сложнейшее уравнение:
16 = (Х*X)/(X+X)+3
16-3=X*X/2*X
13=X/2
X=26
Итак, ответ ответ – конденсаторы CL1/2 должны быть 26pf. Таких в природе нет, зато есть 27pF, что нам более чем подходит.
Теперь надо подсчитать, запустится ли генератор. Там чуть дальше есть формула

Считаем
G=4*60*(2*3.14*(8*(10^6))^2*((7+16)*10^(-12))^2)
Возведение в степень я обозначил как ^, её же использует и excel.
Запутаться очень легко, поэтому я сделал простую считалку в excel (файл называется resonator)

Туда подставляем найденные значения и смотрим на значение в ячейке Gain. Согласно документации, оно должно быть больше 5. И чем больше, тем лучше. У меня вот получилось. Хотя если брать резонатор с нагрузочной в 32pF, то будет меньше. Аналогичную процедуру надо будет проделать и с «часовым» кварцем. Возвращаемся к кубу и выставляем значения, попутно щелкая переключателями, что бы нигде красного не было.

Как видим, везде все стало хорошо и микроконтроллер будет работать на максимальной для него частоте - 32 мегагерца.

А проверить?

Но вот гложет меня, правильно ли я подсчитал все. Надо провериться. Достаю описание на stm32l-discovery и открываю там схему. Нахожу часть с резонатором

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

Продолжение следует...

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

Для этого выберем недорогой вариант платы и напишем прошивку в десяток-другой байт (да-да, мигание светодиодом в 2 килобайта сродни «Hello world» в сотни килобайт x86 для неумех). Также научимся писать программы на любом языке программирования для STM32.

Вступление

Какой тип микроконтроллеров изучать? Этот вопрос, по-моему, аналогичен вопросам типа «Какой язык программирования изучать?», «Какой иностранный язык учить?». ИМХО, изучать нужно тот, который нужнее в данную минуту, для данной задачи. Когда знаешь что-то одно, изучение второго дастся намного легче, а на счет третьего и не задумаешься.

Итак, в чем же сложность STM32? Наиболее часто звучит мнение о сложности программирования его периферии. Количество и тип периферии STM32 и AVR примерно одинаков. Конфигурирование ее также не сильно отличается. Так в чем же сложность? В микроконтроллерах STM32 всю периферию нужно предварительно включать. Вот и вся сложность.

Я сравниваю AVR с общественными зданиями: все двери нараспашку, везде мониторы сверкают рекламой и свет горит, а STM32 с личным домом: хочешь телевизор посмотреть - включи сначала, потом переключай каналы, захотел пи-пи - открой дверь и включи там свет, руки помыть - открой воду, и так далее. Не верите? Убедимся вместе.

Обзор платы

Я выбрал самую дешевую плату из предложенных на aliexpress (рисунок выше). Чуть дороже $2, 180 рублей в декабре 2015. На борту минимальная обвязка: два кварцевых резонатора - высокочастотный на 8МГц и часовой на 32.768Гц, кнопка «сброс», два джампера выбора режима загрузки, пара светодиодов - на питание и на ножке PC13 и набор разъемов: microUSB, отладочный, две гребенки для всех выводов микроконтроллера.

Дешевле только купить все детали, сделать самому плату и спаять. Чем шить и отлаживать? Если есть ST-LINK, то лучше им, нет - не беда, есть еще несколько вариантов, например через USB-USART переходник, нет и его - можно напрямую через USB, правда нужно самому написать драйвер для такого случая, никто пока не озаботился. ST-LINK достаточно дешев, да и входит во все платы серии DISCOVERY. Вот и я воспользовался таким.

Подключаем питание, светодиод весело мигает, плата исправна. Скачиваем и устанавливаем программу-программатор (масло-масляное) «STM32 ST-LINK Utility» (все программы и документы берем на сайте производителя). Пытаемся считать прошивку… Программа защищена от чтения. Видимо, недаром все говорят о сложности написания программ для STM32, даже китайцы защитили эту сверхсложную программу от взлома. Или там спрятана закладка-вирус? Разбираться не будем, снимаем защиту и получаем девственно чистый микроконтроллер STM32F103C8T6.

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

Давайте тоже помигаем светодиодом, сделаем, так сказать, реверс-инжиниринг в уме родной прошивки. Чем? Чтобы не городить споры по выбору среды разработки, я это сделаю в родной Visual Studio Community. Мне кажется, для Windows лучше для мужчины нет.

Как там программа мигания для ардуины? Конфигурируем ножку на выход и в цикле переключаем ее с нуля на единицу и обратно.
А как будет выглядеть она же для STM32? Намного сложнее. Сначала включим свет в комнате конфигурации ножек микроконтроллера, а затем «Конфигурируем ножку на выход и в цикле переключаем ее с нуля на единицу и обратно». Я понимаю, сложно… Но мы справимся.

В документе «RM0008. Reference Manual» на наш микроконтроллер посмотрим карту памяти для нужных нам регистров.

- Пойдем простым и логическим ходом.
- Пойдем вместе.

1. Включим тактирование порта C (наш светодиод висит на ножке 13 порта C). Смотрим документ. Нужный нам регистр RCC_ABP2ENR (переводим: регистр сброса и тактирования - вторая низкоскоростная шина периферии). Адрес порта - 0x40021018, нужный бит IOPCEN (порт ввода-вывода C - бит разрешения) четвертый - 0x00000010.

Отступление

У микроконтроллеров все как у взрослых процессоров. Есть высокоскоростная шина AHB aka «Северный мост» и низкоскоростная APB aka «Южный мост». Сам процессор микроконтроллера умеет все для ускорения работы: имеет предвыборку команд, конвейер выполнения команд. Нет кеша, но процессор не намного быстрее памяти, и чтение-запись в память успевает выполняться за один такт. Так что, можно сказать, вся память микроконтроллера - это один большой кеш. Ладно-ладно, не один и не большой. Два маленьких кеша.
Вся периферия отображена (маппирована) на адресное пространство. По сравнению с x86 нет команд in-out, но и Intel оставил их только для совместимости, сейчас они практически не используются.


2. Сконфигурируем ножку на вывод. Смотрим документ. Нужный нам регистр GPIOC_CRH (переводим: регистр порта ввода-вывода C - конфигурационный регистр для старшей половины ножек). Адрес порта - 0x40011004, за конфигурацию каждой ножки отвечают 4 бита, значение для переключения ножки на выход - 0001b, для ножки 13 значение - 0x00100000.

3. Как переключить логическое значение на ножке. Смотрим документ. Нужный нам регистр GPIOC_ODR (переводим: регистр порта ввода-вывода C - регистр вывода данных). Адрес порта - 0x4001100С, его значение напрямую выводится в ножки микроконтроллера, для ножки 13 значение - 0x00002000. Все готово для написания программы (не забыть выложить проект на github):

Int main(void) { *((int*)0x40021018) = 0x00000010; // RCC_APB2ENR = RCC_APB2ENR_IOPCEN *((int*)0x40011004) = 0x00100000; // GPIOC_CRH = MODER_OUTPUT_13 while(1) { *((volatile int*)0x4001100C) ^= 0x00002000; // GPIOC_ODR ^= BIT_13 int i; for (i=1000000; i>0; i--) ; } } extern int _eram; __attribute__ ((section(".isr_vector"))) int g_pfnVectors = { (int)&_eram, // начальное значение стека (int)main // Reset Handler };
С векторами прерываний, надеюсь все понятно? Мы используем только два из них, поэтому незачем занимать память пустышками. Все остальные прерывания включаются программно, не включали - значит они никогда не сработают. Исключение - третий вектор HardFault, если случилось - микроконтроллер неисправен или сбоит, для простых проектов (не космос-авиация, не медицина) можно не обрабатывать.

Это учебный проект, конечно следует оформить все адреса как символические константы в отдельный h-файл с большим количеством дефайнов, как это сделано в CMSIS. Можно взять их и приспособить для своих нужд. Для компиляции использую gcc, прошивка с помощью «STM32 ST-LINK Utility». Прошивка заняла 56 байт (привет, ассемблер).

Еще отступление

Еще одно утверждение о сложности STM32 - мало документации на русском языке. Спорно. Необходимы только два документа - Datasheet и Reference Manual на нужный микроконтроллер. Язык на котором он написан сложно назвать английским. Я изучал язык по непереведенным игрушкам, уровень английского остался на том же уровне, но даташиты я читаю без проблем, незнакомые термины понятны из контекста.



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

Во второй половине расскажу о программировании STM32 на любом языке программирования.

Теги: STM32, микроконтроллеры-это-просто, ардуино-не-надо