Управление адресной светодиодной лентой с помощью atmega8

Обсуждаем контроллеры компании Atmel.
Ответить
Sharcer
Родился
Сообщения: 15
Зарегистрирован: Сб окт 07, 2023 21:34:17

Управление адресной светодиодной лентой с помощью atmega8

Сообщение Sharcer »

Доброго времени дня! Помогите пожалуйста новичку. Пытаюсь управлять адресной светодиодной лентой (WS2811) с помощью atmega8 (далее - МК). Хочу просто зажечь самый первый светодиод в ленте зеленым цветом. Но у меня вся лента просто загорается белым.
Лента питается от отдельного источника 12В.
МК питается от 5В через USB. (тактирование от внутреннего кварца. Частоту в коде задал 8МГц)
Нули питания МК и ленты соединены между собой на макетной плате.
Управляющий сигнал идет от PORTB.1 через резистор 220 Ом.
В коде прописал 3 цикла (по одному на каждый цвет в светодиоде).
Насколько я знаю цвет загорается когда сперва передаем логическую единицу в течение 0.8мкс, а ноль в течение 0.45 мкс. А гаснет светодиод при передаче единицы в течение 0.4мкс, а нуля в течение 0.85мкс.
Зеленый цвет ставлю включаю (байты G7...G0), а красный(R7...R0) и синий(B7...B0) выключаю.

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

Сам код программы в Atmel Studio:
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

int main(void)
{
DDRB=0b1111111;
PORTB=0b0000000;
while (1)
{
for(int i=0;i<8;++i) //передаем биты 1 в G7...G0
{
PORTB=0b0000010;
_delay_us(0.8);
PORTB=0b0000000;
_delay_us(0.4);
}

for(int i=0;i<8;++i) //передаем биты 0 в R7...R0
{
PORTB=0b0000010;
_delay_us(0.4);
PORTB=0b0000000;
_delay_us(0.85);
}

for(int i=0;i<8;++i) //передаем биты 0 в B7...B0
{
PORTB=0b0000010;
_delay_us(0.4);
PORTB=0b0000000;
_delay_us(0.85);
}
_delay_us(50);
}
}
Вложения
скрин2.jpg
(228.78 КБ) 100 скачиваний
Реклама
Аватара пользователя
pasha_zv
Мучитель микросхем
Сообщения: 460
Зарегистрирован: Пт фев 17, 2017 11:18:07
Откуда: Ставрополь-Донское

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение pasha_zv »

посмотри осцилом - что ты передаешь. будет три байтных посылок с зазорами. это не прокатит.
растаскивай свои байты втрое - в битовую последовательность и передавай по SPI.
LIVE - EVIL
Реклама
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25259
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение КРАМ »

[uquote="Sharcer",url="/forum/viewtopic.php?p=4519494#p4519494"]сперва передаем логическую единицу в течение 0.8мкс, а ноль в течение 0.45 мкс. А гаснет светодиод при передаче единицы в течение 0.4мкс, а нуля в течение 0.85мкс.
for(int i=0;i<8;++i) //передаем биты 1 в G7...G0
{
PORTB=0b0000010;
_delay_us(0.8 );
PORTB=0b0000000;
_delay_us(0.4);
}

for(int i=0;i<8;++i) //передаем биты 0 в R7...R0
{
PORTB=0b0000010;
_delay_us(0.4);
PORTB=0b0000000;
_delay_us(0.85);
}[/uquote]
Это шуткатакой? :facepalm: :)))
Любезный, у вас частота ядра МК - 8 МГц. То есть всего ОДНА одноцикловая инструкция (а они далеко не все одноцикловые, особенно условное и безусловное ветвление кода) выполняется за 0,125 мкс.
Каким таким таинственным способом может быть реализована функция _delay_us(0.4), например, если она не кратна 0,125?
Каким таким образом вы полагаете исполнение цикла и управление портом за 0 мкс?
С чего вы вообще взяли, что функция _delay_us() в состоянии оперировать дробным аргументом?
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение Ivanoff-iv »

Я делал с ассемблерной вставкой
Спойлер

Код: Выделить всё

//void Send(uint8_t r, uint8_t g, uint8_t b) {                                   // Послать элемент на ленту 
//void Send(flash uint8_t *addr) {                                   // Послать элемент на ленту по указателю из флеша
void Send(uint8_t *addr) {                                   // Послать элемент на ленту по указателю из ОЗУ
     #asm
        ;ldd  r26,y+2              ; Загрузить в r26 &b
        ;ldd  r27,y+1              ; Загрузить в r26 &r
        ;ld   r25,y                ; Загрузить в r26 g   
        MOVW R30,R26
        ;lpm  r26,z++      ;Загрузка по указателю из флеш
        ;lpm  r27,z++
        ;lpm  r25,z
        ld   r26,z++         ;Загрузка по указателю из ОЗУ
        ld   r27,z++
        ld   r25,z
        ldi  r30,24               ; Загрузить в r22 количество передаваемых бит
        dec  r30                  ; уменьшить количество передаваемых бит на 1
     label_1:                     ; Начало цикла
        brmi label_2              ; Если все биты передались выйти  
        in   r31,0x18             ; запомним состояние порта   !!!!0х18 - адрес порта, автоматизировать не смог!!!!   
     #endasm
     PIN_WS2812=1;          // поднимем пин
     #asm
        ;настройка задержек при изменении тактовой частоты производится изменением числа НОПов
        ;nop                       ; Подождать
        ;nop                       ; Подождать     
        nop                       ; Подождать
        sbrs r27,7                ; Пропустить следующую команду если бит в регистре r27 установлен
        out  0x18,r31             ; восстановим состояние порта (низкий уровень на пине) - с этой командой не пляшет общее время посылки
        ;      !!!!0х18 - адрес порта, автоматизировать не смог!!!!
        ;nop                       ; Подождать
        nop                       ; Подождать
        lsl  r25                   ; g<<1
        rol  r26                   ; b<<1 через перенос чтобы была непрерывность
        rol  r27                   ; r<<1 через перенос чтобы была непрерывность
        dec  r30                   ; уменьшить количество передаваемых бит на 1
     #endasm
     PIN_WS2812=0;          //  Пин к земле
     #asm
        ;nop                       ; Подождать
        ;nop                       ; Подождать
        rjmp label_1              ; Перейти к началу цикла
     label_2:                     ; Выйти из функции
     #endasm                      
     PIN_WS2812=0;          // Пин к земле
    }  
код не допилен до удобоваримого вида, но рабочий.
ПС написано и проверено в Кодевижен.
задефайнены:
#define uint8_t unsigned char
#define PIN_WS2812 PORTB.0

вызов:
Спойлер

Код: Выделить всё

for (i=0;i<sizeof(Chkala);i+=3)  {Send(&Chkala[i]);};
где Chkala[] - массив с выводимыми данными
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Реклама
Эиком - электронные компоненты и радиодетали
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение veso74 »

[uquote="КРАМ",url="/forum/viewtopic.php?p=4519552#p4519552"]Каким таким таинственным способом может быть реализована функция _delay_us(0.4), например, если она не кратна 0,125?[/uquote]Ето 1 цикл (ticks). Пересчитывайте из библиотечного кода. Получается задержка МК в 1 такт.
Спойлер

Код: Выделить всё

void _delay_us(double __us)
{
        double __tmp ; 
#if __HAS_DELAY_CYCLES && defined(__OPTIMIZE__) && \
  !defined(__DELAY_BACKWARD_COMPATIBLE__) &&       \
  __STDC_HOSTED__
        uint32_t __ticks_dc;
        extern void __builtin_avr_delay_cycles(unsigned long);
        __tmp = ((F_CPU) / 1e6) * __us;

        #if defined(__DELAY_ROUND_DOWN__)
                __ticks_dc = (uint32_t)fabs(__tmp);

        #elif defined(__DELAY_ROUND_CLOSEST__)
                __ticks_dc = (uint32_t)(fabs(__tmp)+0.5);

        #else
                //round up by default
                __ticks_dc = (uint32_t)(ceil(fabs(__tmp)));
        #endif

        __builtin_avr_delay_cycles(__ticks_dc);

#else
        uint8_t __ticks;
        double __tmp2 ; 
        __tmp = ((F_CPU) / 3e6) * __us;
        __tmp2 = ((F_CPU) / 4e6) * __us;
        if (__tmp < 1.0)
                __ticks = 1;
        else if (__tmp2 > 65535)
        {
                _delay_ms(__us / 1000.0);
        }
        else if (__tmp > 255)
        {
                uint16_t __ticks=(uint16_t)__tmp2;
                _delay_loop_2(__ticks);
                return;
        }
        else
                __ticks = (uint8_t)__tmp;
        _delay_loop_1(__ticks);
#endif
}
8000000 / 3000000 * 0.4 = 1.0666 -> _delay_loop_1(1); будет 1 такт (tick).
А и каждое меньшее число чем 0.4 сокращается до 1 такт.
(Автор кода решает, нужно ли это. В данном случае я бы пропустил написание этой строки).
Реклама
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25259
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение КРАМ »

[uquote="veso74",url="/forum/viewtopic.php?p=4519622#p4519622"]Пересчитывайте из библиотечного кода. Получается задержка МК в 1 такт.[/uquote]
Не получается. Просто вызов функции и возврат из нее - это ЧЕТЫРЕ машинных цикла. То есть 0,5 мкс при 8 МГц системной частоты.
Реклама
veso74
Поставщик валерьянки для Кота
Сообщения: 1907
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария
Контактная информация:

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение veso74 »

Возможно. Переход с C на ASM мне не близок.

Код: Выделить всё

PORTB=0b0000010;
PORTB=0b0000000;
в других быстрых устройствах работает (напр. AD98XX) напрямую без задержек даже на 16, 32 MHz. Но WS2811 не отличается особой скоростью. Бы добавил целое число задержки.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25259
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение КРАМ »

[uquote="veso74",url="/forum/viewtopic.php?p=4519633#p4519633"]WS2811 не отличается особой скоростью.[/uquote]Времена диаграммы автор озвучил. Можно сделать на nop-ах в АСМе, точно посчитав циклы.
Но лучше делать аппаратно на таймере, либо SPI. Скорость там достаточно высокая с учетом выбранной частоты работы МК.
[uquote="veso74",url="/forum/viewtopic.php?p=4519633#p4519633"]Возможно.[/uquote]
Тут есть два варианта.
Либо это макрос и его тело вставляется вместо функции, а содержимое считается не в рантайме, а на этапе компиляции. Тогда там можно откалибровать с точностью до 1 машинного цикла на основании дефайна системной частоты.
Либо это полноценная функция с передачей в нее аргумента и внутренним циклом. Тогда ни о каких единицах микросекунд речи быть не может.
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15570
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение BOB51 »

Два простейших решения -
1. сделать проект под ардуиноIDE, спользуя библиотеку Adafruit_NeoPixel;
(в составе IDE достаточно "платформ" под атмегу8)
2. использовать ассемблер при максимально возможной частоте МК.
( к примеру таким фрагментом:
Спойлер

Код: Выделить всё

;
;
;         trd2812_ma.txt
;
;         файл обработчика передачи массива
; из буфера вывода в линейку на основе WS2812B
; базовый МК из линейки АТМЕЛ при тактовой частоте
; от 16 Мегагерц ( 0,000000062 S)
;
; требуемые интервалы по даташиту WS2812B
;
;Data transfer time( TH+TL=1.25µs±600ns) 
;  T0H  0 code ,high voltage time  0.4us   ±150ns 
;  T1H  1 code ,high voltage time  0.8us   ±150ns 
;  T0L  0 code ,low voltage time   0.85us  ±150ns 
;  T1L  1 code ,low voltage time   0.45us  ±150ns 
;  RES  low voltage time  Above 50µs
; исходный уровень линии связи = 0
; данные передаются пакетами из трех байт на точку
; старшими битами вперед в последовательности
; соответствующей G - R - B цветам точки
; количество блоков должно соответствовать
; количеству точек в ленте
;
; реальные данные согласно тест - отладки дебаггером (версия1!)
; авр-студио 4.19 
;
; Data transfer time( TH+TL=1.38µs -10ns)
;  T0H  0 code ,high voltage time  0.44us  ±10ns 
;  T1H  1 code ,high voltage time  0.88us  ±10ns 
;  T0L  0 code ,low voltage time   0.94us  ±10ns 
;  T1L  1 code ,low voltage time   0.50us  ±10ns
;  RES  low voltage time  192,88uS (Above 50µs)
;
; длина прерывания с пакетом загрузки (x60*3) = 2175uS (0.002175)
; интервал между прерываниями (irq t/c0) = 0.004S (4000uS)
;
;             define datas
; .equ port_out = PORTB ; порт вывода (по усмотрению)
; .equ out_line = 0 ; линия вывода данных
; .equ bufout = SRAM_START ; начальный адрес буфера вывода
; .equ pixel = 60 ; количество точек в линейке/ленте
; .equ bufout_size = (pixel * 3) ; не может быть более объема ОЗУ - стек!!!


;таблица обьявленных имен - переназначение регистров РОН
;
; .def name = r31 ; ZH регистр (полный)
; .def name = r30 ; ZL регистр (полный)
; .def name = r29 ; YH регистр (полный)
; .def name = r28 ; YL регистр (полный)
; .def name = r27 ; XH регистр (полный) указатель текущей ячейки массива bufout
; .def name = r26 ; XL регистр (полный) указатель текущей ячейки массива bufout
; .def name = r25 ; регистр (полный) BH
; .def name = r24 ; регистр (полный) BL
; .def name = r23 ; регистр (полный)
; .def name = r22 ; регистр (полный)
; .def name = r21 ; регистр (полный)
; .def name = r20 ; регистр (полный)
; .def name = r19 ; регистр (полный)
; .def name = r18 ; регистр (полный)
; .def tmp1 = r17 ; регистр (полный) счетчик байт вывода
; .def tmp0 = r16 ; регистр (полный) буфер выводимого байта
; .def regn = r15 ; регистр (урезан)
; .def regn = r14 ; регистр (урезан)
; .def regn = r11 ; регистр (урезан)
; .def regn = r10 ; регистр (урезан)
; .def regn = r9 ; регистр (урезан)
; .def regn = r8 ; регистр (урезан)
; .def regn = r7 ; регистр (урезан)
; .def regn = r6 ; регистр (урезан)
; .def regn = r5 ; регистр (урезан)
; .def regn = r4 ; регистр (урезан)
; .def regn = r3 ; регистр (урезан)
; .def regn = r2 ; регистр (урезан)
; .def matr = r1 ; регистр (урезан) r1 по возможности не использовать!!!
; .def madr = r0 ; регистр (урезан) r0 по возможности не использовать!!!
;
;-----------------------------------------
;  .macro   ;; ввод и предобработка данных
;     
;     
;    .endmacro
; 
;-----------------------------------------
;
; определение буфера вывода в области данных
;  .dseg
;  .org bufout
;point0: .byte 3 ; g:r:b
;point1: .byte 3 ; g:r:b
;point2: .byte 3 ; g:r:b
;point3: .byte 3 ; g:r:b
;point4: .byte 3 ; g:r:b
;point5: .byte 3 ; g:r:b
;point6: .byte 3 ; g:r:b
;point7: .byte 3 ; g:r:b
;point8: .byte 3 ; g:r:b
;point9: .byte 3 ; g:r:b
;point10: .byte 3 ; g:r:b
;point11: .byte 3 ; g:r:b
;point12: .byte 3 ; g:r:b
;point13: .byte 3 ; g:r:b
;point14: .byte 3 ; g:r:b
;point15: .byte 3 ; g:r:b
;point16: .byte 3 ; g:r:b
;point17: .byte 3 ; g:r:b
;point18: .byte 3 ; g:r:b
;point19: .byte 3 ; g:r:b
;point20: .byte 3 ; g:r:b
;point21: .byte 3 ; g:r:b
;point22: .byte 3 ; g:r:b
;point23: .byte 3 ; g:r:b
;point24: .byte 3 ; g:r:b
;point25: .byte 3 ; g:r:b
;point26: .byte 3 ; g:r:b
;point27: .byte 3 ; g:r:b
;point28: .byte 3 ; g:r:b
;point29: .byte 3 ; g:r:b
;point30: .byte 3 ; g:r:b
;point31: .byte 3 ; g:r:b
;point32: .byte 3 ; g:r:b
;point33: .byte 3 ; g:r:b
;point34: .byte 3 ; g:r:b
;point35: .byte 3 ; g:r:b
;point36: .byte 3 ; g:r:b
;point37: .byte 3 ; g:r:b
;point38: .byte 3 ; g:r:b
;point39: .byte 3 ; g:r:b
;point40: .byte 3 ; g:r:b
;point41: .byte 3 ; g:r:b
;point42: .byte 3 ; g:r:b
;point43: .byte 3 ; g:r:b
;point44: .byte 3 ; g:r:b
;point45: .byte 3 ; g:r:b
;point46: .byte 3 ; g:r:b
;point47: .byte 3 ; g:r:b
;point48: .byte 3 ; g:r:b
;point49: .byte 3 ; g:r:b
;point50: .byte 3 ; g:r:b
;point51: .byte 3 ; g:r:b
;point52: .byte 3 ; g:r:b
;point53: .byte 3 ; g:r:b
;point54: .byte 3 ; g:r:b
;point55: .byte 3 ; g:r:b
;point56: .byte 3 ; g:r:b
;point57: .byte 3 ; g:r:b
;point58: .byte 3 ; g:r:b
;point59: .byte 3 ; g:r:b
;
;-----------------------------------------

  .cseg
bptr0:
  nop
	.org (bptr0 + (256 - (bptr0 & 0x00FF)))
slot0:
     ; 6/14 (6-4=2 посему роль остатка выполняет CBI)
    cbi port_out,out_line ; 2 цикла
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    ret ; 4 цикла
    .org (slot0+16)
slot1:
    nop ; 13/7 (13-4=9)
    nop
    nop
    nop
    nop
    nop
    nop
    cbi port_out,out_line ; 2 цикла
    nop
    nop
    ret ; 4 цикла
    ;.org 0x0060
    .org (slot1+16)
xslot0:
    ; 6/14 (6-5=1 посему роль остатка выполняет CBI с избытком в 1 nop)
    cbi port_out,out_line ; 2 цикла
    cbr zl,(1<<5) ; модификация указателя 1 цикл
    nop
    nop
    nop
    nop
    nop
    nop ; -2 цикла на ld tmp0,x+
    dec tmp1 ; 1 цикл
    brbs SREG_Z,ends_trd ; 1 цикл при неисполнении (в цикле)
    rjmp trasstt ; 2 цикла
    .org (xslot0+16)
xslot1:
    nop ; 13/7 (13-5=8)
    cbr zl,(1<<5) ; модификация указателя 1 цикл
    nop
    nop
    nop
    nop
    nop
    cbi port_out,out_line ; 2 цикла
           ; -2 цикла на ld tmp0,x+
		dec tmp1 ; 1 цикл
    brbs SREG_Z,ends_trd ; 1 цикл при неисполнении (в цикле)
    rjmp trasstt ; 2 цикла
;
ends_trd:
      pop tmp0
      pop tmp1
      pop xl
      pop xh
			pop zl
			pop zh ; восстановить рабочую область из стека
   ret
;-----------------------------------------
;
; предварительно:
; линия out_line настроена на вывод
; исходный уровень out_line =0
; указатель стека усатновлен на RAMEND
; массив данных (bufout:bufout_size) предварительно загружен
; флаг готовности массива данных установлен
;
mass_trm:
     push zh
     push zl
     push xh
     push xl
     push tmp1
     push tmp0 ; храним рабочую область в стеке
res_line:
     ldi tmp0,4
     ser tmp1
     cbi port_out,out_line
res_time:
     dec tmp1
     brne res_time
     dec tmp0
     brne res_time ; =>50uS time out
     ldi xh,high (bufout)
     ldi xl,low (bufout) ; загрузка начального адреса массива
        ; в указатель
     ldi tmp1,bufout_size
     ldiw z,slot0 ; адрес начала таблицы в указателе
;     ldiw z,(bptr0 + (256 - (bptr0 & 0x00FF)))
;-----------------------------------------
trasstt:
    ld tmp0,x+ ; 2 цикла
slot_0:
      sbi port_out,out_line ; 2 цикла реально до установки 3 цикла
			bst tmp0,7 ; 1 цикл
			bld zl,4 ; 1 цикл
			icall ; 3 цикла = 4 цикла от out_line=1
;----------------
slot_1:
      sbi port_out,out_line
      bst tmp0,6 ; 1 цикл
			bld zl,4 ; 1 цикл
			icall ; 3 цикла
;----------------
slot_2:
      sbi port_out,out_line
      bst tmp0,5 ; 1 цикл
			bld zl,4 ; 1 цикл
			icall ; 3 цикла
;----------------
slot_3:
      sbi port_out,out_line
      bst tmp0,4 ; 1 цикл
			bld zl,4 ; 1 цикл
			icall ; 3 цикла
;----------------
slot_4:
      sbi port_out,out_line
      bst tmp0,3 ; 1 цикл
			bld zl,4 ; 1 цикл
			icall ; 3 цикла
;----------------
slot_5:
      sbi port_out,out_line
      bst tmp0,2 ; 1 цикл
			bld zl,4 ; 1 цикл
			icall ; 3 цикла
;----------------
slot_6:
      sbi port_out,out_line
      bst tmp0,1 ; 1 цикл
			bld zl,4 ; 1 цикл
			icall ; 3 цикла
;----------------
slot_7:
      sbi port_out,out_line
      ;sbr zl,(1<<6) ; модификация указателя под завершающий фрагмент
      sbr zl,(1<<5)
                  ; 1 цикл
      bst tmp0,0 ; 1 цикл
			bld zl,4 ; 1 цикл
			ijmp ; 3 цикла
;----------------
)
:roll:
Аватара пользователя
Starichok51
Модератор
Сообщения: 19053
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение Starichok51 »

КРАМ писал(а):Просто вызов функции и возврат из нее - это ЧЕТЫРЕ машинных цикла
3 цикла на вызов (rcall) и 4 на возврат (ret). итого 7 циклов.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25259
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение КРАМ »

[uquote="Starichok51",url="/forum/viewtopic.php?p=4519661#p4519661"]3 цикла на вызов (rcall) и 4 на возврат[/uquote]
Ну вооот, я то надеялся... :))) :))) :)))
У меня перед носом лежит альбом с инструкциями АВР. Но я поленился посмотреть... :oops:
Аватара пользователя
>TEHb<
Друг Кота
Сообщения: 5742
Зарегистрирован: Ср ноя 11, 2009 17:19:30
Откуда: Воронеж
Контактная информация:

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение >TEHb< »

Использовал вот эту библиотеку на тини13 с внутренним генератором на 9,6 МГц. Можно либо её вотпрямсразу использовать, либо посмотреть как там всё внутри устроено. Зависит от целей. Уйма условной компиляции на разные случаи, всё программно. Так что это как минимум возможно.
"Привет!" - соврал он.
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение Ivanoff-iv »

[uquote=">TEHb<",url="/forum/viewtopic.php?p=4519678#p4519678"]Так что это как минимум возможно.[/uquote]Та ну! у меня тини 13 ленту таскает, (и код отправки данных в ленту я привел), или это ничего не доказывает? :dont_know: и на меге 8 на её 8 МГц тактовой тоже работает...

Добавлено after 53 seconds:
Re: Управление адресной светодиодной лентой с помощью atmega8
правда у меня тайминги приходится ручками подбирать... :oops: :)))

Добавлено after 2 minutes 5 seconds:
Re: Управление адресной светодиодной лентой с помощью atmega8
причем можно хоть указатель на ОЗУ или флеш, хоть непосредственно данные в функцию пихать
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
ciaas
Нашел транзистор. Понюхал.
Сообщения: 152
Зарегистрирован: Вт окт 11, 2022 13:45:06

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение ciaas »

Ув. АRV даже статью накатал. Респект.

https://m.radiokot.ru/forum/viewtopic.php?f=57&t=159702
Аватара пользователя
Just_Fluffy
Вымогатель припоя
Сообщения: 532
Зарегистрирован: Ср июн 29, 2022 16:25:45

Re: Управление адресной светодиодной лентой с помощью atmega

Сообщение Just_Fluffy »

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

В этом случае следует учесть, что 2811/2812 диоды требовательны к длительности именно высокого уровня. Низкий можно немного и растянуть. Главное, не дотягивать до 50 мкс - а то будет сброс ))

У меня на 8 МГц тиньке для управления одиночным диодом работает вот такой код (у тиньки ножек было мало и ножки с последовательными интерфейсами были заняты):

Код: Выделить всё

	#define NOP									asm volatile ("nop" : : )

	static void decodeByte(uint8_t val, uint8_t* buff){
		uint8_t mask = 128;
		while (mask) {
			*buff = val & mask;
			buff++;
			mask >>= 1;
		}
	}
	
	void setLedColor(uint8_t R, uint8_t G, uint8_t B){
		uint8_t arr[24];
		decodeByte(G,&arr[ 0]);
		decodeByte(R,&arr[ 8]);
		decodeByte(B,&arr[16]);
		cli();
		GPIO_RESET_BIT(LED2812);
		_delay_us(50);
		register uint8_t* parr = arr;
		for ( uint8_t i = 0; i < 24; i++) {
			if (*parr++) {
				// bit == 1
				GPIO_SET_BIT(LED2812);
				NOP;NOP;NOP;NOP;
				GPIO_RESET_BIT(LED2812);
			} else {
				// bit == 0
				GPIO_SET_BIT(LED2812);
				NOP;
				GPIO_RESET_BIT(LED2812);
				NOP;
			}
		}
		GPIO_SET_BIT(LED2812);
		sei();
	}
GPIO_SET_BIT(LED2812); и GPIO_RESET_BIT(LED2812); - это просто макросы вида PORTx |= (1 << bit) и PORTx &= ~(1 << bit)
Длительность нулевой единички получилась около 375 нс, единичной единички - около 875 нс. Длительность ноликов достигает почти 1 мс, но повторюсь, это не настолько критично, как жесткие тайминги единички. Мерялось лог.анализатором с частотой выборки 24 МГц (каждые 41.6 нс выборка).

Для управления несколькими диодами можно разложить сразу все цвета в массив (если хватит памяти), либо аккуратно раскладывать биты прямо на лету, изменив условие на if (*parr & mask), а в конце либо уменьшать маску, либо инкрементировать parr и заново задавая маску. NOP в нулевом состоянии в ветке else тогда надо убрать, там и так будет перебор за счет доп. условий.

Ну и можно посмотреть еще вот тут - тоже управление диодами ногодрыгом.
Белая и Пушистая
Ответить

Вернуться в «AVR»