Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

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. :confused:
 
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.
 
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)?
 
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:
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.
 
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.
 
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.
 
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
 
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?.
 
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.
 
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).
 
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.
 
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.

orion-remote-jpg.34657


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
    Orion Remote.jpg
    63 KB · Views: 809
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top