; ; CubeFirmware.asm ; ; Created: 10.11.2017 10:21:55 ; Author : Pavel Chechet ; .include "tn2313def.inc" .EQU d0=0x22 .EQU d1=0x6F .EQU d2=0x34 .EQU d3=0x25 .EQU d4=0x69 .EQU d5=0xA1 .EQU d6=0xA0 .EQU d7=0x2F .EQU d8=0x20 .EQU d9=0x21 .EQU da=0x28 .EQU db=0xE0 .EQU dc=0xB2 .EQU dd=0x64 .EQU de=0xB0 .EQU df=0xB8 .EQU dminus=0xFD .EQU ddot=0xDF .EQU dn=0x2A .EQU dm=0xED .EQU dm1=0xEC .EQU dp=0x38 .EQU dh=0xE8 .EQU dl=0xF2 .EQU di=0x6F .EQU dv=0x62 .EQU do=0xE4 .EQU dG=0xA2 .EQU HighStep = 1 ; шаг ускоренной регулировки Encoder'ом dB .EQU HighStep2 = 2 ; шаг ускоренной регулировки Пультом dB .EQU Delay = 8 ; задержка для повтора кнопок ПДУ .EQU AntiJ = 2 ; задержка антидребезга кнопки энкодера .EQU SilentDelay = 18 ;обратный отсчёт автовыключения без звука 5 мин .EQU ShowMode=14 ;время отображения входа 16=1сек .CSEG ;interrupts vectors rjmp start rjmp Rotate ;Int0 rjmp onIRC ;Int1 reti ;Timer1 capture rjmp onTimer1MatchA ;Timer1 match rjmp onTimer1 ;Timer1 overflow rjmp onTimer0 ;Timer0 overflow reti ;USART RX complete reti ;USART no data reti ;USART TX complete reti ;on comparator reti ;Pin change interrupt reti ;Timer1 match B reti ;Timer0 match A reti ;Timer0 match B reti ;USI start reti ;USI overflow reti ;EEPROM ready reti ;Watchdog overflow ;registers usage ;r0 - saving SREG in onTimer0 ;r1 - cчётчик переполнений Timer0 ;r2 - cчётчик антидребезга ;r3,r4 - в подпрограмме корректировки громкости и слагаемого ;r5 - для передачи данных на индикатор ;r6 - saving SREG in Rotate ;r7 - saving SREG in onIRC ;r9:r8 - cохранение времени в onIRC ;r10:r11:r12:r13 - принятый код от пульта ;r14 - счётчик отображения входа ;r15 - значение Gain для управления усилением анализатора спектра ;r16 - temp in main code ;r17 - временный для передачи данных ;r18 - текущий уровень громкости 0-255 ;r19 - поправочное слагаемое для громкости (-128..+127) ;r20 - отметка времени вращение энкодера ;r21 - счётчик числа быстрых сигналов энкодера ;r23:r22 - счётчик времени для раскодировки ПДУ ;r24 - счётчик принятых бит в onIRC ;r25 - обратный отсчёт выключения без звука ;r26 - режимы: норм 0 - mp3, 1 - phone, 2 - aux, 4-9 то же, но настройка и усиление ;r27 - флаги: 1 - признак обновления индикатора, 2 - пересчитать громкость в разряды, 4 - вывод числа, 8 - погасить дисплей, 16 - отобразить вход ; 32 - признак смены режима пультом, 64 - отправить громкость на PGA, 128 -принудительный выкл пультом ;r31:r30:r29:r28 - данные индикаторов start: ldi r16,RAMEND out SPL,r16 ;стек /* clr r16 out EEAR,r16 ldi r17,112 out EEDR,r17 ldi r16,0x4 out EECR,r16 sbi EECR,1 www1: sbic EECR,1 rjmp www1 ldi r16,1 out EEAR,r16 ldi r17,-10 out EEDR,r17 sbi EECR,2 sbi EECR,1 www2: sbic EECR,1 rjmp www2 inc r16 out EEAR,r16 ldi r17,-20 out EEDR,r17 sbi EECR,2 sbi EECR,1*/ ldi r16,3 ;IO out DDRD,r16 ldi r16,0x08 out PortD,r16 ser r16 out DDRB,r16 ldi r16,0x50 out PortB,r16 ldi r16,1 out DDRA,r16 clr r26 sbis PinD,5 ;если кнопка отпущена, обычный режим ldi r26,4 ;иначе режим настройки ldi r16,0x5 ;Timer0 ck/1024 out TCCR0B,r16 ldi r16,1 ;Timer1 ck out TCCR1B,r16 ldi r16,0xC2 ;прерывание по переполнению таймера 0,1 и совпадению A для Timer1 out TIMSK,r16 ldi r16,0x2A ;enable sleep mode и внешние прерывания по срезу out MCUCR,r16 ldi r16,0xC0 ;разрешить прерывания по энкодеру и IRC out GIMSK,r16 ldi r25,SilentDelay ;запустить обратный отсчёт без звука ;ldi r27,3 ;отобразить громкость ldi r27,0x52 ;отобразить вход а потом громкость, + отправить на PGA clr r19 ;на первом входе нет поправки (слагаемое = 0) ;загрузка из EEPROM ldi r16,EpromVol out EEAR,r16 sbi EECR,0 ;запускаем чтение in r18,EEDR inc r16 out EEAR,r16 sbi EECR,0 ;запускаем чтение in r15,EEDR out OCR1AH,r15 ;вывести коэффициент для совпадения таймера 1 out OCR1AL,r19 sei /******///ОСНОВНОЙ ЦИКЛ Loop: //Флаг 64 - Передать на PGA2310 уровень громкости sbrs r27,6 rjmp noPGA cbr r27,64 in r17,PortB andi r17,0x8F out PortB,r17 ;начать вывод (СS=0) ldi r17,2 twice: mov r5,r18 add r5,r19 ;получить нужный уровень громкости для отправки ldi r16,8 Loop2310: lsl r5 brcs is1shifted cbi PortB,5 rjmp cont2310 is1shifted: sbi PortB,5 nop cont2310: sbi PortB,6 ;выдать clock nop cbi PortB,6 dec r16 ;отправить 8 бит brne Loop2310 dec r17 ;отправить дважды одно и то же brne twice nop sbi PortB,4 ;убрать (СS=1) cbi PortB,5 ;на SDI=0 noPGA: //флаг 8 - Выключить дисплей sbrs r27,3 ;выкл дисплей rjmp noDispOff cbr r27,8 sbr r27,1 ;обновить ldi r28,ddot mov r29,r28 mov r30,r28 mov r31,r28 noDispOff: //Флаг 16 - Отобразить вход sbrs r27,4 ;отобразить вход rjmp noShowMode cbr r27,0x10 sbr r27,1 ldi r16,ShowMode mov r14,r16 ;запустить таймер отображения входа //mov r16,r26 //andi r16,3 cpi r26,1 ;узнать режим brlo isMode0 breq isMode1 cpi r26,8 breq isMode8 brsh isMode9 cpi r26,6 breq isMode6 brsh isMode7 cpi r26,4 breq isMode4 brsh isMode5 ;режим 2 ldi r28,dl ldi r29,di ldi r30,dn ldi r31,de rjmp noVolCon isMode1: ;режим 1 ldi r28,dp ldi r29,dh ldi r30,dn ldi r31,de rjmp noVolCon isMode0: ;режим 0 ldi r28,dm1 ldi r29,dm ldi r30,dp ldi r31,d3 rjmp noVolCon isMode4: ;режим 4 ldi r28,di ldi r29,dv ldi r30,do ldi r31,dl rjmp noVolCon isMode5: ;режим 5 ldi r28,dG ldi r29,dn ldi r30,dminus ldi r31,d0 rjmp noVolCon isMode6: ;режим 6 ldi r28,di ldi r29,d1 ldi r30,dminus ldi r31,dv rjmp noVolCon isMode7: ;режим 7 ldi r28,dG ldi r29,dn ldi r30,dminus ldi r31,d1 rjmp noVolCon isMode8: ;режим 8 ldi r28,di ldi r29,d2 ldi r30,dminus ldi r31,dv rjmp noVolCon isMode9: ;режим 9 ldi r28,dG ldi r29,dn ldi r30,dminus ldi r31,d2 rjmp noVolCon noShowMode: ///Пока отображение входа, ничего больше не отображать, только обрабатывать tst r14 ;если сейчас отображение входа, больше ничего не выводить breq checkMore rjmp noVolCon ;переход к блоку вывода инфы checkMore: //Флаг 4 - вывод некоторых значений, для отладки sbrs r27,2 ;просто число вывести rjmp noNum cbr r27,4 mov r17,r10 andi r17,0xF rcall toHex mov r29,r16 mov r17,r10 lsr r17 lsr r17 lsr r17 lsr r17 rcall toHex mov r28,r16 mov r17,r12 andi r17,0xF rcall toHex mov r31,r16 mov r17,r12 lsr r17 lsr r17 lsr r17 lsr r17 rcall toHex mov r30,r16 noNum: //флаг 2 - громкость или слагаемое или коэффициент в разряды для вывода sbrs r27,1 ;громкость в разряды rjmp noVolCon cbr r27,2 ;сбросить флаг преобразования sbr r27,1 ;установить признак вывода cpi r26,5 ;проверить условие вывода коэффициента brlo no579 sbrc r26,0 ;вывод коэффициента в режимах 5,7 и 9 rjmp koef2Dec no579: mov r16,r19 ;загрузить слагаемое cpi r26,5 ;если режимы 0,1,2,4 то вывод громкости, иначе только коэффициента brsh noAddr18 add r16,r18 ;выводить громкость плюс слагаемое noAddr18: mov r17,r16 ;запомнить для корректировки 0,5 ldi r31,d0 ;вывод .0 или .5dB sbrc r16,0 ldi r31,d5 ser r28 ;сбросить знак минуса lsr r16 ;убрать разряд 0.5dB cpi r26,5 ;если режимы 0,1,2,4 то вывод громкости, иначе только коэффициента brsh sumOnly subi r16,96 ;отнять уровень в 0dB brpl more0 ;если громкость >=0 rjmp contOut sumOnly: cpi r17,0x80 ;если cлагаемое >=0 brlo more0 sbr r16,0x80 ;вернуть сдвинутый знаковый разряд contOut: neg r16 ;если <0, получить модуль sbrc r17,0 dec r16 ;корректировка по 0.5 ldi r28,dminus ;установить вывод минуса more0: //перевод десятков clr r17 cpi r16,80 brlo no80 subi r16,80 sbr r17,8 no80: cpi r16,40 brlo no40 subi r16,40 sbr r17,4 no40: cpi r16,20 brlo no20 subi r16,20 sbr r17,2 no20: cpi r16,10 brlo no10 subi r16,10 sbr r17,1 no10: tst r17 ;проверить, если ли в числе десятки? brne est10 mov r29,r28 ser r28 rjmp end10 est10: push r16 ;сохранить оставшееся число rcall toSeg mov r29,r16 ;код для индикатора pop r16 end10: mov r17,r16 ;оставшиеся единицы rcall toSeg mov r30,r16 cbr r30,0x20 ;включить десятичную точку rjmp noVolCon ;Участок вывода коэффициента ТУТ koef2Dec: mov r28,r15 ;берём значение для вывода //перевод сотен clr r17 cpi r28,200 brlo nok200 subi r28,200 sbr r17,2 nok200: cpi r28,100 brlo nok100 subi r28,100 sbr r17,1 nok100: ser r29 tst r17 breq nokH rcall toSeg mov r29,r16 ;сотни clr r17 nokH: //перевод десятков cpi r28,80 brlo nok80 subi r28,80 sbr r17,8 nok80: cpi r28,40 brlo nok40 subi r28,40 sbr r17,4 nok40: cpi r28,20 brlo nok20 subi r28,20 sbr r17,2 nok20: cpi r28,10 brlo nok10 subi r28,10 sbr r17,1 nok10: ser r30 cpi r29,0xFF ;если есть сотни brne isKD ;то десятки выводить в любом случае tst r17 breq nokD isKD: rcall toSeg mov r30,r16 ;десятки nokD: mov r17,r28 rcall toSeg mov r31,r16 ;единицы ser r28 ;выкл первую цифру полюбому noVolCon: //Флаг 1 - передача данных на индикатор sbrs r27,0 ;передача на индикатор rjmp noSendDisplay cbr r27,1 ;сбросить флаг in r17,PortB ;подготовка вывода andi r17,0xF0 ori r17,0x1 out PortB,r17 mov r5,r31 ;копируем rcall sendR5 mov r5,r30 ;копируем rcall sendR5 mov r5,r29 ;копируем rcall sendR5 mov r5,r28 ;копируем rcall sendR5 sbr r17,4 ;вывод 1 в Latch out PortB,r17 cbr r17,4 ;вывод 0 в Latch out PortB,r17 noSendDisplay: //Флаг 32 - смена режима пультом sbrs r27,5 rjmp goMore cbr r27,32 ;сбросить флаг rjmp modeChanged goMore: //обработка кнопки энкодера ldi r16,AntiJ sbis PinD,5 ;если кнопка отпущена rjmp btnDown cp r2,r16 brsh btnEnd inc r2 rjmp btnEnd btnDown: ;кнопка нажата cp r2,r16 brlo btnEnd ;если не было паузы clr r2 cpi r26,3 ;смотрим второй бит brlo noSave ;не сохранять в обычных режимах ;запись в EEPROM mov r16,r26 subi r16,4 ;адрес в EEPROM = режим минус 4 out EEAR,r16 ;подготовить данные для сохранения out EEDR,r18 breq WaitLoop ;если режим 4 - сохранять r18 громкость out EEDR,r19 ;если рижимы 6 или 8 - сохранять r19 слагаемое sbrc r26,0 out EEDR,r15 ;в режимах 5,7 и 9 - сохранять r15 коэффициент Gain WaitLoop: sbic EECR,1 ;подождать освобождения EEPROM rjmp WaitLoop ldi r16,0x4 cli out EECR,r16 sbi EECR,1 sei noSave: inc r26 ;режим++ cpi r26,3 breq mode0 cpi r26,10 brne modeChanged ldi r26,4 rjmp modeChanged mode0: clr r26 modeChanged: sbr r27,0x50 ;включить отображение входа + отправить на PGA cbr r27,128 ;выкл принудительное ВЫКЛ mov r16,r26 ;переключить релюшки cpi r26,3 ;если режимы 0-2 brlo NorModes subi r16,4 ;отнять от режима 4 lsr r16 ;сдвинуть вправо, останется нужный вход NorModes: ori r16,0x8 andi r16,0xB out PortD,r16 ;загрузить cлагаемое с EEPROM WaitLoop2: sbic EECR,1 ;подождать освобождения EEPROM rjmp WaitLoop2 clr r19 andi r16,3 ;оставить только номер режима breq noLoadSum ;в нулевых режимах слагаемое не нужно lsl r16 ;слагаемое по адресам 2 и 4 out EEAR,r16 ;указать, какое слагаемое (1-2) sbi EECR,0 ;запускаем чтение in r19,EEDR noLoadSum: mov r16,r26 cpi r26,3 ;если обычные режимы, то всё brlo PlayModes subi r16,4 ;отнять четыре lsr r16 ;сбросить младший бит PlayModes: lsl r16 ;получить номер ячейки inc r16 out EEAR,r16 sbi EECR,0 ;запускаем чтение in r15,EEDR ;загружаем в r15 коэффициент out OCR1AH,r15 clr r16 ;и вывести коэффициент сравнение Таймера 1 out OCR1AL,r16 ldi r25,SilentDelay;перезапустить ожидание btnEnd: //управление умзч в зависимости от звука ldi r16,0x70 ;выкл УМЗЧ sbrs r27,7 ;если выкл пультом, УМЗЧ не включать ldi r16,0xF0 ;вкл УМЗЧ tst r25 brne play ldi r16,0x70 ;выкл УМЗЧ play: out PortB,r16 sleep rjmp Loop //Отправка r5 на индикатор sendR5: ldi r16,8 ;вывод 8 бит TransferLoop: lsl r5 ;сдвиг cbr r17,8 ;подготовка к выводу 0 brcc isZero sbr r17,8 ;подготовка к выводу 1 isZero: out PortB,r17 ;вывод данных sbr r17,2 ;вывод 1 в Clock out PortB,r17 cbr r17,2 ;вывод 0 в Clock out PortB,r17 dec r16 brne TransferLoop ret //Переполнение таймера0, 15,26Hz onTimer0: in r0,SREG inc r1 sbic PinD,6 rjmp noSound tst r25 brne soundWas sbr r27,16+2;отобразить вход, а потом громкость soundWas: ldi r25,SilentDelay rjmp noDS noSound: tst r1 brne noDS ;каждые 16,77сек tst r25 ;уменьшать до 0 breq noDS dec r25 ;r25-- brne noDS sbr r27,8 ;погасить дисплей noDS: tst r14 breq noDD dec r14 ;(r14>0)?r14-- brne noDD sbr r27,2 ;вывод громкости после окончания отсчёта noDD: out SREG,r0 reti //r17 - число 0-9 => r16 код для вывода на индикатор toSeg: clr r16 cpi r17,5 brlo less5 cpi r17,8 brlo less8 brne is9 ldi r16,d8 ret is9: ldi r16,d9 ret less8: cpi r17,6 brlo is5 breq is6 ldi r16,d7 ret is6: ldi r16,d6 ret is5: ldi r16,d5 ret less5: cpi r17,2 brlo less2 cpi r17,3 brlo is2 breq is3 ldi r16,d4 ret is3: ldi r16,d3 ret is2: ldi r16,d2 ret less2: tst r17 breq is0 ldi r16,d1 ret is0: ldi r16,d0 ret //r17 - число 0-15 => r16 код для вывода на индикатор toHex: clr r16 cpi r17,8 brlo toSeg cpi r17,12 brlo les12 cpi r17,14 brlo les14 brne is15 ldi r16,de ret is15: ldi r16,df ret les14: cpi r17,12 breq is12 ldi r16,dd ret is12: ldi r16,dc ret les12: cpi r17,10 breq is10 brsh is11 cpi r17,9 brlo is8 ldi r16,d9 ret is8: ldi r16,d8 ret is11: ldi r16,db ret is10: ldi r16,da ret //Вращение энкодера Rotate: in r6,SREG ldi r25,SilentDelay ;раз было вращение, перезапустить обратный отсчёт cbr r27,128 ;снять режим принудительный ВЫКЛ sub r20,r1 ;r20=r1-r20 neg r20 cpi r20,2 brlo hiSpeed clr r21 rjmp loSpeed hiSpeed: cpi r21,250 brsh noAdd21 inc r21 noAdd21: cpi r21,2 ;хотябы два вращения brlo loSpeed ldi r20,HighStep*2 rjmp adjVol loSpeed: ldi r20,1 ;шаг 0,5dB adjVol: mov r3,r20 sbis PinD,4 rcall volDown sbic PinD,4 rcall volUp endEnc: mov r20,r1 ldi r27,0x43 ;обновить громкость и экран out SREG,r6 reti //обработчики корректировки громкости volUp: ;значение из r3 mov r4,r18 add r4,r19 ;получаем реальную громкость cpi r26,6 ;если режимы 6 и 8 breq mode56up cpi r26,8 breq mode56up cpi r26,5 ;если режимы 5, 7 и 9 brsh koefinc add r4,r3 ;пробуем добавить brcs plOwf add r18,r3 ;иначе добавляем ret plOwf: mov r18,r19 com r18 ;макс: r18=255-r19 ret mode56up: inc r4 ;пробуем слагаемое++ breq ssa cpi r19,120 brlo csns cpi r19,-120 brlo ssa csns: inc r19 ssa: ret koefinc: mov r4,r15 ;пробуем коэффициент ++ inc r4 breq ssa inc r15 ;коэффициент ++ out OCR1AH,r15 clr r4 ;и вывести коэффициент сравнение Таймера 1 out OCR1AL,r4 ret volDown: ;значение из r3 mov r4,r18 add r4,r19 ;получаем реальную громкость cpi r26,6 ;если режимы 6 и 8 breq mode56dn cpi r26,8 breq mode56dn cpi r26,5 ;если режимы 5, 7 и 9 brsh koefdec sub r4,r3 ;пробуем отнять brcs suOwf sub r18,r3 ;иначе отнимаем ret suOwf: mov r18,r19 neg r18 ;мин: r18=-r19 ret mode56dn: tst r4 ;пробуем слагаемое-- breq sss cpi r19,121 brlo cans cpi r19,-119 brlo sss cans: dec r19 sss: ret koefdec: tst r15 ;пробуем коэффициент -- breq sss dec r15 out OCR1AH,r15 clr r4 ;и вывести коэффициент сравнение Таймера 1 out OCR1AL,r16 ret //обработка пульта ДУ onIRC: in r7,SREG in r22,TCNT0 mov r23,r1 sub r22,r8 sbc r23,r9 ;находим время в r23:r22 cpi r23,1 ;если задержка слишком большая brsh isRepeat cpi r22,3 ;просто помеха, слишком мало brlo IRCError cpi r22,7 brlo logic0 cpi r22,12 brlo logic1 cpi r22,44 brlo IRCError cpi r22,53 brlo repeat cpi r22,57 brlo IRCError cpi r22,66 brlo startIRC cpi r22,170 brlo IRCerror cpi r22,181 brlo repeat rjmp IRCerror startIRC: ;тут старт приёма ldi r24,1 rjmp spike repeat: cpi r24,32+1 brlo IRCError cpi r24,33+Delay brsh spike inc r24 rjmp spike logic0: clc ;получили 0 logic1: ;получили 1, с не сбрасываем in r23,SREG tst r24 ;если нет приёма битов, то не принимать breq spike cpi r24,32+1;32 бита уже принято brsh spike out SREG,r23;сохраняем значение флага C ror r13 ror r12 ror r11 ror r10 inc r24 rjmp spike isRepeat: brne IRCerror ;слишком много времени прошло, ничего не считать rjmp spike IRCerror: clr r24 spike: cpi r24,32+1 ;если нужно, регулировать громкость breq needVol cpi r24,32+1+Delay brne endVolIRC needVol: mov r23,r10 cpi r23,0x6E brne endVolIRC ;неверный префикс ПДУ ldi r25,SilentDelay ;на любую команду перезапустить таймер cbr r27,128 ;и откл. принудительное ВЫКЛ mov r23,r12 ;коды команд cpi r23,0x83 breq iVol1 cpi r23,0x90 breq iVol2 cpi r23,02 breq iVol3 cpi r23,03 breq iVol4 cpi r23,0x14 ;Power breq powerOff cpi r23,0x0B ;Still breq IRCMode0 cpi r23,0x8E ;Display breq IRCMode1 cpi r23,0x16 ;Menu breq IRCMode2 //тут обработка остальных кнопок rjmp endVolIRC IRCMode0: clr r26 sbr r27,32 ;признак смены режима пультом rjmp endVolIRC IRCMode1: ldi r26,1 sbr r27,32 ;признак смены режима пультом rjmp endVolIRC IRCMode2: ldi r26,2 sbr r27,32 ;признак смены режима пультом rjmp endVolIRC powerOff: sbr r27,128+8 ;принудильный ВЫКЛ + выкл дисплей rjmp endVolIRC iVol1: clr r3 inc r3 rcall volDown rjmp endBP iVol2: clr r3 inc r3 rcall volUp rjmp endBP iVol3: ldi r23,HighStep2*2 mov r3,r23 rcall volDown rjmp endBP iVol4: ldi r23,HighStep2*2 mov r3,r23 rcall volUp ;rjmp endBP endBP: sbr r27,0x43 ;обновить экран и громкость endVolIRC: in r8,TCNT0 ;запомнить время последнего срабатывания mov r9,r1 out SREG,r7 reti /////Timer1 overflow 61Hz onTimer1: sbi PortA,0 reti onTimer1MatchA: cbi PortA,0 reti .eseg EpromVol: .db 56 EpromG0: .db 128 EpromS1: .db -6 EpromG1: .db 100 EpromS2: .db -20 EpromG2: .db 82