INTRODUCTION:
My
project was to use a PIC18F27K40-I/SP
8-bit PIC microcontroller to receive an infrared (IR) signal from an
IR remote (as well as one of my smartphones with an IR transmitter on
it) using the NEC protocol, display that character or command sent to
the receiver on an Liquid Crystal Display (LCD), and use pulse width
modulation (PWM) to beep a speaker every time a command is received.
The
IR receiver is a TSOP4838. The microcontroller is an advanced 8-bit
device (18F PIC series). There is more memory and a few more ports
on this microcontroller but it was not needed for this project. I
wanted to be safe hardware-wise though. NEC Electronics was the
company that came up with the protocol used, and that company is now
called Renesas.
REQUIREMENTS:
The
requirements for a single-person group was to use at 3 peripherals.
The peripherals I used were digital I/O (IR encoding protocol for
data), an LCD, and PWM. No more peripherals were added since I did
not have the time to, but there is plenty of space for adding more.
I was able to satisfy my project proposal and get the commands
displayed on an LCD screen and beep every time a command was
received.
HARDWARE
DESIGN DETAILS:
Refer
to the “Parts Used” section for what hardware was used. A
schematic and layout of the hardware used is pictured below in Figure
1. An assortment of standard parts was used, a speaker, an IR
receiver, a couple of resistors, an LED, a power supply, and LCD. A
slightly non-standard part was a serial-to-LCD converter module.
This allowed me to use only one pin for the LCD instead of 11, saving
space to expand for other peripherals or features.
Figure
1: Project Schematic / Layout
SOFTWARE
DESIGN DETAILS:
The
software was intentionally simplistic, using a polling method for the
IR receiver in a while loop and no interrupts. I do all the
initializing of the peripherals at power up:
- Making one pin a digital input for the IR receiver
- Making one pin a digital output for an LED
- Setting up a timer and an output pin for PWM
- Setting up a EUSART port with a TX pin for the LCD.
Once
everything is initialized, I have a while-loop that reads the IR pin.
If the pin is high, I just wait until it goes low. I do this to
make sure that I do not miss an incoming command, the timing is
important. When the pin goes low I begin looking for a high pulse
for 9 milliseconds. I do this with a counter variable and a delay
function that is in one of the compiler libraries for the PIC. The
function is “__delay_us()”, and it delays for the amount of
microseconds put in the parentheses. After the 9 milliseconds high,
I look for 4.5 milliseconds low. Then after waiting for that amount
of time, I can start looking for the actual payloads in the message.
First is an 8-bit address, then that address is inverted. After that
the command is sent, then that command is inverted. I did not do any
error checking but in a commercial product you would check each
address and command to be sure they are total opposites of each
other, before accepting the command. If the timing was for a logical
1 or 0, then that particular bit is set in an unsigned 32 bit
variable. After getting the command, having a small delay for the
beep of the speaker prevents “loop-back” or getting another
command immediately after. It is a kind of “debounce”, like you
would do for buttons.
Figure 2: Software
Flowchart Diagram
IMPLEMENTATION
DETAILS:
The
NEC protocol is a very popular IR protocol. It originally had an
8-bit command length, but those commands were quickly used up by
vendors. An expanded 16-bit version was created, allowing for around
65,535 commands to be used. My decoder currently is only 8-bit
however. The protocol starts with a 9 millisecond pulse high, then a
4.5 millisecond pulse low, then it begins with an 8 bit address, the
inversion of that address, then an 8 bit command, and the inverted
command.
Figure
3: NEC IR Protocol
EXPERIMENT
RESULTS AND DISCUSSION:
I
was having a little trouble getting the address for some reason, but
for my remote I know it is 0xFF. Getting the command is the most
important part and I know I was getting the correct command. An
excellent IR library [7] for the Arduino platform was used to verify
that my codes are correct. In the reference section below I will
attach all the commands from the IR remote. I visually verified with
the Arduino IR library that it was working with the IR transmitter on
my phone, which has an application that can transmit just about all
the IR protocols for TV remotes. The Vizio remote I use on my
Android phone for a Vizio TV happened to be NEC protocol and works
with the decoder.
REFERENCES:
[1] https://www.sparkfun.com/products/258
[2] https://www.sparkfun.com/products/255
[3] http://uk.farnell.com/vishay/tsop4838/ir-receiver-38khz/dp/4913190
[4] http://www.microchip.com/wwwproducts/en/PIC18F27K40
[5] http://www.sbprojects.com/knowledge/ir/nec.php
[6] http://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol#
[7] https://github.com/z3t0/Arduino-IRremote
APPENDIX:
- The codes for one of the IR transmitters are listed below. They include the address (8 bits, not the inverted portion) and the command with the inverted command.
Gray
remote control button commands, starting with top left (red power
button) and going right, then next row, etc.
FFB24D
Decoded
NEC: FFB24D (32 bits)
FF2AD5
Decoded
NEC: FF2AD5 (32 bits)
FF6897
Decoded
NEC: FF6897 (32 bits)
FF32CD
Decoded
NEC: FF32CD (32 bits)
FFA05F
Decoded
NEC: FFA05F (32 bits)
FF30CF
Decoded
NEC: FF30CF (32 bits)
FF50AF
Decoded
NEC: FF50AF (32 bits)
FF02FD
Decoded
NEC: FF02FD (32 bits)
FF7887
Decoded
NEC: FF7887 (32 bits)
FF48B7
Decoded
NEC: FF48B7 (32 bits)
FF40BF
Decoded
NEC: FF40BF (32 bits)
FF38C7
Decoded
NEC: FF38C7 (32 bits)
FF906F
Decoded
NEC: FF906F (32 bits)
FFB847
Decoded
NEC: FFB847 (32 bits)
FFF807
Decoded
NEC: FFF807 (32 bits)
FFB04F
Decoded
NEC: FFB04F (32 bits)
FF9867
Decoded
NEC: FF9867 (32 bits)
FFD827
Decoded
NEC: FFD827 (32 bits)
FF8877
Decoded
NEC: FF8877 (32 bits)
FFA857
Decoded
NEC: FFA857 (32 bits)
FFE817
Decoded
NEC: FFE817 (32 bits)
- Only the main.c file is included here as it is where the main application code is, for the rest of the code, refer to the zip file included with the project submission.
/*
* File: main.c
* Author: Int-Mosfet
*
* Created on April 8, 2017, 11:41 AM
*/
#include <stdio.h>
#include <stdlib.h>
#include "pin_manager.h"
#define SET_BIT(var, pos) (var |= (1
<< pos))
#define CLEAR_BIT(var, pos) (var &=
(~(1 << pos)))
void main(void)
{
// Initialize the device
SYSTEM_Initialize();
//turn on LED
IO_RB6_SetHigh();
//turn off PWM
//1 is off, 0 is on (PWM)
TRISCbits.TRISC6 = 1;
// Value loaded effects volume
output
//PWM3_LoadDutyValue(0xF0);
//TRISCbits.TRISC6 = 0;
//__delay_ms(500);
//TRISCbits.TRISC6 = 1;
//RC6_SetLow();
uint8_t count = 0;
uint8_t i = 0;
//control char of 254 (0xFE)
//must be sent before a command)
uint8_t cntr = 254;
uint8_t clear_cmd = 1;
volatile uint32_t ir_code;
uint16_t address;
uint8_t command, inv_command;
//Clear screen
//EUSART1_Write(cntr);
//EUSART1_Write(clear_cmd);
//set cursor to beginning
//EUSART1_Write(cntr);
//EUSART1_Write(128);
__delay_ms(2000);
printf("ECE471 IR Decode");
printf("NEC Proto, Begin");
while (true)
{
//delay until RC7 goes low
while(IO_RC7_GetValue() ==
1);
//9ms high
while((IO_RC7_GetValue() ==
0) && (count < 200))
{
count++;
__delay_us(50);
}
//if(count > 200 || count
< 160)
// printf("FALSE
ACTIVATION");
//reset counter
count = 0;
//4.5ms low
while((IO_RC7_GetValue()) &&
(count < 100))
{
count++;
__delay_us(50);
}
//if(count > 100 || count
< 80)
// printf("FALSE
ACTIVATION");
// Read IR code, 32 bits
for(i = 0; i < 32; i++)
{
count = 0;
while((IO_RC7_GetValue()
== 0) && (count < 14))
{
count++;
__delay_us(50);
}
count = 0;
while((IO_RC7_GetValue())
&& (count < 40))
{
count++;
__delay_us(50);
}
if( count > 20)
SET_BIT(ir_code, (31
- i));
else // If space width <
1ms
CLEAR_BIT(ir_code,
(31 - i));
}
address = ir_code <<
16;
command = ir_code >> 4;
//clear screen
EUSART1_Write(cntr);
EUSART1_Write(clear_cmd);
printf(" NEC
PROTOCOL");
//printf(" CMD: ");
//printf("%x",
command);
//printf(" ");
EUSART1_Write(cntr);
EUSART1_Write(192);
printf("FULL CODE: ");
printf("%x",
ir_code);
printf(" ");
TRISCbits.TRISC6 = 0;
__delay_ms(200);
TRISCbits.TRISC6 = 1;
}
}
- List of Figures:
- Figure 2: Software Flowchart Diagram
- Figure 3: NEC IR Protocol
- Parts Used:
- PIC18F27K40-I/SP 8-bit PIC microcontroller
- 16 X 2 LCD screen (LCD-00255)
- Serial Enabled LCD Backpack (LCD-00258)
- Vishay TSOP4838 Infrared receiver, 38kHz
- 8 Ω speaker
- 220 Ω current-limiting resistor for speaker
- 1 K Ω current-limiting resistor for LED
- Breadboard
- 3-30V Volt-meter (extra add-on)
- Jumper wire
- Alligator clips
- 5V power supply