PIC16F628 Anenometer (CCP Module)
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
}
}
|