Com a ideia deste exemplo é possível controlar uma resistência elétrica,ventilador (ou cooler), células peltier, motores,transformadores e uma infinidades de circuitos que precisem de usar PWM para seu controle e que dependam da temperatura, neste exemplo foi usado o sensor de temperatura LM35. na imagem abaixo é visualizado a simulação no Proteus:
O Código Fonte:
/* * Fazendo um controle sim-ples de temperatura X PWM * * Compilador : MPlabXC8 * Microcontrolador: 18F13K22 * Autor: Aguivone * Versão: 1 * Data de criação: 11/07/2016. * Exemplo de como fazer um controle simples de PWM com o LM35 */ #include <string.h> //para usar funçoes de string #include <xc.h> #define led LATBbits.LATB4 #define ler_led PORTBbits.RB4 #define _XTAL_FREQ 16000000//usado para rotinas de delays //************************************************************************************/ //VARIAVEIS GLOBAIS //************************************************************************************/ char gcCaracter; long glTemperatura = 0;// em °C long glTemp_min = 18;// menor temperatura em °C long glTemp_max = 20;// maior temperatura em °C long glCorrente = 0;// em A //pwm long uiMax_passos = 0;//frequencia em khz int uiDuty = 30;//25% da largura de pulso int uiTempo = 0; //serial unsigned char gucBufferSerial[5]; // Buffer da serial volatile unsigned int guiTamBuffer; // Usado para contar o tamanho do buffer de recepção. volatile unsigned char gucRecBufferStatus = 'S'; /*******************************configuraçôes do pic ****************************************************/ // CONFIG1H #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config PLLEN = OFF // 4 X PLL Enable bit (PLL is under software control) #pragma config PCLKEN = ON // Primary Clock Enable bit (Primary clock enabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor disabled) #pragma config IESO = OFF // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled) // CONFIG2L #pragma config PWRTEN = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software) #pragma config BORV = 19 // Brown Out Reset Voltage bits (VBOR set to 1.9 V nominal) // CONFIG2H #pragma config WDTEN = OFF // Watchdog Timer Enable bit (WDT is controlled by SWDTEN bit of the WDTCON register) #pragma config WDTPS = 32768 // Watchdog Timer Postscale Select bits (1:32768) // CONFIG3H #pragma config HFOFST = ON // HFINTOSC Fast Start-up bit (HFINTOSC starts clocking the CPU without waiting for the oscillator to stablize.) #pragma config MCLRE = OFF // MCLR Pin Enable bit (RA3 input pin enabled; MCLR disabled) // CONFIG4L #pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset) #pragma config LVP = OFF // Single-Supply ICSP Enable bit (Single-Supply ICSP enabled) desliga programação em baixa voltage #pragma config BBSIZ = OFF // Boot Block Size Select bit (512W boot block size) #pragma config XINST = OFF // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode)) // CONFIG5L #pragma config CP0 = OFF // Code Protection bit (Block 0 not code-protected) #pragma config CP1 = OFF // Code Protection bit (Block 1 not code-protected) // CONFIG5H #pragma config CPB = OFF // Boot Block Code Protection bit (Boot block not code-protected) #pragma config CPD = OFF // Data EEPROM Code Protection bit (Data EEPROM not code-protected) // CONFIG6L #pragma config WRT0 = OFF // Write Protection bit (Block 0 not write-protected) #pragma config WRT1 = OFF // Write Protection bit (Block 1 not write-protected) // CONFIG6H #pragma config WRTC = OFF // Configuration Register Write Protection bit (Configuration registers not write-protected) #pragma config WRTB = OFF // Boot Block Write Protection bit (Boot block not write-protected) #pragma config WRTD = OFF // Data EEPROM Write Protection bit (Data EEPROM not write-protected) // CONFIG7L #pragma config EBTR0 = OFF // Table Read Protection bit (Block 0 not protected from table reads executed in other blocks) #pragma config EBTR1 = OFF // Table Read Protection bit (Block 1 not protected from table reads executed in other blocks) // CONFIG7H #pragma config EBTRB = OFF // Boot Block Table Read Protection bit (Boot block not protected from table reads executed in other blocks) //todas as interrupções são tratadas aqui void interrupt interrupcoes(void)//vetor de interrupção { if(ADIF) {//se interrupção do modulo analogico! ADIF = 0;//limpa flag } /* * interrupções que não serão usada,mas fica aqui para caso alguém precise usar * * if(RCIF ) {//interrupção da serial RCIF = 0;// limpa flag de interrupção de recepção } if(TMR2IF) {//interrupção do timer2 TMR2IF = 0;//não será usado } if(CCP1IF) {//interrupção do ccp1 CCP1IF = 0;//não será usado } */ } //inicializa a serial void inicializa_RS232(unsigned long ulVelocidade,unsigned int uiModo) {//// por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada. // verifique datasheet para ver a porcentagem de erro e se a velocidade é possivel para o cristal utilizado. RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono. int valor; if(uiModo == 1) {//modo = 1 ,modo alta velocidade TXSTA = 0X24;//modo assincrono,trasmissao 8 bits. valor =(int)(((_XTAL_FREQ/ulVelocidade)-16)/16);//calculo do valor do gerador de baud rate } else {//modo = 0 ,modo baixa velocidade TXSTA = 0X20;//modo assincrono,trasmissao 8 bits. valor =(int)(((_XTAL_FREQ/ulVelocidade)-64)/64);//calculo do valor do gerador de baud rate } SPBRG = valor; // RCIE = 1;//habilita interrupção de recepção RCIE = 0;//desabilita interrupção de recepção - neste exemplo não vamos receber nada TXIE = 0;//deixa interrupção de transmissão desligado(pois corre o risco de ter uma interrupção escrita e leitura ao mesmo tempo) } //cria função pra enviar 1 caracter void escreve_RS232(char cValor) { TXIF = 0;//limpa flag que sinaliza envio completo. TXREG = cValor; while(TXIF ==0);//espera enviar caracter __delay_ms(1); } //cria a funcão semelhante ao "print"(pois a funcão nativa não funciona tão bem) void imprime_RS232(const char ccFrase[]) { unsigned char indice = 0; unsigned char tamanho = strlen(ccFrase); while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas { escreve_RS232(ccFrase[indice]); indice++; } } //convete um numero para uma string de numeros, com escolha de quantos digitos será usado void long_to_char_RS232(unsigned long ulQuant,int iTam) { char cTexto[7]; int iValor = 0; while(iValor < 6 ) { cTexto[iValor]='0'; iValor++; } while(ulQuant>=10000) { ulQuant=ulQuant-10000; cTexto[6]++; } while(ulQuant>=10000) { ulQuant=ulQuant-10000; cTexto[5]++; } while(ulQuant>=1000) { ulQuant=ulQuant-1000; cTexto[4]++; } while(ulQuant>=100) { ulQuant=ulQuant-100; cTexto[3]++; } while(ulQuant>=10) { ulQuant=ulQuant-10; cTexto[2]++; } while(ulQuant>=1) { ulQuant=ulQuant-1; cTexto[1]++; } iValor = iTam ; while(iValor != 0 ) { escreve_RS232(cTexto[iValor]); iValor--; } } //usado para ler o LM35 unsigned long ler_adc_un(void) { unsigned long ultensao; ADCON0bits.GO = 1; //inicia conversão while (ADCON0bits.GO_DONE == 1); //espera finalizar leitura ultensao = ADRES;//(ADRESH << 8) | ADRESL; return(ultensao); } //usado para deixar as amostras mais confiaveis void ler_ADC(int giMedia)//numero de amostras { int iMedia=0; glTemperatura = 0; while(iMedia < giMedia) { glTemperatura = glTemperatura + ler_adc_un(); __delay_us(2);//tempo minino para aquisições iMedia++; } glTemperatura = glTemperatura/giMedia; if(glTemperatura <= 1) { glTemperatura = 0; } else { glTemperatura = glTemperatura/2 ; //agora é só corrigir a não linearidade do sensor if(glTemperatura>24) { glTemperatura--; } if(glTemperatura>64) { glTemperatura--; } if(glTemperatura>103) { glTemperatura = 100;//valor maximo aceitavel } } } //configura o pwm void inicializa_PWM1(char prescaler,char pr2,char postcaler)//prescaler / PR2 / postcaler { uiMax_passos =(int) pr2; switch(prescaler) { case 1: { prescaler = 0; }break; case 4: { prescaler = 1; }break; case 16: { prescaler = 3; }break; } T2CON = (postcaler - 1)<<3; T2CON = T2CON + 4 + prescaler;//o 4 é para habilitar o timer 2 PR2 = pr2; CCP1CON = 0X0F;//habilita pwm // desabilita interupções de ccp e timer 2 CCP1IE = 0;//habilita modulo ccp1 TMR2IE = 0; //habilita desliga interrupcçaõde timer 2 } //copnfigurações iniciais void inicializa_cpu(void) { TRISC = 0xDF; TRISA = 0XFF;//configura portA como entrada TRISB = 0X20;//configura portB B5 (pino RX) como entrada PORTB = 0; // limpar as portas que estão configuradas como saidas inicializa_RS232(9600,1);//modo de alta velocidade ADCON0 = 0X21;//liga modulo analogico digital e configura entrada de sinal para o pino RA2(AN2) ADCON1 = 0X00;// Vref- seta ao Vss e Vref+ ao Vdd ADCON2 = 0b10111110;// justificado a direita// tempo de aquisição 20TAD // clk Fosc/64 ANSEL = 0x00;//desabilita portas analogicas(para não atrapalhar recepção no pino)/hab ra2 ANSELH = 0x01;//em alguns casos não funciona nem a interrupção de recepção. imprime_RS232("Controlador LM35 X PWM. \n\r"); imprime_RS232("Temperatura :\n\r"); inicializa_PWM1(1,40,1); //100khz veja no comentario abaixo "SUGESTÃO DE DEFINES :" CCPR1 = uiDuty; PEIE = 1;//habilita interrupção de perifericos do pic GIE = 1; //GIE: Global Interrupt Enable bit } //*******************************Rotina principal*********************************************/ void main(void) { inicializa_cpu(); for(;;) { if(uiTempo == 0) { long_to_char_RS232(glTemperatura,3); imprime_RS232("\n\r"); ler_ADC(6);//pega 6 amostras para tirar media if(glTemperatura > glTemp_max) { if(uiDuty > 25) {// limita um valor maximo para variar, mas se quiser pode por até 0; uiDuty --;//decrementa variavel } CCPR1 = uiDuty; } if(glTemperatura < glTemp_min) { if(uiDuty < 40)//o max é 40 passos nessa frequencia { uiDuty++;//incrementa variavel } CCPR1 = uiDuty; } led = ~ler_led; uiTempo = 50;//seta tempo } else { uiTempo--; } __delay_ms(1); }//loop infinito } /*calculos para pwm * * periodo do pwm * * Tpwm = [PR2+1]*4*Tosc*prescaler(do timer2) * * duty cycle * <bits 5e4> * D = (CCPR1L + CCP1CON) * Tosc * prescaler (do timer2) * * numero de passos do pwm * * N = (Fosc/(Fpwm * 4 * prescaler)) */ /* SUGESTÃO DE DEFINES : * use estes valores como referencia * //clock de 4mhz #define PWM_250HZ_CLK4 inicializa_PWM1(16, 250, 1) // #define PWM_500HZ_CLK4 inicializa_PWM1(16, 125, 1) // #define PWM_1KHZ_CLK4 inicializa_PWM1(4, 250, 1) // #define PWM_1K25HZ_CLK4 inicializa_PWM1(16, 50, 1) // #define PWM_2KHZ_CLK4 inicializa_PWM1(4, 125, 1) // #define PWM_2K5HZ_CLK4 inicializa_PWM1(4, 100, 1) // #define PWM_4KHZ_CLK4 inicializa_PWM1(1, 250, 1) // #define PWM_5KHZ_CLK4 inicializa_PWM1(1, 200, 1) // #define PWM_8KHZ_CLK4 inicializa_PWM1(1, 125, 1) // #define PWM_10KHZ_CLK4 inicializa_PWM1(1, 100, 1) // #define PWM_20KHZ_CLK4 inicializa_PWM1(1, 50, 1) // #define PWM_25KHZ_CLK4 inicializa_PWM1(1, 40, 1) // #define PWM_100KHZ_CLK4 inicializa_PWM1(1, 10, 1) // //clock de 8mhz #define PWM_500HZ_CLK8 inicializa_PWM1(16, 250, 1) // #define PWM_1KHZ_CLK8 inicializa_PWM1(16, 125, 1) // #define PWM_2KHZ_CLK8 inicializa_PWM1(4, 250, 1) // #define PWM_2K5HZ_CLK8 inicializa_PWM1(16, 50, 1) // #define PWM_4KHZ_CLK8 inicializa_PWM1(4, 125, 1) // #define PWM_5KHZ_CLK8 inicializa_PWM1(4, 100, 1) // #define PWM_8KHZ_CLK8 inicializa_PWM1(1, 250, 1) // #define PWM_10KHZ_CLK8 inicializa_PWM1(1, 200, 1) // #define PWM_16KHZ_CLK8 inicializa_PWM1(1, 125, 1) // #define PWM_20KHZ_CLK8 inicializa_PWM1(1, 100, 1) // #define PWM_40KHZ_CLK8 inicializa_PWM1(1, 50, 1) // #define PWM_50KHZ_CLK8 inicializa_PWM1(1, 40, 1) // #define PWM_200KHZ_CLK8 inicializa_PWM1(1, 10, 1) // //clock de 16mhz #define PWM_1KHZ_CLK16 inicializa_PWM1(16, 250, 1) // #define PWM_2KHZ_CLK16 inicializa_PWM1(16, 125, 1) // #define PWM_4KHZ_CLK16 inicializa_PWM1(4, 250, 1) // #define PWM_5KHZ_CLK16 inicializa_PWM1(16, 50, 1) // #define PWM_8KHZ_CLK16 inicializa_PWM1(4, 125, 1) // #define PWM_10KHZ_CLK16 inicializa_PWM1(4, 100, 1) // #define PWM_16KHZ_CLK16 inicializa_PWM1(1, 250, 1) // #define PWM_20KHZ_CLK16 inicializa_PWM1(1, 200, 1) // #define PWM_32KHZ_CLK16 inicializa_PWM1(1, 125, 1) // #define PWM_40KHZ_CLK16 inicializa_PWM1(1, 100, 1) // #define PWM_80KHZ_CLK16 inicializa_PWM1(1, 50, 1) // #define PWM_100KHZ_CLK16 inicializa_PWM1(1, 40, 1) // #define PWM_400KHZ_CLK16 inicializa_PWM1(1, 10, 1) // */
Nenhum comentário :
Postar um comentário
olá,digite aqui seu comentário!