quinta-feira, abril 21, 2011

Pequenos Imãs e Micro Controladores - Parte 7

Vamos completar o nosso contador de giros vendo o software para o circuito apresentado no post anterior.

O software começa com as definições necessários para o compilador utilizado (PIC C) e as definições dos pinos aos quais estão conectados os sinais que nos interessam:
#include <16F676.h>
#device adc=8
#use delay(clock=4000000)
#fuses NOWDT, NOCPD, NOPROTECT
#fuses INTRC_IO, PUT, BROWNOUT, MCLR

#define DLY_SR 10 // delay p/ shift register
#define TAXA_DISP 3 // taxa de varredura dos displays
#define TAXA_ATL 100 // taxa de atualização dos valores nos displays

#define TEMPO_LED 600 // tempo que o LED fica aceso

// Pinos de E/S
#define SENSOR PIN_A5
#define LED PIN_A4

#define SHIFT_DS PIN_A2
#define SHIFT_ST PIN_C0
#define SHIFT_SH PIN_C1

#define SEL_1 PIN_C5
#define SEL_2 PIN_C4
#define SEL_3 PIN_C3
#define SEL_4 PIN_C2
Vamos manter o LED usado anteriormente. Para isto precisamos do contador que temporiza o seu apagamento. Vamos acrescentar um variável para contar as detecções de imã:
// Controle do LED
volatile int16 cntLed;

// Contador de passagens do imã
volatile unsigned int16 cntIma = 0;
Um vetor de quatro posições (segto) armazena a situação dos segmentos nos quatro dígitos do display. Na interrupção de timer usaremos este vetor para refrescar continuamente o display. Na hora de apresentar um novo valor, os segmentos serão preparados inicialmente em um segundo vetor (newsegto).

Uma variável passo controlará a atualização do display:
  • 0 indica que o display deve ser refrescado com o valor em segto
  • 1 indica que um novo valor deve ser montado em newsegto
  • 2 indica que newsegto tem um novo valor que deve ser copiado para segto
O vetor 'digitos' determina quais segmentos devem ser acesos para apresentar os dígitos de 0 a 9.
// Controle dos segmentos do display
// Um byte para cada segmento
// Bit 7 = segto G, Bit 6 = segto F, .. Bit 1 = segto A
unsigned int8 segto [4];
unsigned int8 newsegto [4];
unsigned int8 passo = 0;

// Segmentos a serem acesos para cada dígito
const unsigned int8 digitos[10] =
{
0b01111110, 0b00001100, 0b10110110, 0b10011110, 0b11001100,
0b11011010, 0b11111010, 0b00001110, 0b11111110, 0b11011110
};
No programa inicial temos a iniciação das entradas e saídas e do timer, seguido de um laço infinito onde um novo conteúdo para o display é calculado periodicamente.
// P R O G R A M A   P R I N C I P A L

void main()
{
unsigned int16 aux;

// Iniciações do hardware
set_tris_a (0xEB); // A4 e A2 output
#use fast_io(A)
set_tris_c (0xC0); // C0 a C5 output
#use fast_io(C)

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
setup_vref(FALSE);
setup_adc(ADC_OFF);

output_low (LED);
output_low (SEL_1);
output_low (SEL_2);
output_low (SEL_3);
output_low (SEL_4);

enable_interrupts(INT_RA5);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);


for (;;)
{
if (passo == 1)
{
disable_interrupts(GLOBAL);
aux = cntIma;
enable_interrupts(GLOBAL);

newsegto[0] = digitos [aux / (unsigned int16) 1000];
newsegto[1] = digitos [(aux/100) % 10];
newsegto[2] = digitos [(aux/10) % 10];
newsegto[3] = digitos [aux % 10];
passo = 2;
}
}
}
O tratamento do sensor é igual ao que já vimos antes, acrescido do incremento do contador de detecções:
// S E N S O R

//////////////////////////////////////////////
// Interrupcao de mudança do sinal
// Ocorre qdo sensor detecta imã
//////////////////////////////////////////////
#int_ra
void Sensor_ISR ()
{
output_high (LED);
input_a();
clear_interrupt (INT_RA5);
cntLed = TEMPO_LED;
cntIma++;
if (cntIma > 9999)
cntIma = 0;
}
Na interrupção de tempo real temos as temporizações para o LED e o display:
// T E M P O

//////////////////////////////////////////////
// Interrupcao de tempo real
// Ocorre a cada 256 uSeg
//////////////////////////////////////////////
#int_RTCC
void RTCC_isr()
{
static unsigned int8 cont_disp = TAXA_DISP;
static unsigned int8 cont_atl = TAXA_ATL;

// Tratamento do LED
if (cntLed)
{
if (--cntLed == 0)
output_low (LED);
}

// Atualização do Display
if (--cont_atl == 0)
{
passo = 1;
cont_atl = TAXA_ATL;
}
if (passo == 2)
AtlDisp ();

if (--cont_disp == 0)
{
VarreDisp ();
cont_disp = TAXA_DISP;
}

}
Por último, temos as rotinas de atualização do display:
// D I S P L A Y

static void AtlDisp (void)
{
segto[0] = newsegto[0];
segto[1] = newsegto[1];
segto[2] = newsegto[2];
segto[3] = newsegto[3];
passo = 0;
}

static void VarreDisp (void)
{
static unsigned int8 disp = 0;
unsigned int8 i, mask;

// coloca os valores dos segmentos no registrador
for (i = 0, mask = 0x80; i < 8; i++)
{
if (segto[disp] & mask)
output_low (SHIFT_DS);
else
output_high (SHIFT_DS);
delay_us (DLY_SR);
output_high (SHIFT_SH);
delay_us (DLY_SR);
output_low (SHIFT_SH);
delay_us (DLY_SR);
mask = mask >> 1;
}

// seleciona o display atual
if (disp == 0)
{
output_low (SEL_4);
output_high (SEL_1);
}
else if (disp == 1)
{
output_low (SEL_1);
output_high (SEL_2);
}
else if (disp == 2)
{
output_low (SEL_2);
output_high (SEL_3);
}
else
{
output_low (SEL_3);
output_high (SEL_4);
}

// acende os segmentos
output_high (SHIFT_ST);
delay_us (DLY_SR);
output_low (SHIFT_ST);

// passa para o dígito seguinte
disp = (disp + 1) & 3;
}
O vídeo abaixo mostra hardware e software funcionando. Os mais atentos perceberão que estamos contando as detecções de imã e portanto a contagem é incrementada de dois a cada volta.



Vamos fechar esta série no próximo post, adaptando o código para apresentar no display o número de rotações por minuto e usar os outros dois tipos de sensores.

Nenhum comentário: