Programação em linguagem "C"

Aqui você encontra algumas dicas e exemplos para programar a placa Lab_Uino utilizando a linguagem "C".


Acessando os periféricos e registros do processador.

Todos os registros dos periféricos do processador estão mapeados em endereços de memória. Para acessa-los devemos indicar este endereço no software, o que não é muito confortável. Para facilitar esta operação e tornar mais flexível um arquivo do compilador já possui definições com os nomes e endereços de cada registro e bit disponível no processador, assim o acesso pode ser feito apenas indicando o nome do registro desejado.

Para incluir estas definições a linha #include <avr/io.h> deve ser colocada no inicio do código.

Como exemplo, para se escrever 8 bits na porta B do processador basta fazer PORTB = valor; nota-se que o nome do registro tem que estar em maiúsculo. O valor pode ser uma constante ou variável de 8 bits.

Exemplo:

#include <avr/io.h>

char x;

PORTB = 1;

PORTB = 34;

PORTB = 0x55;

PORTB = 0b01100111;

x = 3;

PORTB = x++;

PORTB = x;


Definindo pinos de entrada e saída

Os pinos do processador podem ser configurados pelo software como entrada ou como saída, possibilitando uma grande flexibilidade de utilização, esta configuração é feita pelo registro DDR (Data Direction Register) .

O processador possui várias portas com até 8 pinos, cada porta do possui o seu DDR e cada bit do DDR define o sentido de um pino do processador ligado a esta porta. Cada pino é identificado pela letra da porta e pelo bit que ele está ligado, veja os pinos ligados na porta B, eles serão PB7, PB6, PB5 ... até PB0.

No AVR quando o bit do DDR for ‘1’ o pino é colocado como saída e quando em ‘0’ o pino é uma entrada. Assim, como exemplo, após o comando DDRB = 0b11110000; os pinos conectados na porta B de bits 7 a 4 serão saídas e de 3 a 0 serão entradas, ou seja PB7 a PB4 saída e PB3 a PB0 entrada.

Pino como Saída

Uma vez o pino colocado como saída após a programação do DDR, o valor de saída é definido pelo registro PORT. Como o DDR cada porta possui o seu registro PORT com 8 bits, sendo um bit para dada pino. Colocando o bit em ‘1’ o pino de saída irá para nível lógico ‘1’, ou seja, ficará conectado a tensão de alimentação do processador (5V, 3.3V). Colocando o bit em ‘0’ ficará conectado ao terra ou 0V.

Pino como entrada

Quando colocado como entrada o processador deixa esse pino desconectado de VCC ou 0V (tri-state) possibilitando um dispositivo externo forneça o nível lógico, Assim o software poderá “ler” este nível e tomar decisões. Para a leitura deve-se utilizar o registro PIN da porta, este registro retornará o valor de cada pino da porta em um bit. Exemplo: valor = PINB; os valores de cada pino da porta B serão colocados na variável valor.

Resistor de Pull-up

Quando um pino está configurado como entrada o nível lógico (0 ou Vcc) deverá ser fornecido pelo dispositivo externo ligado ao processador. Mas em alguns casos, como chaves e alguns sensores, apenas um nível pode ser definido. Neste caso o outro deve ser feito por um resistor para que o pino não fique com um valor indefinido e ocasionando em leituras erras de dados.

Para simplificar o hardware externo do processador o AVR possui este resistor internamente a cada pino, esse resistor está ligado ao VCC (5V) garantindo o nível lógico ‘1’, assim o sensor externo fornece 0V ou nível lógico ‘0’ quando acionado. Porém este resistor deve ser habilitado pelo software quando ele for necessário. Isso é feito colocando o Bit do registro PORTx corespondente em ‘1’.

DDRx

PORTx

Função

descrição

0

0

Entrada tri-state

Define o pino como entrada e não coloca resistor de pull-up (sensores que fornecem 0V e VCC)

0

1

Entrada com pull-up

Define o pino como entrada e coloca resistor de pull-up (Chaves e sensores open-colector)

1

0

Saída nível lógico ‘0’

Pino fornece 0V com baixa corrente

1

1

Saída nível lógico ‘1’

Pino Fornece Vcc (5V) com baixa corrente


Manipulando Bits

É comum no microcontrolador a necessidade de manipular bits de registros, tanto em operações de escrita com de leitura, para isso podemos utilizar números decimais, hexadecimais ou binários, mas em “C” podemos utilizar funções especiais que facilitam estas operações.

Veja o exemplo: PORTB = 32; este comando faz com que os bit 5 porta B fique com nível lógico ‘1’ e os demais bits fiquem em ‘0’, pois 2 é o pesos binário do bit 5 que ficará em ‘1’. Assim basta passar o numero de decimal para binário para verificar o numero da porta, fácil mas trabalhoso. Podemos utilizar números em Hexadecimal, PORTB = 0x10; ou ainda em binário PORTB = 0b0010000; um pouco mais fácil.

Em “C” podemos utilizar o comando de shift para definir estas constantes, o número 32 pode ser escrito (1<<5), ou seja, 1 deslocado para a esquerda 5 bits, 0b00100000, ou mais fácil colocar 1 no bit 5. Assim se desejar colocar 1 no bit 3 basta escrever (1<<3). Assim podemos escrever PORTB = (1<<5);

Para colocar mais de um bit em 1 podemos fazer a operação lógica OR, desta forma o comando PORTB = (1<<6)|(1<<4)|(1<<1); resulta em 0b01010010, que coloca os bits 6, 4 e 1 em nível lógico ‘1’ e os demais bits em ‘0’.

Veja que o comando PORTB = valor; define e altera todos os bits de uma porta, mas muitas vezes queremos alterar apenas um bit da porta mantendo os outros bits com o valor anterior, para isso basta executar operações lógicas com o valor desejado e o valor da porta.

Desta forma para colocar um bit em ‘1’ basta fazer uma operação lógica OR, ou seja, PORTB = PORTB | (1<<5); faz com que o bit 5 da porta B vá para nível lógico ‘1’ e os demais bits não sejam alterados. Este comando também pode ser escrito como PORTB |= (1<<5);

Para colocar o bit em ‘0’ basta fazer uma operação AND com o valor da porta e a constante com o bit desejado em 0 e demais em 1, assim PORTB = PORTB & ~(1<<5); irá colocar ‘0’ no bit 5 da porta B sem alterar os valores dos demais bits. Também pode ser escrito PORTB &= (1<<5);

É possível efetuar operações com mais de um bit, como exemplo para “setar” os bits 2 e 3 podemos utilizar PORTB = PORTB |(1<<6)|(1<<2);

Exemplo, iniciando as portas do LAB_UINO. (veja esquema elétrico da placa).

DDRB = (1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1);

DDRC = (1<<6)|(1<<7);

DDRD = (1<<4)|(1<<6)|(1<<7);

DDRE = 0;

DDRF = 0;

PORTB = 0;

PORTC = 0;

PORTD = (1<<5)|(1<<1)|(1<<0);

PORTE = (1<<2);

PORTF = (1<<7)|(1<<6);

MCUCR |= (1<<JTD);

MCUCR |= (1<<JTD); //desliga interface JTAG.

Estes comandos define o sentido de todos os pinos da placa Lab_Uino , liga os pull-ups necessários e apaga todos os leds da placa.


Utilizando Defines

Alguns comandos embora simples podem ser mais simplificados se utilizarmos o recurso de define em “C”. O define é uma diretiva para o compilador que basicamente cria “apelidos” para alguns comandos, isso facilita o entendimento e alterações futuras no software.

Veja o exemplo: No Lab_Uino o anodo do led5 sinal D0 da placa está ligado na porta D bit 4, assim para ligar o led temos que colocar o bit em ‘1’ com o comando PORTD |= (1<<4); e para apagar colocar o bit em ‘0’ usamos o comando PORTD &= ~(1<<4);.

Podemos assim criar comando tipo liga_D0 e desliga_D0 utilizando o define, isso torna o código muito mais fácil de ser entendido do que uma série de comandos envolvendo portas e bits. Basta então criar as seguintes definições no inicio do código:

#define Liga_D0() PORTD |= (1<<4)

#define Desliga_D0() PORTD &= ~(1<<4)

Para a placa Lab_Uino, estas definições já estão disponíveis no arquivo Lab_Uino.h. Para utilizar incluir a diretiva #include “Lab_Uino.h” no inicio do código. O arquivo deve estar no diretório do projeto.

Agora é só utilizar Liga_D0(); no código quando desejar ligar o led do sinal D0 e Desliga_D0(); para apagar.

Veja os dois códigos abaixo pisca pisca a seguir:

For(x=0;x<9;x++){

PORTD |= (1<<4);_delay_ms(2000);

PORTD &= ~(1<<4);_delay_ms(2000);

}

For(x=0;x<9;x++){

Liga_D0();_delay_ms(2000);

Desliga_D0();_delay_ms(2000);

}


Exemplos

Programa pisca-pisca (aula 1)

O programa pisca-pisca demonstra como criar os defines para ativar saídas do processador. O programa fará o Led5 piscar com tempo de 1 segundo aceso e 1 segundo apagado.

/*****************************************************

* Programa pisca-pisca

* faz o led5 sinal D0 ficar piscando indefinidamente

******************************************************/

// inclui arquivos de definições da biblioteca

#include <avr/io.h>

// define xtal da CPU para rotinas de delay.

#define F_CPU 8000000UL

#include <util/delay.h>

// inclui arquivos e definições da placa

#define Liga_D0() PORTD |= (1<<4)

#define Desliga_D0() PORTD &= ~(1<<4)

//define funções e rotinas

void IO_init(void){

DDRB = (1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1);

DDRC = (1<<6)|(1<<7);

DDRD = (1<<4)|(1<<6)|(1<<7);

DDRE = 0;

DDRF = 0;

PORTB = 0;

PORTC = 0;

PORTD = (1<<5)|(1<<1)|(1<<0);

PORTE = (1<<2);

PORTF = (1<<7)|(1<<6);

MCUCR |= (1<<JTD);

MCUCR |= (1<<JTD); //desliga interface JTAG.

}

// programa principal

int main(void)

{

// bloco de setup da placa

// será executado somente 1 vez após reset

IO_init(); // inicia pinos de IO da placa.

while(1){

//bloco que será executado repetidamente em loop

Liga_D0();

_delay_ms(1000); // aguarda 1s

Desliga_D0();

_delay_ms(1000);

}

}

Programa liga-desliga (aula 2)

O programa liga-desliga demonstra como criar os defines para verificar o estado de uma entrada digital. O programa irá alternar os leds 5 e 12 conforme o usuário aperte as chaves CH4 e CH6.

/*****************************************************

* Programa liga-desliga

* Alterna led5 e led12 com as chaves Busy e Sel_Out

******************************************************/

// inclui arquivos de definições da biblioteca

#include <avr/io.h>

// define xtal da CPU para rotinas de delay.

#define F_CPU 8000000UL

#include <util/delay.h>

// inclui arquivos e definições da placa

#define Liga_D0() PORTD |= (1<<4)

#define Liga_D7() PORTC |= (1<<7)

#define Desliga_D0() PORTD &= ~(1<<4)

#define Desliga_D7() PORTC &= ~(1<<7)

#define Ch_busy_lig !(PIND & (1<<5))

#define Ch_sel_out_lig !(PINF & (1<<6))

//define funções e rotinas

void IO_init(void){

DDRB = (1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1);

DDRC = (1<<6)|(1<<7);

DDRD = (1<<4)|(1<<6)|(1<<7);

DDRE = 0;

DDRF = 0;

PORTB = 0;

PORTC = 0;

PORTD = (1<<5)|(1<<1)|(1<<0);

PORTE = (1<<2);

PORTF = (1<<7)|(1<<6);

MCUCR |= (1<<JTD);

MCUCR |= (1<<JTD); //desliga interface JTAG.

}

// programa principal

int main(void)

{

// bloco de setup da placa

// será executado somente 1 vez após reset

IO_init(); // inicia pinos de IO da placa.

while(1){

//bloco que será executado repetidamente em loop

if(Ch_busy_lig){

Liga_D0();

Desliga_D7();

}

if(Ch_sel_out_lig){

Liga_D7();

Desliga_D0();

}

}

}

Programa Vai-vem (aula 3)

O programa vai-vem alterna qual led ficará aceso, criando um efeito de vai-vem. O programa demonstra como criar funções para facilitar a programação.

Será criado duas funções a led_on para acender um led e a led_off para apagar um led. Estas funções recebem como parâmetro o número do led para receber o comando.

A criação de funções deixa o programa mais simples e ocupando uma menor quantidade de memória pelo reuso destas funções.

/*****************************************************

* Programa vai-vem de leds

*

******************************************************/

// inclui arquivos de definições da biblioteca

#include <avr/io.h>

// define xtal da CPU para rotinas de delay.

#define F_CPU 8000000UL

#include <util/delay.h>

// inclui arquivos e definições da placa

#include "lab_uino.h"

//define funções e rotinas

void IO_init(void){

DDRB = (1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1);

DDRC = (1<<6)|(1<<7);

DDRD = (1<<4)|(1<<6)|(1<<7);

DDRE = 0;

DDRF = 0;

PORTB = 0;

PORTC = 0;

PORTD = (1<<5)|(1<<1)|(1<<0);

PORTE = (1<<2);

PORTF = (1<<7)|(1<<6);

MCUCR |= (1<<JTD);

MCUCR |= (1<<JTD); //desliga interface JTAG.

}

void led_on(unsigned char led){

switch(led){

case 1: Liga_Strobe();

break;

case 2: Liga_Feed();

break;

case 3: Liga_Sel_in();

break;

case 4: Liga_Init();

break;

case 5: Liga_D0();

break;

case 6: Liga_D1();

break;

case 7: Liga_D2();

break;

case 8: Liga_D3();

break;

case 9: Liga_D4();

break;

case 10: Liga_D5();

break;

case 11: Liga_D6();

break;

case 12: Liga_D7();

break;

}

}

void led_off(unsigned char led){

switch(led){

case 1: Desliga_Strobe();

break;

case 2: Desliga_Feed();

break;

case 3: Desliga_Sel_in();

break;

case 4: Desliga_Init();

break;

case 5: Desliga_D0();

break;

case 6: Desliga_D1();

break;

case 7: Desliga_D2();

break;

case 8: Desliga_D3();

break;

case 9: Desliga_D4();

break;

case 10: Desliga_D5();

break;

case 11: Desliga_D6();

break;

case 12: Desliga_D7();

break;

}

}

// programa principal

int main(void)

{

int x;

IO_init(); // inicia pinos de IO da placa.

while(1){

for(x=1;x<13;x++){

led_on(x);

_delay_ms(50);

led_off(x);

}

for(x=12;x>0;x--){

led_on(x);

_delay_ms(50);

led_off(x);

}

}

}

Programa Helo LCD (aula 4)

O programa Helo LCD demonstra como utilizar bibliotecas especificas para ativar dispositivos, neste caso um LCD de 2 linhas por 16 colunas.

Para a execução deve-se incluir no projeto o arquivo LCD_usb.c que possui as rotinas de tratamento do LCD.

No programa principal deve-se incluir o comando #include “LCD_usb.h” para incluir as definições as funções disponíveis para acesso ao LCD.

No inicio do programa o LCD é iniciado com o comando lcd_init(LCD_DISP_ON); feito isto, pode-se utilizar os demais comandos para a impressão de caracteres.

Alguns comandos:

lcd_clrscr();Limpa tela do LCD e posiciona o cursor na posição 0,0 (canto superior esquerdo)

lcd_gotoxy(coluna,linha);Posiciona o cursor na posição indicada pelos valos coluna e linha.

lcd_puts(lcd_buffer);Imprime a string que está definida no vetor LCD_buffer. Para inicializar esta string pode-se utilizar o comando sprinf, que é similar ao comando printf.

No programa exemplo o valor de uma variável será incrementado ou decrementado pelas chaves ACK e Busy. O valor será mostrado no LCD.

/*****************************************************

* Programa helo lcd

*

******************************************************/

// inclui arquivos de definições da biblioteca

#include <avr/io.h>

#include <stdio.h>

// define xtal da CPU para rotinas de delay.

#define F_CPU 8000000UL

#include <util/delay.h>

// inclui arquivos e definições da placa

#include "lab_uino.h"

// inclui funcões do LCD

#include "lcd_usb.h"

//define funções e rotinas

void IO_init(void){

DDRB = (1<<7)|(1<<6)|(1<<5)|(1<<4)|(1<<3)|(1<<2)|(1<<1);

DDRC = (1<<6)|(1<<7);

DDRD = (1<<4)|(1<<6)|(1<<7);

DDRE = 0;

DDRF = 0;

PORTB = 0;

PORTC = 0;

PORTD = (1<<5)|(1<<1)|(1<<0);

PORTE = (1<<2);

PORTF = (1<<7)|(1<<6);

MCUCR |= (1<<JTD);

MCUCR |= (1<<JTD); //desliga interface JTAG.

}

// programa principal

int main(void)

{

char lcd_buffer[20];

char x;

IO_init(); // inicia pinos de IO da placa.

lcd_init(LCD_DISP_ON); //inicia o LCD

lcd_clrscr(); //Limpa tela do LCD

sprintf(lcd_buffer,"LCD ativado ");

lcd_puts(lcd_buffer);

lcd_gotoxy(0,1);

sprintf(lcd_buffer,"aperte ack ");

lcd_puts(lcd_buffer);

x=0;

while(1){

if(Ch_busy_lig){

x--;

lcd_gotoxy(0,0);

sprintf(lcd_buffer,"x= %d ",x);

lcd_puts(lcd_buffer);

lcd_gotoxy(0,1);

sprintf(lcd_buffer,"aperte ack + ");

lcd_puts(lcd_buffer);

}

if(Ch_ack_lig){

x++;

lcd_gotoxy(0,0);

sprintf(lcd_buffer,"x= %d ",x);

lcd_puts(lcd_buffer);

lcd_gotoxy(0,1);

sprintf(lcd_buffer,"aperte busy - ");

lcd_puts(lcd_buffer);

}

_delay_ms(500);

}

}

Programa lendo ADC (aula 5)

A placa Lab_Uino possui 4 entradas preparadas para medidas de sinais analógicos de 0 a 5V.

No lendo ADC é utilizado a função Read_ADC(canal) para efetuar a leitura do canal 1 do Lab_Uino. O valor lido irá de 0 a 1023 conforme a tenão de entrada. É mostrado também como efetuar contas para a conversão deste valor, o programa irá mostrar no LCD o valor lido e a tensão correspondente.

No projeto deverão estar incluídos os arquivos LCD_usb.c e funcoes.c.

/*****************************************************

* Programa lendo ADC

*

******************************************************/

// para incluir printf com float colocar em opcoes do linker

// -Wl,-u,vfprintf -lprintf_flt -lm

#include <avr/io.h>

#include <stdio.h>

#define F_CPU 8000000UL

#include <util/delay.h>

#include "lab_uino.h"

#include "lcd_usb.h"

#include "funcoes.h"

// programa principal

int main(void)

{

char lcd_buffer[20];

int valor_adc;

float tensao;

IO_init(); // inicia pinos de IO da placa.

lcd_init(LCD_DISP_ON); //inicia o LCD

lcd_clrscr(); //Limpa tela do LCD

while(1){

valor_adc=Read_ADC(1);

tensao = valor_adc * 0.004887; //(5/1023)

lcd_gotoxy(0,0);

sprintf(lcd_buffer,"ADC_1 = %d ",valor_adc);

lcd_puts(lcd_buffer);

lcd_gotoxy(0,1);

sprintf(lcd_buffer,"Tensao = %1.2fV ",tensao);

lcd_puts(lcd_buffer);

}

}

Programa ativando o PWM (aula 6)

No programa ativando o PWM é demonstrado como utilizar a função de programação do timer1 do processador para a geração de uma onda tipo PWM (modulação por largura de pulso).

Após o comando Set_PWM_T1C(duty); a saída do Led1 ficará com uma onda quadrada com um período constante de aproximadamente 20ms, Porém o seu duty-cycle (tempo do sinal em ‘1’) dependerá do valor do parâmetro duty. Este valor poderá ser de 0 a 1023, quanto maior o valor maior será o tempo em 1 e maior o brilho do led.

Esta função pode ser utilizada para controle de velocidade de motor, geração de tensão analógica de 0 a 5V ou comandar servo-motor por exemplo.

O programa irá ler uma entrada analógica e controlar o brilho do led conforme o valor lido. O valor será mostrado no LCD.

No projeto deverão estar incluídos os arquivos LCD_usb.c e funcoes.c.

/*****************************************************

* Programa ativando o PWM

*

******************************************************/

#include <avr/io.h>

#include <stdio.h>

#define F_CPU 8000000UL

#include <util/delay.h>

#include "lab_uino.h"

#include "lcd_usb.h"

#include "funcoes.h"

// programa principal

int main(void)

{

char lcd_buffer[20];

int valor_adc;

IO_init(); // inicia pinos de IO da placa.

lcd_init(LCD_DISP_ON); //inicia o LCD

lcd_clrscr(); //Limpa tela do LCD

sprintf(lcd_buffer,"Observe o Led 1 ");

lcd_puts(lcd_buffer);

while(1){

valor_adc=Read_ADC(1);

lcd_gotoxy(0,1);

sprintf(lcd_buffer,"ADC_1 = %d ",valor_adc);

lcd_puts(lcd_buffer);

Set_PWM_T1C(valor_adc);

}

}

Programa interface serial USART (aula 7)

O programa demonstra como programar a interface serial USART para o envio e recepção de bytes (caracteres).

O programa possui rotina para iniciação da interface e rotinas de transmissão e recepção do byte.

No exemplo é mostrado como enviar e receber comandos simples entre duas placas. Quando é apertado as chaves Busy ou Ack um caracter é enviado para a interface serial. Caracteres A e B respectivamente.

Quando é recebido um caracter A ou B pela interface o led Strobe irá acender ou apagar conforme o caracter recebido.

Para testar pode-se interligar duas placas, ligar a placa um em computador com software tipo hiperterminal ou apenas efetuando uma ligação entre o TXD e RXD da própria placa.

Estas funções podem ser utilizadas para efetuar comunicações com módulos Bluetooth por exemplo.

No projeto deverão estar incluídos os arquivos LCD_usb.c e funcoes.c.

/*****************************************************

* Programa interface serial

*

******************************************************/

#include <avr/io.h>

#include <stdio.h>

#define F_CPU 8000000UL

#include <util/delay.h>

#include "lab_uino.h"

#include "lcd_usb.h"

#include "funcoes.h"

//***************************

// Inicia USART

//***************************

void USART_init(void)

{

UBRR1 = 51; // define baud rate e habilita a USART

UCSR1B = (1<<TXEN1) | (1<<RXEN1);

}

//****************************

// Transmite um byte

//****************************

void USART_Send( unsigned char data )

{

while( !(UCSR1A & (1<<UDRE1)) ); // aguarda buffer de transmissão vazio

UDR1 = data; // envia o byte

}

#define tem_caracter (UCSR1A & (1<<RXC1))

//***************************

// Receive one byte

//***************************

unsigned char USART_Get(void)

{

while( !(UCSR1A & (1<<RXC1)) ); //aguarda receber um byte

return UDR1; // retorna byte recebido

}

// programa principal

int main(void)

{

char lcd_buffer[20];

char com_serial;

IO_init(); // inicia pinos de IO da placa.

USART_init(); //inicia USART

lcd_init(LCD_DISP_ON); //inicia o LCD

lcd_clrscr(); //Limpa tela do LCD

sprintf(lcd_buffer,"Aperte ACK/BUSY");

lcd_puts(lcd_buffer);

while(1){

if(Ch_busy_lig){

USART_Send('A');

while(Ch_busy_lig);

}

if(Ch_ack_lig)USART_Send('B');

if(tem_caracter){

com_serial=USART_Get();

lcd_gotoxy(0,1);

lcd_putc(com_serial);

if(com_serial=='A')Liga_Strobe();

if(com_serial=='B')Desliga_Strobe();

}

}

}

Programa timer0 (aula 8)

No programa timer0 é mostrado como ativar o timer 0 para geração de interrupções em um tempo constante entre elas. Estas interrupções permitem que o software efetue várias temporizações de eventos em paralelo, possibilitando que o processador efetue diversas tarefas e não fique “parado” como em funções de delay.

No programa o timer 0 é programado para gerar uma interrupção a dada 5ms.

Ao ocorrer a interrupção, a rotina de tratamento irá incrementar os contadores tempo[], assim para temporizar 1 segundo, basta no programa principal zerar uma das variáveis tempo[] e testar quando esta variável chega ao valor de 200.

Neste exemplo será mostrado o valor de segundos no display e fará piscar os leds D0 e D1 com tempos diferentes.

No projeto deverão estar incluídos os arquivos LCD_usb.c e funcoes.c.

/*****************************************************

* Programa ativando interrupção timer 0

*

******************************************************/

#include <avr/io.h>

#include <stdio.h>

#include <avr/interrupt.h>

#define F_CPU 8000000UL

#include <util/delay.h>

#include "lab_uino.h"

#include "lcd_usb.h"

#include "funcoes.h"

// programa principal

int main(void)

{

char lcd_buffer[20];

char segundo;

IO_init(); // inicia pinos de IO da placa.

Timer0_init();

lcd_init(LCD_DISP_ON); //inicia o LCD

lcd_clrscr(); //Limpa tela do LCD

sprintf(lcd_buffer,"Temporizando ");

lcd_puts(lcd_buffer);

sei();

segundo=0;

tempo[0]=0;

tempo[1]=0;

tempo[2]=0;

while(1){

if(tempo[0]>200){ //200x 5ms

tempo[0]=0;

segundo++;

lcd_gotoxy(0,1);

sprintf(lcd_buffer,"tempo= %d ",segundo);

lcd_puts(lcd_buffer);

}

if(tempo[1]>60){

tempo[1]=0;

Toggle_D0();

}

if(tempo[2]>150){

tempo[2]=0;

Toggle_D1();

}

}

}