|
|
View previous topic :: View next topic |
Author |
Message |
frosties_power Guest
|
adjustable PWM on 2*16LCD |
Posted: Thu Dec 11, 2008 3:32 pm |
|
|
plop,
I've made this program this morning, it was supposed to do a variable PWM between 15.25Hz and 3906Hz.
But here is the thing, I thought that I would be able to set a 256 prescaler (TIMER2_DIVIDED_BY_256) but I can only divide it by 16 maximum.
I only have 4MHz crystal (plus, if I use a slower one, the LCD screen is too slow).
Here is my code:
Code: |
#include <16F876A.h>
#include <stdlib.h>//conversion des float
#include <stdio.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#USE delay(clock=4000000)
#include <Lcd_drivers.c>
int Parameters(int Mode);
void DisplayData(int8 FreqRealNum, int8 DutyRealNum, int Mode);
int8 FreqMode(int8 FreqRealNum, int8 DutyRealNum);
int8 DutyMode(int8 DutyRealNum, int8 FreqRealNum);
////////////////////////////////
char Frequency[] = "F : "; //init variable ocntenant
char Hz[] = "Hz "; //le texte
char DutyChar[] = "Duty : "; //
char Per[] = "% "; //
////////////////////////////////
void main (void){
int8 FreqRealNum = 163;
int8 DutyRealNum = 83;
int Mode = 0;
int8 NextFreq = 0;
////////////////////////////////
output_low(LCD_RW); //init afficheur LCD
LCD_init(); //
////////////////////////////////
////////////////////////////////////////////////
output_low(PIN_C1); //INIT PWM
setup_ccp1(CCP_PWM); //
setup_timer_2(T2_DIV_BY_16, FreqRealNum, 1); //frequence de 50.23Hz (un peride dure de 0 a FreqReakNum)
set_pwm1_duty(DutyRealNum); //Ton durera DutyRealNum incrementation de T2 soit duty = 50
///////////////////////////////////////////
while(1)
{
Mode = Parameters(Mode); //renvoi 1 pour mode freq renvoi 0 pour duty
DisplayData(FreqRealNum, DutyRealNum, Mode); //affiche frequence et duty sur l'afficheur
if (Mode == 1)
{
NextFreq= FreqMode(FreqRealNum, DutyRealNum); //
if (nextfreq < FreqRealNum && DutyRealNum>1) //si la freq augmente
{ //on reduit le duty
DutyRealNum--; //pour qu'il ne depasse
set_pwm1_duty(DutyRealNum); //pas 100%
} //
FreqRealNum = NextFreq; //
setup_timer_2(T2_DIV_BY_16, FreqRealNum, 1);
}
else
{
DutyRealNum = DutyMode(DutyRealNum,FreqRealNum);
set_pwm1_duty(DutyRealNum);
}
}
}
//////////////////////////////////////////////////////////////
void DisplayData(int8 FreqRealNum, int8 DutyRealNum, int Mode)
{ ///
float Freq, Duty; ///
char FreqConv[] = "00.000"; ///
char DutyConv[] = "00.00"; ///
///
Duty = DutyRealNum; ///
Duty = Duty/FreqRealNum; ///
Duty = Duty*100; ///
Freq = 1/(0.000016*FreqRealNum); ///
///
///
sprintf(FreqConv,"%f",Freq); ///
sprintf(DutyConv,"%f",Duty); ///
LCD_curseur_pos(1,1); ///
LCD_send_string(Frequency); ///
LCD_send_string(FreqConv); ///calcul la frequence
LCD_curseur_pos(10,1); ///et le duty a partir
LCD_send_string(Hz); ///des valeurs chargé
///
LCD_curseur_pos(1,2); ///et les affiche
LCD_send_string(DutyChar); ///
LCD_send_string(DutyConv); ///
LCD_curseur_pos(12,2); ///
LCD_send_string(per); ///
///
if (Mode == 0) ///
{ ///
LCD_curseur_pos(16,2); ///
} ///
else ///
{ ///
LCD_curseur_pos(16,1); ///
} ///
lcd_send_car(0xFC); ///
} ///
////////////////////////////////////////////////////////////
////////////////////////////////
int Parameters(int Mode) ///
{ ///
if (input(pin_b2)) ///un appui sur B2 met le programme en pause
{ ///jusqu'au relachement de celui ci
while(input(pin_b2)) ///
{} ///une fois relacher mode est complementer
Mode = !Mode; ///et donc B0 et B1 agiront sur l'autre
return Mode; ///parametre
} ///
return Mode; ///
} ///
///////////////////////////////
/////////////////////////////////////////////////////////////////////////////
int8 DutyMode(int8 DutyRealNum, int8 FreqRealNum) ///
{ ///
////////////////////////////////////////////////// ///
if (input(pin_b0)) // ///
{ //si on appui sur B0, le ///
while(input(pin_b0)) //programme se met en ///
{} //pause j'usqu'a son ///
if (DutyRealNum == 1) //relachement, ensuite ///
{ //DutyRealNow est ///
return DutyRealNum; //decrementé ///
} // ///
else //il y a bien sur ///
{ //verification pour qu'il ///
DutyRealNum--; //n'aille pas en dessous ///
return DutyRealNum;} //de 1 ///
} // ///
////////////////////////////////////////////////// ///
if (input(pin_b1)) // ///
{ // ///
while(input(pin_b1)) //pareil, sauf que c'est ///
{} //B1 et qu'on augmente ///
if (DutyRealNum > (FreqRealNum-4)) // ///
{ // ///
DutyRealNum = FreqRealNum-1; // ///
return DutyRealNum; // ///
} // ///
else // ///
{ // ///
DutyRealNum++; // ///
return DutyRealNum; // ///
} // ///
} // ///
////////////////////////////////////////////////// ///
return DutyRealNum; //si aucun bouton n'a ete ///
} //appuyé, on ne fait rien ///
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
int8 FreqMode(int8 FreqRealNum, int8 DutyRealNum) ///
{ ///
////////////////////////////////////////////////// ///
if (input(pin_b1)) // ///
{ // ///
while(input(pin_b1)) // ///
{} //si on appui sur B1, on ///
if (FreqRealNum == 1) //decremente FreqRealNum ///
{ //ce qui augmente la freq ///
return FreqRealNum; //neanmois cela agit sur ///
} //le duty ///
else // ///
{ // ///
FreqRealNum--; //il y a verif pour que la ///
return FreqRealNum; //freq ne depasse pas le ///
} //max ///
} // ///
////////////////////////////////////////////////// ///
if (input(pin_b0)) // ///
{ // ///
while(input(pin_b0)) // ///
{} // ///
if (FreqRealNum == 254) //idem sauf qu'on ///
{ //incremente ///
return FreqRealNum; // ///
} // ///
else // ///
{ // ///
FreqRealNum++; // ///
return FreqRealNum; // ///
} // ///
} // ///
////////////////////////////////////////////////// ///
return FreqRealNum; // aucun appui on ne fait ///
} // tien ///
/////////////////////////////////////////////////////////////////////////////
|
What can I do:
-use a slower crystal?
-create my owm PWM code using TIMER0?
-use a magic piece of code that will set a 256 presacler?
thanks |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
frosties_power Guest
|
leboss |
Posted: Thu Dec 11, 2008 4:59 pm |
|
|
The thing is, if I'm using a software PWM then I can't put anything on my LCD screen (because my LCD_drivers are using delay and an interrupt can't trigger itself during a delay)
I think I should use 2 pic, one for the LCD screen and one for the PWM, what do you think?
oh and I forgot, I'm using CCS V4.057. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Dec 12, 2008 12:41 am |
|
|
I don't see the problem. Software PWM as suggested means dividing a timer interrupt frequency by counting interrupts and setting the I/O pin by software. As a basic disadvantage, this implies a jitter due to interrupt latencies and may be inappropriate, e. g. to generate clean notes for a tuner.
There is another option to utilize timer1 in compare mode to generate a hardware accurate software PWM, by reprogramming the mode on each half period. I have no programming example at hand, but I see that it's possible by functional specification.
On the other hand, I don't understand the relation to delays. Software delays can coexist with precise interrupt timing. And LCD control normally don't need delays, except during initialisation. |
|
|
frosties_power Guest
|
|
Posted: Fri Dec 12, 2008 1:04 am |
|
|
Don't you need between each data sended?
Well our teacher told us that if an interrupt need to trigger itself while in a delay_ms or a delay_us, she won't be able to do it because delay have priority.
I didn't try it though.
Also, we're using an old version of CCS at school (3.something). |
|
|
Ttelmah Guest
|
|
Posted: Fri Dec 12, 2008 3:29 am |
|
|
Your teacher is wrong.
_Unless_ you use a delay inside an interrupt.
The delay code in CCS, is nothing more than a simple loop, using a counter, and nops as necesssary to get the required timings. It uses a library subroutine generated when you add the 'clock' statement. It can be interrupted just like any other normal code.
However, if you use a delay _inside_ an interrupt handler anywhere, then the compiler has to ensure that this cannot occur inside an 'external' delay, so it disables interrupts around any 'main' delays.
This behaviour itself, can be worked round, by having a second #use delay statement, which then generates _separate_ delays for interrupt use.
Generally, even better not to use delays inside interrupts anyway!...
Do a search here. You will find the syntax for using two clock statements like this if needed.
Best Wishes |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Fri Dec 12, 2008 9:16 am |
|
|
Code: | Don't you need between each data sended? |
You better check HD44780 busy flag. |
|
|
frosties_power Guest
|
|
Posted: Fri Dec 12, 2008 1:53 pm |
|
|
Quote: |
You better check HD44780 busy flag.
|
I can't (imposed by my teachers)
Quote: | Your teacher is wrong.
|
Indeed, I've tried and showed it to him, he was surprised.
Well, thanks to you, I've managed to do it.
Here, adjustable PWM generator, 15Hz to 3906Hz.
Modifing frequency is also modifing the duty cycle but it's not a problem, because modifing the duty cycle do not modify the frequency
I've used this piece of code :
Code: |
#include <16F876A.H>
......
int8 width=0;
int8 LOOPCNT = 100;
int8 loop=0;
int8 pulse = 0;
#INT_RTCC
void tick_interrupt(void) {
if (--loop == 0) {
loop=LOOPCNT;
pulse=width;
}
if (pulse) {
output_high(pin_c2);
--pulse;
}
else output_low(pin_c2);
}
void main(void)
{
code here
}
|
with = x in order to change the duty cycle
and
LOOPCNT = y
loop = y
to change the frequency |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|