В этой статье приводится пример простейшей программы управления микроконтроллером для диммера светодиодных драйверов на NCP3066. Диммер у нас сделан на микроконтроллере ATTiny13 и представляет собой генератор прямоугольных импульсов с регулируемым коэффициентом заполнения.
С представленной ниже программой наш диммер генерирует прямоугольные импульсы на частоте около 600 Гц и умеет регулировать их коэффициент заполнения в зависимости от нажатий двух кнопок: «увеличить», «уменьшить».
Алгоритм обработки нажатий кнопок сделан таким образом, что вам не нужно жать кнопку столько же раз, на сколько шагов нужно изменить коэффициент заполнения. Всё то время, пока вы держите кнопку нажатой — он изменяется. Причём изменение это реализовано с двумя скоростями — сразу после нажатия на кнопку коэффициент заполнения изменяется медленно, а при удержании кнопки дольше определённого времени — она начинает изменяться быстрее. (Пришлось сделать такую фишку, поскольку шагов много и тыкать 256 раз на кнопку или держать её 3 часа нажатой — довольно утомительно).
Управление от ИК-пульта в данной программе не реализовано, поскольку всяких ИК-интерфейсов довольно много и возиться с каждым не хотелось. Если будет нужен какой-то конкретный вариант, с которым вы сами не справитесь, — пишите на форум, — попробуем вместе допилить до нужной кондиции.
Для того, чтобы определить что нужно и чего не нужно делать программе в текущем цикле — нам понадобятся два флага, под которые мы выделим специальный регистр (flags).
Установленный нулевой бит этого регистра будет говорить о том, что мы находимся в режиме изменения, установленный первый бит — о том, что мы держим кнопку уже достаточно долго и изменения нужно производить с повышенной скоростью.
Алгоритм:
.device ATtiny13 .include "tn13def.inc" .list ;-- определяем свои переменные .def w=r16 ; это будет наш аккумулятор .def setup=r17 ; это задание .def flags=r18 ; флаги (0 - изменяем выход, 1 - slow/fast) .def setup_counter=r19 ; - для задержки .def setup_counter2=r20 ; - для задержки .def counter_sch=r21 ; - для отсчёта количества шагов после ; которых включается режим fast ;-------------------------- .equ slow_setup=255 ; задержка большая (slow) .equ fast_setup=64 ; задержка маленькая (fast) .equ s_maximum=255 ; начальное ограничение максимального выхода .equ s_minimum=1 ; начальное ограничение минимального выхода .equ s_setup=128 ; начальное значение выхода ;-- Используемые регистры ; SPL - указатель вершины стека ; ACSR - управление компаратором ; DDRB - направление работы ног ; PORTB - выходы порта ; PCMSK - разрешение прерываний на отдельных входах ; GIMSK - общее разрешение прерываний по входам ; GTCCR - сброс предделителя ; TCCR0B - управление таймером ; TIMSK0 - прерывания от таймера ; PB0 - выход ШИМ, PB1 - вход КН2, PB2- вход КН1, PB3 - вход ИК ;-- начало программного кода .cseg .org 0 rjmp Init ; переход на начало программы ;-- вектора прерываний reti ; INT0 rjmp Pch ; Pin Change reti ; Timer reti ; EEPROM reti ; comparator reti ; timer compare match A reti ; timer compare match B reti ; watchdog reti ; ADC ;-- начало программы Init: ldi w,RAMEND ; устанавливаем указатель вершины out SPL,w ; стека на старший байт RAM sbi ACSR,7 ; выключаем компаратор ldi w,0b00000001 ; определяем входы/выходы порта (1-выход,0-вход) out DDRB,w ldi w,0b11111110 ; включаем подтягивающие резисторы out PORTB,w ; и определяем начальное состояние выходов ldi setup,s_setup; ставим начальное задание для ШИМ ;-- включаем ШИМ на выходе PB0 (OC0A) ldi w,s_setup ; записываем начальный коэффициент заполнения out OCR0A,w ldi w,0b10000011 ; fastPWM, set at TOP, clear at compare out TCCR0A,w ldi w,0b00000011 ; fastPWM, prescale 1:64 out TCCR0B,w ;-- разрешить прерывание от входов ldi w,0b00100000 out GIMSK,w ; разрешаем прерывание от входов ;-- разрешить прерывания на входах PB1, PB2, PB3 Start: ldi w,0b00100000 out GIFR,w ; сбросить флаг прерываний от входов ldi w,0b00001110 out PCMSK,w ; разрешаем прерывания на входах PB2, PB1. (PB3) sei ; разрешить глобальные прерывания ;---------------------------------------------------------------------- Scan: sbrc flags,0 ; если флаг сброшен - пропускаем команду rcall Setup_update rjmp Scan ;--- Меняем задание и выход --- Setup_update: sbis PINB,3 ; если нет приёма от ИК-пульта - пропустить rjmp IR_control dec setup_counter brne End_chs ; если не отсчитали нужный интервал - прыгаем ldi setup_counter,255 dec setup_counter2 brne End_chs ; если не отсчитали нужный интервал - прыгаем Setup_change: sbis PINB,1 ; если первая кнопка не нажата - пропустить rjmp Dec_setup sbis PINB,2 ; если вторая кнопка не нажата - пропустить rjmp Inc_setup clr flags ; если ни одна кнопка не нажата rjmp End_chs Dec_setup: dec setup cpi setup,s_minimum brlo SetMin ; если новое задание меньше минимума - прыгаем rjmp ExitSetup SetMin: ldi setup,s_minimum ; ставим задание равным минимуму rjmp ExitSetup Inc_Setup: inc setup cpi setup,s_maximum brsh SetMax ; если максимум меньше нового задания - прыгаем rjmp ExitSetup SetMax: ldi setup,s_maximum ; ставим задание равным максимуму rjmp ExitSetup IR_Control: ; -- сюда можно вставить обработчик для приёма ИК-сигнала ExitSetup: sbrc flags,1 ; если флаг поднят - fast режим rjmp Fast_change Slow_change: ldi setup_counter2, slow_setup inc counter_sch ; увеличиваем счётчик изменений задания sbrc counter_sch,2 ; если 2-й бит поднят sbr flags,0b00000010 ; переключаемся в режим fast change rjmp End_chs Fast_change: ldi setup_counter2, fast_setup End_chs: out OCR0A,setup ; устанавливаем заданное значение выхода ret ;-- ОБРАБОТЧИК ПРЕРЫВАНИЯ ПО ВХОДУ Pch: sbr flags,0b00000001 ; ставим флаг изменения выхода ldi setup_counter,255 ldi setup_counter2,slow_setup ; задаём задержку clr counter_sch ; обнуляем счётчик изменений ldi flags,0b00000001 ; режим slow change, нужно изменять выход reti ; и выходим |
Вот и вся программа. Чтобы всё корректно работало — в контроллере должны быть «запрограммированы» фьюзы SPIEN, SUT0 и CKSEL0 (то есть в PonyProg напротив них должны стоять галочки).