Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

a remote control using a pic

Status
Not open for further replies.
IR Remote Control Codes attached
 

Attachments

  • IR Remote Control Formats 1.PDF
    154.2 KB · Views: 246
Just succeeded in reproducing my first IR remote signal using swordfish, PIC18F43K22 and IR Click board. Raw bit times are stored in EEPROM.

Proves that it really can be done.

My code is terrible, testing is so far minimal, and I am very limited by only having the free SE version of Swordfish, but it works!

A pointless exercise, but I am so bored right now, that I found the challenge to be fun.
 
do you have a copy of the code?
I need a starting point and waiting on parts (the IR receiver and leds) but supposed to be in the mail this week.
 
whats so unbelievable?
if its the code in post #40, I have a printout and look up on data sheet etc.
I have the extended SF version.
 
Geez oh grief. Just ignore everything inconvenient and don't make the slightest effort to understand anything besides copy and paste.

Good luck in Arduino-land. Ask questions like this in their forums and it will look like a pit bull mauling.
 
I will post the development projects in the order that I created them. If I get bored and decide to make improvements, then I will edit my posts, rather than post multiple versions.

First project is simple LED flash for proving that hardware works
... already posted, but let's have all projects in one place

Code:
// amateur code - use at own risk - author accepts no responsibility for anything, anywhere, ever
// I have used direct-register programming, as it is what I am more familiar with - you may use BASIC style code if you wish
// tested on EasyPIC v7 development board with IR click inserted into mikroBUS 2 socket

Device = 18F43K22
Clock = 8                                 // adjust to suit your setup

// simple IR receiver test - PORTD LEDs reflect IR input status from RA2

// IR input is on RA3 - from 3-pin 38 KHz IR receiver module such as TSOP38338
// IR output is on RC1 - not used here
// LEDs on PORTD.0 and PORTD.1 where D0 mirrors input, D1 is inverted compared to IR input

ANSELA = 0                                // all digital
TRISA = $ff                               // all input for IR and switches
LATA = 0                                  // all low
ANSELD = 0                                // all digital
TRISD = 0                                 // all output for LEDs
LATD = 1                                  // LED pattern 0x01

Repeat
    If PORTA.3 = 1 Then                   // test IR input on RA3
        LATD = 1                          // LED on D0 lit if IR input is high (normal state)  , LED on D1 off
    Else
        LATD = 2                          // LED on D1 lit, LED on D0 off
    EndIf
Until false
 
Second project... Make timer 0 count in microseconds...
Code:
// simple timer 0 16 bit counter running at 1MHz
// 8Mhz clock provides timer 0 with 2Mhz to prescaler, prescaler 1:2 causes timer 0 to count microseconds

Device = 18F43K22
Clock = 8

// initialise

ANSELC = 0                                   // all digital
TRISC = 0                                    // all output
ANSELD = 0                                   // all digital
TRISD = 0                                    // all output

T0CON = $80                                  // timer 0 on, 16 bit, fosc/4, prescaler 1:2 - count microseconds

While true                                   // main program loop...
   LATC = TMR0L                              // background display timer 0 on LEDs - TMR0H read during read of TMR0L
   LATD = TMR0H                              // background display timer 0 on LEDs - expect 15.25Hz on RD7 for 1MHz counter
Wend
 
Third project - read the very first header mark time and show on LEDs...
Code:
// read first header bit of IR remote control signal
// I will test using Sony TV IR remote

// simple timer 0 16 bit counter running at 1MHz
// 8Mhz clock provides timer 0 with 2Mhz to prescaler, prescaler 1:2 causes timer 0 to count microseconds

Device = 18F43K22
Clock = 8


// Sony protocol:
// 40kHz 7 bits command (LSB first) then 5 bits address
// this is 12 bit, there are also 15 bit and 20 bit versions of Sony protocol
// start bit = 2.4mS mark, .6mS space
// 1 = 1.2mS mark .6mS space, 0 = .6mS mark .6ms space
// repeat every 45mS if key is held down
// Sony device will not respond to a single message,
//    - so remotes usually send 3 or more repeated messages


// initialise
ANSELA = 0                                   // all digital
ANSELB = 0                                   // all digital
TRISB = 0                                    // all output for diagnostic LEDs
ANSELC = 0                                   // all digital
TRISC = 0                                    // all output for diagnostic LEDs
ANSELD = 0                                   // all digital
TRISD = 0                                    // all output for diagnostic LEDs

T0CON = $80                                  // timer 0 on, 16 bit, fosc/4, prescaler 1:2 - count microseconds

While true                                   // main program loop...

   LATB = 0                                  // start of a new IR read
   DelayMS(1000)                             // allow time for end of previous IR remote message
   LATB = 1                                  // waiting for header

   While(PORTA.3) = 1                        // wait for IR input to go low - first leader bit 2.4ms (0x0960 microseconds hex)
   Wend
   LATB = 2                                  // header started
   TMR0H = 0                                 // gets written later, when TMR0L is written
   TMR0L = 0                                 // clear count and prescaler

   While(PORTA.3) = 0                        // wait for IR input to go high - end of first leader bit 2.4ms 
   Wend
   LATB = 3                                  // header ended
    
   LATC = TMR0L                              // background display timer 0 on LEDs - TMR0H read during read of TMR0L
   LATD = TMR0H                              // background display timer 0 on LEDs - expect 15.25Hz on RD7 for 1MHz counter
Wend
 
Fourth project - read an IR message to EEPROM - information contained in comments
Code:
// read IR remote control signal to PIC EEPROM
// I will test using Sony TV IR remote

// EEPROM will contain sets of 4 bytes in the order mark-low_byte, mark-high_byte, space_low_byte, space-high-byte
// combine high/low bytes to get number of microseconds mark or space
// number of bits stored as byte in EEPROM location 255

// status 28 December 2020 - seems to work, but this is a really dumb program that does not yet stop at end of message
//      - press the button twice or set correct number of bits in code
//      - will improve if and when I get bored enough
 
// simple timer 0 16 bit counter running at 1MHz
// 8Mhz clock provides timer 0 with 2Mhz to prescaler, prescaler 1:2 causes timer 0 to count microseconds

Device = 18F43K22
Clock = 8

// import EEPROM module
Include "EEPROM.bas"

// Sony protocol:
// 40kHz 7 bits command (LSB first) then 5 bits address
// this is 12 bit, there are also 15 bit and 20 bit versions of Sony protocol
// start bit = 2.4mS mark, .6mS space
// 1 = 1.2mS mark .6mS space, 0 = .6mS mark .6ms space
// repeat every 45mS if key is held down
// Sony device will not respond to a single message,
//    - so remotes usually send 3 or more repeated messages

// There is a fundamental issue with measuring raw timing from IR receiver, as the received signal is a slightly distorted reproduction
//   of the original waveform sent by IR remote. Space times are shortened a little and mark times are lengthened a little.
//   If you are lucky, then the distortion will be small enough that you may acheive re-transmission that is good enough.

Const NumCycles = 35                               // a cycle is considered to be a mark followed by a space
  
Dim mark_microseconds_h As String   (NumCycles + 2)
Dim mark_microseconds_l As String   (NumCycles + 2)
Dim space_microseconds_h As String  (NumCycles + 2)
Dim space_microseconds_l As String  (NumCycles + 2)
Dim bitcount As Byte                               // count bits
Dim int_microseconds As Word
Dim int_microseconds2 As Word
Dim gap_found As Byte                              // count bits up to inter-message gap
Dim junk As Byte                                   // just a throw-away byte

// initialise
ANSELA = 0                                         // all digital
ANSELB = 0                                         // all digital
TRISB = 0                                          // all output for diagnostic LEDs

T0CON = $80                                        // timer 0 on, 16 bit, fosc/4, prescaler 1:2 - count microseconds

While true                                         // main program loop...

   LATB = 0                                        // diagnostic - start of a new IR read
   DelayMS(1000)                                   // allow time for end of previous IR remote message
   LATB = 1                                        // waiting for header

   While(PORTA.3) = 1                              // wait for IR input to go low - first leader bit 2.4ms (0x0960 microseconds hex)
   Wend
   LATB = 2                                        // diagnostic - header started
   TMR0H = 0                                       // gets written later, when TMR0L is written
   TMR0L = 0                                       // clear count and prescaler
   gap_found = 0                                   // initialise

   For bitcount = 0 To (NumCycles -1)              // adjust for the maximum number of bits wanted
      While(PORTA.3) = 0                           // wait for IR input to go high - end of next mark bit 
      Wend
      mark_microseconds_l(bitcount) = TMR0L        // background TMR0H read during read of TMR0L
      mark_microseconds_h(bitcount) = TMR0H        // expect a count of approximately 2400 for 2.4ms
      TMR0H = 0                                    // gets written later, when TMR0L is written
      TMR0L = 0                                    // clear count and prescaler
  
      While(PORTA.3) = 1                           // wait for IR input to go low - first leader bit 2.4ms (0x0960 microseconds hex)
          junk = TMR0L                             // don't care about timer low byte, but need to populate TMR0H
          If TMR0H > 200 Then                      // threshold for determining end of message - 0 is about 20ms
             gap_found = bitcount                  // indicate that an inter-message gap found at bit gap-found
             LATB = 2                              // diagnostic - gap found
          EndIf
      Wend
      space_microseconds_l(bitcount) = TMR0L       // background TMR0H read during read of TMR0L
      space_microseconds_h(bitcount) = TMR0H       // expect a count of approximately 2400 for 2.4ms
      TMR0H = 0                                    // gets written later, when TMR0L is written
      TMR0L = 0                                    // clear count and prescaler
      
   Next
   LATB = 3                                        // diagnostic - numcycles bits received

   EE.WriteByte(255, gap_found)                    // write number of bits to EEPROM...

   For bitcount = 0 To (NumCycles -1)                                             // adjust for the maximum number of bits wanted
      int_microseconds = mark_microseconds_l(bitcount)
      int_microseconds2 = mark_microseconds_h(bitcount)
      int_microseconds2 = int_microseconds2 * 256
      int_microseconds = int_microseconds + int_microseconds2                     // we now have mark time in int_milliseconds

      EE.WriteWord(bitcount * 4, int_microseconds)                                // write mark data to EEPROM...

      int_microseconds = space_microseconds_l(bitcount)
      int_microseconds2 = space_microseconds_h(bitcount)
      int_microseconds2 = int_microseconds2 * 256
      int_microseconds = int_microseconds + int_microseconds2                     // we now have space time in int_milliseconds

      EE.WriteWord((bitcount * 4) + 2, int_microseconds)                          // write space data to EEPROM...

   Next
  
Wend
 
Fifth Project - get timing information from EEPROM (created in project 4) and send to IR when button pushed
Be sure not to erase EEPROM between projects 4 and 5

Code:
// send IR remote control signal using PIC EEPROM raw timing information
// I tested using Sony TV IR remote button '7', but should work for many common remote controls

// IR input is on RA3 - not used here
// IR output is on RC1 - 38Khz PWM 2 output
// button on RA4 goes low when pressed - causes IR message to be sent

// EEPROM should contain sets of 4 bytes in the order mark-low_byte, mark-high_byte, space_low_byte, space-high-byte
// combine high/low bytes to get number of microseconds mark or space
// EEPROM address 255 contains a byte with number of original IR bits in message
// note that what I call an IR bit, is really just a mark/space pair. This may or may not correspond to a bit, depending on protocol

// status 28 December 2020 - seems to work, but not properly tested yet
// there are vast opportinities for improvement, but this examplee proves the concept
 
Device = 18F43K22
Clock = 8

Include "EEPROM.bas"

// Sony protocol:
// 40kHz 7 bits command (LSB first) then 5 bits address
// this is 12 bit, there are also 15 bit and 20 bit versions of Sony protocol
// start bit = 2.4mS mark, .6mS space
// 1 = 1.2mS mark .6mS space, 0 = .6mS mark .6ms space
// repeat every 45mS if key is held down
// Sony device will not respond to a single message,
//    - so remotes usually send 3 or more repeated messages

// There is a fundamental issue with measuring raw timing from IR receiver, as the received signal is a slightly distorted reproduction
//   of the original waveform sent by IR remote. Space times are shortened a little and mark times are lengthened a little.
//   If you are lucky, then the distortion will be small enough that you may acheive re-transmission that is good enough.

Const NumCycles = 60                               // a cycle is considered to be a mark followed by a space
  
Dim bitcount As Byte                               // count bits
Dim int_microseconds As Word
Dim num_bits As Byte                               // message bits found from EEPROM

Sub send_mark()
    T2CON.2 = 1                                    // start PWM
    DelayUS(int_microseconds)
    T2CON.2 = 0                                    // stop PWM
End Sub

Sub send_space()
    DelayUS(int_microseconds)
End Sub

// initialise
ANSELA = 0                                         // all digital
ANSELB = 0                                         // all digital
TRISB = 0                                          // all output for diagnostic LEDs
ANSELC = 0                                         // all digital
TRISC = 0                                          // all output for diagnostic LEDs and PWM out
CCPR2L = 20                                        // duty cycle approx 30%
CCP2CON = $0c                                      // PWM mode
CCPTMRS0 = $0                                      // use timer 2
PR2 = $38                                          // adjust for $38=36kHz, $34=38kHz or $31=40kHz
T2CON = $04                                        // timer 2 off

While true                                         // main program loop...

   LATB = 0                                        // diagnostic - start of a new IR read

   While(PORTA.4) = 1                              // wait for button to go low - button press gives low
   Wend

   num_bits = EE.ReadByte(255)                                                    // read number of bits from EEPROM...
   If num_bits > NumCycles Then                                                   // more bits than can be handled - probably due blank EEPROM
      While true                                                                  // flash PORTB LEDs forever
         LATB = $ff                                                               // all diagnostic LEDs on
         DelayMS(1000)
         LATB = 0                                                                 // all diagnostic LEDs off
         DelayMS(1000)       
      Wend
   EndIf
   For bitcount = 0 To (num_bits)                                                 // adjust for the maximum number of bits wanted
      LATB = bitcount                                                             // diagnostic LEDs

      int_microseconds = EE.ReadWord(bitcount * 4)                                // read mark data from EEPROM...
      send_mark()                                                                 // send mark of length in variable int_microseconds
      
      int_microseconds = EE.ReadWord((bitcount * 4) + 2)                          // read space data from EEPROM...
      send_space()                                                                // send space of length in variable int_microseconds
      

   Next
   DelayMS(1000)                                                                  // limit send repeat rate
  
Wend
 
Project 6 - Receive and transmit in same program - makes it quicker for me to test different protocols - operation instructions within commenting at top of code

Code:
// read IR remote control signal to PIC EEPROM then re-send when wanted
//    the strategy of blindly re-transmitting what is received from 3-pin IR receiver will always have limitations...
//    ... most notably RC5 and similar will not give sensible toggle bit values

// I am using Swordfish SE, so RAM is limited to 256 bytes
// If you use full version, you may wish to increase NumCycles definition up to a maximum of 60
// It would be very nice to print out timing values on UART - but this is just too much for the SE compiler

// EEPROM will contain sets of 4 bytes in the order mark-low_byte, mark-high_byte, space_low_byte, space-high-byte
// combine high/low bytes to get number of microseconds mark or space
// number of bits stored as byte in EEPROM location 255 

// Issues to fix
// IR read sometimes goes wrong - ultra-short messages - or something

// status 31 December 2020 at 01:30 UTC
//   - seems to work, but this is a really dumb program that does not yet stop at end of message
//      - press the button twice or set correct number of bits in code
//      - will improve if and when I get bored enough

// amateur code - use at own risk - author accepts no responsibility for anything, anywhere, ever
// I have used direct-register programming, as it is what I am more familiar with - you may use BASIC style code if you wish
// tested on EasyPIC v7 development board with IR click inserted into mikroBUS 2 socket
// This is original code that author makes no claim to - anyone is free to use and change in any way they like

// tests so far:
//    pass  SIRC12               - Sony TV
//    pass  RC6 mode 0           - Philips TV
//    pass                         Samsung TV
//    pass  NEC 32 bit           - Logik TV
//    pass  NEC extended 32 bit
//    pass  JVC
//    pass  RC5                  - Windows remote - NOTE THAT TOGGLE BIT WILL NEVER WORK CORRECTLY !!!
// seems OK RC6 mode 6           - seems OK, but cannot test with Swordfish SE - needs full version compiler with higher value of NumCycles
//
//    fail                       - Sharp TV - don't know why this does not work, not sure I care

// simple timer 0 16 bit counter running at 1MHz
// 8Mhz clock provides timer 0 with 2Mhz to prescaler, prescaler 1:2 causes timer 0 to count microseconds

// IR input is on RA3 - from 3-pin 38kHz IR receiver module
// IR output is on RC1 - 38Khz PWM 2 output

// operating buttons - all button inputs must have pull-up resistor - take low when pressed
//   button on RA0 goes low when pressed - select receive mode
//   button on RA1 goes low when pressed - select transmit mode

// PORTB LED indications
//    all off - nothing happening
//    B0 on   - receive mode - waiting for IR button press
//    B1 on   - transmit mode - sending IR
//    all LEDs flashing - EEPROM is blank
//  (PORTD LEDs are for diagnostics only and show number if IR cycles received)

Device = 18F43K22
Clock = 8

// configuration fuses... PIC18F43K22 External 8MHz 2-pin crystal (2 x 22pF caps), no PLL for 8MHz Fosc
Public Config
   FOSC = HSMP,                          // [LP, XT, HSHP, HSMP, ECHP, ECHPIO6, RC, RCIO6, INTIO67, INTIO7, ECMP, ECMPIO6, ECLP, ECLPIO6]
   PLLCFG = OFF,                         // [OFF, ON],
   PRICLKEN = ON                         // [OFF, ON],
// default config settings
//   FCMEN = OFF,
//   IESO = OFF,
//   BOREN = ON,
//   WDTEN = OFF,
//   WDTPS = 128,
//   PBADEN = OFF,
//   STVREN = ON,
//   LVP = OFF,
//   XINST = OFF,
//   DEBUG = OFF   

// import library modules
Include "EEPROM.bas"

// Sony protocol:
// 40kHz 7 bits command (LSB first) then 5 bits address
// this is 12 bit, there are also 15 bit and 20 bit versions of Sony protocol
// start bit = 2.4mS mark, .6mS space
// 1 = 1.2mS mark .6mS space, 0 = .6mS mark .6ms space
// repeat every 45mS if key is held down
// Sony device will not respond to a single message,
//    - so remotes usually send 3 or more repeated messages

// There is a fundamental issue with measuring raw timing from IR receiver, as the received signal is a slightly distorted reproduction...
//   ... of the original waveform sent by IR remote. Space times are shortened a little and mark times are lengthened a little.
//   If you are lucky, then the distortion will be small enough that you may acheive re-transmission that is good enough.

Const NumCycles = 50                                   // maximum message length - a cycle is considered to be a mark followed by a space
   
Dim mark_usecs(NumCycles) As Word
Dim space_usecs(NumCycles) As Word

Dim bitcount As Byte                                   // count bits
Dim int_microseconds As Word                           // general purpose store for timing values
Dim gap_found As Byte                                  // count bits up to inter-message gap
Dim num_bits As Byte                                   // message bits found from EEPROM

// stop PWM 2 and take RC1 low
Sub pwm_stop()
    CCP2CON = 0                                        // stop PWM
    LATC.1 = 0                                         // IR Tx off
End Sub

// start PWM 2
Sub pwm_start()
    CCP2CON = $0c                                      // start PWM
End Sub

// IR mark - send 38kHz to IR transmitter for number of us specified in int_microsends 
Sub send_mark()
    pwm_start()
    DelayUS(int_microseconds)
    pwm_stop()
End Sub

// IR space - send nothing to IR transmitter for number of us specified in int_microsends 
Sub send_space()
    pwm_stop()
    DelayUS(int_microseconds)
End Sub

// initialise
ANSELA = 0                                             // all digital
ANSELB = 0                                             // all digital
TRISB = 0                                              // all output for diagnostic LEDs
ANSELC = 0                                             // all digital
TRISC = 0                                              // all output for diagnostic LEDs and PWM out
ANSELD = 0                                             // all digital
TRISD = 0                                              // all output for diagnostic LEDs
LATD = 0                                               // all LEDs off

CCPR2L = 20                                            // PWM duty cycle approx 30%
CCPTMRS0 = $0                                          // PWM use timer 2
PR2 = $38                                              // PWM adjust for $38=36kHz, $34=38kHz or $31=40kHz
T2CON = $04                                            // timer 2 on for PWM

T0CON = $80                                            // timer 0 on, 16 bit, fosc/4, prescaler 1:2 - count microseconds
pwm_stop()                                             // make sure IR Tx output is low

While true                                             // main program loop...

   LATB = 0                                            // diagnostic - nothing happening 

//////   IR Receive (learning) routine   //////

   If PORTA.0 = 0 Then                                 // button or switch on RA0 goes low to read IR message
       DelayMS(1000)                                   // allow time for end of previous IR remote message 
       LATB = 1                                        // waiting for header
    
       While(PORTA.3) = 1                              // wait for IR input to go low - first leader bit 2.4ms (0x0960 microseconds hex) 
       Wend
       TMR0H = 0                                       // gets written later, when TMR0L is written
       TMR0L = 0                                       // clear count and prescaler
       gap_found = 0                                   // initialise
    
       For bitcount = 0 To (NumCycles - 1)             // adjust for the maximum number of bits wanted
          While(PORTA.3) = 0                           // wait for IR input to go high - end of next mark bit  
          Wend
          int_microseconds.bytes(0) = TMR0L            // background TMR0H latches during read of TMR0L
          int_microseconds.bytes(1) = TMR0H
          mark_usecs(bitcount) = int_microseconds      // expect a count of approximately 2400 for 2.4ms
          TMR0H = 0                                    // gets written later, when TMR0L is written
          TMR0L = 0                                    // clear count and prescaler
       
          While(PORTA.3) = 1                           // wait for IR input to go low - first leader bit 2.4ms (0x0960 microseconds hex) 
              WREG = TMR0L                             // don't care about timer low byte, but need to update TMR0H (16-bit mode)
              If TMR0H > 200 Then                      // threshold for determining end of message - 0 is about 20ms
                 gap_found = bitcount                  // indicate that an inter-message gap found at bit gap-found
              EndIf
          Wend
          int_microseconds.bytes(0) = TMR0L            // background TMR0H latches during read of TMR0L
          int_microseconds.bytes(1) = TMR0H
          space_usecs(bitcount) = int_microseconds     // expect a count of approximately 2400 for 2.4ms
          TMR0H = 0                                    // gets written later, when TMR0L is written
          TMR0L = 0                                    // clear count and prescaler         
       Next
    
       EE.WriteByte(255, gap_found)                                                   // write number of bits to EEPROM...
    
       For bitcount = 0 To (NumCycles - 1)                                            // adjust for the maximum number of bits wanted
          EE.WriteWord(bitcount * 4, mark_usecs(bitcount))                            // write mark data to EEPROM...
          EE.WriteWord((bitcount * 4) + 2, space_usecs(bitcount))                     // write space data to EEPROM...
       Next
       LATB = 0                                                                       // diagnostic - IR read finished  
   EndIf   

//////   IR transmit routine   //////
   
   If PORTA.1 = 0 Then                                                                // loop while button/switch is low
       LATB = 2                                                                       // diagnostic - sending IR 
    
       num_bits = EE.ReadByte(255)                                                    // read number of bits from EEPROM...
       LATD = num_bits                                                                // LEDs on PORTD show bit count stored in EEPROM
       If num_bits > NumCycles Then                                                   // more bits than can be handled - probably due blank EEPROM
          For num_bits = 0 To 20                                                      // flash PORTB LEDs to indicate error
             LATB = $ff                                                               // all diagnostic LEDs on
             DelayMS(200)
             LATB = 0                                                                 // all diagnostic LEDs off
             DelayMS(200)       
          Next
          num_bits = 1                                                                // send only 2 bits
       EndIf
  
       For bitcount = 0 To num_bits                                                   // adjust for the maximum number of bits wanted
          int_microseconds = EE.ReadWord(bitcount * 4)                                // read mark data from EEPROM...
          send_mark()                                                                 // send mark of length in variable int_microseconds
          
          int_microseconds = EE.ReadWord((bitcount * 4) + 2)                          // read space data from EEPROM...
          send_space()                                                                // send space of length in variable int_microseconds
       Next
       pwm_stop()
       DelayMS(1000)                                                                  // limit send repeat rate     
   EndIf   
Wend

Above code is original and free for anyone to ignore, fix, use, improve in any way they wish.
 
Last edited:
very detailed now to decipher to be able to use most any remote.
lots of research needed.
thanks
 
Should already work with "most any remote"
I tested using Sony TV remote as it is the simplest protocol, but the project should be good for most popular remote control protocols.
 
Nice job.
My only comment would be your (mis)use of the String data type as a byte array.
It probably doesn't matter here, but you have to watch since strings are meant to be ASCII data and some operations will expect/terminate on a null char (0x00).
Since it's binary data they should really be declared as byte arrays ie 'Dim mark_microseconds_h(NumCycles) As Byte'.

I took the liberty of changing your Project 6 code in post #52 to use word arrays instead of the two byte arrays for l and h data.
It should work pretty much the same... just be a tad faster and saves a few bytes of ram. I left everything else alone.
Code:
// from hexreader
// https://www.electro-tech-online.com/threads/a-remote-control-using-a-pic.160501/page-3 post #52
// v6 rev2 - replace strings with word arrays
//
// read IR remote control signal to PIC EEPROM then re-send when wanted
// I will test using Sony TV IR remote

// EEPROM will contain sets of 4 bytes in the order mark-low_byte, mark-high_byte, space_low_byte, space-high-byte
// combine high/low bytes to get number of microseconds mark or space
// number of bits stored as byte in EEPROM location 255 

// Issues to fix
// IR read sometimes goes wrong - ultra-short messages - or something

// status 29 December 2020 at 02:00 UTC
//   - seems to work, but this is a really dumb program that does not yet stop at end of message
//      - press the button twice or set correct number of bits in code
//      - will improve if and when I get bored enough

// amateur code - use at own risk - author accepts no responsibility for anything, anywhere, ever
// I have used direct-register programming, as it is what I am more familiar with - you may use BASIC style code if you wish
// tested on EasyPIC v7 development board with IR click inserted into mikroBUS 2 socket

// tests so far:
//    pass  Sony TV
//    pass  RC6 mode 0 - Philips TV
//
//    todo  RC6 mode 6
//    todo  RC6 mm
//    todo  RC5
//    todo  Samsung TV
//    todo  NEC 32 bit
//    todo  NEC extended 32 bit

// simple timer 0 16 bit counter running at 1MHz
// 8Mhz clock provides timer 0 with 2Mhz to prescaler, prescaler 1:2 causes timer 0 to count microseconds

// IR input is on RA3 - not used here
// IR output is on RC1 - 38Khz PWM 2 output

// operating buttons - all button inputs must have pull-up resistor - take low when pressed
//   button on RA0 goes low when pressed - select receive mode
//   button on RA1 goes low when pressed - select transmit mode

// PORTB LED indications
//    all off - nothing happening
//    B0 on   - receive mode - waiting for IR button press
//    B1 on   - transmit mode - sending IR
//    all LEDs flashing - EEPROM is blank

Device = 18F43K22
Clock = 8

// import EEPROM module
Include "EEPROM.bas"

// Sony protocol:
// 40kHz 7 bits command (LSB first) then 5 bits address
// this is 12 bit, there are also 15 bit and 20 bit versions of Sony protocol
// start bit = 2.4mS mark, .6mS space
// 1 = 1.2mS mark .6mS space, 0 = .6mS mark .6ms space
// repeat every 45mS if key is held down
// Sony device will not respond to a single message,
//    - so remotes usually send 3 or more repeated messages

// There is a fundamental issue with measuring raw timing from IR receiver, as the received signal is a slightly distorted reproduction
//   of the original waveform sent by IR remote. Space times are shortened a little and mark times are lengthened a little.
//   If you are lucky, then the distortion will be small enough that you may acheive re-transmission that is good enough.

Const NumCycles = 50                                   // maximum message length - a cycle is considered to be a mark followed by a space
   
Dim mark_usecs(NumCycles) As Word
Dim space_usecs(NumCycles) As Word

Dim bitcount As Byte                                   // count bits
Dim int_microseconds As Word
Dim gap_found As Byte                                  // count bits up to inter-message gap
Dim num_bits As Byte                                   // message bits found from EEPROM

// stop PWM 2 and take RC1 low
Sub pwm_stop()
    CCP2CON = 0                                        // stop PWM
    LATC.1 = 0                                         // IR Tx off
End Sub

// start PWM 2
Sub pwm_start()
    CCP2CON = $0c                                      // start PWM
End Sub

Sub send_mark()
    pwm_start()
    DelayUS(int_microseconds)
    pwm_stop()
End Sub

Sub send_space()
    pwm_stop()
    DelayUS(int_microseconds)
End Sub

// initialise
ANSELA = 0                                             // all digital
ANSELB = 0                                             // all digital
TRISB = 0                                              // all output for diagnostic LEDs
ANSELC = 0                                             // all digital
TRISC = 0                                              // all output for diagnostic LEDs and PWM out
ANSELD = 0                                             // all digital
TRISD = 0                                              // all output for diagnostic LEDs
LATD = 0                                               // all LEDs off

CCPR2L = 20                                            // duty cycle approx 30%
CCPTMRS0 = $0                                          // use timer 2
PR2 = $38                                              // adjust for $38=36kHz, $34=38kHz or $31=40kHz
T2CON = $04                                            // timer 2 on

T0CON = $80                                            // timer 0 on, 16 bit, fosc/4, prescaler 1:2 - count microseconds
pwm_stop()

While true                                             // main program loop...

   LATB = 0                                            // diagnostic - nothing happening 
   If PORTA.0 = 0 Then                                 // button or switch on RA0 goes low to read IR message
       DelayMS(1000)                                   // allow time for end of previous IR remote message 
       LATB = 1                                        // waiting for header
    
       While(PORTA.3) = 1                              // wait for IR input to go low - first leader bit 2.4ms (0x0960 microseconds hex) 
       Wend
       TMR0H = 0                                       // gets written later, when TMR0L is written
       TMR0L = 0                                       // clear count and prescaler
       gap_found = 0                                   // initialise
    
       For bitcount = 0 To (NumCycles -1)              // adjust for the maximum number of bits wanted
          While(PORTA.3) = 0                           // wait for IR input to go high - end of next mark bit  
          Wend
          int_microseconds.bytes(0) = TMR0L            // background TMR0H latches during read of TMR0L
          int_microseconds.bytes(1) = TMR0H
          mark_usecs(bitcount) = int_microseconds      // expect a count of approximately 2400 for 2.4ms
          TMR0H = 0                                    // gets written later, when TMR0L is written
          TMR0L = 0                                    // clear count and prescaler
       
          While(PORTA.3) = 1                           // wait for IR input to go low - first leader bit 2.4ms (0x0960 microseconds hex) 
              WREG = TMR0L                             // don't care about timer low byte, but need to update TMR0H (16-bit mode)
              If TMR0H > 200 Then                      // threshold for determining end of message - 0 is about 20ms
                 gap_found = bitcount                  // indicate that an inter-message gap found at bit gap-found
              EndIf
          Wend
          int_microseconds.bytes(0) = TMR0L            // background TMR0H latches during read of TMR0L
          int_microseconds.bytes(1) = TMR0H
          space_usecs(bitcount) = int_microseconds     // expect a count of approximately 2400 for 2.4ms
          TMR0H = 0                                    // gets written later, when TMR0L is written
          TMR0L = 0                                    // clear count and prescaler         
       Next
    
       EE.WriteByte(255, gap_found)                    // write number of bits to EEPROM...
    
       For bitcount = 0 To (NumCycles -1)                                             // adjust for the maximum number of bits wanted
          EE.WriteWord(bitcount * 4, mark_usecs(bitcount))                            // write mark data to EEPROM...
          EE.WriteWord((bitcount * 4) + 2, space_usecs(bitcount))                     // write space data to EEPROM...
       Next
       LATB = 0                                                                       // diagnostic - IR read finished  
   EndIf   
   
   If PORTA.1 = 0 Then                                                                // loop while button/switch is low
       LATB = 2                                                                       // diagnostic - sending IR 
    
       num_bits = EE.ReadByte(255)                                                    // read number of bits from EEPROM...
       LATD = num_bits                                                                // LEDs on PORTD show bit count stored in EEPROM
       If num_bits > NumCycles Then                                                   // more bits than can be handled - probably due blank EEPROM
          For num_bits = 0 To 20                                                      // flash PORTB LEDs to indicate error
             LATB = $ff                                                               // all diagnostic LEDs on
             DelayMS(200)
             LATB = 0                                                                 // all diagnostic LEDs off
             DelayMS(200)       
          Next
          num_bits = 1                                                                // send only 2 bits
       EndIf
  
       For bitcount = 0 To num_bits                                                   // adjust for the maximum number of bits wanted
          int_microseconds = EE.ReadWord(bitcount * 4)                                // read mark data from EEPROM...
          send_mark()                                                                 // send mark of length in variable int_microseconds
          
          int_microseconds = EE.ReadWord((bitcount * 4) + 2)                          // read space data from EEPROM...
          send_space()                                                                // send space of length in variable int_microseconds
       Next
       pwm_stop()
       DelayMS(1000)                                                                  // limit send repeat rate     
   EndIf   
Wend
 
tumbleweed
I took the liberty of changing your Project 6 code in post #52

That is not a liberty, it is doing a great service. Thank you.

I lay no claim to the code and there is no need to credit me in the code

I rarely program in BASIC and am very new to Swordfish, so I have a huge amount to learn. I suspect that I will gain more from this thread than Mr Deb will.

Please make as many changes as you are willing to spend time on. I will not be offended - I will be very happy.

Many thanks for helping me (and possibly Mr Deb) to learn.

EDIT: project 6 post updated with the improved tumbleweed 6v2 code - just to keep it all in one place
 
Last edited:
I rarely program in BASIC and am very new to Swordfish, so I have a huge amount to learn. I suspect that I will gain more from this thread than Mr Deb will.

It's always my hope that in my nearly futile attempts to help MrDEB that somebody will manage to take away something useful. Or at least give Swordfish Basic the benefit of the doubt.

Swordfish deserves to be so much more than it has turned out to be after the rocky start it got.
 
I rarely program in BASIC and am very new to Swordfish, so I have a huge amount to learn. I suspect that I will gain more from this thread than Mr Deb will.
I suspect that's true too. VERY true.

Hey, for a first stab at it you did a great job!
There are a few optimizations that can be done, but they would make it a bit more cryptic, and trying to keep things within the limit of 256 bytes of ram for the SwordfishSE free version can be tricky.
 
Is there a clever trick to make config setting work please?

I tried the PIC18F452 sample config project and read the documentation, and found the syntax to be:
Code:
// standard example of setting configuration fuses
config
   OSC = HSPLL,
   BOR = off,
   BORV = 25
... but the compiler seems to look for a microchip file that it cannot find.

I have MPLABX installed, but maybe - wild, ignorant guess - Swordfish expects path to older MPLAB???

Remember I am new to this, so probably have no idea what I am talking about

EDIT: and now I think a little harder - why would Swordfish require MPLAB presence anyway? - My thinking must be wrong
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top