Представленная ниже программа предназначена для управления RGB-светодиодом с помощью микроконтроллера PIC12F629. Для этого в программе реализован программный трехканальный ШИМ (ссылку на статью, в которой описана теория того, как это реализовано, можно найти в конце этой статьи). Каждый канал имеет разрядность 2 бита, позволяя таким образом сделать 22=4 различных уровня яркости свечения каждого кристалла, что в совокупности даёт возможность отобразить 4*4*4=64 различных цвета. Частота ШИМ — 100 Гц.
Алгоритм:
![]() Поскольку для каждого канала мы используем 2 бита, то можно все три канала закодировать одним байтом (то есть каждый цвет можно кодировать одним байтом). В данной программе переменная "skor" служит для задания скорости смены цветов. Количество импульсов ШИМ с одной и той же уставкой (то есть кличество импульсов, отображающих один и тот же цвет) равно начальному значению переменной "skor". В нашем примере начальное значение "skor"=25, то есть каждая уставка действует в течении 25 импульсов (то есть один и тот же цвет отображается 25 раз). Поскольку частота у нас 100 Гц, то 25 импульсов — это 250 мс. Если есть желание организовать загрузку необходимых цветов с компьютера, то нужно делать аппаратный контроль передачи и, на время обработки подпрограммы прерывания от таймера, запрещать приём данных. Если этого не сделать, то пересылка данных может сбить частоту импульсов. В результате какое-то время некоторые светодиоды могут казаться максимально включенными, а другие — полностью выключенными. |
list p = 12f629 __config 01FC4h ;*** Переменные ****************************************** CBLOCK 0x20 ; Начальный адрес блока Counter ; счётчик (1 полный импульс = 3 отсчётам счётчика) Temp ; вспомогательная переменная Temp2 ; ещё одна вспомогательная переменная Skor ; скорость смены цветов RGB1 ; адрес этой переменной 24h RGB2 ; в этих 7-ми байтах находятся наборы уставок RGB3 ; для 7-ми цветов RGB4 ; в каждом байте первые два бита для Blue, RGB5 ; вторые два бита для Green, третьи для Red RGB6 RGB7 ; адрес этой переменной 2Ah ENDC ;*** Константы / Адреса регистров ************************ T1 equ .48 ; нач.значение аппаратн. счётчика = 255-207=48; 207*16=3328 Status equ 03h ; Регистр выбора банка GPIO equ 05h ; управление защелками порта (банк 0) Cmcon equ 19h ; Регистр компаратора (банк 0) TrisIO equ 05h ; выбор направления работы выводов порта (банк 1) INTCON equ 0Bh ; разрешение(1)/запрет(0) прерываний (любой банк) OPT_REG equ 01h ; Настройка таймера (банк 1) TMR0 equ 01h ; Регистр таймера (банк 0) OSCCAL equ 10h ; хранение калибров-ой константы (банк 1) INDF equ 0h ; Регистр косвенной адресации FSR equ 04h ; Регистр адреса при косвенной адресации ;********************************************************* ; Пусть у нас GP0, GP1, GP5 - выходы управления RGB, ; остальные ноги также сконфигурируем как выходы ; GP5 - Blue, GP0 - Red, GP1 - Green ; В силу того, что у нашего RGB общий плюс, имеем: ; когда на ноге 0 - соответств-ий канал включен, когда 1 - выключен ;********************************************************* org 0 goto start org 4 ;*** Подпрограмма прерывания от таймера ****************** taimer_prer bcf INTCON,7 ; запрет прерываний movlw T1 ; устанавлив.начальн.значение счётчика T1 movwf TMR0 bsf Status,5 ; и предделитель movlw b'00000011' movwf OPT_REG bcf Status,5 ;*** Проверяем программный счётчик *********************** bcf Status,2 ; сбросить бит Z btfsc Counter,2 ; если счётчик не= 4, - следующ.команда пропуск-ся clrf Counter btfss Status,2 ; если выполн.обнуление, пропускаем след.команду goto Proverka ; если счётчик не =0, то мы не отсчитали ; целый импульс - переходим к проверкам ;*** Сюда мы попадаем после каждого целого импульса ****** ;*** Проверяем указатель на текущую уставку ************** ;*** (если он равен 2Bh, то делаем его равным 24h) ******* movlw 2Bh xorwf FSR,0 btfss Status,2 ; если FSR не = 2Bh, - следующ.команда выполн. goto Next movlw 24h movwf FSR ;*** Уменьшаем Skor, если равна нулю, загружаем ********** ;*** новую уставку и выставляем начальное значение ******* Next clrf GPIO ; зажигаем все светодиоды decfsz Skor,1 ; если Skor = 0, - пропускаем следующую команду goto Proverka ;----------------------------- movf INDF,0 ; читаем уставку по адресу, указанному в FSR movwf Temp ; загружаем его в Temp incf FSR,1 ; переводим указатель на следующую уставку movlw .25 ; значение скорости movwf Skor ;*** Сравниваем все значения с уставками, и переключаем если надо Proverka swapf Temp,0 ; после этого уст-ка Red будет в первых 2-х битах W andlw b'00000011' ; выделяем уставку Red xorwf Counter,0 ; если счётчик=уставке, то установится флаг Z btfsc Status,2 ; если Z=0, пропустить следующую команду bsf GPIO,0 ; погасить Red ;--------------------------------------- movf Temp,0 movwf Temp2 ; загружаем Temp в Temp2 rrf Temp2,1 rrf Temp2,0 ; сдвигаем на 2 бита вправо и записываем в W andlw b'00000011' ; выделяем уставку Green xorwf Counter,0 ; если счётчик=уставке, то установится флаг Z btfsc Status,2 ; если Z=0, пропустить следующую команду bsf GPIO,1 ; погасить Green ;--------------------------------------- movf Temp,0 andlw b'00000011' ; выделяем уставку Blue xorwf Counter,0 ; если счётчик=уставке, то установится флаг Z btfsc Status,2 ; если Z=0, пропустить следующую команду bsf GPIO,5 ; погасить Blue ;*** Выход *********************************************** incf Counter,1 ; увеличиваем программный счётчик bcf INTCON,2 ; сбросить флаг прерывания от таймера bsf INTCON,7 ; разрешить прерывания retfie ; выход ;********************************************************* ;*** КОНФИГУРИРОВАНИЕ КОНТРОЛЛЕРА ************************ ;*** Калибровка Генератора ******************************* start bsf Status,5 Call 3FFh ; Загрузить калибровочную константу в w movwf OSCCAL ;*** Установка направления работы и инициализация ног **** bcf Status,5 ; перейти в банк 0 movlw .255 ; 00111111 - все выходы равны 1 movwf GPIO ; инициализация защелок movlw .7 ; биты 0..2 поднять movwf Cmcon ; компаратор выключен bsf Status,5 ; Перейти в 1-й банк clrf TrisIO ; все ноги сконфигурированы как выходы ;*** Конфигурируем таймер и включаем предделитель ******** clrwdt movlw b'00000011' ; предделитель =16, movwf OPT_REG ; TMR0 работает от внутр.тактового сигнала bcf Status,5 ; переходим в банк 0 ;*** Конфигурируем начальные значения переменных ********* clrf Temp movlw .1 movwf Skor ; чтобы в первом цикле попасть на загрузку уставок movlw .4 movwf Counter ; начальное значение счётчика равно 4 movlw 24h movwf FSR ; указатель на первую уставку ;*** Записываем уставки ********************************** movlw b'00110000' ; Красный movwf RGB1 movlw b'00110100' ; Оранжевый movwf RGB2 movlw b'00111100' ; Желтый movwf RGB3 movlw b'00001000' ; Зеленый movwf RGB4 movlw b'00001011' ; Голубой movwf RGB5 movlw b'00000011' ; Синий movwf RGB6 movlw b'00100010' ; Фиолетовый movwf RGB7 ;*** Разрешаем прерывания от таймера ********************* clrf INTCON ; запретить все прерывания bsf INTCON,5 ; Разрешить прерывания от таймера bsf INTCON,7 ; Разрешить немаскированные прерывания ;*** РАБОЧАЯ ЧАСТЬ *************************************** ;*** Сканирование наличия принятой информации ************ Wait nop ; здесь проц может поделать что-то полезное, goto Wait ; пока не придёт прерывание от таймера end |
Теория, как сделать программный n-канальный ШИМ
Схема подключения RGB-светодиодов к контроллеру и результаты работы программы