NEC IR Remote using PIC - Page 1
Forum section: electronics / general

author: luvini
author_rank: Contributor
timestamp: February 25, 2016, 08:52:35 pm
content: 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 usesthe NEC Protocol:http://www.sbprojects.com/knowledge/ir/nec.phpi seen Dave's video about doing it with a Arduinobut i want to do it on a PIC, specifically a PIC16F628Ai 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 bitshere is what i captured(when it goes high, the led is emitting and when it goes low, the led is off)

author: ElectricGuy
author_rank: Regular Contributor
timestamp: February 25, 2016, 11:21:11 pm
content: 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.

author: luvini
author_rank: Contributor
timestamp: February 26, 2016, 04:40:04 am
content: 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 CalculatorPWM Calculator:https://docs.google.com/spreadsheets/d/1VXUw5Sm8fl1sn6Jrq0pawhZ0cFhNQzehLE0Sc8wFf2Q/edit?usp=sharingi also decoded the signal, soRED=0andGREEN=1the final code i made is this, and it works, i can now control my device!Code:#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 PIC16F628Asetup_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);// STARTdelay_ms(9);set_pwm1_duty(0);delay_us(4500);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 0delay_us(560);set_pwm1_duty(0);delay_us(560);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);set_pwm1_duty(12);// 1delay_us(560);set_pwm1_duty(0);delay_us(1690);while(!input(pin_a0)){set_pwm1_duty(12);// REPEATdelay_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 herewhile(!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}

author: luvini
author_rank: Contributor
timestamp: February 26, 2016, 06:16:18 am
content: 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?

author: lapm
author_rank: Frequent Contributor
timestamp: February 26, 2016, 06:33:09 am
content: Well those are basicly just ones and zeroes represented by infrared encoded signals. See if you can identify encoding they use...

author: macboy
author_rank: Super Contributor
timestamp: February 26, 2016, 03:18:58 pm
content: Quote from: luvini on February 26, 2016, 06:16:18 amDo you see that every time you want to send a '0' bit you do exactly this:Code:set_pwm1_duty(12);// 0delay_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:// define some constants:const char channelup = 66 // NOTE this code is fake, replace with correct dataconst char channeldown = 68; // NOTE this code is fake, replace with correct dataconst char device_address = 5; // NOTE this code is fake, replace with correct datasend_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 elsebyte_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.

author: luvini
author_rank: Contributor
timestamp: February 26, 2016, 10:46:48 pm
content: 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:#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 PROTOCOLvoid 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 PIC16F628Asetup_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

author: luvini
author_rank: Contributor
timestamp: February 27, 2016, 05:18:00 am
content: tried to control my TV, and it used the NEC Protocol aswell so it was easy to doCode:#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 PROTOCOLvoid 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 PIC16F628Asetup_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 itCode:#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 PROTOCOLint 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 PIC16F628Asetup_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)

author: luvini
author_rank: Contributor
timestamp: February 27, 2016, 05:21:30 am
content: Quote from: macboy on February 26, 2016, 03:18:58 pmi am... not sure how does that work?

author: macboy
author_rank: Super Contributor
timestamp: February 28, 2016, 02:35:55 pm
content: Quote from: luvini on February 27, 2016, 05:21:30 amInside 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.

author: pascal_sweden
author_rank: Super Contributor
timestamp: February 28, 2016, 08:37:50 pm
content: If you are open to use an Atmel microcontroller, then you can use an existing library, that supports a multitude of IR protocolshttp://www.mikrocontroller.net/articles/IRSNDThis 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!

author: ElectricGuy
author_rank: Regular Contributor
timestamp: February 28, 2016, 08:50:13 pm
content: Quote from: pascal_sweden on February 28, 2016, 08:37:50 pmBut there is no Atmel, only Microchip!!!( Just Kidding )

author: pascal_sweden
author_rank: Super Contributor
timestamp: February 28, 2016, 08:52:01 pm
content: 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

author: luvini
author_rank: Contributor
timestamp: February 29, 2016, 03:21:56 am
content: Quote from: macboy on February 28, 2016, 02:35:55 pmi 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?Quote from: pascal_sweden on February 28, 2016, 08:37:50 pmi want to use a PIC16F628A for this project

author: luvini
author_rank: Contributor
timestamp: February 29, 2016, 03:53:49 am
content: made a full code, but it doesnt compile, giving errorCode:*** 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 herewich 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: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 elsebyte_to_send = byte_to_send>>1;}}maybe this could help?http://stackoverflow.com/questions/1682996/bytes-to-binary-in-cCode:unsigned char byte = 49;//Decimal Numberunsigned char mask = 1; //Bit maskunsigned char bits;//8bits=1Bytefor (int i = 0; i < 8; i++)// Extract the bits{bits = (byte & (mask << i)) != 0;//Mask each bit in the byte and store it}the full code isCode:#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://DeviceIDconst char device_address = 32;//DeviceID of TV//Buttonsconst char OK = 34;//button OK//================================// NEC PROTOCOLvoid 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 elsebyte_to_send = byte_to_send>>1;}}void send_key_OK()//Send button OK{startSending();//Send 9ms START pulsesend_byte(device_address);//Send DeviceIDsend_byte(~device_address);//Send Inverted DeviceIDsend_byte(OK);//Send ButtonCodesend_byte(~OK);//Send inverted ButtonCode}void main(){while(1){if(!input(pin_a0)){send_key_OK();while(!input(pin_a0)){repeatCode();delay_ms(110);}}}}

author: macboy
author_rank: Super Contributor
timestamp: February 29, 2016, 04:54:33 pm
content: First,Code:for (char i=8, i>0, i--)// decrementing is more efficient that incrementingMust be:Code: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:(byte_to_send & 0x1) ? logical1() : logical0();// the ? : is the ternary operator, works like if then elseTo:Code:if (byte_to_send & 0x1){logical1();}else{logical0();}

author: pascal_sweden
author_rank: Super Contributor
timestamp: February 29, 2016, 07:05:45 pm
content: Why do you only want to use a PIC?Note that the library also supports some PIC microcontrollers, and not only Atmelhttp://www.mikrocontroller.net/articles/IRSND#Unterst.C3.BCtzte_.C2.B5CsBut 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!

author: luvini
author_rank: Contributor
timestamp: February 29, 2016, 08:45:54 pm
content: now the code isCode: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 errorCode:*** 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 i3 Errors, 0 Warnings.so i added a "int i;"Code: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 isCode:*** 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 WarningsatCode: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 workCode: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:>>> Warning 203 "test0002.c" Line 100(1,1): Condition always TRUEMemory usage: ROM=8% RAM=3% - 4%0 Errors, 1 Warnings.

author: luvini
author_rank: Contributor
timestamp: February 29, 2016, 08:59:30 pm
content: Quote from: pascal_sweden on February 29, 2016, 07:05:45 pm50EUR is 218BRL, quite expensive when i built a PicKit2 myself under 50BRL and the PIC16F628A is just 12,50BRLbut i will try AVR someday, i think the Arduino even uses it (ATmega328), but i also dont have a Arduino ;Pthe 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

author: differentcurrent
author_rank: Newbie
timestamp: March 01, 2016, 09:31:50 am
content: 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 upSent from my SM-N920C using Tapatalk

author: differentcurrent
author_rank: Newbie
timestamp: March 01, 2016, 09:34:00 am
content: Quote from: pascal_sweden on February 29, 2016, 07:05:45 pmwhy 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 themSent from my SM-N920C using Tapatalk

author: luvini
author_rank: Contributor
timestamp: March 02, 2016, 01:46:04 am
content: Quote from: differentcurrent on March 01, 2016, 09:31:50 amchanging the variable "i" to anything else gives the same errormaybe Dave's Arduino code could help:https://gist.github.com/EEVblog/6206934i think the problem is with that "char" inside the "for(" part, because when i remove it, it compiles with no errorsbut it doesn't work, but at least the compiler gives no errorsCode:for (char i=8; i>0; i--)i dont understand what is this "char" doing inside of the parameters for the "for" function...//=========================voidsend_byte(charbyte_to_send){for(chari=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;}}//=========================can you see the image with the code above?

author: xtoffer
author_rank: Contributor
timestamp: March 05, 2016, 11:42:04 am
content: Quote from: luvini on March 02, 2016, 01:46:04 amThecharis 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 acharor anintis another matter. Note:charis often used as an unsigned 8-bitintfor 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 thecharsuch 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:send_byte(0x19)..would result in the following sequence..Code:logical1();logical0();logical0();logical1();logical1();logical0();logical0();logical0();

author: luvini
author_rank: Contributor
timestamp: March 06, 2016, 02:08:38 am
content: found why the IR LED wasnt doing anything in last version of code, forgot to activate the PWM portCode:setup_ccp1(ccp_pwm); //CCPM1 = PIN_B3 on PIC16F628Asetup_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:but what im getting is:it is sending ZEROs!current code isCode:#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://DeviceIDconst char device_address = 32;//DeviceID of TV//Buttonsconst char OK = 34;//button OKchar i;char byte_to_send;//================================// NEC PROTOCOLvoid 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 pulsesend_byte(device_address);//Send DeviceIDsend_byte(~device_address);//Send Inverted DeviceIDsend_byte(OK);//Send ButtonCodesend_byte(~OK);//Send inverted ButtonCode}void main(){setup_ccp1(ccp_pwm); //CCPM1 = PIN_B3 on PIC16F628Asetup_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 outputit 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.htmthe code for this one isCode:#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://DeviceIDconst char device_address = 32;//DeviceID of TV//Buttonsconst char OK = 34;//button OKchar i;char byte_to_send;//================================// NEC PROTOCOLvoid 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 signalslogical1();output_low(pin_b1);}else{output_high(pin_b0);//probe pin B0 for 0 signalslogical0();output_low(pin_b0);}byte_to_send = byte_to_send>>1;}}//================================void send_key_OK()//Send button OK{++++++++++++++++++++++++++startSending();//Send 9ms START pulsesend_byte(device_address);//Send DeviceIDsend_byte(~device_address);//Send Inverted DeviceIDsend_byte(OK);//Send ButtonCodesend_byte(~OK);//Send inverted ButtonCode}void main(){setup_ccp1(ccp_pwm); //CCPM1 = PIN_B3 on PIC16F628Asetup_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()}}}}

author: luvini
author_rank: Contributor
timestamp: March 06, 2016, 03:23:48 am
content: UPDATE(Blue = logical0(), Red = logical1(), Yellow = PWMoutputi got it to work 31bits!, but they are mirrored every 8 bits (1 byte)!EDITfixed the inverted bytes, changed "byte_to_send = byte_to_send>>1;" to "byte_to_send = 1<<byte_to_send;"Code:0000010011111011010001001011101notice the last bit is missing, its supposed to be a 1, so its not working yet...current codeCode:#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://DeviceIDconst char device_address = 32;//DeviceID of TV//Buttonsconst char OK = 34;//button OKchar i;char byte_to_send;//================================// NEC PROTOCOLvoid 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 signalslogical1();output_low(pin_b1);}else{output_high(pin_b0);//probe pin B0 for 0 signalslogical0();output_low(pin_b0);}byte_to_send = byte_to_send>>1;}}//================================void send_key_OK()//Send button OK{++++++++++++++++++++++++++startSending();//Send 9ms START pulsesend_byte(device_address);//Send DeviceIDsend_byte(~device_address);//Send Inverted DeviceIDsend_byte(OK);//Send ButtonCodesend_byte(~OK);//Send inverted ButtonCodeend_sending();}void main(){setup_ccp1(ccp_pwm); //CCPM1 = PIN_B3 on PIC16F628Asetup_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 codeCode:#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://DeviceIDconst char device_address = 32;//DeviceID of TV//Buttonsconst char OK = 34;//button OKchar i;char byte_to_send;//================================// NEC PROTOCOLvoid 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 signalslogical1();output_low(pin_b1);}else{output_high(pin_b0);//probe pin B0 for 0 signalslogical0();output_low(pin_b0);}byte_to_send = 1<<byte_to_send;}}//================================void send_key_OK()//Send button OK{++++++++++++++++++++++++++startSending();//Send 9ms START pulsesend_byte(device_address);//Send DeviceIDsend_byte(~device_address);//Send Inverted DeviceIDsend_byte(OK);//Send ButtonCodesend_byte(~OK);//Send inverted ButtonCodeend_sending();}void main(){setup_ccp1(ccp_pwm); //CCPM1 = PIN_B3 on PIC16F628Asetup_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 outputCode:00100001101000010010000110100001notice the last bit is always a 1...

author: xtoffer
author_rank: Contributor
timestamp: March 06, 2016, 08:52:49 am
content: QuoteIf 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 beCode: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).

author: dannyf
author_rank: Super Contributor
timestamp: March 06, 2016, 02:15:09 pm
content: 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.

author: luvini
author_rank: Contributor
timestamp: March 06, 2016, 08:03:43 pm
content: Quote from: xtoffer on March 06, 2016, 08:52:49 amthat worked! but why 0x80? isnt that 128?current code:Code:#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//=================//DeviceIDconst char device_address = 32;//DeviceID of TV//Buttonsconst char OK = 34;//button OK//=================char i;char byte_to_send;//================================// NEC PROTOCOLvoid 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 signalslogical1();output_low(pin_b1);}else{output_high(pin_b0);//probe pin B0 for 0 signalslogical0();output_low(pin_b0);}byte_to_send = byte_to_send << 1;}}//================================void send_key_OK()//Send button OK{++++++++++++++++++++++++++startSending();//Send 9ms START pulsesend_byte(device_address);//Send DeviceIDsend_byte(~device_address);//Send Inverted DeviceIDsend_byte(OK);//Send ButtonCodesend_byte(~OK);//Send inverted ButtonCodeend_sending();}void main(){setup_ccp1(ccp_pwm); //CCPM1 = PIN_B3 on PIC16F628Asetup_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();}}//===============================}}

author: xtoffer
author_rank: Contributor
timestamp: March 06, 2016, 09:00:39 pm
content: Quote from: luvini on March 06, 2016, 08:03:43 pmIt 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.

author: dannyf
author_rank: Super Contributor
timestamp: March 06, 2016, 11:32:49 pm
content: 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:/tmr0 isrvoid interrupt isr(void) {T0IF = 0;//clear the flagif (_nec_carrier) {//carrier was sent. now, short the outputif (_nec_mask & *_nec_ptr) TMR0=-NEC_TICK;//this is a 1 bit. followed by 560uselse TMR0=-NEC_TICKx3;//this is a 0 bit. followed by 560us x 3NEC_OFF();//short the output_nec_carrier=0;//output has been shorted_nec_mask = _nec_mask >> 1;//shift to the next bitif (_nec_mask == 0) {//advance to the next char_nec_mask = 0x80;//msb first_nec_ptr+=1;//advance tot he next charIO_FLP(OUT_PORT, OUT_PIN);//flip out_pin for debugging};if (*_nec_ptr==0) {//if no more char to be sent, stop the transmissionT0IE = 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 signalTMR0=-NEC_TICK;//load the offset for the carrier seignalNEC_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: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:uint8_t nRAM={0x55, 0x22, 0xf8, 0x8f, 0};//nec buffer, 10 digits maxSo 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.

author: luvini
author_rank: Contributor
timestamp: March 07, 2016, 03:21:02 am
content: UPDATED CODE, now supports multiple devices, easier to add devices and buttonsCode:#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==============//DeviceIDconst char TV=32 ;const char RGBlamp=0 ;//Buttons//=====TV======const char power=16 ;//TV Powerconst char input=208 ;//TV inputconst char addVol=64 ;//TV Vol+const char subVol=192 ;//TV Vol-const char OK=34 ;//TV OKconst char Mute=144 ;//TV Muteconst char Right=96 ;//TV Rightconst char Left=224 ;//TV Leftconst char Up=2 ;//TV Upconst char Down=130 ;//TV Downconst char Back=20 ;//TV Backconst char Settings =194 ;//TV Settings//===RGBlamp===const char rgbOn=224 ;//RGBlamp ONconst char rgbOff=96 ;//RGBlamp OFFconst char addBright=160 ;//RGBlamp +Brightconst char subBright=32 ;//RGBlamp -Brightconst char white=208 ;//RGBlamp whiteconst char red=144 ;//RGBlamp redconst char green=16 ;//RGBlamp greenconst char blue=80 ;//RGBlamp blue//================================char i;char byte_to_send;int button;int device;//================================int RGBpowerToggle;//================================// NEC PROTOCOLvoid 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 signalslogical1();output_low(pin_b1);}else{output_high(pin_b0);//probe pin B0 for 0 signalslogical0();output_low(pin_b0);}byte_to_send = byte_to_send << 1;}}//================================void send_key()//Send the code{startSending();//Send 9ms START pulsesend_byte(device);//Send DeviceIDsend_byte(~device);//Send Inverted DeviceIDsend_byte(button);//Send ButtonCodesend_byte(~button);//Send inverted ButtonCodeend_sending();//Send final pulse (to complete the last bit)}//================================void main(){setup_ccp1(ccp_pwm);//CCPM1 = PIN_B3 on PIC16F628Asetup_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:PIC16F628AMemory usage: ROM=21% RAM=5% - 7%https://youtu.be/-yqfaucz32k

author: luvini
author_rank: Contributor
timestamp: March 13, 2016, 12:57:30 am
content: current while idle=1227uAhow 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 43uAhttp://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:///////////////////////////////////////////////////////////////////////////// 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 modeshort sleep_mode;// external interrupt when button pushed and released#INT_EXTvoid ext_isr() {static short button_pressed=FALSE;if(!button_pressed) // if button action and was not pressed{button_pressed=TRUE; // the button is now downsleep_mode=TRUE; // activate sleepprintf("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 upsleep_mode=FALSE; // reset sleep flagext_int_edge(H_TO_L); // change so interrupts on press}if(!input(PIN_B0)) // keep button action sychronized wth button flagbutton_pressed=TRUE;delay_ms(100); // debounce button}// main program that increments counter every second unless sleepingvoid main() {long counter;sleep_mode=FALSE; // init sleep flagext_int_edge(H_TO_L); // init interrupt triggering for button pressenable_interrupts(INT_EXT);// turn on interruptsenable_interrupts(GLOBAL);printf("\n\n");counter=0; // reset the counterwhile(TRUE){if(sleep_mode) // if sleep flag setsleep(); // make processor sleepprintf("The count value is: %5ld \r\n",counter);counter++; // display count value and incrementdelay_ms(1000); // every second}}=========================also, would the "void end_sending()" on my code be called a "stop bit"?=========================and i also updated thePWM Calculator:https://docs.google.com/spreadsheets/d/1VXUw5Sm8fl1sn6Jrq0pawhZ0cFhNQzehLE0Sc8wFf2Q/edit?usp=sharingnow it has a graphical preview and is able to be edited without having to download locallytry it and see if its working properly...

author: luvini
author_rank: Contributor
timestamp: April 06, 2016, 04:36:03 am
content: i still need help with decreasing power consumption while idle...

author: macboy
author_rank: Super Contributor
timestamp: April 06, 2016, 02:19:54 pm
content: Quote from: luvini on April 06, 2016, 04:36:03 amYou 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.

author: rstofer
author_rank: Super Contributor
timestamp: April 07, 2016, 12:20:48 am
content: Quote from: differentcurrent on March 01, 2016, 09:34:00 amFor 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?

author: mathsquid
author_rank: Frequent Contributor
timestamp: April 07, 2016, 02:13:17 am
content: Quote from: macboy on April 06, 2016, 02:19:54 pmI'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?

author: macboy
author_rank: Super Contributor
timestamp: April 07, 2016, 02:23:24 pm
content: Quote from: mathsquid on April 07, 2016, 02:13:17 amThe 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.