Roteiro 9 EA870 2S2009

De DCA-Wiki

Contents

Roteiro 9 - Introdução ao teclado e uso de interrupção

  • Experimento com o uso de interrupções
  • Introdução ao uso do teclado da placa auxiliar

Agradecimento

O desenvolvimento deste roteiro teve a grata contribuição de: Carlos Manuel S Cabral, Guilherme A Zalewski (buzzag@gmail.com) e Pedro Augusto (okaitt@gmail.com).

Introdução ao Experimento de Hoje

  • No experimento de hoje, utilizaremos o teclado que possuímos em nossa placa auxiliar. Aprenderemos também uma maneira muito mais eficiente e elegante para tratar requisições de I/O: as interrupções.
  • Lembre-se: utilize as referências de programação em C em caso de dúvidas /1/,/4/.

Roteiro de Estudos

  • 1. Explique, brevemente, como funciona uma matriz de teclado. Tente projetar um circuito.
  • 2. Considere uma matriz de teclado simples, de 3x3 teclas. Como devemos proceder para verificar se a tecla na posição (2,1) está apertada?
  • 3. O que é polling (busy-wait polling)? Lembre-se que utilizamos até hoje essa técnica.
  • 4. O que é uma interrupção?
  • 5. Interrupções são uma melhor opção para tratar requisições de I/O do que o polling. Por que?
  • 6. Explique, brevemente, como funciona o modelo de interrupções do Coldfire.
  • 7. Qual a diferença entre interrupções e exceções? Como as exceções são tratadas no Coldfire?

Roteiro da Aula

Exemplo 1 - Código de Varredura do Teclado (Feito por Guilherme A. Zalewski)

O código a seguir varre o teclado e assinala quais teclas estão pressionadas.

- Programa VARRE_TECLADO/main.c

#include "support_common.h" /* include peripheral declarations and more */
#include <stdio.h>          /* see stdio in /6/  */

#define PORTTC  0x4010000F
#define DDRTC   0x40100027
#define PORTUBP 0x40100042
#define DDRUB   0x4010002A
#define PUBPAR  0x40100072

void varre_teclado(int situacao[])
{
	int i,j, mask;
	int aterra[4] = {0x0E000000,0x0D000000,0x0B000000,0x07000000}; /*Sequencia de saidas para as portas*/
	int io[4] = {0x01000000,0x02000000,0x04000000,0x08000000}; /*Sequencia de configuracao de porta*/
	int *end_aterra = (int *)aterra;  /*Recebe o endereco do vetor de dados*/ 
	int *end_io  = (int *)io; /*Recebe o endereco do vetor de dados*/ 
	int *end_key = (int *)situacao; /*Recebe o endereco do vetor de status do teclado*/ 
	int *porttc  = (int *)PORTTC;
	int *ddrtc   = (int *)DDRTC;
	int *portubp = (int *)PORTUBP;
	int *ddrub   = (int *)DDRUB;
	int *pubpar  = (int *)PUBPAR;

	*pubpar = 0xFF; /*Configura porta UB para trabalhar como porta comum*/
	*ddrub = 0xFF;	/*Configura UB como ENTRADA*/

	/*Rotina para varrer teclado. Previne contra curto quando mais teclas estao apertadas ao mesmo tempo*/
	for (i=0; i<4; i++){  

	/*Faz a leitura da linha i*/
	*ddrtc = *end_io; /*Configura TCi como saida e o restante como entrada*/
	*porttc = *end_aterra; /*Seta ZERO no bit TCi*/

	end_aterra++;  /*Pega o dado seguinte, aterra ou nao*/
	end_io++; /*Pega a configuracao seguinte, Entrada ou Saida*/
	mask = 0x01000000; /*Configura mascara para detectar botao apertado ou nao*/

		for (j=0;j<3;j++){
		
		/*Caso o botao esteja apertado, o bit i do registrador PORTUBP estara em ZERO*/
		if(!(mask & *portubp)) *end_key = 1;
		else *end_key = 0;
        
        mask = mask <<1; /*Verifica bit seguido (colula j)*/
    	end_key++; /*Passa para proximo digito no vetor TECLADO*/
		}
	}
}


int main(void)
{
    int i;
	int teclado[12]={0,0,0,0,0,0,0,0,0,0,0,0};

	varre_teclado(teclado); /*Chama funcao*/
	
	for (i=0;i<12;i++) printf("%d", teclado[i]);  //joga valor na tela
	printf("\n\n");
}
  • Crie um novo projeto no CodeWarrior e utilize o código acima como código principal (main).
  • Utilizando o esquemático de nossa placa auxiliar, busque entender exatamente o que o código faz. Lembre-se de como funciona uma matriz de teclado.

ATENÇÃO: Experimentalmente, para as turmas E e F, o roteiro desta experiência será outro: Roteiro 9 EA870 2S2009 Experimental.


Exemplo 2 - Código do Teclado com interrupção

O código a seguir utiliza a mesma versão da varredura do teclado, porém, agora o processador não fica verificando o teclado; o teclado 'informa' ao processador houve alguma alteração em seu estado, através de interrupção.

- Programa INT_TECLADO/main.c

#include "support_common.h" /* include peripheral declarations and more */
#include <stdio.h>

#define IPSBAR 0x40000000

#define EPPAR IPSBAR + 0x00130000
#define EPIER IPSBAR + 0x00130003
#define EPFR  IPSBAR + 0x00130006
#define IMRL  IPSBAR + 0x00000C0C
#define PORTTC  0x4010000F
#define DDRTC   0x40100027
#define PORTUBP 0x40100042
#define DDRUB   0x4010002A
#define PUBPAR  0x40100072

uint8 *epfr = (uint8*) EPFR;
uint16 *eppar = (uint16*) EPPAR;	
uint8 *epier = (uint8*) EPIER;
uint32 *imrl = (uint32*) IMRL;
uint8 *epdr = (uint8*) IPSBAR + 0x00130004;
int *porttc  = (int *)PORTTC;
int *ddrtc   = (int *)DDRTC;
int *portubp = (int *)PORTUBP;
int *ddrub   = (int *)DDRUB;
int *pubpar  = (int *)PUBPAR;

//Código essencial para declarar a função de interrupção:
__declspec(interrupt) void trata_int_teclado();  //Declara a função como uma função de interrupção

//Função varre telcado
void varre_teclado(int situacao[])
{
	int i,j, mask;
	int aterra[4] = {0x0E000000,0x0D000000,0x0B000000,0x07000000}; /*Sequencia de saidas para as portas*/
	int io[4] = {0x01000000,0x02000000,0x04000000,0x08000000}; /*Sequencia de configuracao de porta*/
	int *end_aterra = (int *)aterra;  /*Recebe o endereco do vetor de dados*/ 
	int *end_io  = (int *)io; /*Recebe o endereco do vetor de dados*/ 
	int *end_key = (int *)situacao; /*Recebe o endereco do vetor de status do teclado*/ 

	*pubpar = 0xFF; /*Configura porta UB para trabalhar como porta comum*/
	*ddrub = 0xFF;	/*Configura UB como ENTRADA*/

	/*Rotina para varrer teclado. Previne contra curto quando mais teclas estao apertadas ao mesmo tempo*/
	for (i=0; i<4; i++){  

	/*Faz a leitura da linha i*/
	*ddrtc = *end_io; /*Configura TCi como saida e o restante como entrada*/
	*porttc = *end_aterra; /*Seta ZERO no bit TCi*/

	end_aterra++;  /*Pega o dado seguinte, aterra ou nao*/
	end_io++; /*Pega a configuracao seguinte, Entrada ou Saida*/
	mask = 0x01000000; /*Configura mascara para detectar botao apertado ou nao*/

		for (j=0;j<3;j++){
		
		/*Caso o botao esteja apertado, o bit i do registrador PORTUBP estará em ZERO*/
		if(!(mask & *portubp)) *end_key = 1;
		else *end_key = 0;
        
        mask = mask <<1; /*Verifica bit seguido (colula j)*/
    	end_key++; /*Passa para próximo digito no vetor TECLADO*/
		}
	}
}

//Função que define a prioridade do microprocessador (prioridade 3, ou seja, 3 ou mais é aceita)
void define_prioridade()
{
	asm
	{
	move.w #0x2300, sr
	}
}

//Função para iniciar o teclado
void inicia_teclado()
{
	*ddrtc = 0xFF000000;
	*porttc = 0;
	*pubpar = 0xFF; /*Configura porta UB para trabalhar como porta comum*/
	*ddrub = 0xFF;	/*Configura UB como ENTRADA*/			
}

//Função para iniciar a interrupção do teclado (deixa-o pronto para receber a interrupção)
void habilita_teclado()
{		
	*epfr = 0b00010000; // reseta flag de IRQ4
	*epier = 0b00010000; // habilita interrupções de IRQ4
	*eppar = 0x0200; // configura interrupção para ser percebida na borda de descida
	*epdr = 0x10; // configura IRQ4 como input
	*imrl = 0xFFFFFFEF; // habilita o tratamento de interrupção
}

//Função que executa ao RECEBER a interrupção
void trata_int_teclado()
{
	int i;
	int teclado[12]={0,0,0,0,0,0,0,0,0,0,0,0};
	
	
	varre_teclado(teclado); /*Chama funcao*/
	
	for (i=0;i<12;i++) printf("%d", teclado[i]);  //joga valor na tela
	printf("\n\n");
    
    inicia_teclado();
    *epfr = 0b00010000; // reseta flag de IRQ4                      
}

//Função principal
int main () 
{
	define_prioridade();
	inicia_teclado();
	habilita_teclado();
	
	while(1)
	{
        //Aguarda ocorrer a interrupção
        //Neste tempo, pode ser executado qualquer código pelo Microprocessador
	}
}

Também precisamos informar que a rotina que vai tratar a interrupção de teclado é a trata_int_teclado. Para isso, faça:

  • Crie um novo projeto no CodeWarrior e utilize o código acima como código principal (main).
  • Um arquivo, exceptions.c, é automaticamente criado. Vamos alterá-lo.
  • Na linha cujo comentário é /* 68 (0x110) Device-specific interrupts */, apague asm_exception_handler, e escreva o nome da nossa função de tratamento de interrupção, trata_int_teclado. O trecho de código resultante será algo assim:
...
asm_exception_handler,           /*  67 (0x10C) Device-specific interrupts */
trata_int_teclado,               /*  68 (0x110) Device-specific interrupts */
asm_exception_handler,           /*  69 (0x114) Device-specific interrupts */
...

Não se esqueça também que no mesmo arquivo, o exceptions.c, deve ser colocado depois de TODAS as definições o seguinte código: void trata_int_teclado(); , para que ele saiba que a função existe.

Relatório

(Veja na página da disciplina, na opção calendário a data referente à entrega de cada relatório).

  • 1. Faça o fluxograma para os programas dos exemplos 1 e 2. Atente para a alteração do fluxo existente quando uma interrupção ocorre.
  • 2. Baseado nos exemplos, crie um programa, SEM INTERRUPÇÃO, que faça o seguinte:
    • O usuário vai digitar números decimais via teclado, de no máximo 3 dígitos (número máximo: 999). Ao digitar um número, ele confirma com a tecla "#" (funciona como um enter). A seguir, o usuário pode digitar mais números. A seqüência é finalizada quando o usuário pressionar "*", depois do último enter ("#"). Você deverá somar todos os números digitados e imprimir a soma via I/O console.
  • 3. Faça o mesmo programa do exercício anterior, mas agora, UTILIZANDO INTERRUPÇÕES.
  • 4. Faça o fluxograma dos programas feitos por você nos itens 2 e 3.

- Referências

Ferramentas pessoais