В Atmel Studio на Assembler написал алгоритм, реализованный в [b]076 проекте[/b]. Добавил режим переключение программ (больше-меньше), с индикацией Количество программ ограничено оставшимся объемом памяти тиньки. Код постарался по максиму комментировать, кто знает Assembler должен разобраться, где и чего менять под свои нужды. [code]/* "ATtiny13A" memory use summary [bytes]: Segment Begin End Code Data Used Size Use% --------------------------------------------------------------- [.cseg] 0x000000 0x000256 598 0 598 1024 58.4% [.dseg] 0x000060 0x000062 0 2 2 64 3.1% [.eseg] 0x000000 0x000000 0 0 0 64 0.0% Assembly complete, 0 errors. 0 warnings */
;=================================== ; Прием и обработка IR-сигналов с пультов ; RC5 ; Управляюший ; бит ; ____ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ; |___| |_| |_| |_| |_ _| |_| |_ _| |_| |_| |_| |_ _| |_| |_| ; | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | ; Старовые | Адрес системы | Команда | ; 2 бита 5 бит 4 бита ; ; Прорамируемая Индекация ; кнопка ; Программа № 0 1 -- ; Программа № MAX 2 - - - ; Программа № MIN 3 -- - - - ; Программа + 4 Зависит от № программы ; Программа - 5 Зависит от № программы ; ; ; ;.DEVICE ATTINY13 ;=================================== ; Определение портов и выводов ;=================================== ;PortB .EQU LED_OUT = 0 ; Выход сигнал к светодиоду //.EQU IN_IR = 1 ; {Толко вход IR} .EQU OUT1 = 2 ; Выход .EQU OUT2 = 3 ; Выход .EQU OUT3 = 4 ; Выход //.EQU OUT4 = 5 ; Выход если задействовать Reset ;=================================== ; Определение констант ;=================================== .EQU NumPr = 6 ; Кол-во программ плюс средняя, кратное 2. .EQU NumMid = 50 ; Средняя точка отсчета программ {0} .EQU R_Count = 100 ; Кол-во повторов для вкл. реж. обучения .EQU F_CPU = 9600000 ; Частота процессора в Гц .EQU ON = 1 ; Включить, записать .EQU OFF = 0 ; Выключить, читать .EQU LED_L = 80 ; Длиный синал .EQU LED_S = 20 ; Короткий синал .EQU LED_P = 30 ; Пауза ;=================================== ; Определение регистров ;=================================== .DEF TOV_Count = R1 ; Таймер повтора ( если < 10 клавиша не отпускалась, 10 клавиша нажата по новой) .DEF Rep_Count = R2 ; Подсчет кол-во повторов для вкл. реж. обучения .DEF Pult_Count = R3 ; Счетчик команд пульта .DEF AdrEE = R4 ; Адрес ЕЕ .DEF IR_TempL = R5 ; Временный регистр .DEF IR_TempH = R6 ; Временный регистр .DEF IR_EETempL = R7 ; Временный регистр .DEF IR_EETempH = R8 ; Временный регистр .DEF Lo_Ref = R16 ; Эталон меньше .DEF Hi_Ref = R17 ; Эталон больше .DEF IR_Flags = R18 ; Флаговый регистр 0b0000_0000 IR посылки (ZH) .EQU IR_New = 0 ; ||||_||||> Поступила новая команда пульта .EQU IR_Key = 1 ; ||||_|||> Клавиша нажата .EQU IR_Tra = 2 ; ||||_||> Активирован режим обучения .EQU IR_Rep = 3 ; ||||_|> Разрешен автоповтор .DEF Frame_Pos = R19 ; Позиция в кадре .DEF TempL = R20 ; Временный регистр .DEF TempH = R21 ; Временный регистр .DEF PrNum = R22 ; № Программы .DEF TempP3 = R23 ; Временный регистр для задежки .DEF TempP1 = R24 ; Временный регистр для задежки} пара .DEF TempP2 = R25 ; Временный регистр для задежки} пара
;=================================== ; Определение переменных в памяти ;=================================== .DSEG IR_PultL : .BYTE 1 ; Рабочий буфер IR_PultH : .BYTE 1 ; Буфер для баланса ;=================================== ; Сброс и вектора прерывания ;=================================== .CSEG .ORG 0 RJMP INIT ; Переход в начало программы ; Вектора прерываний RJMP INT_0 ; Прерывание по спадающему фронту входа 1 RETI RJMP TIMER_0 ; Прерывание по таймеру Т/С1 = СК/1024 RETI RETI RETI RETI RETI RETI ;=================================== ; Прерывание по спадающему фронту ;=================================== INT_0: ; Прерывание по спадающему фронту входа 1 PUSH TempL PUSH TempH IN TempL,SREG PUSH TempL ; Сохраняем регистры и SREG CPI Frame_Pos,255 ; Пошли данные BREQ Get_Data CPI Frame_Pos,3 ; Замерить эталон BREQ Get_Standard CPI Frame_Pos,0 ; Начать запись данных BREQ StartData RCALL Get_CNT INC Frame_Pos INT_EX: POP TempL ; Восстанавливаем регистры и SREG OUT SREG,TempL POP TempH POP TempL RETI Get_Data: RCALL Get_CNT ; Запускаем замер CP Hi_Ref,TempH BRCS Set1 ; Замер больше эталона CP TempH,Lo_Ref BRCS Set1 ; Эталон больше замера Set0: LSL IR_TempL ; Записать 0 ROL IR_TempH RJMP INT_EX Set1: SEC ; Записать 1 ROL IR_TempL ROL IR_TempH RJMP INT_EX Get_Standard: RCALL Get_CNT ; Запускаем замер MOV Hi_Ref,TempH SUBI Hi_Ref,$FE ; +2 MOV Lo_Ref,TempH SUBI Lo_Ref,$02 ; -2 LDI Frame_Pos,$FF RJMP INT_EX StartData: RCALL Get_CNT ; Запускаем замер ORI IR_Flags,(1<<IR_Key) ; Клавиша нажата CLR TOV_Count ; Таймер повтора <- 0 SBRC IR_Flags,IR_Rep ; Если включен повтор выходим RJMP SD_EX SBRC IR_Flags,IR_Tra ; Если включен режим обучения выходим RJMP SD_EX SBI PORTB,LED_OUT ; Включаем светодиод################################################ SD_EX: LDI Frame_Pos,1 RJMP INT_EX Get_CNT: IN TempH,TCNT0 ; Запускаем замер CLR TempL OUT TCNT0,TempL RET ;=================================== ; Прерывание по таймеру Т/С1 ;=================================== TIMER_0: PUSH TempL PUSH TempH IN TempL,SREG PUSH TempL ; Сохраняем регистры и SREG SBRS IR_Flags,IR_Key ; Клавиша нажата RJMP T0_EX ; Выходим CLR Frame_Pos INC TOV_Count LDI TempH,7 CP TOV_Count,TempH BRCS NotUp ANDI IR_Flags,~(1<<IR_Key) ; Клавиша отпушена $FD =~2 CLR Rep_Count ANDI IR_Flags,~(1<<IR_Rep) ; Запрет повтора $F7 =~3 CBI PORTB,LED_OUT ; Гасим светодиод########################################### CLR IR_TempL CLR IR_TempH T0_EX: POP TempL ; Восстанавливаем регистры и SREG OUT SREG,TempL POP TempH POP TempL RETI NotUp: SBRC IR_Flags,IR_Rep ; Если не включен повтор выходим RJMP T0_EX STS IR_PultL,IR_TempL ; Записываем коды клавиш STS IR_PultH,IR_TempH ORI IR_Flags,(1<<IR_New) ; Поступила новая команда SBRC IR_Flags,IR_Tra ; Если включен режим обучения выходим RJMP T0_EX CBI PORTB,LED_OUT ; Гасим светодиод########################################### INC Rep_Count LDI TempH,R_Count CP Rep_Count,TempH BRCS T0_EX ORI IR_Flags,(1<<IR_Rep) ; Вкл обучение ORI IR_Flags,(1<<IR_Tra) ; Вкл автоповтор RJMP T0_EX ;=================================== ; Обучение пульту ;=================================== StudyPult: SBI PORTB,LED_OUT ; Включаем светодиод LDI ZL,1 LDI TempL,5 ; 5 Команд пульта MOV Pult_Count,TempL SP_01: RCALL BlinkShort ; Мигнуть светодиодом ANDI IR_Flags,~(1<<IR_New) ; Обнуляем поступившую каманду SP_02: SBRC IR_Flags,IR_Key ; Ждем отпускания клавиши RJMP SP_02 SP_03: SBRS IR_Flags,IR_New ; Ждем новой команды RJMP SP_03 ORI IR_Flags,(1<<IR_Rep) ; Вкл автоповтор CLI ; Запрещаем прерывания. MOV TempL,ZL LDS TempH,IR_PultL RCALL EEWrite INC ZL MOV TempL,ZL LDS TempH,IR_PultH RCALL EEWrite INC ZL SEI ; Разрешаем прерывания DEC Pult_Count BRNE SP_01 ANDI IR_Flags,~(1<<IR_Tra) ; Сбрасываем автоповтор LDI PrNum,NumMid ; =0 RCALL BlinkShort ; Мигнуть светодиодом RET ;=================================== ; Обработка команд ;=================================== KeyWork: LDI ZL,1 RCALL GetEECom BRNE KW_01 LDI TempH,NumMid ; =0 RJMP SDiv KW_01: RCALL GetEECom BRNE KW_02 LDI TempH,(NumMid+NumPr/2) ; =max RJMP SDiv KW_02: RCALL GetEECom BRNE KW_03 LDI TempH,(NumMid-NumPr/2) ; =min RJMP SDiv KW_03: RCALL GetEECom BRNE KW_04 MOV TempH,PrNum ; Копируем CPI PrNum,(NumMid+NumPr/2) BRSH SDiv ; >= INC TempH ; +1 RJMP SDiv KW_04: RCALL GetEECom BRNE KW_EX MOV TempH,PrNum ; Копируем CPI PrNum,(NumMid-NumPr/2+1) BRLO SDiv ; < DEC TempH ; -1 SDiv: LDI TempL,0 MOV PrNum,TempH ; Копируем во временный регистр CLI ; Запрещаем прерывания. RCALL EEWrite ; Сохроняем RCALL BlinkPN ; Мигнуть светодиодом SEI ; Разрешаем прерывания KW_UP: ORI IR_Flags,(1<<IR_Rep) ; Вкл обучение KW_EX: ANDI IR_Flags,~(1<<IR_New) ; Обнуляем поступившую каманду RET ;=================================== ; Работа с энергонезависимой памятью ;=================================== GetEECom: MOV TempL,ZL RCALL EERead MOV IR_EETempL,TempH INC ZL MOV TempL,ZL RCALL EERead MOV IR_EETempH,TempH INC ZL LDS TempL,IR_PultL LDS TempH,IR_PultH CP TempL,IR_EETempL CPC TempH,IR_EETempH RET EEWrite: OUT EEAR,TempL ; Загружаем адрес нужной ячейки OUT EEDR,TempH ; и сами данные, которые нам нужно записать SBI EECR,EEMWE ; взводим предохранитель SBI EECR,EEWE ; записываем байт EEWait: SBIC EECR,EEWE ; Ждем конца записи в память. Крутимся в цикле RJMP EEWait ; до тех пор пока не очистится флаг EEWE RET ; Возврат из подпрограммы EERead: OUT EEAR, TempL ; Загружаем адрес нужной ячейки SBI EECR,EERE ; Выставляем бит чтения IN TempH, EEDR ; Забираем из регистра данных результат RET ; Возврат из подпрограммы ;=================================== ; Подпрограмма мигания светодиодом ;=================================== BlinkPN: CPI PrNum,(NumMid+1) BRSH BPN_01 ; PrNum > 101 LDI TempH,LED_L ; RCALL BlinkLong ; LDI TempL,NumMid ; SUB TempL,PrNum ; Сколько раз мигать CPI TempL,0 BREQ BPN_EX ; RJMP BPN_02 BPN_01: MOV TempL,PrNum ; Сколько раз мигать SUBI TempL,NumMid BPN_02: RCALL BlinkShort ; DEC TempL ; | Цыкл в цыкле BRNE BPN_02 ; | BPN_EX: RET ; Возврат из подпрограммы BlinkShort: LDI TempH,LED_S ; BlinkLong: SBI PORTB,LED_OUT ; Включаем светодиод RCALL PAUSE ; Задержка CBI PORTB,LED_OUT ; Гасим светодиод LDI TempH,LED_P ; RCALL PAUSE ; Задержка RET ; Возврат из подпрограммы ;=================================== ; Подпрограмма задержки ;=================================== PAUSE: RCALL ms_100 ; | DEC TempH ; | Цыкл в цыкле BRNE PAUSE ; | RET ; Возврат из подпрограммы ms_100: LDI TempP1,LOW(19200) LDI TempP2,HIGH(19200) LDI TempP3,BYTE3(19200) LOOP: SBIW TempP1,1 SBCI TempP3,0 BRNE LOOP RET ;=================================== ; Начало программы ;=================================== INIT: LDI TempL,LOW(RAMEND) ; Указываем стек на последний адрес OUT SPL,TempL CLR TempL ; Таймер отключен от вывода, шим отключен OUT TCCR0A,TempL ; Регистр управления таймером/счетчиком 0A, LDI TempL,(1<<CS02)|(1<<CS00) ; Частота Т/С1 = СК/1024 OUT TCCR0B,TempL ; Регистр управления таймером/счетчиком 0В, LDI TempL,(1<<TOV0) ; Разрешаем прерывание Т/С0 OUT TIMSK0,TempL ; LDI TempL,(1<<LED_OUT)|(1<<OUT1)|(1<<OUT2); Лини порта Входы/Выходы OUT DDRB,TempL // LDI TempL,(1<<LED_OUT)|(1<<OUT1)|(1<<OUT2) ; Выходы в высокий уровень CLR TempL ; Выходы в 0 OUT PORTB,TempL IN TempL,MCUCR ANDI TempL,$FC ORI TempL,(1<<ISC01) ; Прерывание INT0 по спадающему фронту OUT MCUCR,TempL ; CLR TempL ; OUT GIFR,TempL LDI TempL,(1<<INT0) ; Разрешаем прерывание по INT0 OUT GIMSK,TempL ; CLR TempL ; Обнуляем регистры MOV TOV_Count,TempL MOV Rep_Count,TempL MOV Pult_Count,TempL MOV PrNum,TempL MOV AdrEE,TempL MOV Frame_Pos,TempL MOV IR_Flags,TempL RCALL EERead ; Читаем сохраненное состояние из EEPOM MOV PrNum,TempH ; Копируем в PrNum SEI ;=================================== ; Основная программа ;=================================== START: SBRC IR_Flags,IR_Tra ; Активирован режим обучения RCALL StudyPult SBRC IR_Flags,IR_New ; Поступила новая команда пульта RCALL KeyWork CPI PrNum,NumMid BREQ PN0 ; =0 CPI PrNum,(NumMid+1) BREQ PNP1 ; =1 CPI PrNum,(NumMid-1) BREQ PNM1 ; =-1 CPI PrNum,(NumMid+2) BREQ PNP2 ; =2 CPI PrNum,(NumMid-2) BREQ PNM2 ; =-2 CPI PrNum,(NumMid+3) BRSH PNP3 ; =3 CPI PrNum,(NumMid-3) BRSH PNM3 ; =-3 RJMP START ;=================================== ; Обработка программы № 0 ;=================================== PN0: CBI PORTB,OUT1 ; Выкл. выход 1 SBI PORTB,OUT2 ; Включаем выход 2 CBI PORTB,OUT3 ; Выкл. выход 3 RJMP START ;=================================== ; Обработка программы № 1 ;=================================== PNP1: SBI PORTB,OUT1 ; Включаем выход 1 CBI PORTB,OUT2 ; Выкл. выход 2 CBI PORTB,OUT3 ; Выкл. выход 3 RJMP START ;=================================== ; Обработка программы № -1 ;=================================== PNM1: CBI PORTB,OUT1 ; Выкл. выход 1 CBI PORTB,OUT2 ; Выкл. выход 2 SBI PORTB,OUT3 ; Включаем выход 3 RJMP START ;=================================== ; Обработка программы № 2 ;=================================== PNP2: CBI PORTB,OUT1 ; Выкл. выход 1 CBI PORTB,OUT2 ; Выкл. выход 2 CBI PORTB,OUT3 ; Выкл. выход 3 RJMP START ;=================================== ; Обработка программы № -2 ;=================================== PNM2: SBI PORTB,OUT1 ; Включаем выход 1 SBI PORTB,OUT2 ; Включаем выход 2 SBI PORTB,OUT3 ; Включаем выход 3 RJMP START ;=================================== ; Обработка программы № 3 ;=================================== PNP3: SBI PORTB,OUT1 ; Включаем выход 1 SBI PORTB,OUT2 ; Включаем выход 2 CBI PORTB,OUT3 ; Выкл. выход 3 RJMP START ;=================================== ; Обработка программы № -3 ;=================================== PNM3: CBI PORTB,OUT1 ; Выкл. выход 1 SBI PORTB,OUT2 ; Включаем выход 2 SBI PORTB,OUT3 ; Включаем выход 3 RJMP START [/code] Сам проект для Atmel Studio и Fuses прилагаются.
|