PIC12F683 : Single Push Button control four types of PWM output - Page 1
Forum section: electronics / general

author: arul
author_rank: Regular Contributor
timestamp: December 01, 2020, 07:07:55 pm
content: Hi All,I have written a code for PWM as output and push button as an input using PIC12F683.In this code, a single push button control the four types of PWM duty cycle output like 97.6%, 85%, 75% and 1%.Push button is connected to pin no.2 as GP5.PWM output is taken out from pin no.5 as GP2.The following is my codeCode:// PIC12F683 Configuration Bit Settings// 'C' source line config statements// CONFIG#pragma config FOSC = INTOSCCLK // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)#pragma config WDTE = ON // Watchdog Timer Enable bit (WDT enabled)#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)#pragma config MCLRE = ON // MCLR Pin Function Select bit (MCLR pin function is MCLR)#pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled)#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)#pragma config BOREN = ON // Brown Out Detect (BOR enabled)#pragma config IESO = ON // Internal External Switchover bit (Internal External Switchover mode is enabled)#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.#include <xc.h>#include <stdlib.h>#include <stdio.h>#include <stdbool.h>#define _XTAL_FREQ 2000000void delay();typedef enum{S1,S2,S3,S4,}speed_d;static speed_d SPEED = S1;volatile bool flag1 = false ;volatile bool flag2 = true ;volatile bool flag3 = true ;volatile bool flag4 = true ;void delay(){for(int i=0; i<20;i++){;}}void main(void){OSCCON |= 0b01110001;TRISIObits.TRISIO5 = 0x01; //switch inputTRISIObits.TRISIO2 = 0x00; // PWM:OUTCCP1CON = 0b00001100; // pwm configurationPR2 = 0x80; // timer period registerwhile(PIR1bits.TMR2IF); // timer flagT2CONbits.T2CKPS = 0x00; //timer configT2CONbits.TOUTPS=0x00; // timer configT2CONbits.TMR2ON =0x01; // timer ONwhile(1){switch(SPEED){case S1:if(GPIObits.GP5 == 0 && flag1 == false){delay();CCP1CON = 0b00001100;CCPR1L = 0x7D; // 97.6% //if change upto 0x7F onlyflag1 = true ;flag2 = false ;}SPEED = S2;break;case S2:if(GPIObits.GP5 == 0 && flag2 == false){delay();CCP1CON = 0b00001100;CCPR1L = 0x6C; ////85% PWMflag2 = true ;flag3 = false ;}SPEED = S3;break;case S3:if(GPIObits.GP5 == 0 && flag3 == false){delay();CCP1CON = 0b00001100;CCPR1L = 0x5F; ////75% PWMflag3 = true ;flag4 = false ;}SPEED = S4;break;case S4:if(GPIObits.GP5 == 0 && flag4 == false){delay();CCP1CON = 0b00001100;CCPR1L = 0x01; //// 1% like PWM OFFflag4 = true ;flag1 = false ;}SPEED = S1;break;}//////////////////////////////////////}}When I try with hardware, For example, If I pressed push button 1st time, it is going to case:1. Then 2nd time I pressed push button, it skip the case 2, directly going to case:3 else case:4 else staying case:1. Like that switch case is not followed by hardware at all time.The following also circuit...

author: DrG
author_rank: Super Contributor
timestamp: December 01, 2020, 07:38:29 pm
content: There a few things that could be discussed, but one thing that you might want to do is examine your delay routine.As it is written, when pressing and holding the switch closed, your code will just race through the cases. What I think you want to do is to debounce the switch press and then require that it be released before counting another press.When I think the code does not make sense, it usually does make sense, just not the sense I thought it would when I wrote it

author: ggchab
author_rank: Frequent Contributor
timestamp: December 01, 2020, 07:39:13 pm
content: Shouldn't you check somewhere that the button is released ?Otherwise, you will loop through your cases if the button stays pressed.I don't think your flags or the delay (how long is it?) will prevent this from happening ...

author: Leo86
author_rank: Contributor
timestamp: December 01, 2020, 08:18:51 pm
content: // PIC12F683 Configuration Bit Settings// 'C' source line config statements// CONFIG#pragma config FOSC = INTOSCCLK // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)#pragma config WDTE = ON // Watchdog Timer Enable bit (WDT enabled)#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)#pragma config MCLRE = ON // MCLR Pin Function Select bit (MCLR pin function is MCLR)#pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled)#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)#pragma config BOREN = ON // Brown Out Detect (BOR enabled)#pragma config IESO = ON // Internal External Switchover bit (Internal External Switchover mode is enabled)#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.#include <xc.h>#include <stdlib.h>#include <stdio.h>#include <stdbool.h>#define _XTAL_FREQ 2000000void delay();typedef enum{S1,S2,S3,S4,}speed_d;static speed_d SPEED = S1;volatile bool flag1 = false ;volatile bool flag2 = true ;volatile bool flag3 = true ;volatile bool flag4 = true ;void delay(){for(int i=0; i<20;i++){;}}void main(void){OSCCON |= 0b01110001;TRISIObits.TRISIO5 = 0x01; //switch inputTRISIObits.TRISIO2 = 0x00; // PWM:OUTCCP1CON = 0b00001100; // pwm configurationPR2 = 0x80; // timer period registerwhile(PIR1bits.TMR2IF); // timer flagT2CONbits.T2CKPS = 0x00; //timer configT2CONbits.TOUTPS=0x00; // timer configT2CONbits.TMR2ON =0x01; // timer ONwhile(1){switch(SPEED){case S1:if(GPIObits.GP5 == 0 && flag1 == false){delay();//CCP1CON = 0b00001100;CCPR1L = 0x7D; // 97.6% //if change upto 0x7F onlyflag1 = true;flag2 = false;}SPEED = S2;break;case S2:if(GPIObits.GP5 == 0 && flag2 == false){delay();//CCP1CON = 0b00001100;CCPR1L = 0x6C; ////85% PWMflag2 = true;flag3 = false;}SPEED = S3;break;case S3:if(GPIObits.GP5 == 0 && flag3 == false){delay();//CCP1CON = 0b00001100;CCPR1L = 0x5F; ////75% PWMflag3 = true;flag4 = false;}SPEED = S4;break;case S4:if(GPIObits.GP5 == 0 && flag4 == false){delay();//CCP1CON = 0b00001100;CCPR1L = 0x01; //// 1% like PWM OFFflag4 = true ;flag1 = false ;}SPEED = S1;break;}}}Hi arul!I think reconfiguring the register CCP1CON in realtime can generate some error.

author: MarkF
author_rank: Super Contributor
timestamp: December 01, 2020, 09:29:40 pm
content: I suggest your main() processing should be something like this...Edit: 'speed' increment correctedCode:uint8_t sw0=0;uint8_t lastSW0=1;uint8_t speed=0;void main(void){uint8_t pin;OSCCON |= 0b01110001;TRISIObits.TRISIO5 = 0x01; // switch inputTRISIObits.TRISIO2 = 0x00; // PWM:OUTCCP1CON = 0b00001100; // pwm configurationPR2 = 0x80; // timer period registerwhile(PIR1bits.TMR2IF); // timer flag <==== I don't think you need to wait????T2CONbits.T2CKPS = 0x00; // timer configT2CONbits.TOUTPS=0x00; // timer configT2CONbits.TMR2ON =0x01; // timer ONwhile (1) {// Read buttonpin = GPIObits.GP5;if (lastSW0==0 && pin==1) sw0=1; // If button release, set sw0lastSW0 = pin;// If button releasedif (sw0) {sw0 = 0;if ( ++speed > 3 ) speed = 0;// Change speedswitch (speed) {case 0:CCPR1L = 0x7D; // 97.6% //if change upto 0x7F onlybreak;case 1:CCPR1L = 0x6C; // 85% PWMbreak;case 2:CCPR1L = 0x5F; // 75% PWMbreak;case 3:CCPR1L = 0x01; // 1% like PWM OFFbreak;} // End switch} // End button release// Uncomment if you want a delay// __delay_ms(10); // Approx. 100 Hz loop} // End while}

author: newbrain
author_rank: Super Contributor
timestamp: December 02, 2020, 03:37:22 pm
content: Quote from: MarkF on December 01, 2020, 09:29:40 pmThis is not doing what you think it's doing.Parenthesis are redundantThe post increment will allow speed to rise to 4 before being reset the next time roundAlso, debouncing is missing.

author: MarkF
author_rank: Super Contributor
timestamp: December 02, 2020, 04:08:52 pm
content: Quote from: newbrain on December 02, 2020, 03:37:22 pmI was expecting the parenthesis to force the increment before the check.Apparently, it does not. Good catch.Pre-increment should take care of it.Code:if ( ++speed > 3 ) speed = 0;I haven't found that I need any debouncing. Just a simple pull-up resistor.That depends though on how fast you sample the button.A lot of the bouncing should settle between samples.Also @arul, don't write you own delay() function.Use one of the built-in delay macros:Code:__delay_ms(x); // delay 'x' milli-seconds__delay_us(x); // delay 'x' micro-secondsRequires that you have previously defined _XTAL_FREQ

author: newbrain
author_rank: Super Contributor
timestamp: December 02, 2020, 09:27:24 pm
content: QuoteEh, I suspected as much...In quite general terms, parenthesis do not changesequencing, though they can obviously affect order of evaluation.The sections of C11 standard relevant for this case:6.5.1 Primary expressionsQuote6.5.2.4 Postfix increment and decrement operatorsQuoteAs for the debouncing: the delay is commented out, so the loop will run at ludicrous speed - quite surprised to hear that no hiccups are observed.

author: MarkF
author_rank: Super Contributor
timestamp: December 02, 2020, 10:47:07 pm
content: In my use case, the button is sampled within a 500 Hz interrupt ISR(). (i.e. the three lines of code to read and check the button.)The variable, sw0, is then checked in the main() loop.I don't know what speed the OP wants to run his while(1) loop.I just added a commented out __delay_ms() call to indicate where to do the wait.He will need to set his desired delay time.As a note: Adding a delay at the bottom of the while(1) loop is a very crude way of doing the timing.It does NOT account for the execution time through each pass of the loop.In general, tasks performed within the while(1) loop should not be time critical.(As an example, I will redraw a display within the while(1) loop and run the loop as fast as it can go.)I would suggest a delay between 10ms and 50ms without knowing more about his requirements.