Continue to Site

# Modulating IR carrier signal

Status
Not open for further replies.

#### evaine23

##### New Member
I'm currently working on making a simple IR remote just to create the framework for some future projects. I'm using the PIC16F628A and would like to utilize the hardware PWM to free up the processor for other applications. I have the hardware PWM working and according to my scope appears to be outputting ~38.46kHz. I've read a lot of posts on this site and I've seen that Nigel recommends implementing the PWM using software but as I mentioned because of my programming style I would like to continue using the hardware PWM. I'm trying to modulate the carrier signal but most diagrams I've seen use something like th 74HCT132 NAND Schmitt trigger (Simple infrared data communications). I've looked through my stock of parts and I don't appear to have any Schmitt triggered logic devices lying around. I've tried substituting a normal NAND and my signal was all over the place (I expected this but the normal NAND was all I had). My question is, what are my option (While using the hardware PWM) for modulating the carrier signal? I'm trying to avoid placing another order of parts for the time being. I've tried feeding the carrier signal and my data signal back into the PIC but that seems to defeat the purpose of using the hardware PWM. I've been looking for a solution for a few days and I've gotten to the point where I'm going in circles.

#### MikeMl

##### Well-Known Member
Most Helpful Member
Why don't you just use the CCP hardware to create bursts of carrier? A simple NPN transistor between the CCP port pin and the LED will switch the LED at a suitable current level.

#### evaine23

##### New Member
So you're recommending just turning the PWM on an off? Do you know if that would affect the response time (is there a lag time to initialize the PWM)?

#### Nigel Goodwin

##### Super Moderator
Most Helpful Member
As always, I still suggest doing it in software, it's easier, and more accurate - what are you wanting to do at the same time as you send data?.

#### MikeMl

##### Well-Known Member
Most Helpful Member
So you're recommending just turning the PWM on an off? Do you know if that would affect the response time (is there a lag time to initialize the PWM)?

If you wish to unburden the cpu, use a timer unrelated to the CCP module to generate an interrupt after a time delay corresponding to one baud of the modulation. The ISR just has to restart the timer, and turn on/off the CCP port pin. You can leave the CCP running forever at 40kHz. Even re-initing the CCP in the ISR is trivial.

Another option is to keep the CCP running, and then use a software timer to generate the bauds.

Thought of another one: Use the CCP and dynamically load the pulse width register with the number "zero" or "half period". Zero turns the carrier off, and "half period turns it on"

Last edited:

#### evaine23

##### New Member
The NPN transistor outputting the carrier signal and controlled by the modulating pin seems to be a starting point. I'm not sure how I overlooked that option. I am noticing some distortion in the signal but i can play around with that. When i was writing the basic program I saw a post on the ccsinfo form (CCS :: View topic - Generate 38KHz frequency signal using 16F877A) that described using TMR1 instead of the hardware PWM which was set up the same way as my PWM and they said, given the same oscillator speed, that there would be less than 26 instructions that could be executed in addition to the software PWM code. I'm using the CCS C compiler because I never seem to grasp ASM but i've been programing in C for years. I imagine code written in thes language is less efficient, but until i can wrap my head around ASM i'll have to stick to this. I'm working on a universal remote right now that just combines the few buttons on the for or five remotes i have into a single remote right now, so i probably could use the software PWM but I figured the hardware PWM would give me some more wiggle room in my code.

#### Nigel Goodwin

##### Super Moderator
Most Helpful Member
I'm working on a universal remote right now that just combines the few buttons on the for or five remotes i have into a single remote right now, so i probably could use the software PWM but I figured the hardware PWM would give me some more wiggle room in my code.

None at all, as a remote isn't doing anything else whilst transmitting - you're just making it more complicated (and less accurate) for absolutely no gain at all.

#### evaine23

##### New Member
Just out of curiosity, what makes the hardware PWM less accurate than a software version of the same thing? Is the actual signal less accurate or is it made less accurate by the additional hardware needed. Based on some examples I’ve looked at, both can be implemented in a similar fashion only one directly drives an output while you need to use an interrupt for the other.

#### mikeReynolds

##### Member
I will not say that the hardware PWM is less accurate but I will say that generating it in software can be much simpler. If you are shy of using assembler and are using the SIRC protocol - Sony - then take a look at SIRC especially the section on the transmitter. It is written in JALv2 but you should be able to convert it to C without too much trouble.

Mike

#### Nigel Goodwin

##### Super Moderator
Most Helpful Member
Just out of curiosity, what makes the hardware PWM less accurate than a software version of the same thing? Is the actual signal less accurate or is it made less accurate by the additional hardware needed. Based on some examples I’ve looked at, both can be implemented in a similar fashion only one directly drives an output while you need to use an interrupt for the other.

You can set the accuracy of the modulation to within 1uS using a 4MHz clock (200nS if you use a 20MHz clock) - with hardware you've only got a limited number of values, with a much larger step between them.

Next is the accuracy of the series of pulses, in software you send exactly the right number of exact length pulses - using hardware, and turning it ON and OFF commonly produces partial pulses.

It's just more work for a poorer result - if there's any reason for it, then fair enough - but when there's no reason whatsoever, why use a more complicated method that isn't as good?.

#### evaine23

##### New Member
Alright, I’ll give it a try. I’ve been going through Myke Predko’s book Programming & Customizing PICmicro Microcontrollers so I’ll see if I can work this project out on the software side. Its been years since I’ve tried any ASM programming so maybe it’ll stick this time.

#### Nigel Goodwin

##### Super Moderator
Most Helpful Member
Alright, I’ll give it a try. I’ve been going through Myke Predko’s book Programming & Customizing PICmicro Microcontrollers so I’ll see if I can work this project out on the software side. Its been years since I’ve tried any ASM programming so maybe it’ll stick this time.

IR remote control is covered in my tutorials - it's incredibly simple to transmit IR remote signals using a PIC - I've done various devices for various purposes, including a box for converting Sony DVD players to be multi-region (which transmits a long string of IR codes).

#### evaine23

##### New Member
thanks, i've read through your tutorial once but i'll keep it on hand while i work.

#### sahu

##### Member
You can set the accuracy of the modulation to within 1uS using a 4MHz clock (200nS if you use a 20MHz clock) - with hardware you've only got a limited number of values, with a much larger step between them.

Next is the accuracy of the series of pulses, in software you send exactly the right number of exact length pulses - using hardware, and turning it ON and OFF commonly produces partial pulses.

It's just more work for a poorer result - if there's any reason for it, then fair enough - but when there's no reason whatsoever, why use a more complicated method that isn't as good?.

dear sir
i want to know ASM. [ PIC Tutorials ] is practicaly worked.

#### evaine23

##### New Member
There are plenty of tutorials out there to learn ASM from. Nigel’s site is a good source (has the software and circuits to go with the projects). I’m attaching the source for the IR transmitter I was working on, its pretty simplistic if you want to try and work though it. It was my first project written in ASM in a few years. The programming is probably crude and is defiantly a dumbed down version of Nigel’s IR transmitter but it works. The carrier signal seems to be a fairly precise 38 kHz even when using the 4MHz internal oscillator. My particular remote (for an orion TV) seems to send out a 32 bit packed. I captured the signal from the remotes with a camera and pasted them back together. The two signals labeled Vol up and Vol Down are actually Channel up and down. Guess I was pushing the wrong button while I was capturing the signal and didn't find out till I got the whole thing working and the stations started changing instead of the volume.

Code:
#include <p16f628a.inc>

__CONFIG _WDT_OFF & _PWRTE_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_ON & _BOREN_OFF & _LVP_OFF & _DATA_CP_OFF & _CP_OFF

cblock 0x20
nCount1
nCount2
nCarrier
nData
nBits_Data
nIDL
nIDH
nCmdL
nCmdH
endc

Load_Data macro tIDL, tIDH, tCmdL, tCmdH 	;Macro to load the working variables with the remotes 32 bit sequence
MOVLW tIDL
MOVWF nIDL
MOVLW tIDH
MOVWF nIDH
MOVLW tCmdL
MOVWF nCmdL
MOVLW tCmdH
MOVWF nCmdH
endm

;Codes for transmission
vDevIDL	equ	b'01100001'
vDevIDH equ	b'10100000'
vPwrL 	equ	b'11110000'
vPwrH   equ     b'00001111'
vChUL   equ	b'01010000'
vChUH   equ	b'10101111'
vChDL	equ	b'11010000'
vChDH	equ	b'00101111'

ORG 0x000
goto Main

ORG 0x004
goto Main

Main:
BCF OPTION_REG, 7		;enable portb internal pull-up resistors
BSF STATUS, 5 			;Switch to bank1
MOVLW b'00001110'		;Load W with 0;
MOVWF TRISB			;Set everything on PORTB.7-4 to output 3-1 Input, and 0 to output
BCF STATUS, 5			;Switch back to bank0
Start:
BCF PORTB, 6			;Indicator Lights (need to see if there are misfires)
BCF PORTB, 5			;All off unless button pressed
BCF PORTB, 4

BTFSS PORTB, 1
CALL SW1
BTFSS PORTB, 2
CALL SW2
BTFSS PORTB, 3
CALL SW3
GOTO Start
;Three buttons
SW1					;Power Button
BSF PORTB, 6
BCF PORTB, 5
BCF PORTB, 4
Load_Data vDevIDL, vDevIDH, vPwrL, vPwrH
CALL TRANSMIT
return
SW2					;Channel up
BCF PORTB, 6
BSF PORTB, 5
BCF PORTB, 4
Load_Data vDevIDL, vDevIDH, vChUL, vChUH
CALL TRANSMIT
return
SW3					;Channel down
BCF PORTB, 6
BCF PORTB, 5
BSF PORTB, 4
Load_Data vDevIDL, vDevIDH, vChDL, vChDH
CALL TRANSMIT
return

TRANSMIT
MOVWF nData			;Loop 8 times until all 8 bits are sent
MOVLW 0x08
MOVWF nBits_Data
call SEND_START
trans_loop1
RLF nIDL, 1
BTFSC STATUS, C			;Check current bit and send data
CALL SEND_1
BTFSS STATUS, C
CALL SEND_0
DECFSZ nBits_Data
GOTO trans_loop1
MOVLW 0x08
MOVWF nBits_Data
trans_loop2
RLF nIDH, 1
BTFSC STATUS, C			;Skip next instruction if C = 0
CALL SEND_1
BTFSS STATUS, C			;Skip next instruction if C = 1
CALL SEND_0
DECFSZ nBits_Data
GOTO trans_loop2
MOVLW 0x08
MOVWF nBits_Data
trans_loop3
RLF nCmdL, 1
BTFSC STATUS, C
CALL SEND_1
BTFSS STATUS, C
CALL SEND_0
DECFSZ nBits_Data
GOTO trans_loop3
MOVLW 0x08
MOVWF nBits_Data
trans_loop4
RLF nCmdH, 1
BTFSC STATUS, C
CALL SEND_1
BTFSS STATUS, C
CALL SEND_0
DECFSZ nBits_Data
GOTO trans_loop4
MOVLW 0x08
MOVWF nBits_Data
return

;0 takes 0.6ms -> 600us 600/26 = 23 = 17h
;1 and 0 turn on for 600us each
SEND_0				;Total length 1.2ms
MOVLW 0x17		;600us carrier active
CALL ON_38KHZ
NOP
MOVLW 0x17		;600us carrier inactive
CALL OFF_38KHZ
NOP
return
SEND_1				;Total length 2.2ms
MOVLW 0x17		;Turn on for 600 us
CALL ON_38KHZ
NOP
MOVLW 0x3D		;Turn off for 1.6ms
CALL OFF_38KHZ
NOP
return
SEND_START
MOVLW 0xDC		;5.727ms 1 of 2 high
CALL ON_38KHZ
NOP
MOVLW 0xDC		;5.727ms 2 of 2 high
CALL ON_38KHZ
NOP
MOVLW 0xB3		;4.653ms low
CALL OFF_38KHZ
NOP
return

ON_38KHZ				;T = 1/38000 = 0.000026316s -> 0.026315789ms ->26.315789474us
MOVWF nCarrier
carrier_loop1
BSF PORTB, 0			;Turn PORTB.0 on about 35% duty cycle
GOTO $+1 ;Each GOTO takes 2 cycles (command tells it to move one instruction from current pos$)
GOTO $+1 GOTO$+1
GOTO $+1 BCF PORTB, 0 ;Turn PORTB.0 off move this to adjust duty cyle GOTO$+1
GOTO $+1 GOTO$+1
GOTO $+1 GOTO$+1
GOTO $+1 DECFSZ nCarrier, 1 GOTO carrier_loop1 return OFF_38KHZ MOVWF nCarrier carrier_loop2 BCF PORTB, 0 ;Turn PORTB.0 off NOP GOTO$+1
GOTO $+1 GOTO$+1
GOTO $+1 GOTO$+1
GOTO $+1 GOTO$+1
GOTO $+1 GOTO$+1
GOTO \$+1
DECFSZ nCarrier, 1
goto carrier_loop2
return
END

#### Attachments

• Orion Remote.jpg
63 KB · Views: 758
Last edited:
Status
Not open for further replies.

Replies
41
Views
3K
Replies
9
Views
2K
Replies
19
Views
2K
Replies
1
Views
965
Replies
2
Views
963