How can i set the tranmission frequency ?
The documentation on this is a little cryptic so to speak.
I want to convert frequency in hz -> PR2 value whatever that is.
It doesn't have to be exact, within 1khz would do.
Check the Microchip PIC manual (http://http://ww1.microchip.com/downloads/en/DeviceDoc/39632e.pdf) for more details. Once you've calculated PR2 based on Microchip's rules, then use the IRToy command to set a new value.
This is the javascript code found on
http://www.micro-examples.com/public/mi ... calculator (http://www.micro-examples.com/public/microex-navig/doc/097-pwm-calculator)
Maybe someone good at javascript can translate this to C ?
function mkT2CON(v)
{
ret = "0b000001" ;
if(v == 1)
{
ret += "00" ;
}
else if(v == 4)
{
ret += "01" ;
}
else
{
ret += "11" ;
}
return(ret) ;
}
function toBinary(val, n)
{
str = "" ;
while(n > 0)
{
if(val % 2)
{
str = "1" + str ;
}
else
{
str = "0" + str ;
}
n-- ;
val >>= 1 ;
}
return(str) ;
}
function compare_freq(e1, e2)
{
return(e1[0] - e2[0]) ;
}
function PWMsolutions()
{
var res = new Array() ;
obj = document.getElementsByName("result") ;
obj[0].innerHTML = "Computing..." ;
fosc = document.forms.pwm.fosc.value ;
if(fosc == 0)
{
obj[0].innerHTML = "" ;
alert("Please, give me the Fosc clock frequency") ;
return(0) ;
}
fosc *= 1000000 ;
fpwm = document.forms.pwm.fpwm.value ;
if(fpwm == 0)
{
delta = fosc ;
}
else
{
delta = fpwm * 0.05 ;
}
duty = fduty = document.forms.pwm.duty.value ;
if(duty == "")
{
alert("Assuming duty cycle = 50 %") ;
document.forms.pwm.duty.value = duty = fduty = 50 ;
}
if((duty < 0) || (duty > 100))
{
obj[0].innerHTML = "" ;
alert("Bad duty cycle") ;
return(0) ;
}
if(duty > 0)
{
duty -= 0.000000000001 ;
}
i = 0 ;
bestdiff = fosc ;
best = -1 ;
for(pr2 = 0 ; pr2 < 256 ; pr2++)
{
for(tmr2pres = 1 ; tmr2pres <= 16 ; tmr2pres *= 4)
{
period = (pr2 + 1) * 4 * tmr2pres / fosc ;
freq = 1 / period ;
diff = Math.abs(freq - fpwm) ;
if(diff < delta)
{
resol = Math.floor(Math.log(fosc * period) / Math.log(2)) ;
if(resol > 10) resol = 10 ;
reg = Math.floor(fosc * duty / 100 / tmr2pres * period) ;
if(diff < bestdiff)
{
bestdiff = diff ;
best = i ;
}
res[i] = new Array(freq, pr2, tmr2pres, resol, reg, i) ;
i += 1 ;
}
}
}
if(i == 0)
{
obj[0].innerHTML = "" ;
alert("No close solution !nPlease try other clock frequency,nor leave PWM field blank to see all solutions") ;
return(0) ;
}
res.sort(compare_freq) ;
str = "" ;
str += "<table style="font-family: courrier ;" cellpadding=3>" ;
str += "<tr bgcolor=#ccbbaa>" ;
str +="<th align=center colspan=2>PWM</td>" ;
str +="<th align=center rowspan=2>TIMER2<br>Prescaler</td>" ;
str +="<th align=center colspan=4>REGISTERS</td>" ;
str += "</tr>" ;
str += "<tr bgcolor=#ccbbaa>" ;
str +="<th align=center>Frequency<br>(Herz)</td>" ;
str +="<th align=center>Resolution<br>(Bits)</td>" ;
str +="<th align=center>PR2</td>" ;
str +="<th align=center>T2CON</td>" ;
str +="<th align=center>CCPR1L</td>" ;
str +="<th align=center>CCP1CON</td>" ;
str += "</tr>" ;
newbest = -1 ;
for(nb = 0 ; nb < i ; nb++)
{
if((fpwm > 0) && (res[nb][5] == best))
{
str += "<tr bgcolor=#cc9988>" ;
newbest = nb ;
}
else if(nb % 2)
{
str += "<tr bgcolor=#aabbcc>" ;
}
else
{
str += "<tr bgcolor=#bbccdd>" ;
}
str += "<td align=right>" + res[nb][0].toFixed(2) + "</td>" ;
str += "<td align=right>" + res[nb][3] + "</td>" ;
str += "<td align=right>÷" + res[nb][2] ;
str += "</td>" ;
str += "<td align=right>0b" + toBinary(res[nb][1], 8) ;
str += "<td align=right>" + mkT2CON(res[nb][2]) ;
str += "</td>" ;
str += "<td align=right>0b" + toBinary(res[nb][4] >> 2, 8) ;
str += "<td align=right>0b00" + toBinary(res[nb][4] & 0x03, 2) + "1100" ;
str += "</td>" ;
str += "</tr>" ;
}
str += "</table>" ;
The C source is right there on the page. Why bother translating the javascript?
P.S. I wouldn't trust every PIC Timer calculator out there. I have confirmed errors in at least one of them. Your best bet is to look at the documentation from Microchip. It's the definitive resource.
the C source on the page is
How to smoothly blink two LEDs
It doesn't show you how to calculate PR2
[quote author="dukey"]
the C source on the page is
How to smoothly blink two LEDs
It doesn't show you how to calculate PR2
[/quote]Right, but if you type in the specific crystal frequency of the IR Toy, the desired PWM frequency and duty cycle, then the javascript will rewrite the page with a very small C source with just what you need. Since the crystal frequency can't change, and the other variables won't be changing much unless you want to try lots of values, then it's fairly quick to just try out a particular IR modulation frequency.
You may have to convert binary to (hexa)decimal, but you can double-check the values in the C snippet to make sure they make sense given the Microchip data sheet.
I want to build this into my winlirc plugin ! So instead of constants I was really after a calculator, since in theory users could pass all sorts of values for frequencies to use. A few use some totally non standard frequencies. Bang and Olufsen use something like 455khz. I suppose I could use some sort of look up table.
Like I say, everything you need to know is in the Microchip data sheet.
Start with the crystal frequency, adjust for the pre-divide factor, then divide by the desired frequency. The trick is to round the result to an integer, since the Timer cannot handle floating point, and then repeat the above to calculate the exact resulting frequency. i.e. crystal/pre-divide/timer count. If the rounding in the first step is significant, then the resulting frequency will be off by a lot. But if there is no rounded necessary then the frequency will be exact. But you have to take care of whether the counter is counting up or down, and where it triggers (on 0x0000 or 0xFFFF) or else your period count will be wrong - this is where most free PIC calculators fail.
The second half of the equation is the duty cycle. The Capture Compare peripheral is used to count the duty cycle within the Timer period.
I cannot recall whether the IRToy commands allow changing the pre-divide. If it is fixed, then you are a little bit more limited in frequency range. Also, keep in mind that some PIC models run the peripherals like the Timer at 1/4 the CPU clock, so there is already a pre-divide of 4 in addition to the Timer pre-divide (unless they're already combined those).
Since there are only about 3 standard IR modulation frequencies, you could have a very short lookup table. But if you want to allow arbitrary frequencies, the calculations are not that difficult if you read the documentation.
I already figured it out :)
I wrote this
UCHAR SendReceiveData::calcPR2(int frequency) {
//======================
double oscillatorPeriod;
double pwmPeriod;
int pr2;
//======================
oscillatorPeriod = 1.0/48000000.0;
pwmPeriod = 1.0/(double)frequency;
pr2 = (int)((pwmPeriod/(16 * oscillatorPeriod))-0.5);
if(pr2==0 || pr2>255) {
return 0; //failed to match a value
}
return (UCHAR)pr2;
}
for my winlirc plugin, seems to do the trick :)
That looks good. One thing you might want to do is a quick integer calculation of the resulting frequency as a sanity check. I'm not sure how you would display this, but it would be good for at least your debugging stage.
Note 1: It may or may not be desirable to round using 0.5, so you might want to check precise frequencies like 100 kHz to see whether your rounding throws off the pure values.
Note 2: I think that (int) may not be large enough to hold 455 kHz, at least not on all machines. Probably better to specify that as (long) for maximum portability.
Note 3: If you wanted to run this code on the PIC itself (I realize that you don't in this case), then you could use integer math instead of floating point reciprocals.
UCHAR calcPR2(long frequency) {
#define F_OSC 48000000L
#define F_PERIPHERAL (F_OSC/4)
// Timer 2 prescaler can be 1/1, 1/4, or 1/16
#define N_PRESCALE 16
#define Q_TIMER (F_PERIPHERAL/N_PRESCALE)
long PR2 = Q_TIMER / frequency
if (PR2 < 0 || PR2 > 255) return 0;
return PR2;
}Because all of the divisions above are integer, you don't have to bother with floating point at all. That makes the code run much faster on the PIC, and also takes a lot less code memory space.
Also, since the PWM Timer counts up from 0, the interrupt triggers when the value matches PR2, and the Timer/counter is reset to 0 on the next clock, you end up dealing with the actual calculated value. This is in contrast with other Timer modes, particularly the 16-bit Timers, where the Timer counts up from the calculated value, not from 0, and the interrupt triggers when the counter wraps around from 0xFFFF to 0x0000. The latter is where Ian has to deal with calculating 0x010000-value or 0x0000-value with wraparound.
Glad you got it, I should add a paper&pencil example of calculating PR2 to the wiki.
The IR Toy currently has a fixed 4x prescaler and /2 duty cycle, but I'm going to add adjustment to the next firmware.