Universidade Federal de Itajubá [email protected]
Reprodução de Sons e Timers
Timers
São circuitos eletrônicos que realizam a contagem do tempo, podendo ou não disparar eventos em determinados instantes.
Timers
Ao invez de contarmos a quantidade de ciclos que queremos esperar e utilizar um loop for vazio, podemos utilizar os timers Modo de operação
Inicializam-se as congurações necessárias
Prescaler
Fonte de clock
Quantidade de bits (Timer0 apenas)
Congura-se o timer com o valor desejado1
Dispara o hardware
6
7 void AguardaTimer(void){ 8 while(!BitTst(INTCON,2));
9 }
10
11 void ResetaTimer(unsigned int tempo){
12 unsigned ciclos = tempo * 2; //para 8MHz, 1 ms = 2 ciclos
13 ciclos = 65535 - ciclos; //overflow com 2^15-1 = 65535 (16 bits)
14 ciclos -= 14; //subtrai tempo de overhead(experimental) 15 TMR0H = (ciclos >> 8); //salva a parte alta
16 TMR0L = (ciclos & 0x00FF); //salva a parte baixa 17 BitClr(INTCON,2); //limpa a flag de overflow
Interrupções
Até agora, o uxo do programa é determinado apenas pelo programa principal
Problema
Alguns periféricos necessitam de um tempo para que possam executar suas tarefas
Este tempo era gasto fazendo nada - loop vazio - enquanto esperamos uma variável ou ag mudar de estado
Interrupção
Solução: Interrupção
Desenvolver um sistema que nos avise quando uma determinada tarefa acabou
Este sistema deve ser acionado automaticamente
O uxo do programa não deve ser alterado
O dispositivo/periférico em questão deve estar preparado para gerar uma interrupção
Programa
Principal InterrupçãoRotina de ProgramaPrincipal Latência da
Interrupção Acontece a
Interrupção da ISRInicio Continua o fluxodo programa
Tempo Latência da
Interrupção Fim da
Interrupção
Quando gerada uma interrupção o programa é paralizado e uma função de interrupção é executada
Conversor AD: quando o resultado da conversão estiver disponível para leitura.
Porta B: quando algum dos bits congurados como entrada altera seu valor.
Atenção
A função que irá tratar da interrupção não retorna nem recebe nenhum valor
Interrupção
1 //Usando compilador C18 da microchip 2 void NomeDaFuncao(void)
3 {
4 //código ...
5 }
6
7 //Indicar a posição no vetor de interrupções 8 #pragma code high_vector=0x08
9 void interrupt_at_high_vector(void)
10 {
11 _asm GOTO Interrupcao _endasm
12 }
13 #pragma code
1 void NomeDaFuncao(void) interrupt 1
2 {
3 //código ...
Interrupção
Existe uma correlação entre
o número que vem depois da expressão interrupt para o compilador SDCC
o número ao nal da expressão #pragma code high_vector para o C18
Estes números representam a posição para a qual o
microcontrolador vai quando acontece uma interrupção. Estas posições estão numa área conhecida como vetor de
0x00(0)
0x08(1)
0x18(2)
Como muitos periféricos são mapeados na mesma interrupção, a função deve ser capaz de diferenciar entre as diversas fontes de requisição.
Uma maneira de se realizar esta vericação é através das ags de controle, ou seja, bits que indicam a situação de cada
Interrupção
1 void Interrupcao(void) interrupt 1 {
2 if (BitTst(PIR1,0)) { /*codigo*/ } //overflow do TIMER1
3 if (BitTst(PIR1,1)) { /*codigo*/ } //comparação do TIMER2 com PR2 4 if (BitTst(PIR1,2)) { /*codigo*/ } //comparação do CCP1
5 if (BitTst(PIR1,3)) { /*codigo*/ } //fim de operação na porta paralela 6 if (BitTst(PIR1,4)) { /*codigo*/ } //fim de transmissão da Serial 7 if (BitTst(PIR1,5)) { /*codigo*/ } //recepção da Serial
8 if (BitTst(PIR1,6)) { /*codigo*/ } //fim de conversão do AD
9 if (BitTst(PIR1,7)) { /*codigo*/ } //leitura/escrita da porta paralela 10 if (BitTst(PIR2,0)) { /*codigo*/ } //comparação do CCP2
11 if (BitTst(PIR1,1)) { /*codigo*/ } //overflow do TIMER3
12 if (BitTst(PIR1,2)) { /*codigo*/ } //condição de Tensão Alta/Baixa
13 if (BitTst(PIR1,3)) { /*codigo*/ } //detecção de colisão no barramento 14 if (BitTst(PIR1,4)) { /*codigo*/ } //fim escrita na memoria flash 15 if (BitTst(PIR1,5)) { /*codigo*/ } //interrupção da USB
16 if (BitTst(PIR1,6)) { /*codigo*/ } //mudança na entrada de comparação 17 if (BitTst(PIR1,7)) { /*codigo*/ } //falha no oscilador
6 ADvalor = ADRESH ; // lê o resultado 7 ADvalor <<= 8;
8 ADvalor += ADRESL;
9 BitClr(PIR1,6); //limpa a flag
10 }
11 if (BitTst(PIR1,5)) //Serial: recepção { 12 Serial = RCREG; //limpa sozinho quando lê
13 //BitClr(PIR1,5);
14 }
15 if (BitTst(INTCON,2)) //TIMER0: Overflow{ 16 ResetaTimer(50000);
Interrupção
1 BitClr(RCON,7); //desabilita IPEN (modo de compatibilidade) 2 BitSet(PIE1,6); // liga a interrupção para o AD
3 BitSet(PIE1,5); // liga a interrupção para a recepção na serial 4 BitSet(INTCON,5); // liga a interrupção para o timer 0
5 BitSet(INTCON,3); // liga a interrupção para a porta B
6 BitSet(INTCON,7); //habilita todas as interrupções globais 7 BitSet(INTCON,6); //habilita todas as interrupções de periféricos
Interrupção
Filme: O m do loop innito Estrelado por: Watchdog Do mesmo diretor de:
A volta dos que não morram
Poeira em alto mar
Situações incômodas num programa que está rodando
Loop innito
Dead lock
Watchdog
Watchdog
O watchdog visa aumentar a segurança do projeto. Funciona como um temporizador
Precisa ter seu contador constantemente reiniciado.
Caso não seja reiniciado no tempo exigido, o watchdog reinicia o microcontrolador
Interrupção
1 //code char at 0x300003 CONFIG2H = 0x00; // Watchdog controlado por software
2
3 #define CLRWTD() _asm CLRWDT _endasm 4
5 void main(void) interrupt 0
6 {
7 unsigned int i; 8 unsigned char temp; 9 TRISD=0x00;
10 PORTD=0x00;
11 BitSet(WDTCON,0); //liga o sistema de watchdog
12 for(;;)
13 {
14 PORTD++;
15 for(i = 0; i < 10000; i++)
Atenção
O #dene criado na primeira linha do programa anterior faz uso das diretivas _asm e _endasm
Estas diretivas indicam que o código a seguir não deve ser alterado pelo compilador
O comando CLRWDT indica que o micro deve resetar o watchdog