Главная » Статьи » Swordfish

Прием ИК сигнала протокола NEC
Вот и настал момент когда пришлось заняться приемом и декодировки ИК сигнала. После поисков по загашникам не обнаружил пультов (RC 5), зато нашел пульт от TV SHIVAKI (52 кнопки). По протоколу особо рассказывать не буду. Принцип прекрасно расписан здесь.. За основной алгоритм был выбран принцип декодировки с помощью таймера и порта B.0 настроенное на прерывание по спаду сигнала(статья), но так как протоколы NEC и RC5 разные, пришлось переделывать алгоритм декодировки сигнала(алгоритм захвата и измерения остался практически без изменений).

Теперь немного про захват и декодирование.

На рисунке (скрин с протеуса) изображен фрагмент кодовой посылки и байты повтора (IR). /IR входной (инверсный сигнал) поступающий на PORTB.0 и INT - индикация входа в программу прерывания.
Фрагмент кода прерывания:

Code


Public Interrupt On_INT()
  SaveFSR0 = FSR0
  SaveFSR1 = FSR1
  SavePROD = PRODRegister
High(PORTB.4)  
//----------------------------------------------
If TMR0IF=1 Then // если переполнение таймера
  TMR0IF=0 // сбросили флаг

  IR.EndS=1 // выставили флаг признака конца посылки
  IR.IntC=1 // разрешили инкриминирование счетчика переполнений (для детектирования битов повтора или конца посылки)
End If

//-----------------------------------------------
If B0IF=1 Then // если произошел спад сигнала по B.0
  B0IF=0 // сбросили флаг
  TMR0ON=0 // стопронули таймер
  TeMp.Byte0=TMR0l // перенесли 16 битное значение таймера в переменную TEMP
  TeMp.Byte1=TMR0h  
  tmr0h=0 // сбросили в 0 значение таймера
  tmr0l=0  
  IR.Det=1 // выставили флаг признака детектирования сигнала
  IR.EndS=0 // сбросили флаг конца посылки  
' End Select
  TMR0ON=1 // запустили таймер

End If
//-----------------------------------------------

Low(PORTB.4) // тест входа в прерывания
//-----------------------------------------------

  FSR0 = SaveFSR0
  FSR1 = SaveFSR1
  PRODRegister = SavePROD
End Interrupt



При переходу из 1 в 0 происходит прерывание, значение которое успел насчитать TMR0 переносится в переменную TEMP (обрабатываются в основной программе), TMR0 сбрасывается в 0 и запускается по новой. Если происходит прерывание по переполнению TMR0 (фрагмент рисунка между кодовой посылкой и битами повтора), сбрасывается флаг TMR0IF и устанавливаются флаги признака переполнения таймера (обрабатываются в основной программе).

Переменные необходимые для декодирования и их назначение:
Code

// страховочные значения системных регистров при прерывании
Public Dim PRODRegister As PRODL.AsWord,
  SaveFSR0, SaveFSR1, SavePROD As Word

// флаги для PortB0( прерывание и включение)
Public Dim B0IF As INTCON.1, // b0 int flag
  B0IE As INTCON.4 // enable int b0
// флаги для PortB1( прерывание и включение)
Public Dim B1IF As INTCON3.0, // b1 int flag
  B1IE As INTCON3.3 // enable int  

Public Dim
  TMR0IE As INTCON1.5, // TMR0 флаг включения прерывания
  TMR0IF As INTCON1.2, // TMR0 флаг срабатывания прерывания
  TMR0ON As T0CON.7 // TMR0 Приращение вкл

Public Dim TeMp As Word // временная для таймера  

Public Dim
  Start_Flag As Boolean // Флаг разрешения работы

Public Structure TIR // структурируем
  Stat As Byte // байт флагов состояния
  Sta As Stat.bit0 // флаг обнаружения стартового импульса
  EndS As Stat.bit1 // флаг прерывания по переполнению таймера
  Err As Stat.bit2 // флаг ошибки приема  
  Ok As Stat.bit3 // флаг удачой проверки сравнения кода
  Rep As Stat.bit4 // флаг повтора
  Det As Stat.bit5 // флаг прерывания по приему ИК сигнала
  IntC As Stat.bit6 // флаг запрета повторного инкременирования IntN
  Adr As Word // адрес комманды приема H-нормальный, L- инверсия
  Com As Word // код комманды H-нормальный, L- инверсия
  IntN As Byte // пер. кол-ва переполнения таймера  

  Res(50) As Word

  BitN As Byte // количество принятых бит кода
End Structure

Public Dim IR As TIR // объявляем структуру


Самый первых вопрос который возникает. Что значят строчки:
Public Structure TIR // структурируем
End Structure
Public Dim IR As TIR // объявляем структуру

Это так называемое структурирование (применяется в VB6 для упрощения читаемости кода)
каждая сточку следующую после Public Structure TIR можно заменить на Public Dim IR_Stat As Byte например, и т.д.

Теперь кусок кода который детектирует принятые значения таймера (TEMP) и флагов состояний.
Code

IR.Com=0 // сбросили флаги и значения (начальные)
IR.Adr=0
IR.IntN=0
CLR: // сбросили флаги и значения (для приема новой команды)  
IR.Stat=0
IR.BitN=0

loop: // основной цикл

If IR.EndS=1 And IR.IntC=1 Then // если произошло прерывание и зафиксирован признак конца пакета
  Inc(IR.IntN)
  If IR.IntN=5 Then // если произошло больше 4 прерываний по переполнению таймера, то нет сигнала.
  IR.Com=0 // сбросили все переменные в 0
  IR.Adr=0
  IR.Stat=0
  IR.BitN=0
  IR.IntN=4
  Low(PORTB.3) // сбросили индикацию повтора

  End If
  IR.IntC=0 // сброс счеткика переполнения таймера
End If

// ----
If IR.Det=1 Then
  IR.IntN=0

If IR.Sta=0 And TeMp>$8400 And TeMp<$8450 Then // детектируем стартовый импульс
  IR.Sta=1 // если он, выставили флаг
End If

If IR.Sta=1 And TeMp>$15d0 And TeMp<$1640 Then // детектируем "1"

  IR.Com.0=1
  If IR.BitN<31 Then
  IR.Adr= IR.Adr<<1
  IR.Adr.bit0=IR.Com.bit15
  IR.Com= IR.Com<<1
  End If
  Inc(IR.BitN)
End If

If IR.Sta=1 And TeMp>$0Ac0 And TeMp<$0B30 Then // детектируем "0"

  IR.Com.0=0
  If IR.BitN<31 Then
  IR.Adr= IR.Adr<<1
  IR.Adr.bit0=IR.Com.bit15
  IR.Com= IR.Com<<1
  End If
  Inc(IR.BitN)
End If

IR.Det=0

End If
// ---

If IR.Ok=1 And IR.EndS=1 And IR.IntC<4 And TeMp>$6d70 And TeMp<$6ff0 Then // если обнаружен бит повтора, код прошел проверку и не было переполнения по времени
  IR.Rep=1 // сбросили лишнее
  IR.Sta=0
  IR.EndS=0
  High(PORTB.3) // выставляем бит повтора
End If

If IR.EndS=1 And IR.BitN<>32 Then // если не совпала длинна, а уже произошло прерывание по переполнению
  IR.Com=0 // сбросили все переменные в 0
  IR.Adr=0
  IR.Stat=0
  IR.BitN=0
  IR.IntN=4
  Low(PORTB.3)
End If

If IR.EndS=1 And IR.Sta=1 And IR.BitN=32 And IR.Ok=0 Then // если произошло прерывание, был стартовый сигнал, 32 бита приняли

  If IR.Adr.byte1=Not IR.Adr.byte0 And IR.Com.byte1=Not IR.Com.byte0 Then // проверяем что приняли
  IR.Ok=1 // если все совпало, значит код верен. Флаг правильности установили
  IR.Sta=0
  IR.EndS=0

  USART.Write ("Adress :",BinToStr(IR.Adr.byte1,8)," ",BinToStr(IR.Adr.byte0,8),13) // выплюнули код в USART
  USART.Write ("Command :",BinToStr(IR.Com.byte1,8)," ",BinToStr(IR.Com.byte0,8),13,13)

  Else // если не прошел проверку
  IR.Com=0 // сбросили все переменные в 0
  IR.Adr=0
  IR.Stat=0
  IR.BitN=0
  IR.IntN=4
  Low(PORTB.3)  
  End If

End If

GoTo loop

основной блок выполнен по принципу If .. Then .. Else .. End if. То есть постоянно проверяются состояние флагов и значений и в зависимости от этого происходят действия.

1. Ловим стартовый бит 9+4.5ms. Поймали ??? выставили флаг начала приема
2. Если поймали стартовый бит и есть новый бит равный 1 или 0 и кол-во принятых бит меньше 31, то смещаем в право 16 битные регистры адреса IR.Adr и комманд IR.Com и заносим
в IR.Com.bit0 принятый бит

IR.Com.0=0 // заносим в IR.Com.bit.0 0 или 1
If IR.BitN<31 Then // если меньше 31 бита принято, то смещение данных
IR.Adr= IR.Adr<<1
IR.Adr.bit0=IR.Com.bit15
IR.Com= IR.Com<<1
End If
Inc(IR.BitN) // если больше 31 то просто прибавили 1 к счетчику бит

3. После приема 32 бит данных происходит прерывание по переполнению таймера(выставляются флаги окончания приема и переполнения таймера)

If IR.EndS=1 And IR.IntC=1 Then // если произошло прерывание и зафиксирован признак конца пакета
Inc(IR.IntN)
If IR.IntN=5 Then // если произошло больше 4 прерываний по переполнению таймера, то нет сигнала.
IR.Com=0 // сбросили все переменные в 0
IR.Adr=0
IR.Stat=0
IR.BitN=0
IR.IntN=4
Low(PORTB.3) // сбросили индикацию повтора

End If
IR.IntC=0 // сброс счеткика переполнения таймера
End If

4. Проверяем флаги: произошло прерывание, был стартовый сигнал, 32 бита приняли ? Значит можно приступать к проверки кода. Здесь NEC интересно поступил. В 16 битах адреса
(так же и комманд) нужно сравнить старший и младший бит. Если они равны, значит код верен (IR.Adr.byte1=Not IR.Adr.byte0 и IR.Com.byte1=Not IR.Com.byte0).
Выставляем бит правильности принятого кода (IR.Ok=1)

5. Далее ловим бит повтора, и если он обнаружен выставляем флаг повтора (IR.Rep=1).

6. Если кодовая посылка прерывается (или биты повтора) то через 5 прерываний будет сброшен флаг повтора, остальные переменные, данные и программа будет ждать прихода
нового стартового бита.

Схема и проэкт а Протеусе с COF(позволяет производить пошаговую отладку в Протеусе) файлами прикладываю в Архиве. Там же приложенная программа имитация пульта ИК(Работает PORTB.0). Фотки и Видео макетки выложу попозже.

Всем успехов и с наступающим Новым Годом !!!!!

С уважением Алексей (DAlexV)


Категория: Swordfish | Добавил: DAlexV (27.12.2011) | Автор: Алексей
Просмотров: 9595 | Комментарии: 5 | Теги: ИК декодировка, IR Decode, Swordfish, IR NEC, IR, прерывание B.0, ИК NEC | Рейтинг: 5.0/4
Всего комментариев: 5
1 retas   (30.12.2011 01:50)
Спасибо, конечно, но это как Кадилак, а вот чтоб для народа, т.е. не на Рыбе, не на PIC18 да под любой пульт ДУ!!! Извините за наглость.

2 DAlexV   (30.12.2011 09:48)
Quote (retas)
т.е. не на Рыбе, не на PIC18
Так в чем проблема ???? PIC что 16, что 18 или 12. Таймеры и прерывания существуют во всех процессорах. Если есть запарки с переводом, пишите, постараюсь объяснить. Я хотел показать принцип совместного использования прерываний в совокупности с работой основного текста программы(выполнение приема кода без остановки основного листинга.
Это все можно пощупать вживую в Протеусе). Что же касаемо "под любой пульт ДУ", то можно будет попробовать расшириться. Просто пока не имею в своем наличии пульта под RC5, да и как выясняеться что некоторые производители просто "забивают" на стандарты(используют свои), а писать под нестандарт не имеет смысла.

3 ivan_fd   (30.12.2011 11:46)
Спасибо! Отличный проект. biggrin
P.S: Мое мнение, помаленьку нужно забывать о 16-ых пиках. 18-ые и мощнее и дешевле.

4 retas   (30.12.2011 19:27)
Моя мечта, иметь обучаемый приёмник под любую IR посылку.
По ценам у нас 18-ый на 40 лап почти в три раза дороже PIC16F887.

5 Ramirez   (12.02.2014 12:46)
A никто ли не занимался приёмом сигналов протокола RC5?

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]