Vamos começar pela iniciação do hardware: entradas e saídas digitais, USART (para receber os dados do leitor de RFID) e o timer:
// LEDs
#define LED_TOVIVO LED8
#define LED_LEU LED7
#define LED_TRANCA LED6
#define LED_CADASTRA LED2
#define LED_APAGA LED3
// Servo
#define SERVO_PORT PORTB
#define SERVO_DDR DDRB
#define SERVO _BV(PB7)
// Teclas
#define TEC_CADASTRA TEC1
#define TEC_APAGA TEC4
// Inicia as direçoes dos pinos de conexão dos LEDs
LED_DDR |= 0xFF;
// LEDs Apagados
LED_PORT = 0x00;
// Inicia conexão ao servo
SERVO_DDR |= SERVO;
SERVO_PORT &= ~SERVO;
// Liga pullup das teclas
TEC_DDR &= ~(TEC1|TEC2|TEC3|TEC4);
TEC_PORT |= TEC1|TEC2|TEC3|TEC4;
// Programa a USART para 9600 8N1
UCSRA = _BV(U2X); // para maior resolução do baud rate
UCSRB = _BV(RXEN) | _BV(RXCIE); // liga recepção, com interrupção
UCSRC = _BV(URSEL) | _BV(UCSZ1) | _BV(UCSZ0) ; // 8bit, 1 stop, sem paridade
UBRRL = (CLK_CPU / (8 * 9600UL)) - 1; // 9600 bps
// Preparar o timer 1 operar no modo CTC com 16MHz / 8
// gerando interrupcao contando até 100 (0,05 ms)
OCR1A = 100;
TCCR1B = _BV(WGM12) | _BV(CS11);
TIMSK |= (1<<OCIE1A);
Em seguida vamos ler a lista de tags da EEProm. Definimos dois vetores para isto, um na Ram e o outro na EEProm. A indicação EEMEM faz com que o linker coloque eepTags na sessão eeprom.// Lista de tags conhecidos
#define NMAX_TAGS 8
static uint32_t tags[NMAX_TAGS];
// Tags salvos na EEPROM
uint32_t eepTags[NMAX_TAGS] EEMEM;
int i;
// Carrega os tags conhecidos da EEPROM
for (i = 0; i < NMAX_TAGS; i++)
tags[i] = eeprom_read_dword (&eepTags[i]);
A interrupção da USART é usada para receber o código do tag, usando uma pequena máquina de estados. O código do tag lido é colocado em tagLido.// Último tag detectado
volatile uint32_t tagLido;
// Controle do LED de leitura
volatile uint8_t cntLedLeu = 0;
// Interrupção de recepção da USART
ISR(USART_RXC_vect)
{
static uint8_t estado = 0;
static uint32_t idTag;
uint8_t c;
c = UDR;
if (bit_is_clear(UCSRA, FE))
{
// recebeu caracter sem erro
if (estado == 0)
{
// Aguardando o STX
if (c == 0x02)
{
estado = 1;
idTag = 0;
}
}
else if (estado == 9)
{
// Aguardando o ETX
if (c == 0x03)
{
// Recebeu ID com sucesso
tagLido = idTag;
cntLedLeu = 100;
LED_PORT |= LED_LEU;
}
estado = 0;
}
else
{
// recebeu um dígito, vamos tratar como hexadecimal
if ((c >= '0') && (c <= '9'))
idTag = (idTag << 4) | (c & 0xF);
else if ((c >= 'A') && (c <= 'F'))
idTag = (idTag << 4) | (c - 'A' + 10);
else if ((c >= 'a') && (c <= 'f'))
idTag = (idTag << 4) | (c - 'a' + 10);
else
estado = 0xFF;
estado++;
}
}
else
estado = 0;
}
O nosso loop principal também é uma máquina de estados:// Modo de Operação
typedef enum { MODO_NORMAL, MODO_CADASTRA, MODO_APAGA1, MODO_APAGA2 } MODOOPER;
static MODOOPER modo = MODO_NORMAL;
for (;;)
{
if (modo == MODO_NORMAL)
{
if (tagLido != 0)
{
// Procura nos conhecidos
for (i = 0; (i < NMAX_TAGS) && (tags[i] != 0xFFFFFFFF); i++)
{
if (tags[i] == tagLido)
{
// achou, move a tranca
if (tranca == ABERTA)
{
Fecha();
tranca = FECHADA;
}
else
{
Abre();
tranca = ABERTA;
}
tagLido = 0;
break;
}
}
}
}
else if (modo == MODO_CADASTRA)
{
if (tagLido != 0)
{
// Procura nos conhecidos
for (i = 0; (i < NMAX_TAGS) && (tags[i] != 0xFFFFFFFF); i++)
{
if (tags[i] == tagLido)
{
// achou, ignora
break;
}
}
if ((i < NMAX_TAGS) && (tags[i] == 0xFFFFFFFF))
{
// Não encontrou e tem espaço, coloca na lista
tags[i] = tagLido;
eeprom_update_dword (&eepTags[i], tagLido);
}
tagLido = 0;
}
}
else if (modo == MODO_APAGA2)
{
// Apaga a lista de Tags
for (i = 0; i < NMAX_TAGS; i++)
{
tags[i] = 0xFFFFFFFF;
eeprom_update_dword (&eepTags[i], 0xFFFFFFFF);
}
modo = MODO_NORMAL;
}
}
A abertura e fechamento da fechadura é feito enviando pulsos ao servo. A largura destes pulsos é que define a posição do eixo do servo. Para garantir o posicionamento correto são enviados vários pulsos iguais.// Estado da Fechadura
typedef enum { ABERTA, FECHADA } FECHADURA;
static FECHADURA tranca = FECHADA;
// Controle do servo
volatile uint8_t nCiclos = 0;
volatile uint16_t posServo = 0;
// Abre a fechadura
static void Abre(void)
{
posServo = 10; // 0,5 ms
nCiclos = 50;
LED_PORT &= ~LED_TRANCA;
}
// Fecha a fechadura
static void Fecha(void)
{
posServo = 30; // 1,5 ms
nCiclos = 50;
LED_PORT |= LED_TRANCA;
}
A interrupção do timer é usada para testar as teclas e gerar todas as temporizações, inclusive os pulsos de controle do servo:// Interrupção do Timer1
// Ocorre a cada 0,05 ms
ISR(TIMER1_COMPA_vect)
{
static uint16_t cntCiclo = 0; // número de pulsos para o servo
static uint8_t cntServo = 0; // largura do pulso
static uint8_t cnt10ms = 200; // 200*0,05ms = 10ms
// Tempos a seguir usam a base de 10ms
static uint16_t cntCadastra = 500; // 5 seg
static uint16_t cntApaga = 1000; // 10 seg
static uint8_t cntLed = 20; // 0,2 seg
static uint8_t cntToVivo = 50; // 0,5 seg
if (nCiclos != 0)
{
if (cntCiclo == 0)
{
// Fim do ciclo
if (--nCiclos != 0)
{
// Novo ciclo
SERVO_PORT |= SERVO;
cntServo = posServo;
cntCiclo = 400; // 20 ms
}
}
if (nCiclos != 0)
{
if ((cntServo != 0) && (--cntServo == 0))
SERVO_PORT &= ~SERVO;
cntCiclo--;
}
}
if (--cnt10ms == 0)
{
cnt10ms = 200;
if (cntLedLeu != 0)
{
if (--cntLedLeu == 0)
LED_PORT &= ~LED_LEU;
}
if (--cntToVivo == 0)
{
LED_PORT ^= LED_TOVIVO;
cntToVivo = 50;
}
if (modo == MODO_NORMAL)
{
if ((TEC_PIN & TEC_CADASTRA) == 0)
{
if (--cntCadastra == 0)
{
LED_PORT |= LED_CADASTRA;
modo = MODO_CADASTRA;
}
}
else
cntCadastra = 500;
if ((TEC_PIN & TEC_APAGA) == 0)
{
if (--cntApaga == 0)
{
modo = MODO_APAGA1;
cntApaga = 1000;
cntLed = 20;
}
}
else
cntApaga = 1000;
}
else if (modo == MODO_CADASTRA)
{
if ((TEC_PIN & TEC_CADASTRA) == 0)
{
if (--cntCadastra == 0)
{
LED_PORT &= ~LED_CADASTRA;
modo = MODO_NORMAL;
}
}
else
cntCadastra = 500;
}
else if (modo == MODO_APAGA1)
{
if (--cntLed == 0)
{
LED_PORT ^= LED_APAGA;
cntLed = 20;
}
if ((TEC_PIN & TEC_APAGA) == 0)
{
if (--cntApaga == 0)
{
modo = MODO_APAGA2;
cntApaga = 1000;
LED_PORT &= ~LED_APAGA;
}
}
else
{
modo = MODO_NORMAL;
cntApaga = 1000;
LED_PORT &= ~LED_APAGA;
}
}
}
}
Como de costume, o projeto completo está nos arquivos do blog (link lá no alto à direita), neste caso no arquivo bau.zip.

Nenhum comentário:
Postar um comentário