ИК-пульт Attiny13, ассемблер
-
- Читатель
- Сообщения: 9
- Зарегистрирован: 20 авг 2014, 23:43
ИК-пульт Attiny13, ассемблер
Здравствуйте! Наконец-то нашел пульт на тиньке с хорошим ассемблерным кодом! http://radiohlam.ru/program/ikpult_tiny13_prg_nec.htm
Пытаюсь пристроить передатчик под свои нужды, а именно - управление кондиционером. Кодирование сродни NEC, только другие тайминги.
Итак, команды я расшифровал, посылка имеет в моем случае 9 байт. Именно побайтное хранение команд
для передачи очень удобно в данном случае, так как нужно будет изменять конкретные байты (температура, режим...). Я переписал код, чтобы тупо последовательно передавать посылку, и все бы отлично, вот только теряются три последних бита. Имею подозрение, что упираюсь в какое-то ограничение последних регистров (использую r21-r30). Команды, меньшей длины передаются корректно.
Попрошу знатоков дать пару советов. Как обойти такое ограничение? Как бы так хитро подвигать указатель Х..
UPD:
Посылка имеет вид:
00011010 01001000 00000000 11000001 01001011 00010000 00001000 00000000 00001010
Пытаюсь пристроить передатчик под свои нужды, а именно - управление кондиционером. Кодирование сродни NEC, только другие тайминги.
Итак, команды я расшифровал, посылка имеет в моем случае 9 байт. Именно побайтное хранение команд
для передачи очень удобно в данном случае, так как нужно будет изменять конкретные байты (температура, режим...). Я переписал код, чтобы тупо последовательно передавать посылку, и все бы отлично, вот только теряются три последних бита. Имею подозрение, что упираюсь в какое-то ограничение последних регистров (использую r21-r30). Команды, меньшей длины передаются корректно.
Попрошу знатоков дать пару советов. Как обойти такое ограничение? Как бы так хитро подвигать указатель Х..
UPD:
Посылка имеет вид:
00011010 01001000 00000000 11000001 01001011 00010000 00001000 00000000 00001010
- rhf-admin
- администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
- Сообщения: 3060
- Зарегистрирован: 25 авг 2009, 23:19
- Откуда: Уфа
- Контактная информация:
Re: ИК-пульт Attiny13, ассемблер
Теряются именно 3 бита? Интересно. Ты это как определяешь, на сциле видно, что они не посылаются?
Код переделанный можно посмотреть? Без кода что-то не очень понятно.
Код переделанный можно посмотреть? Без кода что-то не очень понятно.
С уважением, администрация сайта.
-
- Читатель
- Сообщения: 9
- Зарегистрирован: 20 авг 2014, 23:43
Re: ИК-пульт Attiny13, ассемблер
Привожу код, тайминги пока не менял.rhf-admin писал(а):Код переделанный можно посмотреть? Без кода что-то не очень понятно.
Код: Выделить всё
;---------------------------------------------------------
;---------------------------------------------------------
.device ATtiny13
.include "tn13def.inc"
.list
;-- определяем свои переменные
.def w=r16 ; это будет наш аккумулятор
.def T_Cr=r17 ; таймер несущей
.def C_imp=r18 ; счётчик кол-ва импульсов
.def N_bit=r19 ; номер посылаемого бита
.def B1=r20 ; первый байт для передачи
.def B2=r21 ; второй байт для передачи
.def B3=r22 ; третий байт для передачи
.def B4=r23 ; четвёртый байт для передачи
;-- определяем константы
.equ Cr1=12 ; длительность 1 несущей
.equ Cr0=64 ; длительность 0 несущей
.equ Th=239 ; 255-длительность высокого уровня (252)
.equ Tl1=199 ; 255-длительность низкого уровня 1-го бита (242)
.equ Tl0=231 ; 255-длительность низкого уровня 0-го бита (250)
.equ Tsl=213 ; 255-длит-ть низкого уровня в стартовой послед-ти
.equ Tsh=172 ; 255-длит-ть высокого уровня в стартовой послед-ти
.equ MP=10 ; кол-во интервалов для межпакетной паузы
.cseg
.org 0
rjmp Init ; переход на начало программы
;-- вектора прерываний
reti ; INT0
reti ; Pin Change
rjmp Timer ; 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,0b00001000 ; определяем входы и выходы порта
out DDRB,w
ldi w,0b11110111 ; включаем подтягивающие резисторы
out PORTB,w ; и определяем начальное состояние выходов
;
;-- Сканирование клавиатуры
Scan: sbis PINB,0 ; если на входе PB4 низкий уровень - нажата КН1
rjmp Form_Com
rjmp Scan
;-- формирование младшего байта пакета
; записываем в третий байт номер команды 4
Form_Com:
ldi r20, 0xff
ldi r21, 0xff
ldi r22, 0xff
ldi r23, 0xff
ldi r24, 0xff
ldi r25, 0xff
ldi r26, 0xff
ldi r27, 0xff
ldi r28, 0x00
;-- Сбрасываем счётчик импульсов, загружаем в таймер время передачи
;-- высокого уровня первого полубита и включаем прерывания от таймера
clr C_imp ; очистить счётчик импульсов
ldi w,Tsh
out TCNT0,w ; загр.в таймер время высокого уровня старт бита
ldi w,0b00000001
out GTCCR,w ; сбросить предделитель
ldi w,0b00000101
out TCCR0B,w ; запустить таймер с делителем на 1024
ldi w,0b00000010
out TIMSK0,w ; разрешить прерывания от таймера
sei ; разрешить немаскированные прерывания
;---------------------------------------------------------
;--- ПОДПРОГРАММЫ ПЕРЕДАЧИ ВЫСОКОГО И НИЗКОГО УРОВНЕЙ ----
;--- передача высокого уровня ----------------------------
Hlevel:
ldi T_Cr,Cr1 ; загрузить длительность импульса
sbi PORTB,3 ; установить 1 на выходе
Cr1_Y:
dec T_Cr
brne Cr1_Y ; точная подстройка частоты несущей
cbi PORTB,3 ; установить 0 на выходе
ldi T_Cr,Cr0 ; длительность паузы в импульсе
Cr0_Y:
dec T_Cr
brne Cr0_Y ; точная подстройка частоты несущей
rjmp Hlevel
;-- передача низкого уровня
Llevel:
nop
rjmp Llevel
;---------------------------------------------------------
;--- ОБРАБОТЧИК ПРЕРЫВАНИЯ ОТ ТАЙМЕРА --------------------
Timer:
cbi PORTB,3 ; сбросить выход (флаг переполн.сбросится аппаратно)
pop w ; выгрузить адрес из стека (2 байта),
pop w ; чтобы указатель не сдвигался
ldi w,0b00000000
out TCCR0B,w ; выключить таймер
brts ETransf ; если T=1 - мы отсчитыв.интерв. для межпак.паузы
; если флаг не установлен - передаём данные
tst C_imp ; проверить C_imp на ноль
breq Send_Start0 ; если счётчик равен нулю - переход на Send_Start0
sbrc C_imp,0 ; если нулевой бит сброшен - пропускаем команду
rjmp Send_HL
ldi w,138
cpse C_imp,w ; если счётчик равен 66 - пропускаем следующ.команду
rjmp Send_LL
set ; ставим флаг, означающий, что мы закончили передачу
ldi C_imp,MP ; загружаем в C_imp кол-во интерв.для межпак.паузы
ETransf:
dec C_imp
breq EPause ; если отсчитали MP интервалов - отсчитали паузу
clr w
out TCNT0,w ; обнуляем таймер
ldi w,0b00000101
out TCCR0B,w ; включаем таймер с делителем на 1024
sei
rjmp Llevel ; и нифига не делаем, пока прерывание не случится
EPause:
clt ; сбрасываем флаг T
rjmp Scan
Send_LL:
ld w,X ; читаем в w байт по адресу X
and w,N_bit
brne Send_L1 ; если флаг Z не установился, то передаваемый бит=1
Send_L0:
ldi w,Tl0
out TCNT0,w ; загрузить в таймер время низкого уровня 0-го бита
rjmp Next
Send_L1:
ldi w,Tl1
out TCNT0,w ; загрузить в таймер время низкого уровня 1-го бита
Next: inc C_imp ; увеличить счётчик импульсов
clc ; сбросить флаг переноса
rol N_bit ; сдвинуть влево регистр N_bit
brcc Next2 ; если флаг не установился - переходим
rol N_bit ; ещё раз сдвигаем влево
inc XL ; увеличиваем адрес указателя
Next2:
ldi w,0b00000100
out TCCR0B,w ; включаем таймер с делителем на 256
sei ; разрешаем прерывания
rjmp Llevel
;---------------------------------------------------------
Send_HL:
inc C_imp
ldi w,Th
out TCNT0,w ; загрузить в таймер время высокого уровня бита
ldi w,0b00000100
out TCCR0B,w ; включаем таймер с делителем на 256
sei
rjmp Hlevel
;---------------------------------------------------------
Send_Start0:
inc C_imp
clr N_bit ; очистить регистр N_bit
sbr N_bit,0b00000001 ; и установить в нём нулевой бит
ldi XL,0x14 ; загружаем в XL указатель на регистр r20
ldi w,Tsl
out TCNT0,w ; загр.в таймер время низк.уровня старт.послед.
ldi w,0b00000101
out TCCR0B,w ; включаем таймер с делителем на 1024
sei
rjmp Llevel
;----------------------------------------------------------
Код: Выделить всё
111111111111111111111111111111111111111111111 11101011 00011111 11100001 x
111111111111111111111111111111111111111111111 11111111 11111111 11100001 y
111111111111111111111111111111111111111111111 11111111 11111111 11100001 z
Спасибо!
- rhf-admin
- администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
- Сообщения: 3060
- Зарегистрирован: 25 авг 2009, 23:19
- Откуда: Уфа
- Контактная информация:
Re: ИК-пульт Attiny13, ассемблер
Ага, точно. XL - это R26, XH - R27.
А у тебя эти регистры инициализируются данными для передачи:
Поскольку регистров нам хватает, то самое простое их просто перегруппировать по-другому, чтобы на X не залезать. Например, вот так:
А у тебя эти регистры инициализируются данными для передачи:
А потом ты XL тут же запарываешь:Form_Com:
ldi r20, 0xff
ldi r21, 0xff
ldi r22, 0xff
ldi r23, 0xff
ldi r24, 0xff
ldi r25, 0xff
ldi r26, 0xff
ldi r27, 0xff
ldi r28, 0x00
Ну и при каждом inc XL ещё немножко.Send_Start0:
inc C_imp
clr N_bit ; очистить регистр N_bit
sbr N_bit,0b00000001 ; и установить в нём нулевой бит
ldi XL,0x14 ; загружаем в XL указатель на регистр r20
ldi w,Tsl
out TCNT0,w ; загр.в таймер время низк.уровня старт.послед.
ldi w,0b00000101
out TCCR0B,w ; включаем таймер с делителем на 1024
sei
rjmp Llevel
Поскольку регистров нам хватает, то самое простое их просто перегруппировать по-другому, чтобы на X не залезать. Например, вот так:
Ну и соответственно, передаваемый код будет храниться по адресам:def w=r16 ; это будет наш аккумулятор
.def T_Cr=r29 ; таймер несущей
.def C_imp=r30 ; счётчик кол-ва импульсов
.def N_bit=r31 ; номер посылаемого бита
.def B1=r17 ; первый байт для передачи
.def B2=r18 ; второй байт для передачи
.def B3=r19 ; третий байт для передачи
.def B4=r20 ; четвёртый байт для передачи
Только теперь в Send_Start0 надо в XL загружать не 0x14, а 0x11.Form_Com:
ldi r17, 0xff
ldi r18, 0xff
ldi r19, 0xff
ldi r20, 0xff
ldi r21, 0xff
ldi r22, 0xff
ldi r23, 0xff
ldi r24, 0xff
ldi r25, 0x00
С уважением, администрация сайта.
-
- Читатель
- Сообщения: 9
- Зарегистрирован: 20 авг 2014, 23:43
Re: ИК-пульт Attiny13, ассемблер
Я так же поигрался с переназначением регистров, но не то пальто получалось.
Во-первых, при компиляции вылазит ворнинг, что 29-31регистры
Во-вторых, последний байт таки вылазит покарёженным[/b].
Все же придется менять логику формирования посылки, где-то еще регистр порится. Я почему так цепляюсь за этот код - очень доступно получилось . Асм есть царь, хотя непросто было мозги перенастроить на подобную логику)
Во-первых, при компиляции вылазит ворнинг, что 29-31регистры
.already defined by the .def directive
Во-вторых, последний байт таки вылазит покарёженным
Код: Выделить всё
11100001
Все же придется менять логику формирования посылки, где-то еще регистр порится. Я почему так цепляюсь за этот код - очень доступно получилось . Асм есть царь, хотя непросто было мозги перенастроить на подобную логику)
- rhf-admin
- администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
- Сообщения: 3060
- Зарегистрирован: 25 авг 2009, 23:19
- Откуда: Уфа
- Контактная информация:
Re: ИК-пульт Attiny13, ассемблер
Ну, ворнинг-то это не страшно. Естественно регистры r29-r31 оказываются определены два раза - первый раз в разделе CPU Register Declarations файла tn13def, который мы в шапке подключаем (в нём все стандартные имена регистров сопоставлены с соответствующими адресами), а второй раз в нашей проге. Ну и бог с ним, это просто нам напоминают, что одни и те же регистры в результате доступны под двумя разными именами, чтоб мы не забыли, что изменяя C_imp, который у нас r30, мы изменим также и ZL, который тоже r30.
А вот почему последний файл всё же получается покорёженным - это вопрос, я вроде больше нигде никаких перекрываний одних и тех же регистров не нашёл.
А вот почему последний файл всё же получается покорёженным - это вопрос, я вроде больше нигде никаких перекрываний одних и тех же регистров не нашёл.
С уважением, администрация сайта.
-
- Читатель
- Сообщения: 9
- Зарегистрирован: 20 авг 2014, 23:43
Re: ИК-пульт Attiny13, ассемблер
Оказалось, я неправильно декодировал 9-байтный код. На примере NEC разобрался, а тут все забывал байты инвертировать!
У меня еще есть пара вопросов к автору. Тайминги, я так понимаю, считаются как (255-количество тиков)*длительность тика. А как считать частоту модуляции? Не хочу снова на мелочах облажаться)
У меня еще есть пара вопросов к автору. Тайминги, я так понимаю, считаются как (255-количество тиков)*длительность тика. А как считать частоту модуляции? Не хочу снова на мелочах облажаться)
- rhf-admin
- администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
- Сообщения: 3060
- Зарегистрирован: 25 авг 2009, 23:19
- Откуда: Уфа
- Контактная информация:
Re: ИК-пульт Attiny13, ассемблер
Чтобы вычислить частоту - надо вычислить время между переключением из 1 в ноль и из нуля в единицу. Я вычислял это время в отладчике, там можно посмотреть количество тактов от одной команды до другой, а если задать частоту, то и время тоже.
С уважением, администрация сайта.
Re: ИК-пульт Attiny13, ассемблер
Добрый день! Возникли вопросы по числам для таймера, определяющих длительности
.equ Th=239 ; 255-длительность высокого уровня (252)
.equ Tl1=199 ; 255-длительность низкого уровня 1-го бита (242)
.equ Tl0=231 ; 255-длительность низкого уровня 0-го бита (250)
Я считал так, что при частоте контроллера 9,6 МГц один тик таймера с делителем 256 будет 1/(9600000/256)=26,667 мкс
Длительность высокого уровня и длительность низкого уровня 0-го бита 560 мкс, то есть 560/26, 667=21 тик
Длительность низкого уровня 1-го бита в 3 раза больше, то есть 63 тика
Получается Th=Tl0=234, Tl1=192. Расхождение небольшое, но почему числа отличаются от ваших?
.equ Th=239 ; 255-длительность высокого уровня (252)
.equ Tl1=199 ; 255-длительность низкого уровня 1-го бита (242)
.equ Tl0=231 ; 255-длительность низкого уровня 0-го бита (250)
Я считал так, что при частоте контроллера 9,6 МГц один тик таймера с делителем 256 будет 1/(9600000/256)=26,667 мкс
Длительность высокого уровня и длительность низкого уровня 0-го бита 560 мкс, то есть 560/26, 667=21 тик
Длительность низкого уровня 1-го бита в 3 раза больше, то есть 63 тика
Получается Th=Tl0=234, Tl1=192. Расхождение небольшое, но почему числа отличаются от ваших?
- rhf-admin
- администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
- Сообщения: 3060
- Зарегистрирован: 25 авг 2009, 23:19
- Откуда: Уфа
- Контактная информация:
Re: ИК-пульт Attiny13, ассемблер
Не всё так просто. В подпрограмме прерывания, пока мы определяем, какое значение загрузить в таймер - тоже время идёт, в это время у нас на выходе низкий уровень висит. Это тоже надо учитывать.
С уважением, администрация сайта.