В предыдущей части урока мы познакомились с цветовой моделью HSV, настроили проект, написали функцию конвертирования данных цветового пространства HSV в RGB, а также написали первый тест.
Попробуем изменить количество радуг, поставим или 2 или 4
ws2812_test01(2,2);
ws2812_test01(4,2);
Продолжаем дальше. Идём в файл ws2812.c и добавим следующий тест, который будет также вращать радугу, но в обратном направлении
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//------------------------------------------------------------------ void ws2812_test02(uint8_t n, uint8_t nm) { uint16_t i; uint16_t j; for(i=0;i<LED_COUNT;i++) { back_buf[i].H = i * 360 / LED_COUNT* n % 360; back_buf[i].S = 255, back_buf[i].V = BRIGHT; } for(j=0;j<LED_COUNT*nm;j++) { memcpy((void*)&back_buf_temp,(void*)&back_buf[LED_COUNT-1],4); for(i=0;i<(LED_COUNT-1);i++) { memcpy((void*)&back_buf[LED_COUNT-i-1],(void*)&back_buf[LED_COUNT-i-2],4); } memcpy((void*)&back_buf[0],(void*)&back_buf_temp,4); ws2812_hsv_to_rgb(); ws2812_rgb_copy_buf_to_dma(); ws2812_light(); HAL_Delay(20); } } //---------------------------------------------------------------------------- |
Добавим прототип, а в файле main.c в бесконечном цикле функции main() закомментируем первый тест и вставим второй
1 2 |
//ws2812_test01(1,2); ws2812_test02(1,2); |
Соберём код, прошьём контроллер и посмотрим результат. Показывать его нет смысла, так как статически это не будет отличаться от первого теста.
Поэтому идём в файл ws2812.c и добавим ещё один тест, в котором плавно помигаем всей лентой, изменяя параметр, отвечающий за яркость
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
//---------------------------------------------------------------------------- void ws2812_test03(uint8_t n, uint8_t nm) { uint16_t i; uint16_t j; uint16_t k; uint8_t yy; for(i=0;i<LED_COUNT;i++) { back_buf[i].H = i * 360 / LED_COUNT* n % 360; back_buf[i].S = 255, back_buf[i].V = BRIGHT; } for(yy=0;yy<nm;yy++) { for(j=0;j<=32;j++) { for(i=0;i<LED_COUNT;i++) { k = BRIGHT * (32-j) / 32; back_buf[i].V = k; } ws2812_hsv_to_rgb(); ws2812_rgb_copy_buf_to_dma(); ws2812_light(); HAL_Delay(10); } for(j=0;j<=32;j++) { for(i=0;i<LED_COUNT;i++) { k = BRIGHT * j / 32; back_buf[i].V = k; } ws2812_hsv_to_rgb(); ws2812_rgb_copy_buf_to_dma(); ws2812_light(); HAL_Delay(10); } } } //---------------------------------------------------------------------------- |
Мы видим, что с использованием пространства HSV изменение яркости также происходит намного легче. В первом параметре также количество радуг, а во втором — количество миганий.
Напишем прототип на данную функцию в заголовочном файле и вызовем данную функцию в бесконечном цикле функции main() файла main.c
1 2 |
//ws2812_test02(4,2); ws2812_test03(4,6); |
Соберём код и прошьём контроллер. Посмотрим результат
Всё работает.
Следующий тест
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
//---------------------------------------------------------------------------- void ws2812_test04(uint8_t n, uint8_t nm) { uint16_t i; uint16_t j; uint16_t k; uint8_t yy; for(i=0;i<LED_COUNT;i++) { back_buf[i].H = i * 360 / LED_COUNT* n % 360; back_buf[i].S = 255, back_buf[i].V = 64; } ws2812_hsv_to_rgb(); for(yy=0;yy<nm;yy++) { for(j=0;j<=64;j++) { for(i=0;i<LED_COUNT;i++) { if((i%(LED_COUNT/n*2)) < LED_COUNT/n) { k = BRIGHT * (64-j) / 64; } else { k = BRIGHT * j / 64; } back_buf[i].V = k; } ws2812_hsv_to_rgb(); ws2812_rgb_copy_buf_to_dma(); ws2812_light(); HAL_Delay(10); } for(j=0;j<=64;j++) { for(i=0;i<LED_COUNT;i++) { if((i%(LED_COUNT/n*2)) < LED_COUNT/n) { k = BRIGHT * j / 64; } else { k = BRIGHT * (64-j) / 64; } back_buf[i].V = k; } ws2812_hsv_to_rgb(); ws2812_rgb_copy_buf_to_dma(); ws2812_light(); HAL_Delay(10); } } } //---------------------------------------------------------------------------- |
В данном тесте мы плавно мигаем каждой радугой, только когда чётная радуга по яркости убывает, нечётная возрастает, поэтому лучше использовать чётное количество радуг, хотя будет работать и с нечётным. В параметрах у нас также количество радуг и количество миганий.
Вызовем функцию теста
1 2 |
//ws2812_test03(4,6); ws2812_test04(4,6); |
Испытаем данный тест
Отлично!
Следующий тест
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
//---------------------------------------------------------------------------- void ws2812_test05(uint8_t n, uint8_t nm) { uint16_t i; uint16_t j; uint16_t k; for(i=0;i<LED_COUNT;i++) { back_buf[i].H = i * 360 / LED_COUNT* n % 360; back_buf[i].S = 255, back_buf[i].V = BRIGHT; } ws2812_hsv_to_rgb(); for(i=0;i<LED_COUNT;i++) { if((i%(LED_COUNT/n)) <= LED_COUNT/n/2) { k = BRIGHT * (i%(LED_COUNT/n)) / (LED_COUNT/n/2) * (i%(LED_COUNT/n)) / (LED_COUNT/n/2); } else { k = BRIGHT * (LED_COUNT/n - (i%(LED_COUNT/n))) / (LED_COUNT/n/2) * (LED_COUNT/n - (i%(LED_COUNT/n))) / (LED_COUNT/n/2); } back_buf[i].V = k; } for(j=0;j<LED_COUNT*nm;j++) { back_buf_temp.V = back_buf[0].V; for(i=0;i<(LED_COUNT-1);i++) { back_buf[i].V = back_buf[i+1].V; } back_buf[LED_COUNT-1].V = back_buf_temp.V; ws2812_hsv_to_rgb(); ws2812_rgb_copy_buf_to_dma(); ws2812_light(); HAL_Delay(20); } } //---------------------------------------------------------------------------- |
Данный тест пробегает маской по всем радугам, затемняя плавно участки. То есть у нас цвет ни у одного светодиода не меняется при вращении маски, меняется лишь яркость.
Здесь есть одна ещё тонкость. Если изменять яркость на участке линейно, то будет слишком много светлого, а тёмные участки будут очень короткими. Поэтому я решил менять яркость по параболическому закону, применяя квадрат текущего значения доли от самого яркого, а не само значение доли.
Сначала я это исследовал в табличном процессоре Excel
Вот так и будет у нас меняться яркость, так как скорее всего так работает зрение человека. Если мы применяем этот закон, то на ленточке радуги получаются с приятненькими плавненькими хвостиками.
Чтобы не париться с плавающими запятыми мы ещё раз умножаем на числитель и делим на знаменатель. Получается то же самое, а АЛУ сильно не грузится.
Вызовем функцию теста
1 2 |
//ws2812_test04(4,6); ws2812_test05(4,2); |
А вот и результат
Получается плавный спад яркости.
Добавим следующий тест, который делает то же самое, но в обратном направлении
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
//---------------------------------------------------------------------------- void ws2812_test06(uint8_t n, uint8_t nm) { uint16_t i; uint16_t j; uint16_t k; for(i=0;i<LED_COUNT;i++) { back_buf[i].H = i * 360 / LED_COUNT* n % 360; back_buf[i].S = 255, back_buf[i].V = BRIGHT; } ws2812_hsv_to_rgb(); for(i=0;i<LED_COUNT;i++) { if((i%(LED_COUNT/n)) <= LED_COUNT/n/2) { k = BRIGHT * (i%(LED_COUNT/n)) / (LED_COUNT/n/2) * (i%(LED_COUNT/n)) / (LED_COUNT/n/2); } else { k = BRIGHT * (LED_COUNT/n - (i%(LED_COUNT/n))) / (LED_COUNT/n/2) * (LED_COUNT/n - (i%(LED_COUNT/n))) / (LED_COUNT/n/2); } back_buf[i].V = k; } for(j=0;j<LED_COUNT*nm;j++) { back_buf_temp.V = back_buf[LED_COUNT-1].V; for(i=0;i<(LED_COUNT-1);i++) { back_buf[LED_COUNT-i-1].V = back_buf[LED_COUNT-i-2].V; } back_buf[0].V = back_buf_temp.V; ws2812_hsv_to_rgb(); ws2812_rgb_copy_buf_to_dma(); ws2812_light(); HAL_Delay(20); } } //---------------------------------------------------------------------------- |
Вызовем тест
1 2 |
//ws2812_test05(4,2); ws2812_test06(4,2); |
Результат смотреть не будем, так как в статике мы ничего не заметим. Так что смотрите видеоурок, а лучше собирайте схему самостоятельно, будет ещё красивее.
Следующий тест, который будет резко мигать яркостью всей ленты, создавая эффект стробоскопа
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
//---------------------------------------------------------------------------- void ws2812_test07(uint8_t n, uint8_t nm) { uint16_t i; uint16_t j; uint8_t k; for(i=0;i<LED_COUNT;i++) { back_buf[i].H = i * 360 / LED_COUNT* n % 360; back_buf[i].S = 255, back_buf[i].V = BRIGHT; } ws2812_hsv_to_rgb(); for(j=0;j<(nm*2);j++) { for(i=0;i<LED_COUNT;i++) { if(j%2==0) { k = BRIGHT; } else { k = 0; } back_buf[i].V = k; } ws2812_hsv_to_rgb(); ws2812_rgb_copy_buf_to_dma(); ws2812_light(); HAL_Delay(150); } } //---------------------------------------------------------------------------- |
Вызовем данный тест
1 2 |
//ws2812_test06(4,2); ws2812_test07(4,12); |
Данный тест интересен также только в динамике.
Следующий тест — тот же стробоскоп, но попеременно чётными и нечётными радугами
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
//---------------------------------------------------------------------------- void ws2812_test08(uint8_t n, uint8_t nm) { uint16_t i; uint16_t j; uint8_t k; for(i=0;i<LED_COUNT;i++) { back_buf[i].H = i * 360 / LED_COUNT* n % 360; back_buf[i].S = 255, back_buf[i].V = BRIGHT; } ws2812_hsv_to_rgb(); for(j=0;j<(nm*2);j++) { for(i=0;i<LED_COUNT;i++) { if(j%2==0) { if((i%(LED_COUNT/n)) < LED_COUNT/n/2) { k = BRIGHT; } else { k = 0; } } else { if((i%(LED_COUNT/n)) < LED_COUNT/n/2) { k = 0; } else { k = BRIGHT; } } back_buf[i].V = k; } ws2812_hsv_to_rgb(); ws2812_rgb_copy_buf_to_dma(); ws2812_light(); HAL_Delay(200); } } //---------------------------------------------------------------------------- |
Вызовем тест
1 2 |
//ws2812_test07(4,12); ws2812_test08(4,12); |
Посмотрим результат теста
В следующей части урока мы напишем ещё несколько тестов, проверим их на тестовой ленте, а также затем проверим на основной ленте на улице.
Предыдущая часть Программирование МК STM32 Следующая часть
Отладочную плату STM32F103C8T6 можно приобрести здесь STM32F103C8T6
Программатор недорогой можно купить здесь ST-Link V2
Ленты светодиодные WS2812B разные можно приобрести здесь WS2812B
Импульсный источник питания 5 В в 40A 200 Вт можно приобрести здесь 5 В в 40A 200 Вт
Логический анализатор 16 каналов можно приобрести здесь
Смотреть ВИДЕОУРОК (нажмите на картинку)
Добавить комментарий