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:
#includeRun the applet | Run the editor (via Webstart)#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 } }