PDA

View Full Version : How to set HPWM to generate 38khz signal? (16F870)



CuriousOne
- 29th June 2016, 09:23
Hello.

I'm building custom IR control, I already wrote the code for ir command generation, but I want to use built in hardwre pwm of 16F870 chip to generate 38khz carrier. PBP supports up to 32khz. Also, I'd be very grateful, if some gives me ASM code insert which simply enables and disables hpwm with already set frequency and duty cycle. The PBP command HPWM does too many things together, like switching port and so on, so it is slow.

mackrackit
- 29th June 2016, 12:20
http://www.picbasic.co.uk/forum/content.php?r=278-Pentax-Nikon-IR-Remote

CuriousOne
- 29th June 2016, 12:23
Thanks, so I need this part of code, right?



ASM
_Pulse38
bcf IRTX,PIN ; 1uS, LED=on
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
goto $+1 ; + 2uS = 11uS
goto $+1 ; + 2uS = 13uS
bsf IRTX,PIN ; 1uS, LED=on
goto $+1 ; + 2uS = 3uS
goto $+1 ; + 2uS = 5uS
goto $+1 ; + 2uS = 7uS
goto $+1 ; + 2uS = 9uS
nop ; + 1uS = 10uS
decfsz _Cycles,f ; + 1uS = 11S
goto _Pulse38 ; + 2uS = 13uS
return ; Return to caller
ENDASM

CuriousOne
- 29th June 2016, 12:31
and by the way, this code does nothing to built-in HPWM, right?

HenrikOlsson
- 29th June 2016, 13:37
No need for assembly code.
You want a PWM period of 1/38000 = 26.315us. Assuming 20MHz operating frequency your instruction cycle time is 200ns so you want a PWM period of 131-132 instruction cycles. Then you simply follow the instructions in the datasheet:

8.4.3 SETUP FOR PWM OPERATION
The following steps should be taken when configuring
the CCP module for PWM operation:
1. Set the PWM period by writing to the PR2 register.
2. Set the PWM duty cycle by writing to the CCPR1L register and CCP1CON<5:4> bits.
3. Make the CCP1 pin an output by clearing the TRISC<2> bit.
4. Set the TMR2 prescale value and enable Timer2 by writing to T2CON.
5. Configure the CCP1 module for PWM operation.


PR2 = 130 ' 1) PWM period of 131 instruction cycles assuming 1:1 prescaler
CCPR1L = 65 ' 2) Dutycycle of ~50%, no need to write 2 LSB for this.
TRISC.2 = 0 ' 3) Pin is output
T2CON = %00000100 ' 4) 1:1 Prescaler, TMR2 ON
CCP1CON = %00001100 ' 5) PWM mode enabled

This sets up the carrier and enables it. To disable the carrier:

CCP1CON = 0

Enable it again:

CCP1CON = 15

I'm not 100% sure what the note in the datasheet says

Note: Clearing the CCP1CON register will force
the CCP1 PWM output latch to the default
low level. This is not the PORTC I/O data
latch.
It either says that as long as you set PortC.2 to 0 the output pin will revert to 0 as soon as the CCP module is disabled (which is good in this case) OR it says that actual output pin is left in the state it was at the time the CCP module was disabled which means that it can be high or low and that you need to force it back down by doing PortC.2 = 0 after turning off the CCP module.
(Untested, please verify against datasheet)

/Henrik.

mackrackit
- 29th June 2016, 14:04
And this tells how to pass data.
https://web.archive.org/web/20120307050558/http://www.rentron.com/PicBasic/VB_PIC_TEMP.htm

CuriousOne
- 29th June 2016, 15:44
Thanks Henrik. Is it possible to do with 4mhz oscillator? I'm testing on breadboard, and with 20mhz oscillator it behaves badly.

HenrikOlsson
- 29th June 2016, 18:31
Short answer is:
Yes.

Question is:
Have you tried yourself with 4MHz? What did you change and why? What did it do, why do you think it didn't work?

Long answer is:
First, PWM period:
* TMR2 "drives" the CCP module.
* TMR2 starts at 0 and counts upwards.
* When the content of TMR2 equals that of PR2, TMR2 starts over from 0 and on it goes. The time it takes for TMR2 to count from 0 to PR2 is the PWM period.

As before, if you want a PWM perdiod of 26.315us you need to set the PR2 register so that TMR2 resets and starts over after 26.315us. At 4MHz the fastest you increment TMR2 (on that devices) is 1MHz, ie it'll "tick" every 1us. So the closest you're going to get is a flat 26us (38.461Hz) and you do this by setting PR2 to 25, right? Because TMR2 will then Count from 0 to 25 (26us) before it starts over and does it again and again and again......

Second, the dutycycle:
This can be a little trickier to understand but basically the dutycycle value as a whole can be though of the value you put into PR2 times 4. That is, when PR2 is 25 as in this case the dutycycle value can go from 0 to 100 (for 0-100% dutycycle). In the previous example with 20MHz Clock and a PR2 value of 130 the dutycycle value, again for 0-100% would go from 0 to 520.

Now, the dutycycle value since it can theoretically be 10bits wide (0-1023) are spread across two registers, CCPR1L contains the 8 high bits and CCP1CON.5 and 4 (from memory) contains the two low bits,

If you want "roughly" 50% dutycycle with a PR2 value of 25 you simply write either 12 or 13 (half of 25) to CCPR1L and that's it. If you want better resolution I'm sure you can figure out what to do with the two least significant bits.


/Henrik.

peterdeco1
- 30th June 2016, 15:26
Hello. A while back I used this routine to generate 38KHZ with a 12F675 running at 4MHZ.

STARTBIT:
High GPIO.4 'GETTING 38KHZ WITH THIS SUBROUTINE
High GPIO.4
Low GPIO.4
Low GPIO.4

LET X = X + 001
IF X < 125 Then STARTBIT '125 = 3MS PULSE, 83 = 2MS pulse, 33 = 1MS pulse

Maybe you can do something with this.

richard
- 1st July 2016, 03:33
Knocked this up when the remote for my aircon died , never really finished it . got a clone remote on ebay for $10 (delivered)
why bother.

this can work for any osc >= 8 MHz




'************************************************* ***************
'* Name : ir38khz.BAS *
'* Author : RICHARD *
'* Notice : *
'* : *
'* Date : 6/30/2016 *
'* Version : 1.0 *
'* Notes : REPL BRA WITH GOTO FOR NASTY OLD CHIPS *
'* : OSC MUST BE AT LEAST 8 MHZ *
'************************************************* ***************





DEFINE OSC 16 ; MIN=8 TESTED OK 8,16,32
DEFINE IRPORT LATC
DEFINE IRPIN 4
define IR_1 2000 ; 1 TIME IN uS MAX 6500 ISH
define IR_0 900 ; 0 TIME IN uS

cycnt var byte bank0 ;set to numbr of 38k cycles req then call irout RANGE 1-255
dly var byte bank0 ;system

goto overasm
asm
_irout1 ;entry point FOR 1 pulse
movlw (IR_1/26)
movwf _cycnt
BRA _irout ;GOTO
_irout0 movlw (IR_0/26) ;entry point FOR 0 pulse
movwf _cycnt

_irout ;entry point for cycnt cycles
nxbt CHK?RP IRPORT
BSF IRPORT ,IRPIN
CALL dly13
CHK?RP IRPORT
BCF IRPORT ,IRPIN
CALL dly13
RST?RP
DECFSZ _cycnt,F
BRA nxbt ;GOTO
RETURN
dly13 movlw (OSC-(16/OSC))
RST?RP
movwf _dly
d13
DECFSZ _dly,F
BRA d13 ;GOTO
RETURN
endasm

overasm:



OSCCON=$78
ANSELA=0
ANSELC=0

TRISA = %111110
TRISC = %11000011 ' set PORTC I/O



main:
cycnt = 100
call irout
pauseus 250
call irout1
pauseus 250
call irout0
pause 50

goto main

CuriousOne
- 5th July 2016, 09:39
Thanks, will have look.