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