Baixe o app para aproveitar ainda mais
Prévia do material em texto
Atividade_03 - Livro AVR e Arduino – Técnicas de Projeto Capítulo: 5 (Portas) Obs.: Deve ser entregue arquivo contendo as perguntas e respectivas respostas. Título: Acessando portas de entrada/saída usando C Objetivos: Utilizar os registradores que controlam as portas de entrada / saída para controlar dispositivos. Nesta prática utilizaremos o Tinkercad para simular um circuito simples usando o microcontrolador Atmega328, utilizado nas placas Arduino UNO. Desta vez, programaremos usando um código C com as diretivas/macros definidos pela AVR para acesso aos registradores. 1. Procedimentos: 1. Acesse sua conta no Tinkercad (tinkercad.com) e vá para a aba circuits (https://www.tinkercad.com/circuits). 2. Você deve fazer um circuito capaz de ler um botão. Note que este projeto já está disponível (na aba Starters → Arduino). O botão pode ser ligado na porta 2 na placa do Arduino UNO (como no projeto Starter). 3. Você deve agora modificar a lógica do botão eliminando a necessidade do resistor externo. Você deve usar somente dois fios conectados ao botão, sendo um deles conectado ao GND. 4. Você deve adicionar 3 leds, nas portas 2, 3 e 28 (A5/PC5) (obrigatoriamente). Somente um led deve ser aceso por vez. A cada clique do botão, um led se apaga e o próximo acende. Use resistores onde necessário, pois vamos implementar estes circuitos usando a placa (talvez não neste momento) e não podemos sair queimando as coisas. Veja o apêndice desta prática. 5. Implemente um clique longo no botão (apertar e segurar por um segundo) para que todos os leds sejam apagados (uma espécie de reset dos leds). Ao primeiro clique com os leds todos apagados, um led se acende e volta a funcionar como descrito no item 4. #include <util/delay.h> #define tst_bit(Y,bit_x)(Y&(1<<bit_x)) //testa o bit x da variável Y (retorna 0 ou 1) unsigned long tempoUltimoDebounce = 0; //Variável que armazenará o tempo do último Debounce unsigned long tempoDebounce = 1000; //Tempo (em milissegundos)que é necessário manter o botão pressionado para ter a certeza de que ele foi pressionado de fato. int contador = 0; void setup(){ DDRD = 0b00000011;// saida porta 2 e 3 DDRC = 0b00100000;// saida porta 28 PORTD = 0b0000100;// coloca como a PD3 a entrada do botão PORTC = 0b00000000;// não alimenta nenhuma porta } void loop(){ if (!tst_bit(PIND, PD2)){// verifica se o botão foi pressionado tempoUltimoDebounce = millis(); while(!tst_bit(PIND, PD2)); // verifica se o botão foi pressionado _delay_ms(10); contador++; //Incrementa +1 na variável contador. (contador++ é o mesmo que: contador = contador +1) if(contador == 1) { //Se o contador for 1 significa que o botão foi pressionado uma única vez PORTC = 0b00100000; PORTD = 0b00000100; }else if (contador == 2){ //Se o contador for 2 significa que o botão foi pressionado duas vezes PORTC = 0b00000000; PORTD = 0b00000101; }else { contador = 0; //zeramos a variável contador PORTC = 0b00000000; PORTD = 0b00000110; } _delay_ms(300); } } 6. Modifique o código de maneira a usar as diretivas: PORTX, DDRX e PINX. Procure no datasheet o que são elas (Seção 18, página 97 do datasheet). Use PXn (ou PORTXn) e DDXn, onde n é o número do pino na porta X. Use ou | e & binários para setar ou desligar bits nos registradores. #include <util/delay.h> #define tst_bit(Y,bit_x)(Y&(1<<bit_x)) //testa o bit x da variável Y (retorna 0 ou 1) #define cpl_bit(Y,bit_x)(Y^=(1<<bit_x)) //troca o estado do bit x da variável Y #define clr_bit(Y, bit_x)(Y &= ~(1 << bit_x)) // limpa o bit x da variável Y (coloca em 0) unsigned long tempoUltimoDebounce = 0; //Variável que armazenará o tempo do último Debounce unsigned long tempoDebounce = 1000; //Tempo (em milissegundos)que é necessário manter o botão pressionado para ter a certeza de que ele foi pressionado de fato. int contador = 0; void setup(){ DDRD = 0b00000011;// saida porta 2 e 3 DDRC = 0b00100000;// saida porta 28 PORTD = 0b0000100;// coloca como a PD3 a entrada do botão PORTC = 0b00000000;// nao alimenta nenhuma porta } void loop(){ if (!tst_bit(PIND, PD2)){// verifica se o botão foi pressionado tempoUltimoDebounce = millis(); while(!tst_bit(PIND, PD2)){// enquanto o botão for pressionado if ((millis() - tempoUltimoDebounce) > tempoDebounce) {//verifica se o tempo que o botao foi pressionado é suficiente para apagar os leds clr_bit (PORTD, PD0);//limpa o bit da PD0 colocando-a em 0 clr_bit (PORTC, PC5);//limpa o bit da PC5 colocando-a em 0 clr_bit (PORTD, PD1);//limpa o bit da PD1 colocando-a em 0 } } _delay_ms(10); contador++; if(contador == 1) { cpl_bit(PORTC, PC5);// troca o estado da PC5 para ligar a led clr_bit(PORTD, PD0); clr_bit(PORTD, PD1); }else if (contador == 2){ clr_bit (PORTC, PC5); cpl_bit (PORTD, PD0);//troca o estado da PD0 para ligar a led clr_bit(PORTD, PD1); }else { contador = 0; clr_bit (PORTC, PC5); cpl_bit (PORTD, PD1);//troca o estado da PD1 para ligar a led clr_bit(PORTD, PD0); } if ((millis() - tempoUltimoDebounce) > tempoDebounce) { clr_bit (PORTD, PD0); clr_bit (PORTC, PC5); clr_bit (PORTD, PD1); } } _delay_ms(100); } 7. Os pinos não usados devem ser configurados como pinos de entrada. 8. Pergunta teórica: É interessante ficar preso em um laço lendo se um botão foi apertado? Quais problemas podem acontecer com o circuito implementado (problemas elétricos quando o botão é pressionado e quando está sendo despressionado – procure por button debouncing)? Seria mais interessante usar uma interrupção (imagine que temos muito código para executar no Loop)? Não, pois o código não consegue realizar outras funções além do loop. Um dos problemas é que, se em um pequeno espaço de tempo o botão for pressionado mais de uma vez pode ocorrer pequenas vibrações que tem como consequência toque nas placas. Sim, pois com a interrupção não há necessidade de usar o loop, assim o código pode executar outras ações. 9. Cole o código fonte do microcontrolador ao final deste arquivo e inclua a imagem de seu design. Importante: Deixe seu circuito público no Tinkercad e cole o link para ele aqui: Diagrama Descrição gerada automaticamente https://www.tinkercad.com/things/0pR2FwJo5wf ATENÇÃO: A função/objetivo deve ocorrer no clique do botão, e não na sua soltura. No caso do clique longo, a função/objetivo deve ocorrer assim que o tempo limite for atingido. ATENÇÃO: Usar as funções pinMode(), digitalWrite() e digitalRead() estão proibidos nesta prática. O uso delas fará a nota atribuída ser zero. ATENÇÃO: Documente seu código. Cada linha/bloco deve deixar explícito o seu papel. ______________________________________________________________ RÚBRICA: Pergunta teórica: 15% Circuito: 15% Diretivas PORT e DDR: 30% Lógica da programação: 40% Valor desta atividade na média: 1.0 Para a entrega você pode apagar o apêndice. APÊNDICE: Calculando o resistor limitador de corrente necessário para um led com características conhecidas. Usando o circuito ao lado, você deve conhecer três valores para determinar o valor do resistor limitador de corrente. i = LED forward current in Amps (found in the LED datasheet) Vf = LED forward voltage drop in Volts (found in the LED datasheet) Vs = Voltagem da fonte Uma vez que você tenha os três valores, é só usar a fórmula: Tenha em mente o seguinte ao usar o circuito acima: - A corrente i, vindo da fonte, atravessando o resistor e o LED, e voltando a fonte é a mesma. (Lei da corrente de Kirchhoff). - A queda de tensão no resistor, mais o forward voltage drop no LED é igual o potencial (voltagem) da fonte. (Lei da voltagem de Kirchhoff). A corrente máxima que um LED suporta varia bastante, mas podemos usar um limite conservador de 10mA, ou seja 0.01A. Valores típicos para a queda de tensão (forward voltage drop) de LEDs: Exemplo de cálculo: Vs = 5V Vf = 2V i = 10mA ou 0.01A R = (5-2)/0.01 = 300 ohms
Compartilhar