EEVblog Electronics Community Forum

Electronics => Microcontrollers => Topic started by: luvini on February 25, 2016, 08:52:35 pm

Title: NEC IR Remote using PIC
Post by: luvini on February 25, 2016, 08:52:35 pm
i am trying to make a IR Remote using a PIC, and i will be using the NEC Protocol because thats what i want to control uses

the NEC Protocol: http://www.sbprojects.com/knowledge/ir/nec.php (http://www.sbprojects.com/knowledge/ir/nec.php)

i seen Dave's video about doing it with a Arduino
https://www.youtube.com/watch?v=BUvFGTxZBG8 (https://www.youtube.com/watch?v=BUvFGTxZBG8)

but i want to do it on a PIC, specifically a PIC16F628A

i recorded a command i want to send using Audacity and a IR receiver connected to the computer's microphone input, i cant see the carrier frequency of 38Khz but i can see the bits

here is what i captured
(http://i66.tinypic.com/5phf6x.png)
(when it goes high, the led is emitting and when it goes low, the led is off)
Title: Re: NEC IR Remote using PIC
Post by: ElectricGuy on February 25, 2016, 11:21:11 pm
Hi Luvini;

Tha PIC Micro has PWM. Use the PWM to generate de carrier or 38Khz. Then, you just need to turn on or off the PWM mpdule, acording to the timming protocol.

--------------------------------------------------------

Caro Luvini.

Esse PIC possui PWM. Utiliza o PWM para gerar a portadora de 38Khz. Depois sempre que quiseres enviar um bit ligas o PWM de acordo com os tempos do protocolo.

Title: Re: NEC IR Remote using PIC
Post by: luvini on February 26, 2016, 04:40:04 am
i decided to use PWM, i didnt know how to make a proper PWM signal, but i guess i learned now, i even made a Excel PWM Calculator  :-+

PWM Calculator: https://docs.google.com/spreadsheets/d/1VXUw5Sm8fl1sn6Jrq0pawhZ0cFhNQzehLE0Sc8wFf2Q/edit?usp=sharing (https://docs.google.com/spreadsheets/d/1VXUw5Sm8fl1sn6Jrq0pawhZ0cFhNQzehLE0Sc8wFf2Q/edit?usp=sharing)

(http://i66.tinypic.com/x2uvz4.png)

i also decoded the signal, so RED=0 and GREEN=1
(http://i68.tinypic.com/m94ri1.png)


the final code i made is this, and it works, i can now control my device!

Code: [Select]
#include <16F628A.h>

#fuses NOWDT //Disable Watchdog Timer
#fuses NOPROTECT //Disable Read/Write Protect
#FUSES NOCPD //Disable EE protection
#fuses NOLVP //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO //Set CLK pins as I/O
#fuses NOMCLR //Disable Master Clear

#use delay(clock=4000000)

void main()
{

setup_ccp1(ccp_pwm); //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1); //38Khz PWM using 4Mhz Osc.

delay_us (20);

//================================
// NEC PROTOCOL
//
// set_pwm1_duty(12); // START
// delay_ms(9);
// set_pwm1_duty(0);
// delay_us(4500);
//
// set_pwm1_duty(12); // 1
// delay_us(560);
// set_pwm1_duty(0);
// delay_us(1690);
//
// set_pwm1_duty(12); // 0
// delay_us(560);
// set_pwm1_duty(0);
// delay_us(560);
//
// set_pwm1_duty(12); // REPEAT
// delay_ms(9);
// set_pwm1_duty(0);
// delay_us(2250);
// set_pwm1_duty(12);
// delay_us(560);
// set_pwm1_duty(0);
// delay_us(560);
//================================

while(true)
{
if(!input(pin_a0))
{
set_pwm1_duty(12); // START
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

set_pwm1_duty(12); // 1
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);

while(!input(pin_a0))
{
set_pwm1_duty(12); // REPEAT
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}
}

if(!input(pin_a1))
{

//command goes here

while(!input(pin_a1))
{
set_pwm1_duty(12); // REPEAT (NEC PROTOCOL)
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}
}


set_pwm1_duty(0); //turn off IR LED while not pressing any button

}//loop
}
Title: Re: NEC IR Remote using PIC
Post by: luvini on February 26, 2016, 06:16:18 am
ok, the code worked for ONE button, so i tried to add more buttons, and it did work up to TREE buttons, why? because anything past that will be too much and wont fit into the memory... maybe theres a better way to make this code? one that use less memory?
Title: Re: NEC IR Remote using PIC
Post by: lapm on February 26, 2016, 06:33:09 am
Well those are basicly just ones and zeroes represented by infrared encoded signals. See if you can identify encoding they use...
Title: Re: NEC IR Remote using PIC
Post by: macboy on February 26, 2016, 03:18:58 pm
ok, the code worked for ONE button, so i tried to add more buttons, and it did work up to TREE buttons, why? because anything past that will be too much and wont fit into the memory... maybe theres a better way to make this code? one that use less memory?
Do you see that every time you want to send a '0' bit you do exactly this:
Code: [Select]
set_pwm1_duty(12); // 0
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
And something similar for a '1' bit? Put each code block in a function, then call the function instead of repeating the same two pieces of code 32 times for each key.

Also the signal appears to be a start or preamble followed by a key code that is 16 bits long, correct? How about encoding each key as a two-byte (16 bit) data. Then you can write a function that will transmit the two bytes, one bit at a time. It will call the functions you created above (for sending a 0 or 1 bit).

Code: [Select]
// define some constants:
const char channelup = 66       // NOTE this code is fake, replace with correct data
const char channeldown = 68;    // NOTE this code is fake, replace with correct data

const char device_address = 5;    // NOTE this code is fake, replace with correct data

send_key_channelup()
{
    send_start()
    send_byte(device_address);
    send_byte(~device_address);
    send_byte(channelup);
    send_byte(~channelup);
    // optionally repeat
    ....
}

send_byte(char byte_to_send)
{
    for (char i=8, i>0, i--)    // decrementing is more efficient that incrementing
    {
        (byte_to_send & 0x1) ? send_onebit() : send_zerobit();     // the ? : is the ternary operator, works like if then else
        byte_to_send = byte_to_send>>1;
    }
}
...
I hope that gives you some ideas. There is a lot more you can do but that is a good start.
Title: Re: NEC IR Remote using PIC
Post by: luvini on February 26, 2016, 10:46:48 pm
i never used functions, but that was easy to learn, as was PWM the other day, now the code looks like this, and it only uses 20% of the chip memory, with EIGHT buttons!

Code: [Select]
#include <16F628A.h>

#fuses NOWDT      //Disable Watchdog Timer
#fuses NOPROTECT   //Disable Read/Write Protect
#FUSES NOCPD      //Disable EE protection
#fuses NOLVP      //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO      //Set CLK pins as I/O
#fuses NOMCLR      //Disable Master Clear

#use delay(clock=4000000)

//================================
//      NEC PROTOCOL

void startSending() // START
{
set_pwm1_duty(12);;
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}
//================================

void deviceCode()
{
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
logical1();
logical1();
logical1();
}

//================================

void main()
{
setup_ccp1(ccp_pwm);            //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1);   //38Khz PWM using 4Mhz Osc.
delay_us(20);

while(true)
{

//================================================================

if(!input(pin_a0))   //White
{
startSending();

deviceCode();

logical1();
logical1();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical0();
logical0();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a0))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a1))   //Red
{
startSending();

deviceCode();

logical1();
logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical0();
logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a1))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a2))   //Green
{
startSending();

deviceCode();

logical0();
logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical1();
logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a2))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a3))   //Blue
{
startSending();

deviceCode();

logical0();
logical1();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical1();
logical0();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a3))
{
repeatCode();
}
}

//================================================================

if(!input(pin_b0))   //OFF
{
startSending();

deviceCode();

logical0();
logical1();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_b0))
{
repeatCode();
}
}

//================================================================
if(!input(pin_b1))   //ON
{
startSending();

deviceCode();

logical1();
logical1();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical0();
logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_b1))
{
repeatCode();
}
}

//================================================================
if(!input(pin_b4))   //-Bright
{
startSending();

deviceCode();

logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_b4))
{
repeatCode();
}
}

//================================================================
if(!input(pin_b5))   //+Bright
{
startSending();

deviceCode();

logical1();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical0();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_b5))
{
repeatCode();
}
}

//================================================================

set_pwm1_duty(0);   //turn off IR LED while not pressing any button
}//loop
}

yes, i am controlling a RGB LED Lamp
Title: Re: NEC IR Remote using PIC
Post by: luvini on February 27, 2016, 05:18:00 am
tried to control my TV, and it used the NEC Protocol aswell so it was easy to do
Code: [Select]
#include <16F628A.h>

#fuses NOWDT      //Disable Watchdog Timer
#fuses NOPROTECT   //Disable Read/Write Protect
#FUSES NOCPD      //Disable EE protection
#fuses NOLVP      //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO      //Set CLK pins as I/O
#fuses NOMCLR      //Disable Master Clear

#use delay(clock=4000000)

//================================
//      NEC PROTOCOL

void startSending() // START
{
set_pwm1_duty(12);;
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}
//================================

void deviceCode()
{
logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
}

//================================

void main()
{
setup_ccp1(ccp_pwm);            //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1);   //38Khz PWM using 4Mhz Osc.
delay_us(20);

while(true)
{

//================================================================

if(!input(pin_a0))   //Power
{
startSending();

deviceCode();

logical0();
logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical1();
logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();



while(!input(pin_a0))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a1)) //inputs
{
startSending();

deviceCode();

logical1();
logical1();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical0();
logical0();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a1))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a2))   //Mute
{
startSending();

deviceCode();

logical1();
logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical0();
logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a2))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a3))   //OK
{
startSending();

deviceCode();

logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical1();
logical0();

logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical0();
logical1();

while(!input(pin_a3))
{
repeatCode();
}
}

//================================================================

if(!input(pin_b0))   //Right
{
startSending();

deviceCode();

logical0();
logical1();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_b0))
{
repeatCode();
}
}

//================================================================
if(!input(pin_b1))   //Left
{
startSending();

deviceCode();

logical1();
logical1();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical0();
logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_b1))
{
repeatCode();
}
}

//================================================================
if(!input(pin_b4))   //Up
{
startSending();

deviceCode();

logical0();
logical0();
logical0();
logical0();
logical0();
logical0();
logical1();
logical0();

logical1();
logical1();
logical1();
logical1();
logical1();
logical1();
logical0();
logical1();

while(!input(pin_b4))
{
repeatCode();
}
}

//================================================================
if(!input(pin_b5))   //Down
{
startSending();

deviceCode();

logical1();
logical0();
logical0();
logical0();
logical0();
logical0();
logical1();
logical0();

logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
logical0();
logical1();

while(!input(pin_b5))
{
repeatCode();
}
}
//================================================================
if(!input(pin_a6))   //+Volume
{
startSending();

deviceCode();

logical0();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a6))
{
repeatCode();
}
}
//================================================================
if(!input(pin_a7))   //-Volume
{
startSending();

deviceCode();

logical1();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();

logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a7))
{
repeatCode();
}
}
//================================================================
if(!input(pin_a4))   //Back
{
startSending();

deviceCode();

logical0();
logical0();
logical0();
logical1();
logical0();
logical1();
logical0();
logical0();

logical1();
logical1();
logical1();
logical0();
logical1();
logical0();
logical1();
logical1();

while(!input(pin_a4))
{
repeatCode();
}
}
//================================================================
if(!input(pin_b2))   //Settings
{
startSending();

deviceCode();

logical1();
logical1();
logical0();
logical0();
logical0();
logical0();
logical1();
logical0();

logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical0();
logical1();

while(!input(pin_b2))
{
repeatCode();
}
}
//================================================================

set_pwm1_duty(0);   //turn off IR LED while not pressing any button
}//loop
}


i tried to make it possible to control 2 different devices, with different ids, and it worked as i just needed to make a new DeviceID function for it
Code: [Select]
#include <16F628A.h>

#fuses NOWDT      //Disable Watchdog Timer
#fuses NOPROTECT   //Disable Read/Write Protect
#FUSES NOCPD      //Disable EE protection
#fuses NOLVP      //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO      //Set CLK pins as I/O
#fuses NOMCLR      //Disable Master Clear

#use delay(clock=4000000)

//================================
//      NEC PROTOCOL

int RGBpower;

void startSending() // START
{
set_pwm1_duty(12);;
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}
//================================

void deviceCodeTV()
{
logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
}

void deviceCodeRGB()
{
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical1();
logical1();
logical1();
logical1();
logical1();
logical1();
logical1();
}

//================================

void main()
{
setup_ccp1(ccp_pwm);            //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1);   //38Khz PWM using 4Mhz Osc.
delay_us(20);

RGBpower=0;

while(true)
{

//================================================================

if(!input(pin_a0))   //TV Power
{
startSending();

deviceCodeTV();

logical0();
logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical1();
logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();



while(!input(pin_a0))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a1)) //TV inputs
{
startSending();

deviceCodeTV();

logical1();
logical1();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical0();
logical0();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a1))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a2))   //TV +Volume
{
startSending();

deviceCodeTV();

logical0();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a2))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a3))   //TV -Volume
{
startSending();

deviceCodeTV();

logical1();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();
logical0();

logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a3))
{
repeatCode();
}
}

//================================================================
//================================================================

if(!input(pin_b0)) //RGBpower TOGGLE
{
if(RGBpower==0) //RGB OFF
{
startSending();

deviceCodeRGB();

logical0();
logical1();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
}

if(RGBpower==1) //RGB ON
{
startSending();

deviceCodeRGB();

logical1();
logical1();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical0();
logical0();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();
}

RGBpower++;
if(RGBpower==2)
{
RGBpower=0;
}

delay_ms(50);

while(!input(pin_b0))
{
repeatCode();
}
}

//================================================================

if(!input(pin_b4)) //RGB White
{
startSending();

deviceCodeRGB();

logical1();
logical1();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical0();
logical0();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_b4))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a6)) //RGB Red
{
startSending();

deviceCodeRGB();

logical1();
logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical0();
logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a6))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a7)) //RGBGreen
{
startSending();

deviceCodeRGB();

logical0();
logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical1();
logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a7))
{
repeatCode();
}
}

//================================================================

if(!input(pin_a4)) //RGB Blue
{
startSending();

deviceCodeRGB();

logical0();
logical1();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();

logical1();
logical0();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_a4))
{
repeatCode();
}
}

//================================================================

if(!input(pin_b5)) //RGB -Bright
{
startSending();

deviceCodeRGB();

logical0();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical1();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_b5))
{
repeatCode();
}
}

//================================================================

if(!input(pin_b1)) //RGB +Bright
{
startSending();

deviceCodeRGB();

logical1();
logical0();
logical1();
logical0();
logical0();
logical0();
logical0();
logical0();

logical0();
logical1();
logical0();
logical1();
logical1();
logical1();
logical1();
logical1();

while(!input(pin_b1))
{
repeatCode();
}
}

//================================================================

set_pwm1_duty(0);   //turn off IR LED while not pressing any button
}//loop
}
(even added a power TOGGLE for the RGB LED Lamp, as it had 2 separate buttons for ON and OFF)


https://www.youtube.com/watch?v=6wf-omsfNpE (https://www.youtube.com/watch?v=6wf-omsfNpE)
Title: Re: NEC IR Remote using PIC
Post by: luvini on February 27, 2016, 05:21:30 am
...
Also the signal appears to be a start or preamble followed by a key code that is 16 bits long, correct? How about encoding each key as a two-byte (16 bit) data. Then you can write a function that will transmit the two bytes, one bit at a time. It will call the functions you created above (for sending a 0 or 1 bit).

Code: [Select]
// define some constants:
const char channelup = 66       // NOTE this code is fake, replace with correct data
const char channeldown = 68;    // NOTE this code is fake, replace with correct data

const char device_address = 5;    // NOTE this code is fake, replace with correct data

send_key_channelup()
{
    send_start()
    send_byte(device_address);
    send_byte(~device_address);
    send_byte(channelup);
    send_byte(~channelup);
    // optionally repeat
    ....
}

send_byte(char byte_to_send)
{
    for (char i=8, i>0, i--)    // decrementing is more efficient that incrementing
    {
        (byte_to_send & 0x1) ? send_onebit() : send_zerobit();     // the ? : is the ternary operator, works like if then else
        byte_to_send = byte_to_send>>1;
    }
}
...
I hope that gives you some ideas. There is a lot more you can do but that is a good start.

i am... not sure how does that work?
Title: Re: NEC IR Remote using PIC
Post by: macboy on February 28, 2016, 02:35:55 pm
i am... not sure how does that work?
Inside the loop, the byte is bitwise ANDed with 1 (binary 00000001), which results in 1 if the first bit of the byte is 1 and 0 if it is zero. A 1 evaluates to true, so the first statement is run. A 0 is false, which means the second statement (the one after the : ) is run instead. So we call send_zero_bit() when the bit is zero and send_one_bit()  when it is one. Then we shift the byte to the right one bit, so that the next time through the loop we are working on the second bit of the byte that was passed in. The third iteration of the loop works on the third but and so on.  The loop runs 8 times for 8 bits.
Title: Re: NEC IR Remote using PIC
Post by: pascal_sweden on February 28, 2016, 08:37:50 pm
If you are open to use an Atmel microcontroller, then you can use an existing library, that supports a multitude of IR protocols :)

http://www.mikrocontroller.net/articles/IRSND (http://www.mikrocontroller.net/articles/IRSND)

This library can run on different Atmel microcontrollers, and supports many IR protocols.
Next to the send library, there is also a counterpart decode library.

I have used these libraries myself, both the decode library and the send library, and everything works like a charm!

Forget Microchip. Go for Atmel. Make things easy! :)
Title: Re: NEC IR Remote using PIC
Post by: ElectricGuy on February 28, 2016, 08:50:13 pm

Forget Microchip. Go for Atmel. Make things easy! :)

But there is no Atmel, only Microchip!!!  :-DD ( Just Kidding )
Title: Re: NEC IR Remote using PIC
Post by: pascal_sweden on February 28, 2016, 08:52:01 pm
I just read the news about the acquisition in another thread.
Didn't know about it until just now.

Hopefully they will keep the name Atmel, as I like it better than Microchip.

Actually I was surprised that Microchip is so much bigger than Atmel. I thought they were in the same league.

Pity, that it isn't the other way around. Atmel is a better company, and a better name as well :)
Title: Re: NEC IR Remote using PIC
Post by: luvini on February 29, 2016, 03:21:56 am
i am... not sure how does that work?
Inside the loop, the byte is bitwise ANDed with 1 (binary 00000001), which results in 1 if the first bit of the byte is 1 and 0 if it is zero. A 1 evaluates to true, so the first statement is run. A 0 is false, which means the second statement (the one after the : ) is run instead. So we call send_zero_bit() when the bit is zero and send_one_bit()  when it is one. Then we shift the byte to the right one bit, so that the next time through the loop we are working on the second bit of the byte that was passed in. The third iteration of the loop works on the third but and so on.  The loop runs 8 times for 8 bits.
i think that makes sense, i just dont understand the function that will read each bit individually, could you explain that part?
the function would need to read, for example: ABCDEFGH, and each time it is run, it would read only a single character, if its run again, it would read only the next character, but how?


If you are open to use an Atmel microcontroller, then you can use an existing library, that supports a multitude of IR protocols :)

http://www.mikrocontroller.net/articles/IRSND (http://www.mikrocontroller.net/articles/IRSND)

This library can run on different Atmel microcontrollers, and supports many IR protocols.
Next to the send library, there is also a counterpart decode library.

I have used these libraries myself, both the decode library and the send library, and everything works like a charm!

Forget Microchip. Go for Atmel. Make things easy! :)

i want to use a PIC16F628A for this project
Title: Re: NEC IR Remote using PIC
Post by: luvini on February 29, 2016, 03:53:49 am
made a full code, but it doesnt compile, giving error
Code: [Select]
*** Error 51 "test0002.c" Line 70(6,10): A numeric expression must appear here
*** Error 51 "test0002.c" Line 72(46,47): A numeric expression must appear here

wich happens at the "void send_byte(char byte_to_send)" and "for (char i=8, i>0, i--)"
and thats the part of the code i cannot understand...
Code: [Select]
void send_byte(char byte_to_send)
{
for (char i=8, i>0, i--)// decrementing is more efficient that incrementing
{
(byte_to_send & 0x1) ? logical1() : logical0(); // the ? : is the ternary operator, works like if then else
byte_to_send = byte_to_send>>1;
}
}

maybe this could help? http://stackoverflow.com/questions/1682996/bytes-to-binary-in-c (http://stackoverflow.com/questions/1682996/bytes-to-binary-in-c)
Code: [Select]
unsigned char byte = 49;//Decimal Number
unsigned char mask = 1; //Bit mask
unsigned char bits[8]; //8bits=1Byte

for (int i = 0; i < 8; i++)// Extract the bits
{
bits[i] = (byte & (mask << i)) != 0;//Mask each bit in the byte and store it
}


the full code is
Code: [Select]
#include <16F628A.h>

#fuses NOWDT //Disable Watchdog Timer
#fuses NOPROTECT //Disable Read/Write Protect
#FUSES NOCPD //Disable EE protection
#fuses NOLVP //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO //Set CLK pins as I/O
#fuses NOMCLR //Disable Master Clear
#FUSES NOBROWNOUT //Disable Reseting On Power Loss
//#FUSES HS //Crystal With More than 4Mhz

#use delay(clock=4000000)

//=================
//DeviceID of TV
//00100000=32
//
//Code of button OK
//00100010=34
//=================

// define some constants:
//DeviceID
const char device_address = 32; //DeviceID of TV
//Buttons
const char OK = 34; //button OK

//================================
//      NEC PROTOCOL

void startSending() // START
{
set_pwm1_duty(12);;
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}
//================================

void send_byte(char byte_to_send)
{
for (char i=8, i>0, i--)// decrementing is more efficient that incrementing
{
(byte_to_send & 0x1) ? logical1() : logical0(); // the ? : is the ternary operator, works like if then else
byte_to_send = byte_to_send>>1;
}
}

void send_key_OK() //Send button OK
{
startSending(); //Send 9ms START pulse
send_byte(device_address); //Send DeviceID
send_byte(~device_address); //Send Inverted DeviceID
send_byte(OK); //Send ButtonCode
send_byte(~OK); //Send inverted ButtonCode
}

void main()
{
while(1)
{
if(!input(pin_a0))
{
send_key_OK();
while(!input(pin_a0))
{
repeatCode();
delay_ms(110);
}
}
}
}
Title: Re: NEC IR Remote using PIC
Post by: macboy on February 29, 2016, 04:54:33 pm
First,
Code: [Select]
for (char i=8, i>0, i--)// decrementing is more efficient that incrementingMust be:
Code: [Select]
for (char i=8; i>0; i--)// decrementing is more efficient that incrementingNote the semicolons in place of the commas. This was a typo on my part, but you could have found this.

Change:
Code: [Select]
(byte_to_send & 0x1) ? logical1() : logical0(); // the ? : is the ternary operator, works like if then else
To:
Code: [Select]
if (byte_to_send & 0x1)
        {
            logical1();
        }
        else
        {
            logical0();
        }
Title: Re: NEC IR Remote using PIC
Post by: pascal_sweden on February 29, 2016, 07:05:45 pm
Why do you only want to use a PIC?

Note that the library also supports some PIC microcontrollers, and not only Atmel :)
http://www.mikrocontroller.net/articles/IRSND#Unterst.C3.BCtzte_.C2.B5Cs (http://www.mikrocontroller.net/articles/IRSND#Unterst.C3.BCtzte_.C2.B5Cs)

But really, you should consider Atmel AVR instead of PIC!
Much better software tools (Atmel Studio) and the best programmer/debugger (AVR Dragon) for only 50 EUR!

Title: Re: NEC IR Remote using PIC
Post by: luvini on February 29, 2016, 08:45:54 pm
now the code is

Code: [Select]
void send_byte(char byte_to_send)
{

for (char i=8; i>0; i--)// decrementing is more efficient that incrementing
{

if (byte_to_send & 0x1)
{
logical1();
}

else
{
logical0();
}

byte_to_send = byte_to_send>>1;
}
}

with error
Code: [Select]
*** Error 51 "test0002.c" Line 71(6,10): A numeric expression must appear here
*** Error 12 "test0002.c" Line 71(16,17): Undefined identifier   i
*** Error 12 "test0002.c" Line 71(21,22): Undefined identifier   i
      3 Errors,  0 Warnings.

so i added a "int i;"
Code: [Select]
void send_byte(char byte_to_send)
{
int i;
for (char i=8; i>0; i--)// decrementing is more efficient that incrementing
{

if (byte_to_send & 0x1)
{
logical1();
}

else
{
logical0();
}

byte_to_send = byte_to_send>>1;
}
}

and the error is
Code: [Select]
*** Error 51 "test0002.c" Line 71(6,10): A numeric expression must appear here
*** Error 76 "test0002.c" Line 71(24,25): Expect ;
      2 Errors,  0 Warnings

at
Code: [Select]
for (char i=8; i>0; i--)

however if i remove the "char" from "for (char i=8; i>0; i--)" it does compile, but doesnt work
Code: [Select]
void send_byte(char byte_to_send)
{
int i;
for (i=8; i>0; i--)// decrementing is more efficient that incrementing
{

if (byte_to_send & 0x1)
{
logical1();
}

else
{
logical0();
}

byte_to_send = byte_to_send>>1;
}
}
Code: [Select]
>>> Warning 203 "test0002.c" Line 100(1,1): Condition always TRUE
      Memory usage:   ROM=8%      RAM=3% - 4%
      0 Errors,  1 Warnings.
Title: Re: NEC IR Remote using PIC
Post by: luvini on February 29, 2016, 08:59:30 pm
Why do you only want to use a PIC?

Note that the library also supports some PIC microcontrollers, and not only Atmel :)
http://www.mikrocontroller.net/articles/IRSND#Unterst.C3.BCtzte_.C2.B5Cs (http://www.mikrocontroller.net/articles/IRSND#Unterst.C3.BCtzte_.C2.B5Cs)

But really, you should consider Atmel AVR instead of PIC!
Much better software tools (Atmel Studio) and the best programmer/debugger (AVR Dragon) for only 50 EUR!

50EUR is 218BRL, quite expensive when i built a PicKit2 myself under 50BRL and the PIC16F628A is just 12,50BRL

but i will try AVR someday, i think the Arduino even uses it (ATmega328), but i also dont have a Arduino ;P

the PICs supported for that library are:
-PIC12F1840 (8pins)
-PIC18F4520 (40 pins)

i want to use a small chip, but with enough pins for all the buttons, so a 8pin chip wouldn't be enough, and a 40pins would be too much, however the PIC16F628A fits what i want with 18pins
Title: Re: NEC IR Remote using PIC
Post by: differentcurrent on March 01, 2016, 09:31:50 am
i think the compiler is confusing with "i"  try giving it another name like "j"  or "temp_looo".
when it's jumping to other functions "i"  variable is messed up

Sent from my SM-N920C using Tapatalk

Title: Re: NEC IR Remote using PIC
Post by: differentcurrent on March 01, 2016, 09:34:00 am
Why do you only want to use a PIC?

Note that the library also supports some PIC microcontrollers, and not only Atmel :)
http://www.mikrocontroller.net/articles/IRSND#Unterst.C3.BCtzte_.C2.B5Cs (http://www.mikrocontroller.net/articles/IRSND#Unterst.C3.BCtzte_.C2.B5Cs)

But really, you should consider Atmel AVR instead of PIC!
Much better software tools (Atmel Studio) and the best programmer/debugger (AVR Dragon) for only 50 EUR!
why atmel is better than microchip?
i am using pic for a couple of years and it's working fine.
i be glad if give me a good reason to try them

Sent from my SM-N920C using Tapatalk
Title: Re: NEC IR Remote using PIC
Post by: luvini on March 02, 2016, 01:46:04 am
i think the compiler is confusing with "i"  try giving it another name like "j"  or "temp_looo".
when it's jumping to other functions "i"  variable is messed up

Sent from my SM-N920C using Tapatalk

changing the variable "i" to anything else gives the same error

maybe Dave's Arduino code could help: https://gist.github.com/EEVblog/6206934 (https://gist.github.com/EEVblog/6206934)

i think the problem is with that "char" inside the "for(" part, because when i remove it, it compiles with no errors
but it doesn't work, but at least the compiler gives no errors

Code: [Select]
for (char i=8; i>0; i--)

i dont understand what is this "char" doing inside of the parameters for the "for" function...

//=========================
void send_byte(char byte_to_send)
{

 for (char i=8; i>0; i--)// decrementing is more efficient than incrementing
 {

  if (byte_to_send & 0x1)
  {
  logical1();
  }

  else
  {
  logical0();
  }

 byte_to_send = byte_to_send>>1;
 }
}
//=========================

(http://i65.tinypic.com/315fiw6.png)

can you see the image with the code above?
Title: Re: NEC IR Remote using PIC
Post by: xtoffer on March 05, 2016, 11:42:04 am
i dont understand what is this "char" doing inside of the parameters for the "for" function...

The char is used to declare the iterative variable inside the for-loop. However this is not always allowed in all versions of C, and most likely not in your case. The solution is, as you have already figured out, to declare it right before. (Whether it is actually a char or an int is another matter. Note: char is often used as an unsigned 8-bit int for spacesaving/speed reasons.)

So the function goes through each bit and executes the appropriate output function in turn. To make it actually work you have to setup the bits in the char such that the right sequence is sent. Note that the least significant bit is always taken from what is left to send. This decides the order in which the bits are sent. (If you want to reverse the order you can instead mask with 0x80 and shift the other way.)

For example..
Code: [Select]
send_byte(0x19)..would result in the following sequence..
Code: [Select]
logical1();
logical0();
logical0();
logical1();
logical1();
logical0();
logical0();
logical0();
Title: Re: NEC IR Remote using PIC
Post by: luvini on March 06, 2016, 02:08:38 am
found why the IR LED wasnt doing anything in last version of code, forgot to activate the PWM port  :palm:
Code: [Select]
setup_ccp1(ccp_pwm);            //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1);   //38Khz PWM using 4Mhz Osc.
delay_us(20);

the expected result at the IR output when sending the code would be:
(http://i65.tinypic.com/n3w9jc.png)

but what im getting is:
(http://i67.tinypic.com/2s0obgx.png)

it is sending ZEROs!

current code is
Code: [Select]
#include <16F628A.h>

#fuses NOWDT //Disable Watchdog Timer
#fuses NOPROTECT //Disable Read/Write Protect
#FUSES NOCPD //Disable EE protection
#fuses NOLVP //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO //Set CLK pins as I/O
#fuses NOMCLR //Disable Master Clear
#FUSES NOBROWNOUT //Disable Reseting On Power Loss
//#FUSES HS //Crystal With More than 4Mhz

#use delay(clock=4000000)

//=================
//DeviceID of TV
//00100000=32
//
//Code of button OK
//00100010=34
//=================

// define some constants:
//DeviceID
const char device_address = 32; //DeviceID of TV
//Buttons
const char OK = 34; //button OK

char i;
char byte_to_send;

//================================
//      NEC PROTOCOL

void startSending() // START
{
set_pwm1_duty(12);;
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}
//================================

void send_byte(OK)
{
for (i=8; i>0; i--) // decrementing is more efficient than incrementing
{

if (byte_to_send & 0x1)
{
logical1();
}

else
{
logical0();
}

byte_to_send = byte_to_send>>1;
}
}

//================================

void send_key_OK() //Send button OK
{
startSending(); //Send 9ms START pulse
send_byte(device_address); //Send DeviceID
send_byte(~device_address); //Send Inverted DeviceID
send_byte(OK); //Send ButtonCode
send_byte(~OK); //Send inverted ButtonCode
}

void main()
{
setup_ccp1(ccp_pwm);            //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1);   //38Khz PWM using 4Mhz Osc.
delay_us(20);

while(1)
{
if(input(pin_a0))
{
send_key_OK();
while(input(pin_a0))
{
repeatCode(); //comment this line to one-shot troubleshot on osciloscope the output of send_key_OK()
delay_ms(110); //comment this line to one-shot troubleshot on osciloscope the output of send_key_OK()
}
}
}
}

changing "if (byte_to_send & 0x1)" to " if (byte_to_send & 1)" or " if (byte_to_send = 1)" gives the same output...


===========

some timing info: Blue channel is 0, Red is 1, Yellow is the actual IR LED output
(http://i66.tinypic.com/jpztci.png)
it is actually going into the logical0() function, otherwise it wouldn't have the same timing. Something is preventing it from getting into logical1(), maybe the formula is wrong? wrong type of comparison? wrong type of data? http://www.tutorialspoint.com/cprogramming/c_operators.htm (http://www.tutorialspoint.com/cprogramming/c_operators.htm)

the code for this one is
Code: [Select]
#include <16F628A.h>

#fuses NOWDT //Disable Watchdog Timer
#fuses NOPROTECT //Disable Read/Write Protect
#FUSES NOCPD //Disable EE protection
#fuses NOLVP //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO //Set CLK pins as I/O
#fuses NOMCLR //Disable Master Clear
#FUSES NOBROWNOUT //Disable Reseting On Power Loss
//#FUSES HS //Crystal With More than 4Mhz

#use delay(clock=4000000)

//=================
//DeviceID of TV
//00100000=32
//
//Code of button OK
//00100010=34
//=================

// define some constants:
//DeviceID
const char device_address = 32; //DeviceID of TV
//Buttons
const char OK = 34; //button OK

char i;
char byte_to_send;

//================================
//      NEC PROTOCOL

void startSending() // START
{
set_pwm1_duty(12);;
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}
//================================

void send_byte(OK)
{
for (i=8; i>0; i--) // decrementing is more efficient than incrementing
{

if (byte_to_send & 0x1)
{
output_high(pin_b1); //probe pin B1 for 1 signals
logical1();
output_low(pin_b1);
}

else
{
output_high(pin_b0); //probe pin B0 for 0 signals
logical0();
output_low(pin_b0);
}

byte_to_send = byte_to_send>>1;
}
}

//================================

void send_key_OK() //Send button OK
{++++++++++++++++++++++++++
startSending(); //Send 9ms START pulse
send_byte(device_address); //Send DeviceID
send_byte(~device_address); //Send Inverted DeviceID
send_byte(OK); //Send ButtonCode
send_byte(~OK); //Send inverted ButtonCode
}

void main()
{
setup_ccp1(ccp_pwm);            //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1);   //38Khz PWM using 4Mhz Osc.
delay_us(20);

while(1)
{
if(input(pin_a0))
{
send_key_OK();

while(input(pin_a0))
{
// repeatCode(); //comment this line to one-shot troubleshot on osciloscope the output of send_key_OK()
// delay_ms(110); //comment this line to one-shot troubleshot on osciloscope the output of send_key_OK()
}
}
}
}
Title: Re: NEC IR Remote using PIC
Post by: luvini on March 06, 2016, 03:23:48 am
UPDATE

(http://i65.tinypic.com/nvaxwz.png)
(Blue = logical0(), Red = logical1(), Yellow = PWMoutput
i got it to work 31bits!, but they are mirrored every 8 bits (1 byte)!
EDIT
fixed the inverted bytes, changed "byte_to_send = byte_to_send>>1;" to "byte_to_send = 1<<byte_to_send;"

(http://i64.tinypic.com/2412w7q.png)
Code: [Select]
00000100
11111011
01000100
1011101
notice the last bit is missing, its supposed to be a 1, so its not working yet...

current code
Code: [Select]
#include <16F628A.h>

#fuses NOWDT //Disable Watchdog Timer
#fuses NOPROTECT //Disable Read/Write Protect
#FUSES NOCPD //Disable EE protection
#fuses NOLVP //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO //Set CLK pins as I/O
#fuses NOMCLR //Disable Master Clear
#FUSES NOBROWNOUT //Disable Reseting On Power Loss
//#FUSES HS //Crystal With More than 4Mhz

#use delay(clock=4000000)

//=================
//DeviceID of TV
//00100000=32
//
//Code of button OK
//00100010=34
//=================

// define some constants:
//DeviceID
const char device_address = 32; //DeviceID of TV
//Buttons
const char OK = 34; //button OK

char i;
char byte_to_send;

//================================
//      NEC PROTOCOL

void startSending() // START
{
set_pwm1_duty(12);;
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void end_sending()
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
}

//================================

void send_byte(byte_to_send)
{
for (i=8; i>0; i--)
{

if (byte_to_send & 0x1)
{
output_high(pin_b1); //probe pin B1 for 1 signals
logical1();
output_low(pin_b1);
}

else
{
output_high(pin_b0); //probe pin B0 for 0 signals
logical0();
output_low(pin_b0);
}

byte_to_send = byte_to_send>>1;
}
}

//================================

void send_key_OK() //Send button OK
{++++++++++++++++++++++++++
startSending(); //Send 9ms START pulse
send_byte(device_address); //Send DeviceID
send_byte(~device_address); //Send Inverted DeviceID
send_byte(OK); //Send ButtonCode
send_byte(~OK); //Send inverted ButtonCode
end_sending();
}

void main()
{
setup_ccp1(ccp_pwm);            //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1);   //38Khz PWM using 4Mhz Osc.
delay_us(20);

while(1)
{
if(!input(pin_a0))
{
send_key_OK();

while(!input(pin_a0))
{
delay_ms(110); //comment this line to one-shot troubleshot on osciloscope the output of send_key_OK()
repeatCode(); //comment this line to one-shot troubleshot on osciloscope the output of send_key_OK()
}
}
}
}


and the code
Code: [Select]
#include <16F628A.h>

#fuses NOWDT //Disable Watchdog Timer
#fuses NOPROTECT //Disable Read/Write Protect
#FUSES NOCPD //Disable EE protection
#fuses NOLVP //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO //Set CLK pins as I/O
#fuses NOMCLR //Disable Master Clear
#FUSES NOBROWNOUT //Disable Reseting On Power Loss
//#FUSES HS //Crystal With More than 4Mhz

#use delay(clock=4000000)

//=================
//DeviceID of TV
//00100000=32
//
//Code of button OK
//00100010=34
//=================

// define some constants:
//DeviceID
const char device_address = 32; //DeviceID of TV
//Buttons
const char OK = 34; //button OK

char i;
char byte_to_send;

//================================
//      NEC PROTOCOL

void startSending() // START
{
set_pwm1_duty(12);;
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void end_sending()
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
}

//================================

void send_byte(byte_to_send)
{
for (i=0; i<8; i++)
{

if (byte_to_send & 1)
{
output_high(pin_b1); //probe pin B1 for 1 signals
logical1();
output_low(pin_b1);
}

else
{
output_high(pin_b0); //probe pin B0 for 0 signals
logical0();
output_low(pin_b0);
}

byte_to_send = 1<<byte_to_send;
}
}

//================================

void send_key_OK() //Send button OK
{++++++++++++++++++++++++++
startSending(); //Send 9ms START pulse
send_byte(device_address); //Send DeviceID
send_byte(~device_address); //Send Inverted DeviceID
send_byte(OK); //Send ButtonCode
send_byte(~OK); //Send inverted ButtonCode
end_sending();
}

void main()
{
setup_ccp1(ccp_pwm);            //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1);   //38Khz PWM using 4Mhz Osc.
delay_us(20);

while(1)
{
if(!input(pin_a0))
{
send_key_OK();

while(!input(pin_a0))
{
delay_ms(110); //comment this line to one-shot troubleshot on osciloscope the output of send_key_OK()
repeatCode(); //comment this line to one-shot troubleshot on osciloscope the output of send_key_OK()
}
}
}
}
gives the output
Code: [Select]
00100001
10100001
00100001
10100001
notice the last bit is always a 1...
Title: Re: NEC IR Remote using PIC
Post by: xtoffer on March 06, 2016, 08:52:49 am
Quote
fixed the inverted bytes, changed "byte_to_send = byte_to_send>>1;" to "byte_to_send = 1<<byte_to_send;"

If you want to send the data in the reverse direction, a correct way of reversing would be just to replace the operator. In your case you are now shifting a 1, byte_to_send number of times left.

So to be clear that would be
Code: [Select]
byte_to_send = byte_to_send << 1;
And as I tried to explain above, if you shift the other way because you want to reverse the direction you need to read from the other end of the byte as well. You can do this by (byte_to_send & 0x80).
Title: Re: NEC IR Remote using PIC
Post by: dannyf on March 06, 2016, 02:15:09 pm
an alternate approach to what you are doing is to generate a 38Khz carrier signal, and then short it periodically to ground to generate the signal to be transmitted. This can be done with a separate pin controlled in a timer interrupt.

The benefit of this approach is so that all transmission can be done in the interrupt and your main loop can be freed to do something else, like processing user buttons.
Title: Re: NEC IR Remote using PIC
Post by: luvini on March 06, 2016, 08:03:43 pm
Quote
fixed the inverted bytes, changed "byte_to_send = byte_to_send>>1;" to "byte_to_send = 1<<byte_to_send;"

If you want to send the data in the reverse direction, a correct way of reversing would be just to replace the operator. In your case you are now shifting a 1, byte_to_send number of times left.

So to be clear that would be
Code: [Select]
byte_to_send = byte_to_send << 1;
And as I tried to explain above, if you shift the other way because you want to reverse the direction you need to read from the other end of the byte as well. You can do this by (byte_to_send & 0x80).

that worked! but why 0x80? isnt that 128?

current code:
Code: [Select]
#include <16F628A.h>

#fuses NOWDT //Disable Watchdog Timer
#fuses NOPROTECT //Disable Read/Write Protect
#FUSES NOCPD //Disable EE protection
#fuses NOLVP //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO //Set CLK pins as I/O
#fuses NOMCLR //Disable Master Clear
#FUSES NOBROWNOUT //Disable Reseting On Power Loss
//#FUSES HS //Crystal With More than 4Mhz

#use delay(clock=4000000)
//=================
// Examples
//DeviceID of TV
//00100000=32
//
//Code of button OK
//00100010=34
//=================

//DeviceID
const char device_address = 32; //DeviceID of TV
//Buttons
const char OK = 34; //button OK


//=================
char i;
char byte_to_send;
//================================
//      NEC PROTOCOL

void startSending() // START
{
set_pwm1_duty(12);;
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void end_sending()
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
}
//================================

void send_byte(byte_to_send)
{
for (i=0; i<8; i++)
{
if (byte_to_send & 0x80)
{
output_high(pin_b1); //probe pin B1 for 1 signals
logical1();
output_low(pin_b1);
}
else
{
output_high(pin_b0); //probe pin B0 for 0 signals
logical0();
output_low(pin_b0);
}
byte_to_send = byte_to_send << 1;
}
}

//================================

void send_key_OK() //Send button OK
{++++++++++++++++++++++++++
startSending(); //Send 9ms START pulse
send_byte(device_address); //Send DeviceID
send_byte(~device_address); //Send Inverted DeviceID
send_byte(OK); //Send ButtonCode
send_byte(~OK); //Send inverted ButtonCode
end_sending();
}

void main()
{
setup_ccp1(ccp_pwm);            //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1);   //38Khz PWM using 4Mhz Osc.
delay_us(20);

while(1)
{
//===============================
if(!input(pin_a0))
{
send_key_OK();
while(!input(pin_a0))
{
delay_ms(110);
repeatCode();
}
}
//===============================
}
}
Title: Re: NEC IR Remote using PIC
Post by: xtoffer on March 06, 2016, 09:00:39 pm
that worked! but why 0x80? isnt that 128?

It is! Some people find it easier to think in hex because it is easy to convert between hex and binary (each digit in hex represents four digits in binary). To be even more obvious in the code you could write something like (1 << 7) to select the eighth bit.
Title: Re: NEC IR Remote using PIC
Post by: dannyf on March 06, 2016, 11:32:49 pm
I took my old soft_uart module (on a LM4F120) and got it working on a pic16f684 to send a string under the nec protocol.

The basic set-up is to generate a 38Khz carrier signal via the CCP1 module on RC5/CCP1 pin. That signal is periodically grounded by RC0 controlled by tmr0 interrupt, to produce the desired '1' and '0'.

Code: [Select]
/tmr0 isr
void interrupt isr(void) {
T0IF = 0; //clear the flag
if (_nec_carrier) { //carrier was sent. now, short the output
if (_nec_mask & *_nec_ptr) TMR0=-NEC_TICK; //this is a 1 bit. followed by 560us
else TMR0=-NEC_TICKx3; //this is a 0 bit. followed by 560us x 3
NEC_OFF(); //short the output
_nec_carrier=0; //output has been shorted
_nec_mask = _nec_mask >> 1; //shift to the next bit
if (_nec_mask == 0) { //advance to the next char
_nec_mask = 0x80; //msb first
_nec_ptr+=1; //advance tot he next char
IO_FLP(OUT_PORT, OUT_PIN); //flip out_pin for debugging
};
if (*_nec_ptr==0) { //if no more char to be sent, stop the transmission
T0IE = 0; //stop the interrupt
_nec_ready=1; //nec ready
};
} else { //output has been shorted. now see if we can transmitt new data
//send the carrier signal
TMR0=-NEC_TICK; //load the offset for the carrier seignal
NEC_ON(); //send the carrier signal
_nec_carrier=1; //carrier has been sent
}
}

The set-up is a fire-and-forget type: the main loop looks to see if the nec module is ready. Once it is ready, it loads up the string to be sent and go about doing its other businesses.

Code: [Select]
while (1) {
if (nec_isready()) nec_send(nRAM); //if nec unit is ready, send data
}

The buffer, nRAM, contains the chars to be sent. And in this case, it is defined as:

Code: [Select]
uint8_t nRAM[11]={0x55, 0x22, 0xf8, 0x8f, 0}; //nec buffer, 10 digits max

So it is a typical C string.

In the ISR, I flipped RC2 to indicate the chars being sent.

The timing parameters are defined and calculated by the compiler so the code can be easily adopted to other mcus, including non-PIC ones. The same concept can be used to produce soft-peripherals, like spi, i2c, uart, etc.

Comparing to the polling approach, it has very low cpu load: about 3% in this case.


Title: Re: NEC IR Remote using PIC
Post by: luvini on March 07, 2016, 03:21:02 am
UPDATED CODE, now supports multiple devices, easier to add devices and buttons

Code: [Select]
#include <16F628A.h>

#fuses NOWDT //Disable Watchdog Timer
#fuses NOPROTECT //Disable Read/Write Protect
#FUSES NOCPD //Disable EE protection
#fuses NOLVP //Disable Low Voltage Programming (ICSP) ==keep low during operation if enabled to prevent entering ICSP mode==
#fuses INTRC_IO //Set CLK pins as I/O
#fuses NOMCLR //Disable Master Clear
#FUSES NOBROWNOUT //Disable Reseting On Power Loss
//#FUSES HS //Crystal With More than 4Mhz

#use delay(clock=4000000)

//==============CODES==============
//DeviceID
const char TV = 32 ;
const char RGBlamp =   0 ;

//Buttons
//=====TV======
const char power = 16 ;//TV Power
const char input = 208 ;//TV input
const char addVol = 64 ;//TV Vol+
const char subVol = 192 ;//TV Vol-
const char OK = 34 ;//TV OK
const char Mute = 144 ;//TV Mute
const char Right = 96 ;//TV Right
const char Left = 224 ;//TV Left
const char Up =   2 ;//TV Up
const char Down = 130 ;//TV Down
const char Back = 20 ;//TV Back
const char Settings = 194 ;//TV Settings

//===RGBlamp===
const char rgbOn = 224 ;//RGBlamp ON
const char rgbOff = 96 ;//RGBlamp OFF
const char addBright= 160 ;//RGBlamp +Bright
const char subBright= 32 ;//RGBlamp -Bright
const char white = 208 ;//RGBlamp white
const char red = 144 ;//RGBlamp red
const char green = 16 ;//RGBlamp green
const char blue = 80 ;//RGBlamp blue


//================================
char i;
char byte_to_send;
int button;
int device;
//================================
int RGBpowerToggle;
//================================
//      NEC PROTOCOL

void startSending() // START
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(4500);
}

void logical1() // 1
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(1690);
}

void logical0() // 0
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void repeatCode() // REPEAT
{
set_pwm1_duty(12);
delay_ms(9);
set_pwm1_duty(0);
delay_us(2250);
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
delay_us(560);
}

void end_sending()
{
set_pwm1_duty(12);
delay_us(560);
set_pwm1_duty(0);
}
//================================
void send_byte(byte_to_send)
{
for (i=0; i<8; i++)
{
if (byte_to_send & 0x80)
{
output_high(pin_b1); //probe pin B1 for 1 signals
logical1();
output_low(pin_b1);
}
else
{
output_high(pin_b0); //probe pin B0 for 0 signals
logical0();
output_low(pin_b0);
}
byte_to_send = byte_to_send << 1;
}
}
//================================
void send_key() //Send the code
{
startSending(); //Send 9ms START pulse
send_byte(device); //Send DeviceID
send_byte(~device); //Send Inverted DeviceID
send_byte(button); //Send ButtonCode
send_byte(~button); //Send inverted ButtonCode
end_sending(); //Send final pulse (to complete the last bit)
}
//================================
void main()
{
setup_ccp1(ccp_pwm); //CCPM1 = PIN_B3 on PIC16F628A
setup_timer_2(T2_DIV_BY_1,25, 1); //38Khz PWM using 4Mhz Osc.
delay_us(20);
//================================

RGBpowerToggle = 0;

while(1)
{
//===============================
if(!input(pin_a0))
{
device=TV;
button=power;

send_key();
while(!input(pin_a0))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_a1))
{
device=TV;
button=input;

send_key();
while(!input(pin_a1))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_a2))
{
device=TV;
button=addVol;

send_key();
while(!input(pin_a2))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_a3))
{
device=TV;
button=subVol;

send_key();
while(!input(pin_a3))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_b0))
{
device=RGBlamp;

if(RGBpowerToggle==0)
{
button=rgbOn;
}

if(RGBpowerToggle==1)
{
button=rgbOff;
}

RGBpowerToggle++;

if(RGBpowerToggle==2)
{
RGBpowerToggle=0;
}

send_key();
while(!input(pin_b0))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_b1))
{
device=RGBlamp;
button=addBright;

send_key();
while(!input(pin_b1))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_b5))
{
device=RGBlamp;
button=subBright;

send_key();
while(!input(pin_b5))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_b4))
{
device=RGBlamp;
button=white;

send_key();
while(!input(pin_b4))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_a6))
{
device=RGBlamp;
button=red;

send_key();
while(!input(pin_a6))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_a7))
{
device=RGBlamp;
button=green;

send_key();
while(!input(pin_a7))
{
delay_ms(110);
repeatCode();
}
}
//===============================
if(!input(pin_a4))
{
device=RGBlamp;
button=blue;

send_key();
while(!input(pin_a4))
{
delay_ms(110);
repeatCode();
}
}
//===============================

}
}

Code: [Select]
PIC16F628A
Memory usage:   ROM=21%      RAM=5% - 7%

https://youtu.be/-yqfaucz32k (https://youtu.be/-yqfaucz32k)
Title: Re: NEC IR Remote using PIC
Post by: luvini on March 13, 2016, 12:57:30 am
current while idle=1227uA

how do i decrease power consumption while idle now?
i think there was a sleep function, how does that work?

i tried to add "Sleep();" in the loop, just to see what happens, and indeed, the current stays at 375uA, much lower, but i looked on google, and it seems it should get as low as 43uA http://embedded-lab.com/blog/lab-17-sleep-and-wake-pic-microcontrollers/ (http://embedded-lab.com/blog/lab-17-sleep-and-wake-pic-microcontrollers/)

But then after going into Sleep() it does nothing, how would i wakeup the device from any input(button)?

theres this Example file "EX_WAKUP.C"
Code: [Select]
/////////////////////////////////////////////////////////////////////////
////                          EX_WAKUP.C                             ////
////                                                                 ////
////  This example shows how to use the sleep function.  When the    ////
////  button is pushed, the processor goes into sleep mode.  When    ////
////  the button is released, the processor wakes up and continues   ////
////  counting.                                                      ////
////                                                                 ////
////  Configure the CCS prototype card as follows:                   ////
////     Jumper from pin B0 to a switch.                             ////
////                                                                 ////
////  Jumpers:                                                       ////
////     PCM,PCH    pin C7 to RS232 RX, pin C6 to RS232 TX           ////
////                                                                 ////
////  This example will work with the PCM and PCH compilers.  The    ////
////  following conditional compilation lines are used to include a  ////
////  valid device for each compiler.  Change the device, clock and  ////
////  RS232 pins for your hardware if needed.                        ////
/////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2003 Custom Computer Services         ////
//// This source code may only be used by licensed users of the CCS  ////
//// C compiler.  This source code may only be distributed to other  ////
//// licensed users of the CCS C compiler.  No other use,            ////
//// reproduction or distribution is permitted without written       ////
//// permission.  Derivative programs created using this software    ////
//// in object code form are not restricted in any way.              ////
/////////////////////////////////////////////////////////////////////////


#if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#endif

// global flag to send processor into sleep mode
short sleep_mode;

// external interrupt when button pushed and released
#INT_EXT
void ext_isr() {
static short button_pressed=FALSE;

   if(!button_pressed)        // if button action and was not pressed
   {
      button_pressed=TRUE;    // the button is now down
      sleep_mode=TRUE;        // activate sleep
      printf("The processor is now sleeping.\r\n");
      ext_int_edge(L_TO_H);   // change so interrupts on release
   }
   else                       // if button action and was pressed
   {
      button_pressed=FALSE;   // the button is now up
      sleep_mode=FALSE;       // reset sleep flag
      ext_int_edge(H_TO_L);   // change so interrupts on press
   }
   if(!input(PIN_B0))         // keep button action sychronized wth button flag
      button_pressed=TRUE;
   delay_ms(100);             // debounce button
}

// main program that increments counter every second unless sleeping
void main()   {
   long counter;

   sleep_mode=FALSE;          // init sleep flag

   ext_int_edge(H_TO_L);      // init interrupt triggering for button press
   enable_interrupts(INT_EXT);// turn on interrupts
   enable_interrupts(GLOBAL);

   printf("\n\n");

   counter=0;                 // reset the counter
   while(TRUE)
   {
      if(sleep_mode)          // if sleep flag set
         sleep();             // make processor sleep
      printf("The count value is:  %5ld     \r\n",counter);
      counter++;              // display count value and increment
      delay_ms(1000);         // every second
   }
}

=========================

also, would the "void end_sending()" on my code be called a "stop bit"?

=========================

and i also updated the PWM Calculator: https://docs.google.com/spreadsheets/d/1VXUw5Sm8fl1sn6Jrq0pawhZ0cFhNQzehLE0Sc8wFf2Q/edit?usp=sharing (https://docs.google.com/spreadsheets/d/1VXUw5Sm8fl1sn6Jrq0pawhZ0cFhNQzehLE0Sc8wFf2Q/edit?usp=sharing)
now it has a graphical preview and is able to be edited without having to download locally
(http://i66.tinypic.com/2edazuw.png)
try it and see if its working properly...
Title: Re: NEC IR Remote using PIC
Post by: luvini on April 06, 2016, 04:36:03 am
i still need help with decreasing power consumption while idle...
Title: Re: NEC IR Remote using PIC
Post by: macboy on April 06, 2016, 02:19:54 pm
i still need help with decreasing power consumption while idle...
You need to put the PIC to sleep, and more importantly, you need to wake it up again!

To wake up, generally you will need a reset, an interrupt (either internal or external) or a watchdog timer timeout. The WDT can be used to periodically wake up the PIC to check for things to be done (like scanning for a button press). You can also use any interrupt source, such as a timer reaching zero*, comparator interrupt, or an interrupt-on-change pin (for 16F628A, these are RB4..RB7). (note that internally timed timers stop during sleep since the oscillator is turned off during sleep).

For your case, you will likely want a WDT wake-up. You will setup up the WDT for a suitable timeout period, then go to sleep. After that timeout, you wake up and execute the next instruction (no reset occurs as with some lower end PICs). You can then disable the WDT, scan for a key press, and send a code if necessary. When no keys are pressed, enable WDT and sleep.

There are notes in the datasheet about lowering power consumption while sleeping... oscillator options, disabling voltage reference, etc.
Title: Re: NEC IR Remote using PIC
Post by: rstofer on April 07, 2016, 12:20:48 am

why atmel is better than microchip?
i am using pic for a couple of years and it's working fine.
i be glad if give me a good reason to try them

Sent from my SM-N920C using Tapatalk

For 16F PICs and the assembly level programmer (and C is pretty grim on an 8 bit PIC as well), the banking and paging nonsense of the PIC will drive you crazy!  The AVR has a larger instruction set and the interrupts are easier to handle.  The architecture of the PIC is something from the deep lagoon back in the '60s.  But there are a lot of them around.  Clearly, they outsell Atmel so what do I know?

Title: Re: NEC IR Remote using PIC
Post by: mathsquid on April 07, 2016, 02:13:17 am
You need to put the PIC to sleep, and more importantly, you need to wake it up again!

To wake up, generally you will need a reset, an interrupt (either internal or external) or a watchdog timer timeout. The WDT can be used to periodically wake up the PIC to check for things to be done (like scanning for a button press). You can also use any interrupt source, such as a timer reaching zero*, comparator interrupt, or an interrupt-on-change pin (for 16F628A, these are RB4..RB7). (note that internally timed timers stop during sleep since the oscillator is turned off during sleep).

I've done a few IR remote circuits, but they've all been either temporary circuits I'm just playing with or a web-controlled  remote powered by a USB cable. I've wondered about powering a remote long-term using a battery.  Is it standard to have the microcontroller cycle between sleep and wake frequently enough to catch up a normal-length button press?  Or would it be more common to use a pin change interrupt so that a button press would wake it up?  Or is there some better method I don't know about?
Title: Re: NEC IR Remote using PIC
Post by: macboy on April 07, 2016, 02:23:24 pm
You need to put the PIC to sleep, and more importantly, you need to wake it up again!

To wake up, generally you will need a reset, an interrupt (either internal or external) or a watchdog timer timeout. The WDT can be used to periodically wake up the PIC to check for things to be done (like scanning for a button press). You can also use any interrupt source, such as a timer reaching zero*, comparator interrupt, or an interrupt-on-change pin (for 16F628A, these are RB4..RB7). (note that internally timed timers stop during sleep since the oscillator is turned off during sleep).
I've done a few IR remote circuits, but they've all been either temporary circuits I'm just playing with or a web-controlled  remote powered by a USB cable. I've wondered about powering a remote long-term using a battery.  Is it standard to have the microcontroller cycle between sleep and wake frequently enough to catch up a normal-length button press?  Or would it be more common to use a pin change interrupt so that a button press would wake it up?  Or is there some better method I don't know about?
The best way for power consumption would be interrupt on change. With a 16 key (4x4) key matrix, you could use 4 IOC capable pins to achieve this. Before sleeping, drive all 4 columns and enable IOC interrupt on all 4 row inputs. After the interrupt fires, do the normal key scanning (driving one column at a time) to determine which key is pressed. The PIC can sleep for hours or days on end this way. The WDT wake-up works if you don't have IOC pins or not enough of them (only four on the '628A) or if you use a resistor ladder and ADC to do key scanning rather than a matrix. You can also forgo sleeping and switch to the low speed internal oscillator and just continue polling the inputs as usual (but at ~1/100 the normal execution speed) then switch to high speed before sending the IR signals. This method also gives the lowest possible latency since it does not incur the OST (Oscillator Startup Timer) delay upon wake-up. Using the internal 4 MHz RC oscillator also incurs less wake up delay, only 1 us vs. 1024 cycles for an external crystal. That delay before the code runs means wasted power.
About the best you can do is run at ~ 2.0 V for lowest current consumption, use the internal RC oscillator for lowest wake up delay, and use IOC pins to wake from sleep.