ИК-пульт 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
Аватара пользователя
rhf-admin
администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
Сообщения: 3060
Зарегистрирован: 25 авг 2009, 23:19
Откуда: Уфа
Контактная информация:

Re: ИК-пульт Attiny13, ассемблер

Сообщение rhf-admin »

Теряются именно 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
    ;----------------------------------------------------------
Перепрошил еще раз сегодня. Уже не теряет биты последние, но вот шлет неправильный код. И все-таки грешу на то, что влезаю своими байтами даных в регистры пар. Вот заметил, что меняя Х, Y, Z получаю разными последние байты, хотя только последний должен быть нулевым :shock:

Код: Выделить всё

111111111111111111111111111111111111111111111 11101011 00011111 11100001	x

111111111111111111111111111111111111111111111 11111111 11111111 11100001	y

111111111111111111111111111111111111111111111 11111111 11111111 11100001    z
Как определяю: имеется собранное на атмеге8515 устройство, что ловит код и потом по USART'у выплевывает мне его в терминалку. Код и схему улавливателя команды могу привести, но в нем-то сомнений нету) Со всех пультов считывает одинаково команды.

Спасибо!
Аватара пользователя
rhf-admin
администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
Сообщения: 3060
Зарегистрирован: 25 авг 2009, 23:19
Откуда: Уфа
Контактная информация:

Re: ИК-пульт Attiny13, ассемблер

Сообщение rhf-admin »

Ага, точно. XL - это R26, XH - R27.
А у тебя эти регистры инициализируются данными для передачи:
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
А потом ты 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
Ну и при каждом inc XL ещё немножко. :)

Поскольку регистров нам хватает, то самое простое их просто перегруппировать по-другому, чтобы на 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 ; четвёртый байт для передачи
Ну и соответственно, передаваемый код будет храниться по адресам:
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
Только теперь в Send_Start0 надо в XL загружать не 0x14, а 0x11.
С уважением, администрация сайта.
Деятель культуры
Читатель
Читатель
Сообщения: 9
Зарегистрирован: 20 авг 2014, 23:43

Re: ИК-пульт Attiny13, ассемблер

Сообщение Деятель культуры »

Я так же поигрался с переназначением регистров, но не то пальто получалось.
Во-первых, при компиляции вылазит ворнинг, что 29-31регистры
already defined by the .def directive
.
Во-вторых, последний байт таки вылазит покарёженным

Код: Выделить всё

11100001
[/b].
Все же придется менять логику формирования посылки, где-то еще регистр порится. Я почему так цепляюсь за этот код - очень доступно получилось :clapping: . Асм есть царь, хотя непросто было мозги перенастроить на подобную логику)
Аватара пользователя
rhf-admin
администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
Сообщения: 3060
Зарегистрирован: 25 авг 2009, 23:19
Откуда: Уфа
Контактная информация:

Re: ИК-пульт Attiny13, ассемблер

Сообщение rhf-admin »

Ну, ворнинг-то это не страшно. Естественно регистры r29-r31 оказываются определены два раза - первый раз в разделе CPU Register Declarations файла tn13def, который мы в шапке подключаем (в нём все стандартные имена регистров сопоставлены с соответствующими адресами), а второй раз в нашей проге. Ну и бог с ним, это просто нам напоминают, что одни и те же регистры в результате доступны под двумя разными именами, чтоб мы не забыли, что изменяя C_imp, который у нас r30, мы изменим также и ZL, который тоже r30.

А вот почему последний файл всё же получается покорёженным - это вопрос, я вроде больше нигде никаких перекрываний одних и тех же регистров не нашёл. :-?
С уважением, администрация сайта.
Деятель культуры
Читатель
Читатель
Сообщения: 9
Зарегистрирован: 20 авг 2014, 23:43

Re: ИК-пульт Attiny13, ассемблер

Сообщение Деятель культуры »

Оказалось, я неправильно декодировал 9-байтный код. На примере NEC разобрался, а тут все забывал байты инвертировать! :lol2:

У меня еще есть пара вопросов к автору. Тайминги, я так понимаю, считаются как (255-количество тиков)*длительность тика. А как считать частоту модуляции? Не хочу снова на мелочах облажаться)
Аватара пользователя
rhf-admin
администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
администратор, спонсор, писатель, дизайнер, инженер, программист, идеолог
Сообщения: 3060
Зарегистрирован: 25 авг 2009, 23:19
Откуда: Уфа
Контактная информация:

Re: ИК-пульт Attiny13, ассемблер

Сообщение rhf-admin »

Чтобы вычислить частоту - надо вычислить время между переключением из 1 в ноль и из нуля в единицу. Я вычислял это время в отладчике, там можно посмотреть количество тактов от одной команды до другой, а если задать частоту, то и время тоже.
С уважением, администрация сайта.
Guguca
Читатель
Читатель
Сообщения: 1
Зарегистрирован: 13 сен 2014, 09:59

Re: ИК-пульт Attiny13, ассемблер

Сообщение Guguca »

Добрый день! Возникли вопросы по числам для таймера, определяющих длительности

.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, ассемблер

Сообщение rhf-admin »

Не всё так просто. В подпрограмме прерывания, пока мы определяем, какое значение загрузить в таймер - тоже время идёт, в это время у нас на выходе низкий уровень висит. Это тоже надо учитывать.
С уважением, администрация сайта.
Ответить

Вернуться в «Устройства на микроконтроллерах»