Здравствуйте, Хабровчане!
В преддверии Нового года хочу поделиться с вами опытом изготовления поделки, в основе которой лежит бесплатная "девборда" из условно одноразового изделия. В статье разберемся, как управлять адресными светодиодами при помощи микроконтроллера PUYA PY32F002BF и как отслеживать заряд батареи при помощи АЦП.
Лирическое отступление.
В наш век доступности всего и вся может возникнуть вопрос - "А зачем ты это делаешь?". Именно этот вопрос задал мне сын, глядя на мигающие огоньки. Ведь можно купить адресную гирлянду на ёлку с кучей режимов и приложением на телефон. Я задумался и ответил: "Хочу чтобы эта штучка мигала именно так, как я хочу". Потом ещё подумал и пришел к выводу, что скорее всего найденная платка мне не давала покоя. Разобрал, увидел контроллер, светодиоды - наверное можно управлять и отложил в ящичек. Потом коллега по работе нашел такую-же платку и предложил подпаять STMку, дабы сделать условную ёлку в виде платы в USB разъем для усиления новогоднего настроения на рабочем месте. Уже звучало как вызов. Зачем припаивать, если уже всё есть на плате. А вызовы и ответы на них - это эволюция. С интересом для себя обнаружил, что приобретенные знания в таких, казалось бы, бесполезных проектиках находят применение в более сложных, нужных и оплачиваемых задачах.
Итак, приступим. Для быстрого старта необходимо ознакомиться со статьёй. Там описано как настроить цепочку инструментов и подготовить народный "свисток" ST-LINK V2.
Готовим железо
Аккуратно разбираем найденное (отобранное с лекцией о вреде пагубных привычек у друга/подруги/подростка), пока ещё не запрещенное в Российской Федерации, одноразовое изделие. Я аккуратно пропиливал (не насквозь) часть шва пластикового корпуса и вскрывал поворотным движением отвертки в прорези. Плата держится на двух саморезах. Саморезики в коллекцию, остальное утилизировать согласно правилам раздельного сбора.
Запись в журнале по требованиям безопасности. Плановый инструктаж о мерах предосторожности при работе с литий-содержащими элементами питания. Такие элементы пожароопасны и требуют осторожности в обращении обученным и допущенным персоналом!
Методом пайки отсоединяем аккумулятор (не замкните жалом контактные площадки!) от платы, и убираем его от лиц, которые не сдали на допуск и не расписались в журнале по ТБ. Проводим осмотр платы. Определяем маркировку микроконтроллера, ищем документацию. Находим выводы для программатора.
Вооружившись тестером в режиме прозвонки, ищем места, где подпаять провода. На этом этапе я был слегка огорошен. Первый и пятнадцатый вывод не разведены, ровно как и выводы данных на USB разъеме. Скорее всего, на линию монтажа контроллеры идут уже прошитые. Самая сложная часть этого проекта - подпаяться к 1 и 15 выводам. Я сделал это следующим образом. Методом скрайбирования подготовил две площадки в свободном месте платы для пайки проводов. К этим площадкам припаял две жилы провода (приблизительно 0,15 мм). Вторые концы паял к выводам микросхемы тыкая концом жала в вывод. Паял без микроскопа. Первый вывод получилось сразу, второй с третьей попытки. Проверяем прозвонкой.
Теперь самое время вставить программатор и послать команду pyocd erase -t py32f002bx5 --chip --config ./Misc/pyocd.yaml.
В отличии от моего предыдущего опыта, не пришлось ловить момент старта заводской прошивки. Чип стёрся сразу, можно продолжать.
Подключаем ленту
В заводской топологии лента подключена к 7 выводу (PB5). Согласно даташиту, этот вывод может быть: SPI_NSS, USART_RX, TIM1_CH3, TIM14_CH1. И тут я не увидел быстрого способа запустить ленту. Скорее всего, китайцы управляли лентой при помощи ШИМа на таймере и DMA (как тут). Это решение мне нравится, так как не надо менять топологию. Но быстро я это не освою, а у нас же проект выходного дня. Готовое решение я нашел у IOsetting, путь к примеру - Examples/PY32F07x/HAL/SPI/WS2812_LED. Управление лентой строится на посылке нужных сигналов через выход SPI. Я подключил ленту к 20 выводу (PA7 - SPI_MOSI, дорожку от PB5 перерезал). Самое время написать встраиваемое специальное программное обеспечение.
Программируем программу
Все файлы проекта располагаются в папке User.
В Makefile раскомментируем наш микроконтроллер - MCU_TYPE = PY32F002Bx5
. В файле py32f002b_hal_conf.h откроем необходимую нам периферию (ADC и SPI - #define HAL_ADC_MODULE_ENABLED
и #define HAL_SPI_MODULE_ENABLED
). В файле 32f002b_hal_msp.c добавим инициализацию и деинициализацию SPI.
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
GPIO_InitTypeDef GPIO_InitStruct; // Структура для хранения настроек
if (hspi->Instance == SPI1)
{
__HAL_RCC_GPIOA_CLK_ENABLE(); // Тактирование
__HAL_RCC_SPI1_CLK_ENABLE();
/* PA7 -> AF0 -> MOSI */
GPIO_InitStruct.Pin = GPIO_PIN_7; // Настройка режима SPI
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi)
{
if (hspi->Instance == SPI1)
{
__HAL_RCC_SPI1_FORCE_RESET();
__HAL_RCC_SPI1_RELEASE_RESET();
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_7);
}
}
В фале ws2812_spi.h задаем количество светодиодов в ленте - #define WS2812_NUM_LEDS 9
.
Так как работа с адресными лентами хорошо описана, и информация доступна в сети, в этой статье не будем рассматривать это подробно. Нас интересуют функции установки цвета светодиода ws2812_pixel(uint16_t led_no, uint8_t r, uint8_t g, uint8_t b) и отправки сформированного массива s2812_send_spi().
В исходном варианте схемы питание на светодиоды подается через транзистор Q3 (видимо, для возможности отключения ленты в момент бездействия изделия). Транзистор управляется через PB3. Этот вывод сконфигурируем как GPIO. В файле main.c добавим включения заголовочных файлов и функции конфигурации портов ввода-вывода и SPI (APP_GpioConfig()
). Из примера в главном цикле запустим простое изменение цвета всей ленты.
....
int main(void)
{
uint8_t i = 0, r = 0, g = 0x60, b = 0xC0; // Цвета со смещением, иначе у нас будет
// только белый цвет
HAL_Init();
APP_GpioConfig(); // Настраиваем ранее описанную перифериию
HAL_GPIO_WritePin(GPIOB,GPIO_PIN_3,0); // включаем ленту - 0, выключаем - 1
ws2812_pixel_all(r, g, b);
ws2812_send_spi();
while (1)
{
i = (i + 1) % WS2812_NUM_LEDS;
ws2812_pixel(i, r++, g++, b++); // Устанавливаем цвет
ws2812_send_spi(); // Отправляем данные
HAL_Delay(20);
}
}
...
Компилируем и прошиваем. После нескольких проб и ошибок (например, я не описывал прототип функции в самом начале и пытался к ней обращаться) лента радостно засветилась.
Где взять "эффекты"?
Простое изменение цвета это хорошо, но одинаково и скучно. Я стал искать, как без библиотек (типа NeoPixel) реализовать что-то весёлое и новогоднее (типа радуги). Поиски привели к LED Strip Effects Generator. Это конструктор, в котором можно задать параметры своей ленты, выбрать эффект (или несколько) и на выходе получить код для Arduino. После небольших правок (я поменял функции отправки и некоторые параметры эффекта) мне удалось запустить радугу на своем устройстве. Далее, чтобы не загромождать тут всё кодом, сошлюсь на github этого проекта.
Измеряем напряжение питания
Для контроля заряда аккумулятора воспользуемся АЦП. Имея список каналов АЦП и соответствующих им ножек микроконтроллера, я стал искать делители. И, похоже, что замер напряжения происходил в момент включения нагревательных элементов, потом сохранялся и отображался с учетом логики заводской программы. Альтернативой этого метода выступил способ измерения каналом ADC_CHANNEL_VREFINT. Для этого была добавлена функция конфигурации АЦП (APP_AdcConfig(void)
). Сам замер максимально прост.
APP_AdcConfig();
HAL_ADC_Start(&AdcHandle);
HAL_ADC_PollForConversion(&AdcHandle,1000000);
adc_value[0]=HAL_ADC_GetValue(&AdcHandle);
T_VCC=adc_valie[0];
В даташите есть формула пересчета попугаев в Вольты, но без внятных средств отладки (нужно было подпаивать UART), я так и не получил внятных результатов. Значения в отсчетах я нашел методом научного перебора (менял напряжение питания на лабораторнике и смотрел сколько у меня загорелось светодиодов, попутно меняя условия их зажигания в попугаях). Этот код я сюда конечно же вставлять не буду, но все желающие могут его увидеть на указанном выше гите. Последним вопросом для меня осталась индикация заряда. Процесс заряда организован при помощи Li-Polymer Charger LP-4068. В оригинальной схеме пятый вывод LP-4068 подключен к входу микроконтроллера и программно отслеживается. Я посмотрел осциллографом эту ножку при подключенном внешнем питании. На ней появлялся периодический импульс, этот импульс, скорее всего, включал светодиод.
Быстрого решения использовать это я не нашел (скорее всего используется внешнее прерывание-установка флага-контроль по времени). Но, примерно на этом этапе, выяснилось, что у микроконтроллера есть встроенный датчик температуры. А в процессе заряда LP-4068 нагревается. По повышению температуры я могу показывать индикацию заряда. Датчик подключен к тому-же каналу АЦП, что и ADC_CHANNEL_VREFINT. В зависимости от того, что требуется измерить (напряжение питания или температуру), нужно переконфигурировать канал АЦП. Общий алгоритм работы выглядит так:
после подачи питания настраивается периферия, и мы попадаем в главный цикл;
если напряжение питания больше 2.9 В и температура не выше 27 градусов - включаем радугу на минуту (радуга постепенно ускоряется, потом горят синие и красные огни, как мигалка полиции);
выключаем ленту на 30 секунд;
включаем индикацию заряда, потом температуры.
повторяем цикл.
При нагреве больше 27 градусов работает только индикация заряда и температуры. При напряжении питания 2.9 В и ниже грустно моргает один светодиод красным цветом. Ниже видео основного режим работы в проектном положении на ёлке. Осторожно, вспышки яркого света! (очень сложно телефоном снять, в живую цвета другие)
Ниже индикация заряда и температуры. При нагреве, синие светодиоды постепенно выключаются, остаются только красные. В качестве корпуса я использовал прозрачный "желток" от шоколадного яйца (покрасил внутри акрилом из баллончика).
На сколько автономно?
Потребление схемы в самом затратном режиме - около 47 мА. На комплектной батарее работает чуть больше 12 часов. Для увеличения времени работы можно уменьшить яркость, увеличить время простоя, и при этом переводить контроллер в режим низкого энергопотребления. По даташиту в режиме СТОП обещают 1.7 мкА.
Заключение
"Шарик" получился довольно необычным. Те, кто его видят, спрашивают что это и как это. Ещё больше удивляются, из чего он сделан. Что ещё сделать из этой платки? Если напечатать вращающееся основание, то можно получить круговой экран с механической разверткой. Схема работает от 2.4 Вольт. Можно сделать значок или кулончик на Coin Cell Challenge.
Желаю творческих успехов в наступающем Новом году!
Скрытый текст
Рассказываю про подобное в своем канале - https://t.me/modelistconstruktor