IR Remote Control programs for the NEC Protocol and Variants.
| Author | Message | ||||
| phil99 Guru Joined: 11/02/2018 Location: AustraliaPosts: 3344 |
Updates to include Apple remotes in Rx and Tx programs. See also Apple thread ' "NEC Apple, JVC16 Samsung32 IR code receiver v5.bas" ' tested on PicoMite v6.00.03, & ArmMiteF4 v5.07.02b4, 160MHz Dim Integer Dev, Key, V, IRpin = MM.Info(PinNo GP1) '<- set your Pico pin 'Dim Integer Dev, Key, V, IRpin = 1 '= PE2 <- set your F4 pin 'Main prog. after Sub Sub IR_Rx_NEC_V 'SetPin IRpin, off : SetPin IRpin, DIN 'stop interrupt and prepare to get data Local float T=Timer, T1, T2, T3, Tmax=300, Z=T+Tmax Local Integer n, W=0, Wr=0 'W = LSB first data Word, Wr is MSB first version dev = 0 : key = 0 : V = 0 : KN = "" T2=Pulsin(IRpin,1)/1000 ': Print "High after first carrier burst ="; T2;"uS" T3 = Timer - T - T2 'Print :Print "Start sequence ="; T3; " mS Low (carrier burst), ", T2; " mS High then 560 uS Low" 'wait for start sequence to complete then get data pulses 'Print "Data pulses, 560uS = 0, 3 x 560uS = 1" For n=0 To 31 T1=Pulsin(IRpin,1) 'Print T1, If (T1 < 2000) AND (T1 > 400) Then If T1>1000 AND T1<2000 Then 'measure bits, add to word, LSB first into MSB and shifting down W=(W>>1) + &H80000000 'add 1 to MSB Wr=(Wr<<1) + 1 'add 1 to LSB Else W=W>>1 'shift down = add 0 (Variant 1 & 3) Wr = Wr<<1 'shift up = add 0 (Reverse bit order = Variant 0 & 2) EndIf Else Exit For EndIf Next 'Print "Data as LSB first = &b"; Bin$(W,32), "&h";Hex$(W,8), W AND &Hffff, (W>>16) AND 255, (W>>24) AND 255, 255-((Wm>>24) AND 255);" Byte 4 inverted" 'Print "Data as MSB first = &b"; Bin$(Wr,32), "&h";Hex$(Wr,8), (Wr>>16), (Wr>>8) AND &Hff, Wr AND 255, 255-(Wr AND 255);" Byte 4 inverted" :Print SetPin IRpin, off ' Print :Print "Start pulse";T2;"mS ";Bin$(m,32); " Bit order has been reversed so MSB is on the left" 'Test for Samsung32 Variant If ((W AND 255) = ((W>>8) AND 255)) AND (T3 > 3) AND (T3 < 6) AND (V = 0) Then V = 4 'Samsung32, LSB first dev = W AND &Hff 'get device code key = W >> 16 AND &Hff 'get key code EndIf 'Test for JVC16 Variant If ((W AND &Hffff) = 0) AND (T3 > 7) AND (T2 < 11) AND (V = 0) Then V = 5 'JVC16 8 bit codes, LSB first dev = (W >> 16) AND &Hff 'get device code key = (W >> 24) AND &Hff 'get key code EndIf 'Test for Apple Variant If ((W AND &hFFFF) = &h87EE) AND (T3 > 7) AND (T3 < 11) AND (V = 0) Then V = 6 'Apple IR, LSB first, 16 bit device code = &h87EE after reversing bits Dev = (W>>24) AND &Hff 'get ID code (Apple is not standard so Dev is used for ID code parity = W >> 16 AND 1 'get parity bit (LSB of 8 bit Key) key = W >> 17 AND 127 'get 7 bit Key code Print "V =";V, "parity =";parity, "Key =";Key, "ID =";Dev : Print EndIf 'Test for NEC 8 bit Dev code, LSB first Variant (assumes Variant 3) 'MSB first and LSB first 8 bit Dev code variants (2 & 3) can't be distinguished so test several Keys, ' if the Dev code changes instead of the Key code use V = 2 instead of 3 If (T3 > 7) AND (T3 < 11) AND (V < 4) Then If (((255-(W>>24)) AND 255) = ((W>>16) AND 255)) AND (((255-(W>>8)) AND 255) = (W AND 255)) Then V = 3 'NEC 8 bit device code, LSB first dev = W AND &Hff 'get device code key = (W>>16) AND &Hff 'get key code Print "Codes for 8 bit Dev MSB first (V = 2): Dev ="; (Wr>>16) AND 255; " Key ="; (Wr>>8) AND 255 Print "Codes for 8 bit Dev LSB first (V = 3): Dev ="; Dev; " Key ="; Key : Print EndIf EndIf 'Test for NEC 16 bit Dev code, Variants 0 & 1 If (T3 > 7) AND (T3 < 11) AND (V < 2) Then If (((255-(W>>24)) AND 255) = ((W>>16) AND 255)) AND (((255-(W>>8)) AND 255) <> (W AND 255)) Then V = 1 'NEC 16 bit device code, LSB first dev = W AND &Hffff 'get device code key = (W >> 16) AND &Hff 'get key code Else V = 0 dev = (Wr>>16) AND &Hffff 'get device code MSB first key = (Wr>>8) AND &Hff 'get key code EndIf EndIf ' If V=6 Then ' Print "W, T3, T2, V, parity, Key, ID",, W AND &hFFFF,T3,T2,V,parity,key,dev ' Else ' Print "W, T3, T2, V, Dev, Key",, W AND &hFFFF,T3,T2,V,dev,key ' EndIf ' If V<>6 Then Print Dev, Key : Print If dev<>0 AND key<>0 Then 'output data If V = 6 Then Print "ID, Key, V", Hex$(Dev);","; Hex$(Key,2);","; V, Select Case Key Case 1 : KN$ = "Menu" Case 46 : KN$ = "Center, Select" Case 3 : KN$ = "Right, Next/Fast-Forward" Case 4 : KN$ = "Left, Previous/Rewind" Case 5 : KN$ = "Up, Volume +" Case 6 : KN$ = "Down, Volume -" Case 47 : KN$ = "Play/Pause" Case 2 : KN$ = "follows Center/Select or Play/Pause" Case Else : KN$ = "QUIT" End Select :Print KN$ EndIf If KN$ = "" Then Print "Device =";Dev, "Key =";Key, "Variant =";V, Input " Enter the Key name "; KN$ EndIf If (KN$ = "Quit") OR (KN$ = "quit") OR (KN$ = "QUIT") Then Print #3, : Print #3,"To use NECsend without the Variant number" Print #3,"replace the Device code:- ";Dev;" with:- ";Dev + (V<<16) Print #3,"except for Apple (V6) replace ID:- ";Dev;" with:- ";Dev + &h60000 : Print #3,"" Pause 55 Close #3 List "NEC_Key_Codes.txt" End Else Print #3, Dev;","; Key;","; V; " '"; KN$ EndIf EndIf Pause 300 'prevent re-triggering, Samsung & JVC remotes always send code twice SetPin IRpin, INTL, IR_Rx_NEC_V 'prepare for next input End Sub 'Main Dim string KN$ Open "NEC_Key_Codes.txt" For append As #3 Pause 55 Print "To save the data (NEC_Key_Codes.txt) press any RC key" Print " and type Quit at the 'Enter Key name ?' prompt." Print "Except for Apple (V = 6), use Key = 0 to quit" : Print Print "Device, Key, Variant, 'Function" Print #3, "'Device, Key, Variant, 'Function,,NEC_Key_Codes.txt" Timer = 0 SetPin IRpin, INTL, IR_Rx_NEC_V Do : Loop End ' "NECsend with Apple, JVC16 & Samsung32 variants v5.bas" Dim Integer IRpin = MM.Info(pinno GP0) 'pin 1 for PicoMite ' Dim Integer IRpin = 23 '= PA0 'for ArmMiteF4 Dim Integer dev, key, V Print "for NEC MMBasic IR command compaitbility (MSB first, 16 bit Dev code) - V = 0, or omit" Print "for NEC, LSB first, 16 bit Dev code - V = 1 (NEC standard)" Print "for NEC, MSB fits,t 8 bit Dev code - V = 2 (not really needed)" Print "for NEC, LSB first, 8 bit Dev code - V = 3 (old NEC standard)" Print "for Samsung32, LSB first - V = 4" Print "for JVC16, LSB first - V = 5" Print "for Apple, LSB first - V = 6, Dev is the Remote ID No. (byte 4). The actual Dev. code is &hEE, &h87 always" Print " and the least significant bit of the Key byte is a parity bit over the Key byte and the ID byte." Print " The ID code of an Apple remote may be changed by -" Print " 'Press and hold MENU + PLAY/PAUSE on any Apple remote to change (roll) its ID'" Print "Alternatively those Variants numbers can instead be denoted by adding them to Dev above bit 16" Print "eg. for S32 (V=4) added to Device &H0005 gives &H40005 or Dev = 262149" Print :Print 'Measure Device Bitstream startup time. Dim integer d(1390) : Dim float T, TD Math Set 13, d() '13uS intervals T=Timer Device Bitstream IRpin, 1390, d() T=Timer-T ':Print T, TD = T-13*1390/1000-0.1 ': Print "TD ="; TD "mS Bitstream calibration value" Erase d(), T 'Main Do 'Your program here. Input "Enter Device, Key, Variant (NEC=0 to 3, S32=4, JVC=5, Apple=6) codes "; dev, key, V NECsend IRpin, dev, key, V Loop Sub NECsend IRpin As integer, Dev As integer, Key As integer, V As integer 'For Apple codes (V = 6) Dev is the Remote ID No. 1 byte. The actual Dev. code is &h87EE Local Integer word, d(1390), m, n = 1 Local Float T Pin(IRpin) = 0 Math set 14, d() 'fill array. 13=1000/(38*2) uS - duration of a half cycle @ 38kHz If V = 0 Then V = (Dev >> 16) ' if V missing or 0 then look for V in Dev above bit 16 Dev = Dev And &hFFFF If (V=2) Or (V=3) Then Inc Dev, ((255-Dev) << 8) 'convert 8 bit address to 16 if required If (V=1) Or (V=3) Then key = ((Key And 255) * &H0202020202 And &H010884422010) Mod 1023 ' reverse Key bit order, 8 bit dev16 = (((dev And 255) * &H0202020202 And &H010884422010) Mod 1023) << 8 ' reverse Dev bit order, low byte dev = dev16 + ((dev >> 8) * &H0202020202 And &H010884422010) Mod 1023 'now reverse high byte & swap bytes EndIf word = (dev<<16) + (key<<8) + 255-key 'assemble 32 bits for 16 bit Device, Key and inverted Key 'Print "Word = &b"; Bin$(word,32), "&h"; Hex$(word,8) ' Samsung32. usage - Sub NECsend IRpin, Dev, Key, 4 If V = 4 Then dev = ((Dev And 255) * &H0202020202 And &H010884422010) Mod 1023 'ensure 8 bits only & key = ((Key And 255) * &H0202020202 And &H010884422010) Mod 1023 ' reverse bit order word = (dev<<24) + (dev<<16) + (key<<8) + 255-key 'assemble 32 bits Device bitstream IRpin, 324, d() 'send 4.5ms start 38kHz EndIf ' JVC16 usage - Sub NECsend IRpin, Dev, Key, 5 If V=5 Then dev = ((dev And 255) * &H0202020202 And &H010884422010) Mod 1023 ' reverse Dev bit order, 8 bit key = ((Key And 255) * &H0202020202 And &H010884422010) Mod 1023 ' reverse Key bit order, 8 bit word = (dev<<24) + (key<<16) EndIf ' Apple IR. usage - Sub NECsend IRpin, ID, Key, 6 'In this section ID uses the variable Dev If V = 6 Then ' ID = &h4D = 77 - WhiteWizard. ID = &h59, &h68, &h15 =(89, 104, 21) - Wikipedia ' press and hold MENU + PLAY/PAUSE on any Apple remote to change (roll) its ID - ' https://hifiduino.wordpress.com/apple-aluminum-remote/ ' LSB-> &hEE, &h87, Key, ID <-MSB, LSB of Key = parity bit (1=even) for next 15 bits. Key code (7 bits) and ID (8 bits) Local Integer Pbit = 1 'Parity bit is 1 if data bits are even For n= 0 To 7 : Pbit = (Pbit + ((Dev>>n) And 1)) And 1 : Next 'find parity bit For n= 0 To 6 : Pbit = (Pbit + ((Key>>n) And 1)) And 1 : Next Key = ((Key And 127)<<1) + Pbit 'convert 7 bit Key to 8 bits and add parity bit Key = ((Key And 255) * &H0202020202 And &H010884422010) Mod 1023 ' reverse bit order, 8 bit Dev = ((Dev And 255) * &H0202020202 And &H010884422010) Mod 1023 ' reverse bit order, 8 bit word = (30689<<16) + (key<<8) + dev 'assemble 32 bits '16 bit address only. dev = Apple ID No. EndIf ' Print "Word = &b"; Bin$(word,32), "&h"; Hex$(word,8) If V <> 4 Then Device bitstream IRpin, 650, d() 'send 9ms start 38kHz T = Timer : n = 1 For m = 42 To 1386 Step 42 'load data after start sequence, step 42 = 21 cycle IR pulse d(m) = (((word>>(32-n)) And 1)*2 + 1) * 560 'convert bits to duration (560uS = 0, 1680uS = 1) Inc n 'step to next data bit Next Do : Loop Until Timer > T+4.5-TD 'mS. Less than 4.5mS due to bitstream initialization time, ' adjust for CPU speed and firmware version. If V<>5 Then Device bitstream IRpin, 1386, d() 'send NEC data EndIf If V=5 Then Device bitstream IRpin, 698, d() 'send V5 JVC data Pause 33 Device bitstream IRpin, 698, d() 'repeat JVC data EndIf ' Math V_Print d() Pin(IRpin) = 0 End Sub End Edit. In recent PicoMite firmware Device Bitstream takes longer to load than older versions. This affects the pause time between the initial carrier burst and the start of data. Adjust to get close to 4.5mS. Some devices are very tolerant, others not so much. Do : Loop Until Timer > T+4.04 'mS. Less than 4.5mS due to bitstream initialization time To determine the required adjustment on your system use this program. SetPin gp3, dout Dim a(999) Math set 10,a() 'make a 10mS data stream For n=0 To 9 T=Timer Device bitstream gp3,1000,a() T=Timer-T-10 Print "Bitstream startup time"; T; "mS" Next > RUN Bitstream startup time 0.4710000008mS Bitstream startup time 0.4790000021mS Bitstream startup time 0.4640000015mS Bitstream startup time 0.4649999999mS Bitstream startup time 0.4609999992mS Bitstream startup time 0.4510000013mS Bitstream startup time 0.4539999999mS Bitstream startup time 0.4629999995mS Bitstream startup time 0.4599999972mS Bitstream startup time 0.4619999975mS > So to get a 4.5mS pause:- 4.5 - 0.46 = 4.04mS The size of the array only has a small effect on the time. I guess this measurement could done be in the program in the setup area to make it self calibrating. Edit 2. Auto calibration has been added to the NECsend program. Edited 2025-08-02 16:22 by phil99 Footnote added 2025-08-05 09:54 by phil99 Noticed a typo in the NECsend Sub. Sub NECsend IRpin As integer, Dev As integer, Key As integer, V As integer 'For Apple codes (V = 6) Dev is the Remote ID No. 1 byte. The actual Dev. code is &h87EE Local Integer word, d(1390), m, n = 1 Local Float T Pin(IRpin) = 0 Math set 14, d() 'fill array. 13=1000/(38*2) uS - duration of a half cycle @ 38kHz Math set 14, d() should be Math set 13, d() All the devices I have tolerate this carrier frequency ok so hadn't noticed it. 14uS was a fudge for a previous version of the ArmMiteF4 firmware whose Bitstream command ran a little fast. Footnote added 2025-08-05 11:40 by phil99 Getting even more forgetful. Changing that changes the length of the starting carrier burst. Once again has no effect on anything I have but for accuracy here are the changes with the new bitstream values in red. ' Samsung32. usage - Sub NECsend IRpin, Dev, Key, 4 If V = 4 Then dev = ((Dev And 255) * &H0202020202 And &H010884422010) Mod 1023 'ensure 8 bits only & key = ((Key And 255) * &H0202020202 And &H010884422010) Mod 1023 ' reverse bit order word = (dev<<24) + (dev<<16) + (key<<8) + 255-key 'assemble 32 bits Device bitstream IRpin, 350, d() 'send 4.5ms start 38kHz EndIf and If V <> 4 Then Device bitstream IRpin, 700, d() 'send 9ms start 38kHz T = Timer : n = 1 For m = 42 To 1386 Step 42 'load data after start sequence, step 42 = 21 cycle IR pulse d(m) = (((word>>(32-n)) And 1)*2 + 1) * 560 'convert bits to duration (560uS = 0, 1680uS = 1) Inc n 'step to next data bit Next |
||||