problems with PWM and 16F628A

POWERMAN

New Member
Hello everybody,

I use PIC16F628A for driving 3 outputs in PWM and i meet some problems with my C code.
I want to control 3 differents PWM, for the moment i've just connect 2 switchs (up and down) for control PWM hard only.
I don't understand, because when i push up switch i've just 3 differents duty cycles (same when i push down) but only 2 when i up again, and i locked at the 3rd cycle.
My wish was to obtain 10% for each push in "up switch" and same for "down switch" progress.
I've fixed F=500Hz and that is good.
I joined my program (Hitech C).
I hope some assistance, thanks by advance.

Powerman.

Moved to correct forum - moderator!
 

Attachments

Last edited by a moderator:
People maybe able to help. Unfortunately, your files are unreadable. Try loading them into a text editor and saving them so that the end of line characters are inserted. Or, cut and paste them into a CODE tag.

Mike.
 
You're severely limiting your chance of a response by using C, most PIC programming is done in assembler.

However, many C compiler manufacturers have forums, you might try asking there?.
 
hi,

i respect you nigel but i'm not agree, assembler for me is out of date.

Sorry.

Pommie i try to insert in text editor:


pwm.c

//**********************
ushort Compteur62us ;
uchar Flag62us ;

ushort ValeurPwmS1 ;
ushort ValeurPwmS2 ;
ushort ValeurPwmS3 ;

uchar Valeur3Pas ;

uchar CompteurPression ;
uchar CombinaisonBPs ;


pwm.c

//*********************
void init_pic(void);
void interrupt traite_int(void);
void clock_pic(void);

void DelayMs(uchar cpt) ;
void init_var(void) ;

void init_pwm(void) ;
void stop_pwm(void) ;
void setDC_pwm(ushort dc) ;

uchar TestBPs(void) ;
void GestionBPs(void) ;

//***************************************************************

/****************************************************************
Timmings in ms
****************************************************************/
void DelayMs(uchar cpt)
{
ushort t ;
while (cpt != 0)
{
CLRWDT() ;
-- cpt ;
t = 112 ;
while (t !=0) -- t ;
}
}

/****************************************************************
interrupts
****************************************************************/
void interrupt traite_int(void)
{
if(TMR1IF)
{
TMR1IF = 0 ;
Flag62us = 1 ;
TMR1H = 0xFF ;
TMR1L = 0xC1 ; // 0xFFFF - 0xFFC1 = 62 => 62 x 1 µs = 62 µs
}

}

/****************************************************************
Init PIC
****************************************************************/
void init_pic(void)
{
// Configuration du module CCP
CCP1CON = 0x00 ; // module CCP1 désactivée

// Configuration du port B
RBPU = 0 ; // active pull up
RBIE = 0 ;

// Configuration des I/O
PwmS1 = 0 ; // à l'init. S1 = 0
PwmS2 = 0 ; // S2 = 0
PwmS3 = 0 ; // S3 = 0
TRISA = ConfigIOPortA ;
TRISB = ConfigIOPortB ;

// Timer 0 (8 bits) est utilisé pour le wachtdog à 2,3 s.
T0CS = 0 ; // Clock interne
PSA = 1 ; // timer0 = Wachtdog
PS2 = 1 ; // \
PS1 = 1 ; // => 111 + WDT => 18 ms x 128 = 2,304 s
PS0 = 1 ; // /

// Timer 1 (16 bits) est utilisé pour l'horloge: base de 62 µs. Quartz 4 Mhz => 1 instruction = 1 µs
T1CON = 0x00 ; // Prédivision de l'horloge par 1
TMR1H = 0xFF ;
TMR1L = 0xC1 ; // 0xFFFF - 0xFFC1 = 62 => 62 x 1 µs = 62 µs
TMR1ON = 1 ; // On lance le timer 1
TMR1IE = 1 ; // On autorise les interruptions du timer 1

// Autorisation des interruptions
PEIE = 1 ; // Autorisation des IT peripherique
GIE = 1 ; // Autorisation général des IT
}

/****************************************************************
Init var glob
****************************************************************/
void init_var(void)
{
Flag62us = 0 ;
Compteur62us = 0 ; // Raz compteur clock

ValeurPwmS1 = 0 ;
ValeurPwmS2 = 0 ;
ValeurPwmS3 = 0 ;

Valeur3Pas = 0 ;
}

/****************************************************************
Init PWM
****************************************************************/
void init_pwm(void)
{
CCP1CON = 0x00 ; // module off
TMR2 = 0 ; // raz timer2 value
PR2 = 0x7C ; // PR2 = 124 --> f = 500 Hz
CCPR1L = 0 ; // Duty cycle = 0 à l'init
TRISB3 = 0 ; // RB3 = output
T2CKPS1 = 1 ; // Prescaler = 1:16
T2CKPS0 = 1 ;
CCP1CON = 0x0C ; // Mode PWM 10 bits + init two LSBs of PWM duty cycle at 0
TMR2ON = 1 ; // Timer2 ON
}

/****************************************************************
stop PWM
****************************************************************/
void stop_PWM(void)
{
RB3 = 0 ;
TMR2ON = 0 ;
CCP1CON = 0x00 ;
}

/****************************************************************
load duty cycle PWM [0-1023] -> [0-100%]
****************************************************************/
void setDC_PWM(ushort dc)
{
CCP1CON = CCP1CON & 0b11001111 ; // clear CCP1CON<5:4>
CCP1CON = CCP1CON | ((dc << 4) & 0b00110000) ; // set the two LSBs duty cycle
CCPR1L = dc >> 2 ; // set the eight MSBs duty cycle
}

/****************************************************************
management clock PIC
****************************************************************/
void clock_pic(void)
{
Flag62us = 0 ;

// ValeurPwmSx [0-256]
// Compteur62us [0-256]

if (ValeurPwmS1 == 0) PwmS1 = 0 ;
else
{
if (Compteur62us == 0) PwmS1 = 1 ;
else if (Compteur62us == ValeurPwmS1) PwmS1 = 0 ;
}

if (ValeurPwmS2 == 0) PwmS2 = 0 ;
else
{
if (Compteur62us == 0) PwmS2 = 1 ;
else if (Compteur62us == ValeurPwmS2) PwmS2 = 0 ;
}

Compteur62us = Compteur62us + 8 ;

if (Compteur62us == 256) Compteur62us = 0 ; // période = 2 ms

}

/****************************************************************
Tests switchs
*****************************************************/
uchar TestBPs(void)
{
CompteurPression = 0 ;
CombinaisonBPs = AUCUNE ;

while (!BoutonUp)
{
DelayMs(10) ;
++CompteurPression ;
if (!BoutonDown) CombinaisonBPs = UP_ET_DOWN ;
else CombinaisonBPs = UP ;
if (CompteurPression > 200) break ; // expiration
}

while (!BoutonDown)
{
DelayMs(10) ;
++CompteurPression ;
if (!BoutonUp) CombinaisonBPs = UP_ET_DOWN ;
else CombinaisonBPs = DOWN ;
if (CompteurPression > 200) break ; // expiration
}

return(CombinaisonBPs) ;
}

/****************************************************************
management switchs
****************************************************************/
void GestionBPs(void)
{
switch (CombinaisonBPs)
{
case UP :
if (CompteurPression > 100)
{
if (ValeurPwmS1 < 256) ValeurPwmS1 = ValeurPwmS1 + 8 ;
if (ValeurPwmS2 < 256) ValeurPwmS2 = ValeurPwmS2 + 8 ;
if (ValeurPwmS3 < 256) ValeurPwmS3 = ValeurPwmS3 + 2 ;
}
else
{
if (ValeurPwmS1 < 256) ValeurPwmS1 = ValeurPwmS1 + 32 ;
if (ValeurPwmS1 < 256) ValeurPwmS2 = ValeurPwmS2 + 32 ;
if (ValeurPwmS1 < 256) ValeurPwmS3 = ValeurPwmS3 + 8 ;
}
break ;
case DOWN :
if (CompteurPression > 100)
{
if (ValeurPwmS1 > 7) ValeurPwmS1 = ValeurPwmS1 - 8 ;
if (ValeurPwmS2 > 7) ValeurPwmS2 = ValeurPwmS2 - 8 ;
if (ValeurPwmS3 > 7) ValeurPwmS3 = ValeurPwmS3 - 2 ;
}
else
{
if (ValeurPwmS1 > 31) ValeurPwmS1 = ValeurPwmS1 - 32 ;
if (ValeurPwmS1 > 31) ValeurPwmS2 = ValeurPwmS2 - 32 ;
if (ValeurPwmS1 > 31) ValeurPwmS3 = ValeurPwmS3 - 8 ;
}
break ;
case UP_ET_DOWN :
if (CompteurPression > 100)
{
switch (Valeur3Pas)
{
case 0 :
Valeur3Pas = 50 ; // 50%
ValeurPwmS1 = 128 ;
ValeurPwmS2 = 128 ;
ValeurPwmS3 = 128 ;
break ;
case 50 :
Valeur3Pas = 100 ; // 100%
ValeurPwmS1 = 256 ;
ValeurPwmS2 = 256 ;
ValeurPwmS3 = 256 ;
break ;
case 100 :
Valeur3Pas = 0 ; // 0%
ValeurPwmS1 = 0 ;
ValeurPwmS2 = 0 ;
ValeurPwmS3 = 0 ;
break ;
}
}
break ;
}

// S1 est mis à jour par ValeurPwmS1 --> Timer1
// S2 est mis à jour par ValeurPwmS2 --> Timer1
// S3 est mis à jour par ValeurPwmS3 --> PWM

setDC_PWM((ValeurPwmS3 * 4)-1) ; // on se ramène à l'échelle [0-1023]

while (TestBPs() != AUCUNE) CLRWDT() ; // attent le relâchement

Compteur62us = 0 ;

}

/****************************************************************
main program
****************************************************************/
main()
{
CLRWDT() ;

// init registres
init_pic();
// init variables globales
init_var() ;

// init PWM hard
init_pwm() ;
setDC_PWM((ValeurPwmS3 * 4)-1) ;

while(1)
{
// raffraichi le watchdog
CLRWDT() ;

// gestion 62 µs
if (Flag62us) clock_pic();

// gestion des boutons poussoirs
if (TestBPs() != AUCUNE) GestionBPs() ;
}
}


regards
 
and pwm.h


pwm.h

/*====================================================================
-----= Predefined instructions =-----
====================================================================*/
// Predefined instructions
#define PORTBIT(adr, bit) ((unsigned)(&adr)*8+(bit))
#define NOP() asm(" nop")
#define FALSE 0
#define TRUE !FALSE
#define BYTE unsigned char /* sizeof(BYTE) must == 1 */
#define uchar unsigned char
#define ushort unsigned short
#define ulong unsigned long

// Descriptions des différentes entrées et sorties
static bit PwmS1 @ PORTBIT(PORTA, 6) ; // sortie S1 PWM
static bit PwmS2 @ PORTBIT(PORTA, 7) ; // sortie S2 PWM
static bit PwmS3 @ PORTBIT(PORTB, 3) ; // sortie S3 PWM
static bit BoutonUp @ PORTBIT(PORTB, 6) ; // entrée poussoir UP
static bit BoutonDown @ PORTBIT(PORTB, 7) ; // entrée poussoir DOWN

// Remarque: 1 = input, 0 = output
#define ConfigIOPortA 0x3F // RA6 et RA7 = PWM outputs, other in input
#define ConfigIOPortB 0xFF // port B input

#define AUCUNE 0x00
#define UP 0x01
#define DOWN 0x02
#define UP_ET_DOWN 0x03
 
Maybe but majority is rarely the reference for me.
C is more portable and more readable.
In assembler, if you change µC you learn assembler again, in C not.

C is more efficient for complex program, no?
 
POWERMAN said:
Maybe but majority is rarely the reference for me.
C is more portable and more readable.
In assembler, if you change µC you learn assembler again, in C not.

And every C compiler is different!, the portability of C is GREATLY exaggerated, and is particularly non-portable for micro-controllers.

However, it is HUGELY more portable than assembler!.

C is more efficient for complex program, no?

Depends on your programming skills?, and the number of proven routines you have available - and also on your definition of 'efficient' - a competent C programmer, with a good working knowledge of assembler on the target device, could certainly write large programmes far faster than in pure assembly.
 
i'm agree.

In my case, write in C is more practical.

In my program, i suspect variables init or wrong calculation, i would like your opinion.
I don't think a mistake for pwm use, i have read more and more your tutorial and Microchip specs, but without result...

regards.
 
Hi Nigel,

finally i've found a mistake here:

void GestionBPs(void)
{
switch (CombinaisonBPs)
{
case UP :
if (CompteurPression > 100)<----- 100 is too high, with 1 it's OK.

Thanks.
 
POWERMAN said:
Hi Nigel,

finally i've found a mistake here:

void GestionBPs(void)
{
switch (CombinaisonBPs)
{
case UP :
if (CompteurPression > 100)<----- 100 is too high, with 1 it's OK.

It's all those curly brackets in C, it's just SO confusing!

Anyway, I'm pleased you found your fault!.
 
This code is very suspicious
Code:
else
{
if (ValeurPwmS1 < 256) ValeurPwmS1 = ValeurPwmS1 + 32 ;
if (ValeurPwmS1 < 256) ValeurPwmS2 = ValeurPwmS2 + 32 ;
if (ValeurPwmS1 < 256) ValeurPwmS3 = ValeurPwmS3 + 8 ;
}

should probably be

Code:
else
{
if (ValeurPwmS1 <= 256-32) ValeurPwmS1 = ValeurPwmS1 + 32 ;
if (ValeurPwmS2 <= 256-32) ValeurPwmS2 = ValeurPwmS2 + 32 ;
if (ValeurPwmS3 <= 256-8) ValeurPwmS3 = ValeurPwmS3 + 8 ;
}

ditto in the other place
 
Nigel Goodwin said:
It's all those curly brackets in C, it's just SO confusing!

Anyway, I'm pleased you found your fault!.
i agree , and what is void ? no need explaining , its just weird thats all
Nigel thanks for the link
 
williB said:
a question : could one , set up a stack in ram?

I'm agree with Nigel, in C stack control is a problem, so i look with debugger for monitor it.
Have you an exemple for use a stack in ram?
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…