Вы не вошли.
2Liv, почему ценность и преподносится?, просто что то искал на ЧИПИНФО, заодно и запросил SFH , а они мне про два часа написали, защищаются т.о. от чего то. Можно и погуглить конечно, или сходить на www.alldatasheet.com , да мало ли куда , было бы желание....
Отредактировано Vasil (03.11.2006 17:29:10)
Вне форума
Хотя в одном месте он всё-же мешает: в кассетной деке TK-140 www.spetspribor.com/nsm/images/tk140.jpg в режиме перемотки команды ДУ приводят к пропускам в работе счетчика ленты.
Хех, да там точно может мешать! Благо я не собираюсь заниматься кассетными магнитофонами ни в ближайшем, ни в далеком будущем.
Приходит прерывание по спаду. Загружаем в таймер задержку 3/4 периода. Приходит прерывание таймера. Считываем состояние выхода фотоприемника, задвигаем в регистр. Если был ноль, перестраиваем прерывание по фронту, иначе - по спаду. После того, как все биты приняты, переписываем код команды и ситемы в соответствующие переменные. Всё, если не считать обработки тайм-аута.
Спасибо за алгоритм! Как всегда решение лежит на поверхности, а я ползаю где-то по дну… Ну ничего, в качестве «зарядки для хвоста» попробую и так и эдак: и одним прерыванием и как Вы предлагаете. Авось пригодиться.
И еще. Временной интервал одного бита для RC-5 жестко определен стандартом, поэтому измерять длительность старт-бита не только не нужно, но и вредно (фотоприемник может искажать длительность импульсов). Поэтому длительность периода можно рассматривать как заранее известную константу.
Я в общем-то тоже так думал, но на всякий случай написал измерение. Но могу и убрать. Как раз и программа упроститься. Надо наверно так и сделать.
......There is someone in my head, but it's not me.......
Вне форума
VladI+
А где, собственно, текст декодера (функции Getrc5)?
2Liv ,
подпрограмма Getrc5 встроена в этот замечательный компилятор.
И поэтому описывать ее в тексте программы не требуется.
Приведеная выше программа готова к компиляции - получим hex файл для прошивки микроконтроллера.
Отредактировано VladI+ (04.11.2006 11:36:47)
Вне форума
VladI+
Встроена-то встроена, но работает она не по прерываниям. Такой декодер даром не нужен.
Вне форума
VladI+
Встроена-то встроена, но работает она не по прерываниям. Такой декодер даром не нужен.
Liv
вообще то программа выглядит так:
$regfile = "attiny2313.dat"
$crystal = 12000000
$lib "mcsbyte.lbx"
Config Lcd = 16 * 2
Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.3 , Rs = Portb.2
Config Rc5 = Pind.0
Dim Address As Byte , Command As Byte
Enable Interrupts
Cls
Lcd "Waiting for RC5"
Cursor Off
Do
Getrc5(address , Command)
If Address < 255 Then
Command = Command And &B01111111
Cls
Lcd "Adress: " ; Address
Lowerline
Lcd "Command:" ; Command
Waitms 100
End If
Loop
End
Сейчас проверим на макетке
Вне форума
2 Liv. Тут у меня некоторые соображения все по тому же поводу. О том как раскодировать ентот гребаный RC5. Замучился я уже. Если где-то буду не прав, поправьте пожалуйста.
1. Значит нам нужно принять сигнал и 6 бит команды вывести на 6 светодиодов. В случае некорректности посылки (превышения таймаутов) зажечь светодиод индикации ошибки.
2. Что нам нужно.
а) 2 опорных времени. Ref1 = 84 (3/4 периода, прескалер СК/64, кварц 4 МГц). Ref2 = 139 (около 5/4 периода).
б) переменные (или регистры) для хранения принятых данных.
в) счетчик принятых бит. Макс кол-во принимаемых бит = 13. первый стартовый мы не принимаем (мы на нем синхронизируемся, он вызывает первое внешнее прерывание)
3. Алгоритм.
Инициализация:
а) Настраиваем внешнее прерывание на падающий фронт и разрешаем его
б) Загружаем в регистры сравнения ТС0 Ref1 и Ref2 (используем регистры OCRA и OCRB).
Обработка прерываний:
а) Происходит внешнее прерывание падающим фронтом. Разрешаем прерывания по совпадению А и В ТС0. Обнуляем TCNT0. ТС0 начинает считать с нуля. Выходим из прерывания.
б) Происх. прерывание по совпадению А (прошло ¾ периода). Проверяем выход приемника. Если была 1, сохраняем 1, 0 -> сохраняем 0. При сохранении инкрементим счетчик бит. Проверяем, сколько он насчитал. Если меньше 13, значит перестраиваем внешнее прерывание (если был 0 на восходящий фронт, если 1 – на падающий). Запрещаем прерывание по совпадению А ТС0, выходим.
Если счетчик бит насчитал 13, значит посылка принята целиком. Убиваем в адресе системы ненужный стартовый бит, внешнее прерывание перестраиваем на падающий фронт, разрешаем его, обнуляем счетчик бит, запрещаем оба прерывания по совпадению ТС0, выходим.
в) Если произошло прерывание по совпадению В ТС0 (прошло 5/4) с момента обнуления таймера, значит посылка некорректна. При правильном приеме этого прерывания не произойдет, т.к. через ¼ после сохранения очередного бита перепадом сигнала будет вызвано внешнее прерывание, в котором TCNT0 принудительно обнуляется. Т.е. таймер до Ref2 попросту не досчитает (при нормальной работе). Ежели досчитал и прерывание по совпадению В ТС0 все же случилось, в обработчике этого прерывания возвращаем код (или флаг) ошибки, обнуляем переменные (или регистры) хранящие данные RC5, внешнее прерывание перестраиваем на падающий фронт, разрешаем его, обнуляем счетчик бит, запрещаем оба прерывания по совпадению ТС0, выходим.
4 Основной цикл программы. Проверяем счетчик бит. Как только он станет равен 0 (вся посылка принята), берем код команды и выпихиваем его в порт. Параллельно проверяем код (или флаг) ошибки, и как только ошибочная ситуация возникнет, гасим все 6 светодиодов и зажигаем светодиод индикации ошибки.
Вот такой алгоритм. Правильно??
......There is someone in my head, but it's not me.......
Вне форума
1. Значит нам нужно принять сигнал и 6 бит команды вывести на 6 светодиодов. В случае некорректности посылки (превышения таймаутов) зажечь светодиод индикации ошибки.
Индикация ошибки - это лишнее. Ошибки декодера появляются довольно часто, но не из-за того, что он неправильно разбирает посылку, а из-за одиночных импульсных помех, которые иногда стартуют декодер. Поэтому светодиод ошибки только будет смущать.
Загружаем в регистры сравнения ТС0 Ref1 и Ref2 (используем регистры OCRA и OCRB).
Я бы не использовал регистры сравнения таймера 0, так они есть далеко не у каждого AVR (например, у ATmega8 нет), а программа декодера должна быть по возможности переносимой. Тем более, в данном случае можно обойтись прерыванием по переполнению таймера. Вместо загрузки регистра сравнения и обнуления таймера в обработчике внешнего прерывания можно просто загрузить в таймер число 0х100 - Ref1. Прерывание по переполнению наступит через Ref1 тактов таймера. А в прерывании таймера загружаем 0х100 - Ref2 в качестве тайм-аута.
Основной цикл программы. Проверяем счетчик бит. Как только он станет равен 0 (вся посылка принята), берем код команды и выпихиваем его в порт.
Счетчик бит - это внутренняя переменная декодера, я бы ее не трогал. Лучше пусть декодер после приема последнего бита посылки проверит номер системы, если не совпадает - то ничего не делать. Если совпадает - загрузить код команды в специальную переменную. основная программа постоянно мониторит эту переменную. Когда нет посылки, там какой-нибудь неиспользуемый код (например, 0xFF). Когда приходит посылка, там появляется код команды. Основная программа его берет, выполняет команду и снова записывает в переменную 0xFF (команда выполнена).
Пока что Вы ничего не писали про control-bit. Начнете работать - понадобится
Вне форума
Я бы не использовал регистры сравнения таймера 0, так они есть далеко не у каждого AVR (например, у ATmega8 нет), а программа декодера должна быть по возможности переносимой.
Странно... а у "неполноценного" ATtiny2313 есть.... У меги8 эти регитры есть у 16-битного таймера. Если применить его, то можно и прескалер не использовать, разрядности хватит. Да и у 8-ми битного ТС2 в меге8 это тоже есть, правда регистр такой там 1.
Ну да ладно.
Тем более, в данном случае можно обойтись прерыванием по переполнению таймера. Вместо загрузки регистра сравнения и обнуления таймера в обработчике внешнего прерывания можно просто загрузить в таймер число 0х100 - Ref1. Прерывание по переполнению наступит через Ref1 тактов таймера. А в прерывании таймера загружаем 0х100 - Ref2 в качестве тайм-аута.
В этом случае Ref2 должно быть равно 1/2 периода, как я понимаю. Через Ref1 наступит первое прерывание (3/4) а потом если счетчик не обнулился еще через 1/2 (3/4+1/2 = 5/4) наступит второе прерывание.
Я в общем-то так и сделал сперва. Ничего уменя опять не вышло. Программу могу прислать. (Щас тока еще немного покумекаю..)
Счетчик бит - это внутренняя переменная декодера, я бы ее не трогал. Лучше пусть декодер после приема последнего бита посылки проверит номер системы, если не совпадает - то ничего не делать. Если совпадает - загрузить код команды в специальную переменную. основная программа постоянно мониторит эту переменную. Когда нет посылки, там какой-нибудь неиспользуемый код (например, 0xFF). Когда приходит посылка, там появляется код команды. Основная программа его берет, выполняет команду и снова записывает в переменную 0xFF (команда выполнена).
Я не знаю какой номер системы у моего пульта. Использую для экскрементов пульт с надписью "for HORIZONT" и ниже "RC-5/F". Наверно система та, что для ТВ.
Пока что Вы ничего не писали про control-bit. Начнете работать - понадобится
Да до этого еще не дошло. Мне бы эти светодиоды гребаные зажечь.
......There is someone in my head, but it's not me.......
Вне форума
2 Liv
Вот она, та программа. Как и следовало ожидать, не работает.
;Программа декодирования кода RC-5 путем вызывания прерывания на каждом импульсе.
;МК ATtiny2313 Частота кварца 4 МГц
;
;================================================
.include "tn2313def.inc" ;подключаем описание регистров
;-------------------------------
;Константы:
.equ Ref1 = 84 ;3/4 периода RC5 (это значение насчитает за 3/4 периода ТС0 с прескалером СК/64)
.equ Ref2 = 55 ;2/4 периода RC5 (это значение насчитает за 2/4 периода ТС0 с прескалером СК/64)
;используем после того как насчитали 3/4
.equ StartPoint = 256-Ref1 ;точка начала отсчета для переполнения через 3/4 периода
.equ ErrTimeOut = 256-Ref2 ;точка начала отсчета для переполнения через 2/4 периода
.equ StBitClr = 0x3F ;константа для очистки ненужного стартового бита
;Будем делать так. Прерывание по переполнению ТС0 использовать проще. Поэтому принудительно будем грузить в
;регистр таймера (TCNT0) число равное T-Ref1, где Т - период переполнения ТС0. Для Ref2 тоже самое.
;Следовательно переполнение ТС0 будет происходить как раз через нужные нам 3/4 и 5/4 периода RC5
.equ NumberOfBits = 13 ;макс кол-во принимаемых бит. (1 стартовый (1-й не сохраняется)
;1 управляющий, 5 адрес системы и 6 код команды)
;Порты:
.equ PIN_PORTD = PIND ;регистр порта D для ввода
;Ноги:
;Вывод
;На порт В выводим по порядку биты кода команды.
;Ввод
.equ IR_Signal = PD3 ;выход ик-приемника на ноге РD3 (используем прерывание INT1)
;Байты направления портов:
.equ DIR_PORTB = 0xFF ;Направление для порта В.
.equ DIR_PORTD = (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD4) | (1<<PD5) | (1<<PD6)
;Порт D нога PD3 - ввод, остальное вывод.
;Байты первоначального состояния портов:
.equ PUP_PORTB = 0x00 ;после сброса весь порт B ставим в 0
.equ PUP_PORTD = (1<<PD3) ;после сброса Pull-Up на PD3
;Глобальные регистровые переменные:
.def temp = r16 ;temporary register temp
.def SysAddress = r17 ;здесь будем хранить принятый адрес системы
;(в младшем бите переменной младший бит адреса системы,
;управляющий бит в 5-м бите переменной)
.def CommandCode = r18 ;зесь храним код принятой команды
;(в младшем бите переменной младший бит адреса системы,
;управляющий бит в 5-м бите переменной)
;-----------------------------------------
.DSEG ;сегмент данных, описание переменных в ОЗУ
BitCounter: .byte 1 ;программный счетчик принятых битов
SysVar: .byte 1 ;сюда кладем принятый адрес системы
CommandVar: .byte 1 ;а сюда код команды. Значение 0xFF здесь означает ошибку.
Ref1Flag: .byte 1 ;флаг. Значение 0xFF означает, что прерывание по переполнению ТС0
;через 3/4 периода было. Флаг очищается в обработчике INT1.
;Т.е. при нормальной работе (когда таймаут не превышен) флаг очищается
;при возникновении ожидаемого перепада сигнала RC5. Если возникает прерывание по
;переполнению ТС0 и в нем обнаруживается, что флаг установлен, значит
;таймаут превышен. В CommandVar записывается 0xFF, флаг сбрасывается и МК
;ожидает новой посылки RC5
;----------------------------------------
.CSEG ;сегмент кода
;Векторы прерываний:
.org 0 ;по адресу 0 вектор сброса
rjmp Init ;переход на основную программу
.org INT1addr ;по адресу INT1addr прерывание по внешнему сигналу INT1
rjmp EdgeRC5
.org OVF0addr ;по адресу OVF0addr вектор прерывания по
rjmp Timer ;переполнению таймера 0
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
;Программа начинает выполняться отсюда:
;Здесь пишем всякую инициализацию, которая должна
;выполняться один раз при старте программы.
Init: ldi temp,low(RAMEND) ;константа RAMEND определена в tn2313def.inc
out SPL,temp ;инициализируем SatckPoiter
;ldi temp,high(RAMEND)
;out SPH,temp
ldi temp,NumberOfBits
sts BitCounter,temp ;инициализируем счетчик бит
;Настройка портов:
ldi temp,PUP_PORTB
out PORTB,temp ;Включаем Pull-Up в PORTB
ldi temp,DIR_PORTB ;
out DDRB,temp ;Настраиваем направление для PORTB
ldi temp,PUP_PORTD ;
out PORTD,temp ;Включаем Pull-Up в PORTD
ldi temp,DIR_PORTD
out DDRD,temp ;настраиваем направление для PORTD
;Настройка оборудования:
ldi temp,(0<<ISC10) | (1<<ISC11) ;ставим бит ISC11 в 1 для
out MCUCR,temp ;разрешения прерывания по падающему фронту
;(для приема первого стартового бита)
ldi temp,(1<<INT1) ;бит INT1 в GIMSK равен 1, остальные нули.
out GIMSK,temp ;разрешаем внешнее прерывание INT1
ldi temp,(1<<CS00) | (1<<CS01) ;предделитель таймера ставим на СК/64
out TCCR0,temp ;записываем в регистр TCCR0
sei ;global interrupts enable
;=========================================================
;Основной цикл программы.
Main: lds temp,CommandVar ;грузим код команды из переменной
out PORTB,temp ;выводим на порт
clr temp
sts CommandVar,temp
rjmp Main ;цикл
;=========================================================
;Обработчик внешнего прерывания:
EdgeRC5:
push temp ;сохранение темп
in temp,SREG
push temp ;сохранение SREG
lds temp,StartPoint ;грузим начало отсчета
out TCNT0,temp ;таймер начинает считать с точки 256-Ref1
ldi temp,(1<<TOIE0) ;ставим бит TOIE0 в 1
out TIMSK,temp ;разрешаем прерывание по переполн ТС0
clr temp
sts Ref1Flag,temp ;сбрасываем Ref1Flag
pop temp
out SREG,temp ;восст. SREG
pop temp ;восст. temp
reti ;выходим и разрешаем прерывания
;=========================================================
;Обработчик по переполнению ТС0 через 3/4 периода:
;
Timer:
push temp ;сохранение темп
in temp,SREG
push temp ;сохранение SREG
;Проверка Ref1Flag
lds temp,Ref1Flag ;грузим флаг отмечающий прерывание
tst temp
breq InitBitCounter ;0 - все ок, принимаем сигнал
;нет - ошибка
;Обработка превышения таймаута
clr temp
sts Ref1Flag,temp ;сбрасываем флаг отмечающий прерывание
clr SysAddress ;очищаем регистр хранения адреса системы
sts SysVar,SysAddress ;очищаем переменную
ser CommandCode
sts CommandVar,CommandCode ;записываем код ошибки 0xFF в переменную
rjmp ErrVixod ;выходим с ошибкой
;Проверка счетчика битов:
InitBitCounter:
lds temp,BitCounter ;грузим счетчик битов
cpi temp,NumberOfBits ;сравниваем с макс. кол-вом битов
brne StartRecieve ;не равно - переходим на прием бита
clr SysAddress ;равно - чистим регистры для приема новых данных
clr CommandCode
;Опрос выхода фотоприемника
StartRecieve:
sbis PIN_PORTD,IR_Signal ;проверяем выход приемника
rjmp Store0 ;Ноль - идем сохранять 0, 1 - сохраняем 1.
;Сохранение 1:
sec ;set "carry" flag
lds temp,BitCounter ;грузим счетчик бит
cpi temp,6 ;сравниваем с 6. Если меньше 6, значит 2-й стартовый,
;командный бит и адрес ситемы уже сохранили.
brlo StoreCom1 ;Сохраняем 1 в код команды. Нет - сохраняем 1 в адрес системы
rol SysAddress ;задвигаем флаг переноса в SysAddress
rjmp IntSwitch1 ;переходим на переключение прерывания
StoreCom1:
rol CommandCode ;задвигаем флаг переноса в CommandCode
IntSwitch1:
ldi temp,(0<<INT1) ;запрет прерывания INT1
out GIMSK,temp
ldi temp,(0<<ISC10) | (1<<ISC11)
out MCUCR,temp ;переключение INT1 на падающий фронт
ldi temp,(1<<INT1) ;разрешение прерывания INT1
out GIMSK,temp
rjmp BitCount ;переходим на счет битов
;Сохранение 0:
Store0: clc ;clear "carry" flag
lds temp,BitCounter ;грузим счетчик бит
cpi temp,6 ;сравниваем с 6. Если меньше 6, значит 2-й стартовый,
;командный бит и адрес ситемы уже сохранили.
brlo StoreCom0 ;Сохраняем 0 в код команды. Нет - сохраняем 0 в адрес системы
rol SysAddress ;задвигаем флаг переноса в SysAddress
rjmp IntSwitch0 ;переходим на переключение прерывания
StoreCom0:
rol CommandCode ;задвигаем флаг переноса в CommandCode
IntSwitch0:
ldi temp,(0<<INT1) ;запрет прерывания INT1
out GIMSK,temp
ldi temp,(1<<ISC10) | (1<<ISC11)
out MCUCR,temp ;переключение INT1 на возрастающий фронт
ldi temp,(1<<INT1) ;разрешение прерывания INT1
out GIMSK,temp
;Подсчет принятых битов:
BitCount:
lds temp,BitCounter ;грузим счетчик бит
dec temp ;temp-1
sts BitCounter,temp ;сохраняем новое значение
tst temp ;проверяем temp на 0
breq EndRecieve ;0 - завершаем прием посылки
ser temp ;не 0 - ставим Ref1Flag,
;разрешаем прероывание по таймеру, выходим
sts Ref1Flag,temp ;
ldi temp,(1<<TOIE0) ;ставим бит TOIE0 в 1
out TIMSK,temp ;разрешаем прерывание по переполн ТС0
rjmp Vixod
EndRecieve:
ldi temp,NumberOfBits
sts BitCounter,temp ;перезагружаем счетчик битов
andi SysAddress,StBitClr ;чистим ненужный 2-й стартовый бит
sts SysVar,SysAddress ;сохраняем адрес системы в переменную
sts CommandVar,CommandCode ;сохраняем код команды в переменную
ErrVixod:
ldi temp,(0<<INT1) ;запрет прерывания INT1
out GIMSK,temp
ldi temp,(0<<ISC10) | (1<<ISC11)
out MCUCR,temp ;переключение INT1 на падающий фронт
ldi temp,(1<<INT1) ;разрешение прерывания INT1
out GIMSK,temp
ldi temp,(0<<TOIE0) ;чистим бит TOIE0
out TIMSK,temp ;запрещаем прерывание по переполн ТС0
Vixod:
pop temp ;восст SREG
out SREG,temp
pop temp ;восст temp
......There is someone in my head, but it's not me.......
Вне форума
Странно... а у "неполноценного" ATtiny2313 есть.... У меги8 эти регитры есть у 16-битного таймера.
Не забывайте, что ATtiny2313 - более новый контроллер. Забирать 16-битный таймер под декодер RC-5 - слишком жирно.
Я в общем-то так и сделал сперва. Ничего уменя опять не вышло. покумекаю..
Программу сейчас гляну.
Вне форума
[ Сгенерировано за 0.058 сек, 7 запросов выполнено - Использовано памяти: 681.76 Кбайт (Пик: 732.13 Кбайт) ]