Программа, рассмотренная в этой статье, разработана специально для самодельного ИК-пульта дистанционного управления на контроллере PIC12F629. Если вы измените аппаратную часть (например, будете использовать другой порядок ног, повесите внешний генератор), то программу также нужно будет переделать.
Естественно, прежде чем разбираться с программой, полезно разобраться с самим протоколом SIRC. Если с протоколом всё понятно — можете смело читать дальше.
Представленный вариант полностью написан на ассемблере, в конце статьи выложены сорцы (с комментариями) и прошивка. Программа написана для 15-ти битной версии протокола (она самая распространённая, но в принципе нет ничего сложного в переделывании её на 12-ти или 20-ти битную версию), частота несущей — 40 кГц.
Для начала как всегда немного текстовых пояснений. Итак, в данном случае для отсчёта времени импульса и паузы используется встроенный таймер TMR0. Для управления передачей, в алгоритме используются два специальных управляющих регистра (на самом деле это обычные регистры общего назначения, которые у нас выполняют специальную функцию, поэтому я и пишу «специальных»). Один из них — счётчик количества передаваемых импульсов и пауз, причём отсчёт начинается с паузы стартовой последовательности (нулевое значение счётчика). Соответственно, если значение счётчика нечётное — мы должны передать импульс, а если чётное — паузу. Второй регистр служит для указания позиции передаваемого бита. В начале передачи мы взводим в этом регистре младший бит и потом, после передачи каждого бита посылки, сдвигаем наш указатель влево, перебирая таким образом все позиции от младшего бита к старшему. После того, как указатель сдвинется влево 8 раз, указатель адреса передаваемого байта устанавливается на следующий предназначенный для передачи байт, а указатель позиции передаваемого бита снова позиционируется на нулевой бит.
Ну вот, вкратце идею описали, теперь перейдём к подробному алгоритму и программе.
Алгоритм:
Итак, пусть в аппаратной части мы имеем:
входы: GP5 — кнопка SB1, GP2 — кнопка SB2, GP4 — кнопка SB3, GP1 — кнопка SB4
выходы: GP0 — вывод информации по протоколу SIRC.
MCLR внешне подтянут к питанию; используется внутренний генератор.
list p = 12f629 __config 01FE4h ;*** Переменные ****************************************** CBLOCK 0x20 ; Начальный адрес блока пользовательской памяти T_Cr ; таймер несущей C_imp ; счетчик кол-ва импульсов. если 0-й бит (C_imp-1) = 0 - последним ; посылали единичный полубит, если единице - нулевой. ; биты 1-3 - № посылаемого бита. биты 4-7 - № посылаемого байта Nbit ; позиция посылаемого бита Byte1 ; первый байт для передачи Byte2 ; второй байт для передачи ENDC ;*** Константы / Адреса регистров ************************ P1 equ .200 ; константа для паузы P2 equ .200 ; константа для паузы Cr1 equ .2 ; длительность 1 несущей Cr0 equ .4 ; длительность 0 несущей Tl equ .238 ; 255-длительность низкого уровня (236) Th1 equ .219 ; 255-длительность высокого уровня 1-го бита (218) Th0 equ .238 ; 255-длительность высокого уровня 0-го бита (236) Tsl equ .238 ; 255-длит-ть низкого уровня в старт. последов-ти (236) Tsh equ .182 ; 255-длит-ть высокого уровня в старт. последов-ти (180) AL equ b'00000100' ; адрес 01h (заданный байт адреса) CMD_11 equ 10h ; код команды 1 (младшие 8 бит) CMD_12 equ 0h ; код команды 1 (старшие 2 бита) CMD_21 equ 11h ; код команды 2 (младшие 8 бит) CMD_22 equ 0h ; код команды 2 (старшие 2 бита) CMD_31 equ 12h ; код команды 3 (младшие 8 бит) CMD_32 equ 0h ; код команды 3 (старшие 2 бита) CMD_41 equ 13h ; код команды 4 (младшие 8 бит) CMD_42 equ 0h ; код команды 4 (старшие 2 бита) ;--------------------------------------------------------- Status equ 03h ; Регистр выбора банка GPIO equ 05h ; Регистр управления защелками порта Cmcon equ 19h ; Регистр Cmcon - компаратора TrisIO equ 05h ; выбор направления работы выводов порта OPT_REG equ 01h ; Настройка таймера (банк 1) TMR0 equ 01h ; Регистр таймера (банк 0) INTCON equ 0Bh ; Регистр разрешения(1)/запрета(0) прерываний INDF equ 0h ; регистр косвенной адресации FSR equ 04h ; регистр адреса при косвенной адресации OSCCAL equ 10h ; Регистр хранения калибровочной константы F equ 1 ; Результат направить в регистр. ;********************************************************* ; Пусть у нас GP0 - выход на транзистор управления ИК-диода, ; GP1, GP2, GP4, GP5 - входы ;********************************************************* org 0 ;*** НАЧАЛЬНАЯ НАСТРОЙКА КОНТРОЛЛЕРА ********************* ;*** Калибровка Генератора ******************************* bsf Status,5 Call 3FFh ; Загрузить калибровочную константу в w movwf OSCCAL goto start ;********************************************************* ;*** ПОДПРОГРАММА ПРЕРЫВАНИЯ ***************************** bcf GPIO,0 ; выключить выход, если он был включен bcf INTCON,2 ; сбросить флаг переполнения TMR0 ;-------------------- movf C_imp,1 ; проверяем счётчик импульсов на ноль btfsc Status,2 ; если счётчик равен 0 - переход на Send_Start0 goto Send_Start0 ;-------------------- btfss C_imp,0 ; проверяем 0-й бит счётчика, если ; он = 0 - посылаем низкий уровень, goto Send_LL ; который у нас всегда одинаковой длины ;--- если передали 30 имп-сов (т.е. должны перед. 31-й) - передача окончена movlw .31 xorwf C_imp,0 btfss Status,2 ; если флаг Z установился - пропускаем переход ; к передаче высокого уровня и завершаем передачу goto Send_HH ;------------------- Send_end clrf INTCON ; сбрасываем все прерывания и флаги call Pause ; выдерживаем паузу goto Scan ; переходим к сканированию клавиш ;--- посылаем высокий уровень --- Send_HH movf INDF,0 ; читаем передаваемый байт andwf Nbit,0 ; "И" передаваемого байта с указ.передаваем. бита btfss Status,2 ; если Z=1 - в передаваемом байте, в поз.Nbit у нас 0 goto Send_H1 ;--- загружаем длит-ть высокого уровня, соответствующую нулевому биту --- Send_H0 movlw Th0 movwf TMR0 ; загружаем Th0 в TMR0 goto Next ;--- загружаем длит-ть низкого уровня, соответствующую единичному биту --- Send_H1 movlw Th1 movwf TMR0 ; загружаем Th1 в TMR0 Next incf C_imp,1 ; увеличить счётчик импульсов bsf INTCON,7 ; разрешить немаскированные прерывания goto Hlevel ;-------------------- Send_LL movlw Tl movwf TMR0 ; загрузить Th в TMR0 incf C_imp,1 ; увеличить счётчик импульсов bcf Status,0 ; сбросить флаг переноса rlf Nbit,1 ; сдвинуть указатель передаваемого бита btfss Status,0 ; если С=1 - ещё раз сдв.влево указ.бита и увелич.FSR goto Next2 rlf Nbit,1 incf FSR,1 Next2 bsf INTCON,7 ; разрешить немаскированные прерывания goto Llevel ;-------------------- Send_Start0 clrf Nbit ; очищаем указатель позиции передаваемого бита bsf Nbit,0 ; поднимаем в указателе 0-й бит movlw Byte1 movwf FSR ; адрес косвенной адресации ставим на первый байт movlw Tsl movwf TMR0 ; загрузить Tsl в TMR0 incf C_imp,1 ; увеличить счётчик импульсов bsf INTCON,7 ; разрешить немаскированные прерывания goto Llevel ;*** КОНЕЦ ПРЕРЫВАНИЯ ************************************ ;*** ПРОДОЛЖЕНИЕ НАЧАЛЬНОЙ НАСТРОЙКИ ********************* start bcf Status,5 ; перейти в банк 0 clrf GPIO ; инициализация защелок (нули на всех защелках) movlw .7 ; биты 0..2 поднять movwf Cmcon ; компаратор выключен, GP0, GP1, GP2 - цифровые вх/вых bsf Status,5 ; Перейти в 1-й банк movlw .62 ; Записать конфигурацию GPIO в аккумулятор (W) ; .62=00 111110 GP0 - выход, остальные - входы movwf TrisIO ; Скопировать конфигурацию GPIO из W в регистр TrisIO. ;--- Настраиваем предделитель таймера --- movlw b'00000100'; настройка предделителя 1:32, 32*256=8,192 мс movwf OPT_REG bcf Status,5 ; Перейти в 0-й банк ;*** КОНЕЦ НАЧАЛЬНОЙ НАСТРОЙКИ *************************** ;*** СКАНИРОВАНИЕ КЛАВИАТУРЫ ***************************** Scan btfss GPIO,5 ; если на входе GP5 низкий уровень - нажата клавиша 1 goto Tx_CMD1 btfss GPIO,2 ; если на входе GP2 низкий уровень - нажата клавиша 2 goto Tx_CMD2 btfss GPIO,4 ; если на входе GP4 низкий уровень - нажата клавиша 3 goto Tx_CMD3 btfss GPIO,1 ; если на входе GP1 низкий уровень - нажата клавиша 4 goto Tx_CMD4 goto Scan ;*** КОНЕЦ СКАНИРОВАНИЯ ********************************** ;*** ПОДГОТОВКА К НАЧАЛУ ПЕРЕДАЧИ ************************ Tx_CMD1 movlw CMD_11 ; в первый байт для передачи movwf Byte1 ; пишем младшие 8 бит команды movlw CMD_12 ; пишем в аккумулятор старшие 2 бита команды goto Form_Com ;------------------------ Tx_CMD2 movlw CMD_21 ; в первый байт для передачи movwf Byte1 ; пишем младшие 8 бит команды movlw CMD_22 ; пишем в аккумулятор старшие 2 бита команды goto Form_Com ;------------------------ Tx_CMD3 movlw CMD_31 ; в первый байт для передачи movwf Byte1 ; пишем младшие 8 бит команды movlw CMD_32 ; пишем в аккумулятор старшие 2 бита команды goto Form_Com ;------------------------ Tx_CMD4 movlw CMD_41 ; в первый байт для передачи movwf Byte1 ; пишем младшие 8 бит команды movlw CMD_42 ; пишем в аккумулятор старшие 2 бита команды Form_Com movwf Byte2 movlw AL ; перед старшими битами команды дописываем 5 iorwf Byte2,1 ; бит адреса - получаем второй байт для передачи ;--- Сбрасываем счётчик импульсов, загружаем в таймер время передачи ;--- высокого уровня стартовой послед-ти и включаем прерывания от таймера clrf C_imp ; сбросить счётчик импульсов movlw Tsh movwf TMR0 ; загрузить Tsh в таймер bcf INTCON,2 ; сбросить флаг переполнения таймера bsf INTCON,5 ; разрешить прерывание от таймера bsf INTCON,7 ; разрешить немаскированные прерывания ;--- goto Hlevel - эту команду не пишем, переход и так происходит на Hlevel ;*** КОНЕЦ ПОДГОТОВКИ ************************************ ;*** ПРОЦЕДУРЫ ПЕРЕДАЧИ ВЫСОКОГО И НИЗКОГО УРОВНЯ СИГНАЛА ;*** Передача высокого уровня *** Hlevel movlw Cr1 ; поместить константу Cr1 в аккумулятор movwf T_Cr ; скопир-ть аккум-р в регистр T_Cr (таймер несущей) bsf GPIO,0 ; установить на выходе GP0 единицу Cr1_Y decfsz T_Cr,F ; декремент содержимого регистра T_Cr с ветвлением goto Cr1_Y ; переход на метку Cr1_Y nop ; для точной подстройки времени высокого уровня ; (и соответственно частоты и скважности) bcf GPIO,0 ; Установить на выходе GP0 ноль movlw Cr0 ; поместить константу Cr0 в аккумулятор movwf T_Cr ; скопировать содержимое аккум-ра в регистр T_Cr Cr0_Y decfsz T_Cr,F goto Cr0_Y nop ; для точной подстройки времени низкого уровня nop ; для точной подстройки времени низкого уровня goto Hlevel ;*** Передача низкого уровня *** Llevel nop goto Llevel ;*** КОНЕЦ ПРОЦЕДУР ПЕРЕДАЧИ ***************************** ;*** ПОДПРОГРАММА ПАУЗЫ ********************************** Pause movlw P1 movwf T_Cr cikl2 movlw P2 movwf C_imp cikl1 nop decfsz C_imp,1 goto cikl1 decfsz T_Cr,1 goto cikl2 return ;********************************************************* end ;--------------------------------------------------------- |
Скачать готовую прошивку и asm-файл
Внимание. Во избежание затирания калибровочных констант — алгоритм заливки этой прошивки в контроллер следующий:
- Считываем текущую конфигурацию контроллера.
- Записываем значение битов калибровки схемы BOR (12-й, 13-й биты слова конфигурации, они же bandgap).
- Записываем значение последнего слова программного кода (слово по адресу 03FF) — биты калибровки генератора.
- Открываем нашу прошивку в программе программатора, и меняем в ней биты калибровки схемы BOR и генератора на считанные и записанные значения.
- Всё, теперь эту (исправленную для конкретного экземпляра PIC12) прошивку можно заливать в контроллер.