O comportamento gerado pelo firmware é o seguinte:
- Durante um período "longo" (2 minutos no código abaixo) a abóbora está "dormindo" (LEDs apagados e servomotor na posição de boca fechada).
- Ao "acordar" os LEDs dos olhos são acesos e o servomotor muda de posição para "abrir a boca da abóbora".
- Completada a abertura, é aceso o LED dentro da boca. A boca permanece aberta por alguns segundos.
- O servo motor retorna rapidamente para a posição de boca fechada, ao final do fechamento os LEDs são apagados.
enum { DORMINDO, ABRINDO, ABERTA, FECHANDO } estAbobora;
A interrupção de timer do PIC, que é programada para ocorrer a cada 64 microsegundos, é utilizada para gerar o sinal PWM de controle do servomotor e para decrementar um contador que indica a passagem de um décimo de segundo.unsigned int16 cntDSeg;
unsigned int16 cnt_periodo;
unsigned int8 cnt_duty, duty;
//////////////////////////////////////////////
// Interrupcao de tempo real
// Ocorre a cada 64 uSeg
//////////////////////////////////////////////
#int_RTCC
void RTCC_isr()
{
SET_TIMER0 (192); // conta de 192 a 255
// Trata Servo
if ((estAbobora != DORMINDO) && (estAbobora != ABERTA)
{
if (--cnt_periodo == 0)
{
// fim de um ciclo
cnt_periodo = TMPUS_PERIODO/TMPUS_OVF;
cnt_duty = duty;
output_high (MOTOR);
}
else if (cnt_duty != 0)
{
cnt_duty--;
if (cnt_duty == 0)
output_low (MOTOR);
}
}
if (cntDSeg != 0)
cntDSeg--;
}
O programa principal contém a iniciação do hardware e a lógica de mudança de estado a cada décimo de segundo:#define MOTOR PIN_A2
#define LED_OLHO PIN_A4
#define LED_BOCA PIN_A5
#define TMPUS_OVF 64l // tempo uSeg entre interrupções do timer
#define TMPUS_PERIODO 20000l // periodo do PWM em uSeg
#define TMPUS_DSEG 100000l
#define TMPDSEG_DORME 1000
#define TMPDSEG_ABRINDO 3
#define TMPDSEG_FECHANDO 1
#define TMPDSEG_ABERTA 30
#define DUTY_0 400 // tempo para 0 graus
#define DUTY_90 1000 // tempo para 90 graus
#define DUTY_180 1600 // tempo para 180 graus
#define DUTY_ABERTA 768
#define DUTY_FECHADA 576
unsigned int16 cntEstado;
void main()
{
// configura os periféricos
#use fast_io(A)
set_tris_A(0xCB);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
SET_TIMER0 (192); // conta de 192 a 255
setup_timer_1(T1_DISABLED);
setup_comparator(NC_NC);
setup_vref(FALSE);
output_high (LED_BOCA);
output_high (LED_OLHO);
output_low (MOTOR);
// inicia as variaveis
estAbobora = FECHANDO;
cntDSeg = TMPUS_DSEG/TMPUS_OVF;
cnt_periodo = TMPUS_PERIODO/TMPUS_OVF;
cnt_duty = duty = DUTY_FECHADA / TMPUS_OVF;
cntEstado = 3;
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
for (;;)
{
// Trata atualização do estado a cada décimo de segundo
if (cntDSeg == 0)
{
disable_interrupts(GLOBAL);
cntDSeg = TMPUS_DSEG/TMPUS_OVF;
if (--cntEstado == 0)
{
switch (estAbobora)
{
case DORMINDO:
estAbobora = ABRINDO;
duty = DUTY_FECHADA / TMPUS_OVF;
output_high (LED_OLHO);
cntEstado = TMPDSEG_ABRINDO;
break;
case ABRINDO:
if (duty == (DUTY_ABERTA / TMPUS_OVF))
{
estAbobora = ABERTA;
output_high (LED_BOCA);
cntEstado = TMPDSEG_ABERTA;
}
else
{
duty++;
cntEstado = TMPDSEG_ABRINDO;
}
break;
case ABERTA:
estAbobora = FECHANDO;
cntEstado = TMPDSEG_FECHANDO;
break;
case FECHANDO:
if (duty == (DUTY_FECHADA / TMPUS_OVF))
{
estAbobora = DORMINDO;
output_low (LED_BOCA);
output_low (LED_OLHO);
output_low (MOTOR);
cntEstado = TMPDSEG_DORME;
}
else
{
duty--;
cntEstado = TMPDSEG_FECHANDO;
}
break;
}
}
enable_interrupts(GLOBAL);
}
}
}
No próximo post da série vamos ver a montagem da minha "abóbora" (que acabou sendo uma esfera de isopor).
Nenhum comentário:
Postar um comentário