CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

adjustable PWM on 2*16LCD

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
frosties_power
Guest







adjustable PWM on 2*16LCD
PostPosted: Thu Dec 11, 2008 3:32 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Dec 11, 2008 3:43 pm     Reply with quote

Quote:
It was supposed to do a variable PWM between 15.25Hz and 3906Hz.

Use software PWM. See this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=35160
frosties_power
Guest







leboss
PostPosted: Thu Dec 11, 2008 4:59 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Dec 12, 2008 12:41 am     Reply with quote

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







PostPosted: Fri Dec 12, 2008 1:04 am     Reply with quote

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







PostPosted: Fri Dec 12, 2008 3:29 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Dec 12, 2008 9:16 am     Reply with quote

Code:
Don't you need between each data sended?

You better check HD44780 busy flag.
frosties_power
Guest







PostPosted: Fri Dec 12, 2008 1:53 pm     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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