Hades logoHades applet banner
PIC16F628 Anenometer (CCP Module)

applet icon

The image above shows a thumbnail of the interactive Java applet embedded into this page. Unfortunately, your browser is not Java-aware or Java is disabled in the browser preferences. To start the applet, please enable Java and reload this page. (You might have to restart the browser.)

Circuit Description

This applet demonstrates the Capture/Compare Module of the PIC16F628 microcontroller. The circuit consists of the microcontroller, a standard text-mode LC display, and a few input switches.

The program uses the CCP module to count input pulses on the input pin B4 of the microcontroller. The software then also calculates the maximum, minimum, and average values of the pulse count (over a one-minute interval). Use the switch connected to port B5 to select which value to display on the LCD. A typical application for this setup is a anemometer (or wind-speed meter), where a short pulse is generated for each full rotation of a rotating mill. The faster the wind, the more pulses are generated, and the pulse count can then be converted to actual wind speed (meters/second) in software.

Once the simulation is running and the display has been initialized, try clicking the pulse-switch connected to pin B4 slowly or rapidly, and watch the resulting values on the display.

The program running on the microcontroller is based on the following C source code:

#include 

#include "lcdaasmt.c"


__CONFIG(9);

/*
 * Compilar com
 * 
 picl -16f627 anemometro.c -Zg -Ohex

misim
LCD - 2x24, Port A:x7654 & Port B:xxxxRSEx

*/



#define timeout_limit 1 // valor correto -> 125

#define Config_interrupt_RB0 ((INTE = 1), ( INTF = 0 ),( INTEDG = 0))  // configura interrupcao em RB0


#define sensor RB0  // liga sensor a RB0


#define zero_button RB4  // botao para zerar o contador
#define rate_button RB5  // botao para opcao entre taxa maxima, media ou instantanea

#define MAX 0
#define AVG 1
#define INST 2



bit old_RB0;  // guarda ultimo valor de RB0 antes de ser gerada uma interrupcao em RB0
bit old_RB4;  // guarda ultimo valor de RB4 antes de ser gerada uma interrupcao em RB4
bit old_RB5;  // guarda ultimo valor de RB5 antes de ser gerada uma interrupcao em RB5

unsigned char option = MAX; // modo MAX, AVG or INST  

int counter = 0; // contador instantaneo
long global_counter = 0;  // contador global


unsigned char interrupt_tmr0 = 0;  // numero de interrupcoes em tmr0

int seconds = 0;  // segundos decorridos
long minutes = 0;  // minutos decorridos

int max_rate = 0;      // taxa maxima
int average_rate = 0;  // taxa media
int shot_rate = 0;     // taxa instantanea




main() {

   // ******** DECLARACAO DE VARIAVEIS **********
   int rate;  // taxa atual a ser exibida no display
   unsigned char i;
   unsigned char c;


   // ******* CONFIGURACAO DE ENTRADA E SAIDA ********
   TRISA=0x00; // configura todos como saida, PORTA A    
   TRISB=0xF1; // configura como entrada B7..B4   e B3...b1  saida e B0 entrada



   // ******* INTERRUPCOES EM TMR0 *********
   T0IE = 1;  // habilita interrupção do TMR0
   T0IF = 0;  // zera o flag de interrupcao em TMR0

   T0CS = 0; // seleciona fonte de clock para incremento de TMR0 ( 1 -> pino RA4, 0 -> clock interno )

   // configuracao do prescaler
   PSA = 0;  // liga prescaler ao TMR0
   PS2 = 0;  PS1 = 1;  PS0 = 0;    // cofigurando o pre-scaler 1:8 

   TMR0 = 0b00000110;  // seta TMR0 para 6 para serem necessarios 
                       // 250 incrementos para chamar a interrupcao
  
     

   // ********* INTERRUPCOES EM RB0 **************
   Config_interrupt_RB0;  // configura interrupcao



   // ********* INTERRUPCOES EM RB4 E RB5************
   RBIE = 1; /* habilita interrupção em RB4 e RB5
                ( reset e opção de taxa mostrada, respectivamente ) */ 
   RBIF = 0; // zera o flag de interrupcao em RB4 e RB5


   // *********** inicializacao das entradas *************
   sensor = 0;  // inicializa entrada do sensor
   zero_button = 0;  // inicializa botao de zerar
   rate_button = 0;  // inicializa botao de taxa



   // inicializa variaveis que guardam os valores antigos das respectivas entradas
   old_RB0 = 0;
   old_RB4 = 0;
   old_RB5 = 0;


   GIE = 1;  // habilita todo tipo de interrupção


   // inicializa lcd
   lcd_init();


   // laco infinito
   while(1) {
      // Cursor para direita
      put_cmd(6);

      // inicio da linha
      adress_ddram(0x80); 

      // modo de exibicao
      if ( option == MAX ) {
         write_lcd("MAX   ");
         rate = max_rate; 
      } else if ( option == AVG ) {
         write_lcd("AVG   ");
	 rate = average_rate;
      } else if ( option == INST ) {
         write_lcd("INST  ");
	 rate = shot_rate;
      }
	
		
      // Cursor para esquerda
      put_cmd(4); 

      // Posiciona na 10a posicao da primeira linha
      adress_ddram(0x89);

  
      // envia taxa para ser exibida no display
      for ( i = 0; i < 4; i++ ) {
         c = rate % 10 + 48;	
         write_lcd_char(c);
         rate = rate/10;
      }
        
   }  // fim do laco while

}  // fim da main



// atualizacao das taxas maxima, media e instantanea
void update_rates() {
   if ( max_rate < 2*counter )  // se a taxa atual eh maxima
	max_rate = 2*counter;     // atualiza taxa maxima

   shot_rate = 2*counter;  // atualiza taxa instantanea


   // atualiza taxa media
   if ( seconds == 0 )   // se fracao de tempo amostrada eh inteiro
      average_rate = global_counter / minutes;

   else  // senao, se fracao de tempo amostrada nao for inteiro, faz ajuste
	average_rate = (2*global_counter) / (2*minutes + 1);

   counter = 0;  // zera contador
   
}


static void interrupt isr(void) {   
   // se interrupção em TMR0
   if ( T0IF == 1 ) {
      TMR0 = 0b00000110;  // seta TMR0 para o valor 6, proxima interrupcao 
                          // ocorrera dentro de 250 incrementos (pulsos) em TMR0

      interrupt_tmr0++; // marca mais uma interrupcao
	
      if ( interrupt_tmr0 == timeout_limit ) {  // se numero de interrupcoes chegou ao limite
	   interrupt_tmr0 = 0;  

	   seconds += 1;  // incrementa um segundo

	   if ( seconds % 30 == 0 ) {  // testa se completou mais um ciclo
                                       // de atualizacao das taxas( a cada 30s )
              
	      if ( seconds == 60 ) { // se completou um minuto
 	           minutes += 1;      // incrementa minutos
		   seconds = 0;       // zera segundos
	      }

               
	      update_rates(); // atualiza taxas maxima, media e instantanea
        
		
           } 
      }
      
      T0IF = 0;  // zera flag de interrupcao em TMR0
   }


   else if ( INTF == 1 ) {
      counter++;
      global_counter++;         
                
      INTF = 0;   // zera flag de interrupcao em RB0
   }
   

   // se interrupcao em RB4, RB5 ou em RB6
   else if ( RBIF == 1 ) {

      // se interrupcao em RB4
      if ( (zero_button & (!old_RB4)) | ((!zero_button) & old_RB4) ) { // testa se a entrada mudou de valor
            if ( zero_button & (!old_RB4) ) {

	    	global_counter = counter = 0;  // zera contadores

	        seconds = minutes = 0;  // zera tempo
	    
	       	max_rate = average_rate = shot_rate = 0; // zera taxas
            }

            old_RB4 = zero_button;  // guarda "novo valor antigo" da porta RB4

      }

      // se interrupcao em RB5
      else {  //if ( (rate_button & (!old_RB5)) | ((!rate_button) & old_RB5) ) {
            if ( (rate_button & (!old_RB5)) ) {
	        option = (option + 1) % 3;  // muda o option... 0 -> MAX , 1 -> MED, 2 -> INST
	    } 

	    old_RB5 = rate_button;  // guarda "novo valor antigo" da porta RB5
      }


      RBIF = 0;   // zera flag de interrupcao em RB4-RB7
   }
   
}

Print version | Run this demo in the Hades editor (via Java WebStart)
Usage | FAQ | About | License | Feedback | Tutorial (PDF) | Referenzkarte (PDF, in German)
Impressum http://tams.informatik.uni-hamburg.de/applets/hades/webdemos/95-dpi/pic16f628-anemometer/anemometro.html