Телесистемы
 Разработка, производство и продажа радиоэлектронной аппаратуры
На главную   | Карта сайта | Пишите нам | В избранное
Требуется программист в Зеленограде
- обработка данных с датчиков; ColdFire; 40 тыс.
e-mail:jobsmp@pochta.ru

Телесистемы | Электроника | Конференция «Микроконтроллеры и их применение»

Инфо

Отправлено djn 01 августа 2007 г. 20:22
В ответ на: Ответ: готовая программа отправлено <font color=gray>djn</font> 01 августа 2007 г. 20:21

NEC Decoder
The NEC protocol allows control of over 256 different devices with 256 different commands per device. On my PIC IR decoder addresses are shown on the left two digits, while commands are shown on the right two. The device address and the command number are both displayed in hexadecimal format.
Only the first message actually contains the address and command information. All other messages contain only a pre-pulse and one single stop pulse to indicate key repetition. This will continue for as long as the key is held down.
The software will only detect repetition pulses for as long as the display is still valid. This means that it will not respond to repetition messages once the display is cleared.
The right most decimal point of the display will light when the software detect a difference between the normal and inverted values of the message. Otherwise this decimal point remains off.
NEC Decoder Software
In my knowledge base you can read that the NEC protocol uses pulse distance modulation of the IR carrier to transmit a total of 32 bits. Addresses and commands are transmitted twice. The first time with normal polarity, the second time with inverted polarity. During normal polarity a logical zero is represented by an interval of 1.12 ms, while a logical one is represented by double that value which is 2.25 ms. I'm going to use the average value between these intervals as a threshold to determine wether a "0" or a "1" was received. Any interval shorter than 1.5 ms is interpreted as a "0" and intervals above 1.5 ms are interpreted as a "1". Intervals longer than 3 ms cause the routine to exit with an error condition.
This loose checking of the intervals makes the decoding process a lot easier, but it may happen that the receiver listens to foreign protocols too. In our case this is not very important. But if you intend to control more critical devices you should check the interval boundaries a little more careful. A good alternative would be to check whether the intervals are within a ±10% range of the nominal values.

Example of the states of the IR state machine

Repeat message states of the IR state machine
Again the IR decoding software relies on a state machine. The picture above shows all different states during the decoding process.
;-----------------------------------------------------------------------------
; IR receiver state machine
;-----------------------------------------------------------------------------

IR_MACHINE MOVF IR_STATE,W Jump to present state
MOVWF PCL
Here we go again! Nothing new here. As usual the IR_MACHINE routine is called every 50 µs by the main program loop.
;---------------------------------------STATE 0, WAIT FOR FIRST FALLING EDGE--

IR_STATE_0 BTFSC PORTA,4 Input still high?
RETURN Yes! Nothing to do here

CLRF IR_SHIFT Prepare shift register
CLRF IR_SHIFT+1
CLRF IR_SHIFT+2
MOVLW %1000.0000
MOVWF IR_SHIFT+3
CLRF BIT_TIMER Clear bit timer
MOVLW IR_STATE_1 Next stop is state 1
MOVWF IR_STATE
RETURN
As long as the input remains high we return immediately. Otherwise the IR shift register, which will hold the received message, is initialized. The "1" in the most significant bit of the shift register will eventually roll out after 32 shifts, indicating the end of the message.
BIT_TIMER is cleared to 0 and will increment every 50 µs. Obviously this timer is going to be used as pulse distance timer.
;-------------------------IR STATE 1, LET'S SEE IF THIS IS THE 9MS PRE-PULSE--

IR_STATE_1 INCF BIT_TIMER Increment bit timer
BTFSC PORTA,4 Input still low?
GOTO .HIGH Nope!

MOVLW 9900/50*-1 Longer than 9ms + 10% low?
ADDWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN No, OK!

MOVLW IR_ERROR_0 Wait until input returns high
MOVWF IR_STATE and then start all over again
RETURN

.HIGH MOVLW 8100/50*-1 See if length was at least 9ms - 10%
ADDWF BIT_TIMER,W
BTFSS STATUS,CARRY Carry will be set if it was
GOTO IR_ERROR_1 Exit with error if it wasn't

MOVLW IR_STATE_2 Next stop measure the length of the
MOVWF IR_STATE gap between pre-pulse & message
CLRF BIT_TIMER
RETURN
We arrive at state 1 when a low level on the input was detected and we will stay here until the input goes high again or until the maximum pulse width is reached. We are expecting to find a 9 ms long pre-pulse in this state. First of all we increment BIT_TIMER. Then we check to see if the input is still low. If it's not we jump to label .HIGH. As long as the input remains low we check to see if the maximum pulse width of about 9.9 ms is exceeded (9ms + 10%). Otherwise we stay in state 1.
In case the input has gone high we verify if the pulse lasted at least 9 ms -10% and then we continue with state 2.
;--------------------------STATE 2, PRE-PULSE DETECTED, NOW MEASURE GAP TIME--

IR_STATE_2 INCF BIT_TIMER Increment bit timer
BTFSS PORTA,4 Input still high?
GOTO .LOW Nope!

MOVLW 4950/50*-1 Longer than 4.5ms + 10% high?
ADDWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN No, OK!

GOTO IR_ERROR_1 We give up!
RETURN

.LOW MOVLW 3350/50*-1 See if it was a long or short pause
ADDWF BIT_TIMER,W

MOVLW IR_STATE_4 Let's get the message if it was a long
BTFSS STATUS,CARRY one (if Carry is set)
MOVLW IR_STATE_3 It was a short one! It's a repetition!

MOVWF IR_STATE
CLRF BIT_TIMER
RETURN
During this state we determine if we have a short interval (repeat message) or a long interval (normal message) between the pre-pulse and the first data pulse.
Things are wrong if the input signal remains high longer than 4.5 ms +10%. I use the average value between a short and a long interval to set the trip point of the comparison. Any value below the trip point will send us to state 3 (repeat message) and any value above the trip point will send us to state 4 (normal message).
;----------STATE 3, REPETITION DETECTED, LET'S SEE IF DISPLAY IS STILL VALID--

IR_STATE_3 MOVLW IR_STATE_8 Next state will be 8 anyway, so let's
MOVWF IR_STATE set it now

MOVLW %1011.1111 See if display time still valid
XORWF DIGIT1,W
BTFSC STATUS,ZERO
RETURN No! Forget about the repetition then

MOVLW CLR_TIME Restart display stimer
MOVWF CLR_DELAY
MOVLW DP_TIME And also flash the DP
MOVWF DP_DELAY
BCF DIGIT2,7

RETURN
We arrive at state 3 when a repeat message is received. This is the most simple message, consisting of only one stop pulse. We're at the center of this stop pulse now.
The effect of the repeat message will be that the receive dot on the display is triggered again and that the display time out will be reset. But this is only done if the display value was still valid. Nothing will happen if the display was cleared before due to a time out.
In any case the next state will be state 8, where we wait for the input to return high again.
;---------------------------------STATE 4, INPUT IS LOW, MUST BE A PULSE THEN--

IR_STATE_4 INCF BIT_TIMER Increment bit timer
BTFSC PORTA,4 Input still low?
GOTO .HIGH No! Pulse is over now.

MOVLW PULSE_MAX See if max pulse width reached
XORWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN Not yet!

MOVLW IR_ERROR_0 Wait until pulse goes high again
MOVWF IR_STATE before accepting new command
RETURN

.HIGH MOVLW IR_STATE_5 Input is now high
MOVWF IR_STATE Next stop is state 2
RETURN
A low signal has been detected. We start by incrementing BIT_TIMER. Then we check that BIT_TIMER hasn't exceeded the maximum pulse width.
Finally we check to see if the input is still low. If it is not we continue with state 5.
;-------------STATE 5, WAIT FOR PULSE TO GO LOW AGAIN, THEN MEASURE INTERVAL--

IR_STATE_5 INCF BIT_TIMER Increment bit timer
MOVLW BIT_TIME*3 Should we keep waiting?
XORWF BIT_TIMER,W
BTFSC STATUS,ZERO
GOTO IR_ERROR_1 No, we've waited 3 bit times already!

BTFSC PORTA,4
RETURN Keep waiting while input remains high

MOVLW BIT_TIME/2+BIT_TIME*-1 Use 1.5 bit time as threshold
ADDWF BIT_TIMER,W Carry is 1 if more than 1.5 times

RRF IR_SHIFT+3,F Roll carry into result
RRF IR_SHIFT+2,F
RRF IR_SHIFT+1,F
RRF IR_SHIFT,F

CLRF BIT_TIMER Restart bit timer
MOVLW IR_STATE_4 Return to state 1 if not done yet
MOVWF IR_STATE

BTFSS STATUS,CARRY See if we're done
RETURN Not done yet, continue with state 1

MOVLW IR_STATE_6 Message received, but wait 3ms longer
MOVWF IR_STATE to see if nothing follows.
CLRF BIT_TIMER
RETURN
Again we increment BIT_TIMER. Then we check to see if BIT_TIMER has reached its upper limit of 3 bit times. Clearly that would indicate an error situation and causes us to jump to IR_ERROR_1. If the bit time is still OK we check to see if the input is still high, which it is in between two adjacent pulses. If it is we can simply return to the main program loop again.
But if the input has gone low we arrived at the next pulse and we can now evaluate BIT_TIMER. I already said that I use a threshold value of 1.5 times the "0" bit time. Because the SB-Assembler can handle only integers the formula to do this calculation may seem a bit odd. First we do BIT_TIME/2 and add BIT_TIME to that value, which is the same as 1.5 times BIT_TIME. At the end we multiply the entire value with -1 to get a negative number which can be added to BIT_TIMER. Thus actually this addition is a subtraction. Please note that the SB-Assembler knows nothing about mathematic precedence and will perform calculations in the order in which they appear in the formula.
Subtracting 1.5 bit-time from BIT_TIMER will cause the Carry to be set only if BIT_TIMER was larger than 1.5 bit-time. This Carry is then simply rolled into the IR_SHIFT registers from the left to build up the end result.
Since we've arrived at the next pulse now we must clear BIT_TIMER before we can measure the next interval. And if more bits are to follow we must continue with state 4 again.
We know that more bits follow if the shifting process left the Carry cleared. Otherwise we forget about state 4 and will continue with state 6, where we are going to make sure no more bits follow.
;-------------------STATE 6, RECEIVED MESSAGE, WAIT 3MS TO ENSURE IT WAS NEC--

IR_STATE_6 INCF BIT_TIMER Increment bit timer
BTFSC PORTA,4 Input still low?
GOTO .HIGH No! Pulse is over now.

MOVLW PULSE_MAX See if max pulse width reached
XORWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN Not yet!

MOVLW IR_ERROR_0 Wait until pulse goes high again
MOVWF IR_STATE before. accepting new command
RETURN

.HIGH MOVLW IR_STATE_7 Input is now high
MOVWF IR_STATE Continue with 3ms delay
RETURN
After receiving the entire message we must make sure that no more bits follow.
I want to state that any similarities with state 4 are purely coincidental! Of course they are not. All I want to do now is wait until the last pulse ends, just like we did in state 4. When the input goes high we go to state 7, where we wait 3 ms before finally accepting the received code.
;---------------------------STATE 7, INPUT MUST REMAIN HIGH FOR AT LEAST 3MS--

IR_STATE_7 INCF BIT_TIMER Increment bit timer

BTFSS PORTA,4 Has the input gone low now?
GOTO .ERROR Yes! This is not good!

MOVLW BIT_TIME*3 Have we waited long enough now?
XORWF BIT_TIMER,W
BTFSS STATUS,ZERO
RETURN Not yet!

MOVLW CLR_TIME Set display clear timer
MOVWF CLR_DELAY


MOVLW DP_TIME Flash receive LED
MOVWF DP_DELAY

SWAPF IR_SHIFT,W Work from left to right
CALL HEX2SEGMENTS
MOVWF DIGIT1

MOVF IR_SHIFT,W Do the same with 2nd digit
CALL HEX2SEGMENTS
ANDLW %0111.1111 Flash dot of this digit
MOVWF DIGIT2

SWAPF IR_SHIFT+2,W And with the 3d digit
CALL HEX2SEGMENTS
MOVWF DIGIT3

MOVF IR_SHIFT+2,W And finally with the last digit
CALL HEX2SEGMENTS
MOVWF DIGIT4

MOVF IR_SHIFT,W Compare normal and inserted codes
ADDWF IR_SHIFT+1,F
INCF IR_SHIFT+1,F
MOVF IR_SHIFT+2,W
INCF IR_SHIFT+3,F
ADDWF IR_SHIFT+3,W
IORWF IR_SHIFT+1,W Result should be 0 now!

BTFSS STATUS,ZERO Did the checksum match?
BCF DIGIT4,7 Light right DP if it didn't

MOVLW IR_STATE_0 We're done! Let's get some rest
MOVWF IR_STATE
RETURN

.ERROR MOVLW IR_ERROR_0 Wait until input gets high again
MOVWF IR_STATE before returning to state 0
RETURN
The first few lines of this state are responsible for ensuring that no more bits follow the received code, which would tell us that we're not receiving a NEC protocol. Once we are certain that nothing follows we can finally display the received message.
We've seen all this before. So I'm not going to explain it again. There's one thing I would like to say about the rest of the code though. The NEC protocol transmits the data twice, once normal and once inverted. At the end of state 7 I compare these two values. If the don't match I light the right most decimal point on the display to indicate the error situation.
;----------------------------------IR ERROR 0, WAIT FOR INPUT TO RETURN HIGH--

IR_STATE_8
IR_ERROR_0 MOVLW IR_STATE_0 Reset state machine only if input is
BTFSC PORTA,4 high
MOVWF IR_STATE
RETURN
;-----------------------------------------------------------IR ERROR STATE 1--

IR_ERROR_1 MOVLW IR_STATE_0 Return to IR state 0
MOVWF IR_STATE
RETURN
Should I really explain these two routines again? We've seen them a couple of times before.



Составить ответ | Вернуться на конференцию

Ответы


Отправка ответа
Имя*: 
Пароль: 
E-mail: 
Тема*:

Сообщение:

Ссылка на URL: 
URL изображения: 

если вы незарегистрированный на форуме пользователь, то
для успешного добавления сообщения заполните поле, как указано ниже:
сложите три и три:

Перейти к списку ответов | Конференция | Раздел "Электроника" | Главная страница | Карта сайта

Rambler's Top100 Рейтинг@Mail.ru
 
Web telesys.ru