IR Remote Control programs for the NEC Protocol and Variants.


Author Message
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 3191
Posted: 11:50am 30 Aug 2024      

Here is a MMBasic version of the NECsend Subroutine that supports 8 and 16 bit Device Codes,
with or without bit order reversal*** and the Samsung32 variant.
Tested on Picomite and ArmMiteF4.

***The MMBasic IR reading command outputs codes with MSB first and 16 bit Device Code so this is the default setting
but the NEC specifies LSB first. This can be selected with an extra parameter if you have codes intended for that format.

Usage:
Call "NECsend DeviceCode, KeyCode [, Variant]"

If using the Sub in an existing program that can't have a separate Variant parameter the parameter can instead be bit shifted up 16 and added to the DeviceCode.

eg Inc DeviceCode, (Variant << 16)
Then Call "NECsend DeviceCode, KeyCode

Variant:
0  standard NEC 16 bit DeviceCode, MSB first (default)
1  Samsung32
2  standard NEC 8 bit DeviceCode, MSB first
3  standard NEC 16 bit DeviceCode, LSB first
4  standard NEC 8 bit DeviceCode, LSB first

' "NECsend with option for Samsung32 variant.bas"
'Dim Integer IRpin=MM.Info(pinno GP0) 'for Picomite - set your output pin
Dim Integer IRpin=MM.Info(pinno PA0) 'for ArmMiteF4 - set your output pin
Dim Integer dev, key, V 'for standard NEC V = 0, or omit. V = 1 for Samsung32
'for 8 bit NEC Dev code V = 2
'for 16 bit, LSB first NEC Dev code V = 3
'for 8 bit, LSB first NEC Dev code V = 4

'Alternatively those variants can instead be denoted by adding them to Dev above bit 16
'eg. for S32 (V=1) Device 5 Dev = &H10005 = 65541
Do
'Your program here.
 Input "Enter Device, Key, Variant (NEC=0, S32=1) codes "; dev, key, V
 NECsend IRpin, dev, key, V
Loop

Sub NECsend IRpin As integer, Dev As integer, Key As integer, V As integer
Local Integer word, d(1390), m, n = 1
Local Float T
Pin(IRpin) = 0
Math set 13, d() 'fill array. 13=1000/(38*2) uS - duration of a half cycle @ 38kHz
'Math set 14, d() 'to overcome F4 timing error use this instead of line above

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 = 1 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
  BitBang bitstream IRpin, 330, d() 'send 4.5ms start 38kHz
 Else

  If (V=2) OR (V=4) Then dev = (Dev << 8) + 255-Dev  'convert 8 bit address to 16 if required
  If (V=3) OR (V=4) 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 ':Print Bin$(word,32) 'assemble 32 bits '16 bit address only
  BitBang bitstream IRpin, 620, d() 'send 9ms start 38kHz
EndIf

T = Timer' :Print t
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 (short = 0, long = 1)
 Inc n ':Print d(m); 'step to next data bit
Next

Do : Loop Until Timer > T+4.3 ':Print Timer-T 'less than 4.5 due processing time, adjust for CPU speed
BitBang bitstream IRpin, 1386, d() 'send the data

'Pin(IRpin) = 0
End Sub

'Samsung32 specification:-
  'coding: Pulse Distance (same as NEC, fixed length pulses, long pause=1 short=0)
  'Frame: 1 start + 32 Coding + 1 Stop bit (same as NEC)
  'Data: 8 bit address + 8 bit address + 8 bit command + inverted 8 bit command - all bytes LSB first
  '       (old NEC 8bit address similar but 2nd copy inverted. Most NEC use 16bit address)
  'Start Bit: 4500uS pulse 4500uS pause (NEC Start Bit: 9000uS pulse 4500uS pause)
  'Data: 0 bit = 550uS pulse + 550uS pause, 1 bit = 550uS pulse + 1650uS pause
  '              (close enough to NEC - 562.5uS, difference = 1/2 cycle & 38kHz)
  'Stop Bit 550uS pulse (almost same as NEC - 562.5uS)
  'Repetition after 47mS
End

The current F4 BitBang Bitstream command has a small timing error, however for most devices it is close enough.
If some don't work changing: Math set 13, d() to Math set 14, d() should fix it.

The MMBasic IR command reads Sony and standard NEC codes but not the Samsung32 variant.
So here is a IR code reader for the Samsung32 variant. Tested on a PicoMite.
Samsung32 has a 4.5mS start pulse instead of 9mS and has an 8 bit device code repeated without inverting.
Bit timings are multiples of 550uS instead of 562.5uS but I found 560uS works for both.
' "Samsung32 IR code receiver.bas"
' tested on PicoMite v5.09.00 126MHz to 400MHz
Dim Integer Dev, Key, IRpin=MM.Info(pinno GP6) ' set your pin
SetPin IRpin, INTL, IR_Rx_Samsung32
Print
Print "Dev", "Key"

Do : Loop

Sub IR_Rx_Samsung32
 SetPin IRpin, off :SetPin IRpin, DIN 'stop interrupt and prepare to get data
 Local float T=Timer, T1, Tmax=300, Z=T+Tmax
 Local Integer n, m

 Do :Loop Until Pin(IRpin)Or(Timer>Z),:Do While Pin(IRpin)And(Timer<Z):Loop :T1=Timer-T
 'wait for start sequence to complete then get time, falling edge to falling edge
 For n=0 To 31
  T=Timer :Do :Loop Until Pin(IRpin):Do While Pin(IRpin):Loop :T1=Timer-T

  If T1>1.4 And T1<2.4 Then 'measure bits, add to word, LSB first into MSB and shifting down
    m=(m>>1) + &H80000000 'add 1
   Else
    m=m>>1 'add 0
  EndIf
 Next

 SetPin IRpin, off
'  Print :Print Bin$(m,32), "Bit order reversed so MSB is on the left" :Print

'  Print Bin$(m And &Hff,8), Bin$(m>>16 And &Hff,8) 'show assembled bytes 1 & 3 (m is in reverse order)
'  Print Bin$(m>>8 And &Hff,8), Bin$(255-(m>>24) And &Hff,8) 'show assembled bytes 2 & inverted 4
   'error check. compare byte 1 and byte 2
 If ((m And 255) = ((m>>8) And 255)) And (((m>>16) And 255) = (255-((m>>24) And 255))) Then
   dev = m And &Hff 'get device code
   key = m >> 16  And &Hff 'get key code
   Print Dev, Key
  Else
   dev=-1 :key=-1
 EndIf

 Pause 300 'prevent re-triggering, Samsung remote always sends code twice
 SetPin IRpin, INTL, IR_Rx_Samsung32 'prepare for next input

End Sub

'Samsung32 specification:-
  'coding: Pulse Distance
  'Frame: 1 start + 32 Coding + 1 Stop bits
  'Data: 8 bit address + 8 bit address + 8 bit command + inverted 8 bit command all LSB first
  'Start Bit: 4500uS pulse 4500uS pause
  'Data: 0 bit = 550uS pulse + 550uS pause, 1 bit = 550uS pulse + 1650uS pause
  'Stop Bit 550uS pulse
  'Repetition after 47mS
  'on the remote control I have a button press always sends the code at least twice

Edited 2024-08-30 22:00 by phil99

Footnote added 2024-08-31 11:18 by phil99
First Bug - MM.INFO(Pinno xx) is different on F4 to Pico. It gives the first pin of the Port, not the individual pin number.
By blind luck the pin I used was the first pin of that port so it worked.

For the F4 define IRpin this way:-
' "NECsend with option for Samsung32 variant.bas"
'Dim Integer IRpin = MM.Info(pinno GP0) 'for Picomite - set your output pin
Dim Integer IRpin = 23  '= PA0  for ArmMiteF4 - set your output pin