BASIC Stamp, Microchip PIC, 8051, and Remote Control Projects

Using The PIC Microcontroller Hardware PWM Feature
& Infrared Communications Links

Based on feedback on this article, we now have a new 8-pin custom programmed PIC designed for infrared serial communications & remote control applications. Click HERE for details.

Parts Kits now in stock for this application HERE.

Many applications can benefit from an infrared communications link.  This article will hopefully shed some light on how to send & receive serial data between microcontrollers such as the BASIC Stamp, or PICMicro programmed with PicBasic.

Note: You can build these simple circuits, cut & paste the code into the PicBasic Pro compiler, and have a full-blown serial infrared communications network operating between several PICMicro's or even a BASIC Stamp. You do not need the PicBasic compiler to do this. If you can program a PIC, we have sample code at the end of this article for an 8-pin PIC that will generate the 38KHz carrier for this application instead of using the hardware PWM feature of the more expensive PICMicro.

Now - let's dive right in to the code.

PicBasic Pro Code:

' Setting up hardware PWM for 38KHz operation.


DEFINE LOADER_USED 1'Setup for boot-loader programming

TRISC.2 = 0  ' CCP1 (PortC.2 = Output)
PR2 = 25     ' Set PWM Period for approximately 38KHz
CCPR1L = 13  ' Set PWM Duty-Cycle to 50% 
CCP1CON = %00001100  ' Select PWM Mode
T2CON = %00000100    ' Timer2 = ON + 1:1 prescale
TRISB.0 = 0

ADDRESS	VAR BYTE
DAT	VAR BYTE
ID	VAR BYTE
ADDRESS	= 10
ID	= 25

BEGIN:
	FOR DAT = 0 TO 255
	    SEROUT PORTB.0,4,[ID,ADDRESS,DAT]
	    PAUSE 100
	NEXT
	GOTO BEGIN

The hardware PWM is configured in the beginning of our code. After we define the PWM frequency, and duty cycle, our code can proceed to performing other tasks while the hardware continues to operate in the background. Notice how program execution falls into a tight loop once it reaches the routine BEGIN. Even though we stay within this loop sending serial data continuously, the PWM signal continues without the need for software intervention to generate the 38KHz carrier.

Hardware peripherals offer true multi-tasking not available otherwise. Yes - you'll hear some people boasting of using interrupts or "C" for multi-tasking, but it's still a far cry far from the real thing. Background hardware operation is the "real deal" -- period.

How it works:

This example was tested on the FLASH-Lab 77 development board with PicBasic Pro for rapid development. The FLASH-Lab 77 boards use a boot-loader program. If you're not using the boot-loader, just strip the line DEFINE LOADER_USED 1 line from the code above, and proceed as normal.

PortC.2 on the PIC16F877 also functions as the hardware PWM output pin (CCP1) when not being used for normal I/O operations. Several registers need to be configured to use the PWM feature.

Timer2 (TMR2), and PR2 (timer2 module's period register) are used to establish the period. Figure 1 shows a graphical representation of how this works.


Figure 1:  PWM Output

As shown in the previous code segment, we first have to load the timer2 period register (PR2) to setup the period for our required frequency (38KHz) output. A PWM output (Figure 1) has a time base (period) and a time that the output stays high (duty cycle). The frequency of the PWM is the inverse of the period - which is (1/period).

Figure 1 shows the period from TMR2 = PR2 to TMR2 = PR2. This represents one complete cycle. To determine the period required to generate a frequency of 38KHz, simply take 1/38KHz, or 1/38,000. The result is 1/38,000 = 0.000026316 (26.3uS). We know that in order to generate our 38KHz frequency, we'll need each period to be approximately 26 microseconds. A duty cycle of 50% would need 13uS high, and 13uS low on the I/O-pin to generate our required frequency of 38KHz at a duty cycle of 50%.

Frequency ( f ) and period ( P ) are inversely proportional. f = 1/P, & P = 1/f.

To calculate the value to be loaded into PR2:
(4MHz / (4 * TMR2 prescale value * 38KHz)) - 1= PR2.

We'll use a prescale value of 1 for timer2.

4 * 1 * 38,000 = 152,000
4,000,000 / 152,000 = 26.315
26.315 - 1 = 25.315

We'll load 25 into PR2, and accept the minimal error.


Figure 2:  Finding Our Resolution

Figure 2 shows how to find the maximum PWM resolution (in bits) for a given PWM frequency, with our selected oscillator frequency. This application uses the PIC16F877 with a 4MHz oscillator, so we need to calculate: Log (4MHz/38KHz) / Log(2) to find our maximum resolution in bits....

Log (4,000,000/38,000 ) = 2.022
Log(2) = .301
Our maximum resolution is found to be 2.022/.301 = 6.7-bits

Note: Resolution refers to the resolution of the duty cycle, and not the actual frequency of the PWM signal.

I randomly chose a duty cycle of 50% for this application. To setup the duty cycle, there are two registers that need to be configured.

CCPRL1  contains the eight (most significant bits), and CCP1CON <4:5> (CCP1CON bits 4 and 5) contain the two (least significant bits). Since we will only have a maximum of 6-bits resolution, we only need to load the CCPR1 register. CCP1CON bits 4 & 5 will be loaded with 0's.

To figure the value to load into CCPRL1 for 38KHz @ 4MHz with a 50% duty cycle:

(PR2 + 1) * TMR2 prescale * 50% Duty Cycle = value for CCPRL1, or
(25 + 1) * 1 * 0.50 = 26 * 0.50 = 13

TRISC.2 = 0        ' CCP1 (PortC.2 = Output)
PR2 = 25            ' Set PWM Period for approximately 38KHz
CCPR1L = 13      ' Set PWM Duty-Cycle to 50% 
CCP1CON = %00001100  ' Mode select = PWM
T2CON = %00000100       ' Timer2 ON + 1:1 prescale

Above is the code we use. Notice register CCP1CON is loaded with a binary value that sets bits 2 and 3. These are CCP1M3 and CCP1M2, and set the PWM mode. Timer2 T2CON bit 2 is set to start the timer. Bits 1 and 0 are left clear for a prescaler of 1. TRISC.2 sets up portC.2 as an output which is necessary to have portC.2 output the 38KHz carrier (PWM) frequency.

Now that we have our 38KHz carrier with a 50% duty cycle setup, we'll need a circuit that will combine our carrier and serial data signal.

Note: We are actually just controlling the carrier frequency with our serial data-stream by turning the carrier ON/OFF for the duration of each data-bit.

Using the 74HCT132 NAND Schmitt trigger as shown below in Figure 6, simplifies the procedure. One input will be connected directly to PortC.2 which will generate our 38KHz carrier using the PIC hardware PWM feature. The remaining input will connect to PortB.0 which will be used to output our serial data-stream.

The NAND output (pin #3) will only go to logic 0 when both inputs 1 & 2 are at logic 1. This effectively holds the PNP drive transistor OFF until both inputs are at logic 1. Since the carrier frequency is 38KHz, and considerably faster than our serial data, the serial data will cause the transistor to turn ON during each logic 1 data-bit.

To further explain what's happening, think of it as the serial data just turning the carrier ON/OFF for the same bit-time as each data-bit in the serial data-stream.

This combination of both inputs to the NAND will give us the 38KHz modulated data signal on the output pin of the NAND.

Here's what both signals being applied to inputs 1 & 2 of the NAND gate look like when connected to an O-scope.


Figure 3  Serial data & PWM carrier fed to NAND gate inputs

Figure 3 shows the two separate signals being applied to the two inputs (1 & 2) of the NAND Schmitt Trigger. Trace A is the actual serial data being sent out from the PIC on PortB.0. Trace B is the 38KHz PWM carrier being generated by the PIC hardware, and output on PortC.2 to the input of the NAND gate.

Now look at the modulated data signal on (Trace A) coming out of the NAND gate on pin #3.


Figure 4 NAND output to PNP drive transistor.

Notice from trace A (signal being fed to the base of the PNP drive transistor) that the base of the transistor & our serial data is now modulated at 38KHz, and inverted. Trace B still shows the 38KHz carrier from portC.2 into pin 1 of the NAND gate.

Figure 5 (shown below) shows our serial data being input to the NAND (trace B), and the actual output of data from the PNA4602M 38KHz IR detector module (trace A).

Notice how the output signal from the detector (trace A) has the 38KHz carrier stripped from the incoming data-signal. The detector module removes the carrier (38KHz), and outputs the data (minus) the 38KHz carrier.

The slight phase shift you see below is due to the response times of the infrared detector module, drive transistor, and NAND gate combined.


Figure 5 Serial signal on pin #2 of NAND & data out from IR detector module.

The Transmitter:

Below is the simple transmitter circuit. To use the circuit below, just connect CCP1 of the PIC you use (PortC.2 for the PIC16F877) to one of the two inputs to the NAND gate. Use any other I/O-pin you want to send serial data to the other input of the NAND gate.

Tip: Don't substitute another NAND gate for this project. The 74HCT132 is a NAND Schmitt Trigger. The Schmitt Trigger function helps to stabilize circuit oscillation.


Figure 6  IR LED Drive + NAND Circuit

A simple two input NAND Schmitt Trigger is used to combine the two incoming signals into an output data signal modulated at 38KHz.

The receiver is very simple. Just take the serial data directly from the data output pin of the detector module as shown in figure 7.


Figure 7 Receiver circuit.

For the receiver, I used the BASIC Stamp II for rapid testing & verification of operation. Converting this code to PicBasic is simple. Here's the BS2 code.

' BS2 program to test IR communication program
' using the PIC16F877 hardware PWM.

SYNCH CON 25     'Establish synchronization byte
BAUD  CON 396    'NON INVERTED 2400 baud (MAX)
DAT   VAR byte   'Data storage variable
DIRH = %11111111 'All outputs
ADDRESS VAR BYTE

START:

SERIN 0,BAUD,[WAIT(SYNCH),ADDRESS,DAT]
OUTH = dat
GOTO START

Notice how the Stamp waits until it receives the SYNCH byte first before accepting the remaining data. This helps to synchronize the receiver to the transmitter. The address byte shows one method of talking to multiple receivers by using addressing. This is only an example. You can use the address byte to force the program to only respond if it receives its own unique address first, or ignore the technique altogether.

DAT is the data (byte) that will be transferred to the Stamp port pins P8 to P15. Connect 8 LEDs to the Stamp I/O-pins P8 to P15. Use 470 ohm series resistors for each LED to limit current to acceptable levels. When IR data is received, you can verify reception visibly by watching the LED's count from 0 to 255.

Note: Due to the limited response time of the detector module, the maximum baud-rate is normally around 2400. If you experiment with this project - you'll see first-hand how increasing the baud-rate will degrade data.

The simple infrared transmitter circuit shown above in Figure 6 can also be used with various encoder ICs such as the Holtek 4-bit HT-12E encoder, and even the 8-bit versions as well. The only requirement is that you have a stable oscillator such as the PIC using hardware PWM, a 555 timer circuit, or another oscillator source capable of providing a stable carrier frequency.

The data output pin of the encoder provides the serial data on the transmitter. Use the circuit shown below in Figure 8 when using the Holtek decoder IC's instead of serial data with a microcontroller.

The circuit shown below is a simple inverter circuit, and necessary for use with the HT-12D and other decoders. If you prefer, you can use this receiver circuit for serial as well. Either one will work with serial data, but use the one below for the HT-12D decoder IC.


Figure 8: Circuit for use with Holtek decoder ICs.

Tip: The PNA4602M output has an internal pull-up resistor. This causes the output to hold a logic 1 (high) on the base of the NPN transistor. The HT-12D decoder IC will go into low power or sleep mode when the data input pin is at ground conserving power in the receiver circuit until data is being received.

If you don't own PicBasic, or simply don't wish to commit a large PIC such as the PIC16F877 or F876 to this simple task, you can easily use the smaller 8-pin version (PIC12C508) to generate the 38KHz carrier.

Here's a short code-sample for generating a 38KHz frequency using the small 8-pin PIC12C508. It's not hardware PWM, but it works very well, and it's cheap.

Note: For higher precision, use an external crystal or ceramic resonator. The internal oscillator for the PIC12C508 is a low precision oscillator. For most instances - the internal oscillator works fine, but increased precision of the carrier frequency will increase receiver sensitivity - and hence increase the overall operating range.

*** NEW ***
We have sample code for using the hardware PWM module on the 18-pin PIC16F628 now as well, and it works quite nice for this project. Click HERE to see how to do this with a $4.00 PIC..

To use an external oscillator with the sample code below - replace IntRC_OSC with XT_OSC before assembling the code, and burning the PIC12C508.

Assembled with MPASMWIN V03.30  Download the .HEX file HERE
   PROCESSOR 12c508
   #include "p12c508.inc"
   __CONFIG  _MCLRE_OFF & _CP_OFF & _WDT_OFF & _IntRC_OSC
   #DEFINE PORT B'11111101'
	MOVF OSCCAL
	MOVLW PORT
	TRIS GPIO
		
   BEGIN
	BCF GPIO, 1     ;1uS
	NOP	        ;2uS each nop is 1uS long
	NOP		;3uS
	NOP		;4uS
	NOP		;5uS
	NOP		;6uS
	NOP		;7uS
	NOP		;8uS
	NOP		;9uS
	NOP		;10uS
	NOP		;11uS
	NOP		;12uS
	NOP		;13uS
	NOP		;14uS
	NOP		;15uS
	NOP		;16uS
	NOP		;17uS
	NOP		;18uS
	NOP	        ;19uS low on gpio.0
	BSF GPIO, 1 	;1uS Begin HIGH duty cycle
	NOP		;2uS
	NOP		;3uS
	NOP		;4uS
	NOP		;5uS
	GOTO BEGIN      ;2uS (26uS total for 38KHz)
	END
	

The tiny 8-pin PIC12C508 can easily be programmed to output a steady 38KHz carrier. If you just need the 38KHz oscillator for this project - this PIC is very inexpensive, and works quite well.

The assembly code shown above will provide a duty cycle of approximately 27%. Adjusting the time between the BCF and BSF commands, will adjust the duty cycle. Be sure to maintain an overall time (period) of 26uS to keep the frequency stable at 38KHz.

Tip #1: Try swapping the BCF & BSF instructions around - or just split the difference between each command to set & clear the I/O-pin GPIO.1.

Tip #2: If you really want to crank power to the LED, try reducing the duty-cycle of the carrier to around 1uS, and using a very small (or no) current limiting resistor for the IR LED. You'll want to replace the 2N4403 LED drive transistor with one that can handle this power level.

Port-pin GPIO.1 is simply connected to one of the NAND inputs, and will replace the larger PIC used in this application. The serial data can then come directly from a PIC or BASIC Stamp I/O-pin, and you're ready to go with infrared data communications.

We have a component parts KIT for this application in stock. The KIT includes the following components:

bullet

[1] 38 to 40KHz (Programmable) PIC frequency generator with resonator.

bullet

[1] 74HCT132 Quad 2-Input NAND Schmitt trigger.

bullet

[1] Panasonic PNA4602M infrared detector module.

bullet

[2] Lumex OED-EL-8L, High-Power 180mW, 940nm Infrared LEDs.

bullet

[1] 2N4403 PNP LED drive transistor.

bullet

[1] 5.1-Ohm LED current limiting resistor.

bullet

[1] 330-Ohm PNP drive transistor base resistor.


Click HERE For
Remote Control Store
Holtek remote control ICs, RF and Infrared parts in stock.

The assembly code above was compiled using MPASM.EXE available from http://www.microchip.com/ You'll find the FREE assembler in the MPLAB software package.

Other Stock Items:

bullet

PicBasic Compilers HERE

bullet

BASIC Stamps HERE

bullet

RF Remote Control & Infrared Components HERE

Until the next project - have fun.......;o]

-Bruce

* NEW ** NEW *
MicroCode Studio Plus ICD
In-Circuit Debugger For PicBasic Pro Compiler
** Available HERE **

 

Copyright © 1999-2001
Reynolds Electronics

| Contact Information |

Reynolds Electronics
3101 Eastridge Lane
Canon City, Co. 81212
Voice: (719) 269-3469
Fax:    (719) 276-2853