/**
* @file l6q1a.c
* @brief Neste programa desejamos comutar o estado de um LED a cada 1 s. Neste
* programa alteramos a especificação do problema com respeito ao intervalo
* entre as interrupções geradas pelo TC0 de 2 us para 6 us
*/
#include <stdint.h> /* usamos os tipos uint8_t e uint16_t */
#define __AVR_ATmega2560__ /* programa para */
#include <avr/interrupt.h> /* usamos interrupções */
#include <avr/io.h> /* definições das entradas e saÃdas */
volatile uint32_t tick = 166667; /**< variável decrementada a cada interrupção do timer0. */
volatile uint8_t change_LED_state; /**< se setada, ocorreu um intervalo de 1 s */
/**
* @brief Rotina de interrupção quando ocorre o valor do contador TCNT0 é igual
ao contador OCR0A. Esperamos que a cada 6 us a variável tick seja
incrementada. A cada 166667 ticks, equivalente ao intervalo de 1 s, a
variável change_LED_state é setada.
*/
ISR(TIMER0_COMPA_vect) {
if (tick > 0) { // decrementamos tick até 0
tick--;
}
if (tick == 0) { // se tick chegou a zero, transcorreu 1 s
change_LED_state = 1; // setamos a variável sinalizando que o LED deve ser comutado
tick = 166667; // começamos a medir um novo intervalo de tempo de 1 s
}
}
/**
* @brief Configura o timer0 para gerar interrupções a cada 6 us
*/
void TC0_configura(void) {
/* configura o timer0 para gerar interrupções a cada 6 us e executar a rotina
de interrupção TIMER0_COMPA_vect */
TCCR0A = 0x02; // COM0A[1:0]=00 COM0B[1:0]=00 reservado[1:0]=00 WGM0[1:0]=10
TCCR0B = 0x01; // FOC0A = 0 FOC0B = 0 reservado[1:0]=00 WGM0[2]=0 CS0[2:0] = 001
TIMSK0 = 0x02; // reservado[4:0]=00000 OCIE0B=0 OCIE0A=1 TOIE0=0
OCR0A = 95; // valor de TOP = 95
TCNT0 = 0x00; // zeramos o contador
sei(); // habilita as interrupções globalmente
}
/**
* @brief Fazemos a porta PB7 uma saÃda. Neste terminal está ligado o LED L da placa
* de desenvolvimento.
*/
void porta_B_configura(void) {
// Configura PB7 como um terminal de saÃda. Este terminal é ligado a um LED
DDRB = DDRB | (1 << DDB7); // faz o terminal TERMINAL_LED uma saÃda
PORTB = PORTB & (~(1 << PORTB7)); // envia o valor 0 para o terminal TERMINAL_LED
}
/**
* @brief Mudamos o estado do LED em PB7 a cada 1 s. Monitoramos a variável change_LED_state.
* A cada 1 s ela é setada na sub-rotina para o tratamento das interruções do temporizador/
* contador 0. Quando esta variável é setada, mudamos o estado do LED e
* fazemos change_LED_state=0, para um novo intervalo de 1 s.
* @return int. O procedimento principal nunca retorna.
*/
int main(void) {
// configuramos o sistema
porta_B_configura(); // Configuramos PB7 como uma saÃda
TC0_configura(); // Configuramos o TC0 para gerar interrupções a cada 2 us
while (1) { // repita
if (change_LED_state) { // se change_LED_state = 1
PORTB ^= (1 << PORTB7); // mudamos o estado do LED em PB7
change_LED_state = 0; // fazemos change_LED_state=0 para um novo intervalo de tempo
}
};
return 0;
}