Roteiro 8 EA870 2S2009

De DCA-Wiki

Contents

Roteiro 8 - Introdução ao uso de Interrupção: Geração de onda quadrada.

  • Uso do PIT - Timers programáveis geradores de interrupção

Agradecimento

O desenvolvimento deste roteiro teve a grata contribuição de-

Guilherme A. Zalewski (buzzag@gmail.com) e Pedro Augusto (okaitt@gmail.com).

Introdução ao Experimento de Hoje

Atenção, foi feita uma inversão na ordem deste roteiro e o da interrupção via teclado. Entretanto não houve tempo de fazer a adequação dos textos, assim, peço que leiam no roteiro da interrupção do teclado, as partes introdutórias sobre interrupção no ColdFire.

  • Neste experimento iremos continuar a utilizar da interrupção, entretanto com uma aplicação dos timers PIT do MCF. Esses timers fazem a contagem a partir de um módulo(valor) fornecido e geram a interrupção ao chegarem a contagem em zero. Desse modo, fica possível a criação de interrupções síncronas. Através de uma rotina que será vista aqui, a geração de uma onda quadrada é facilmente controlada.

Roteiro de Estudos

  • 1. O que se entende por onda quadrada?
  • 2. O que vem a ser o PIT? Quais são as configurações mais relevantes de PIT para geração da onda quadrada? /3/ cap 19
  • 3. As interrupções usam flags para serem detectadas, quais as flags dos timers PIT? /3/ cap 19
  • 4. Quais os registradores de controle de interrupção dos timers PIT? /3/ cap 19
  • 5. Com base nas duas respostas anteriores, pode-se dizer que os dois timers são funcionais mesmo que simultaneamente? /3/ cap 19
  • 6. Baseado no programa exemplo, por que dizemos que o período da onda é de 2 vezes o período da interrupção?
  • 7. Como obtenho um período de onda quadrada de X segundos? /3/ cap 19
  • 8. O que significa preescaler? /3/ cap 19 (Lembre-se que na verdade o que utilizamos no código para a configuração da interrupção é a potência, e não o valor do preescaler em si).
  • 9 O que significa módulo ? /3/ cap 19
  • 10. Quais são os valores do preescaler e do modulo (uma possibilidade) para que tenhamos um período de onda quadrada de aproximadamente 600 micro segundos ?

Roteiro da Aula

Mais uma vez utilizaremos a interrupção do MCF52221. Agora, programaremos um timer para que gere interrupções a cada tempo pré-determinado e que essa interrupção mude o status de um pino IO comum da placa. Assim, a cada vez que entramos na interrupção, ou seja, a contagem foi estourada, mudamos o pino para 1 ou 0 (dependendo da última configuração), formando uma onda quadrada de período 2x o período da interrupção.

Fique atento agora às configurações e não se esqueça de sempre atualizar o arquivo exceptions.c, assim como no roteiro anterior.

O programa exemplo:

- Programa SQUARE/main.c

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

//Porta TC
#define PORTTC	0x4010000F
#define DDRTC	0x40100027

//Porta AN
#define PORTAN	0x4010000A
#define DDRAN	0x40100022

//Variaveis temporais (controlarao o período da interrupção)
int modulus=0;
int prescaler=0;
int flag=0;
int conta=0;

//Define os apontadores para a porta TC, onde será gerado a onda quadrada
uint8 *ddrtc = (uint8 *)DDRTC;
uint8 *porttc = (uint8 *)PORTTC;

//Idem para a porta AN
uint8 *ddran = (uint8 *)DDRAN;
uint8 *portan = (uint8 *)PORTAN;

__declspec(interrupt) void interrupcao_pit0();  //Declara a função como uma função de interrupção

//Função quando ocorre quando há interrupção
void interrupcao_pit0()
{
//Esta função seta 1 ou 0 na porta TC0 e simultaneamente na porta AN2
//Com isso geramos uma onda quadrada de período 2* o definido pelo contador na MAIN  
//Primeiro verificamos o status da porta:
	conta++; // Apenas para verificar se a rotina de interrupção está funcionando
        if (flag==0)
	{
		//Se a porta ficou abaixada, agora é levantada
		*porttc = 0x01;
		*portan = 0x04;
		//Altera a flag:
		flag = 1;
	}
	else
	{
		*porttc = 0x00;
		*portan = 0x00;
		flag = 0;
	}
        MCF_PIT0_PCSR |= MCF_PIT_PCSR_PIF; // Limpa flag de interrupçãp
}


int main(void)
{
//Vetores que podem ser utilizados
char inicio[41] = {"#### FEEC - GERACAO DE ONDA QUADRADA ####"};
char msg1[23] = {"ENTRE COM O PREESCALER:"};
char msg2[31] = {"ENTRE COM O MODULO DE CONTAGEM:"};
char msg3[8] = {"PERIODO:"};

//Configura a porta TC0 como saída
*ddrtc = 0x01;
*porttc = 0x00;	//Zera a porta TC0

//Configura a porta AN2 como saida
*ddran = 0x04; // Apenas pino AN2 e saida
*portan = 0x00;	//Zera a porta AN0


//Configuração das interrupções gerais
//Queremos liberar apenas para a interrupçao de numero 55 (visto no manual que este é o número do INT0)

MCF_INTC0_ICR55 = 0 | MCF_INTC_ICR_IP(0) | MCF_INTC_ICR_IL(1); //Nivel de prioridade 0
MCF_INTC0_IMRL &= ~MCF_INTC_IMRL_MASKALL;	// Não mascara as interrupções (master)
MCF_INTC0_IMRH &= ~MCF_INTC_IMRH_INT_MASK55;	// Desmascara a interrupção do INT0 (55) (enable)

//Configurações do contador:

//CUIDADO: O CONTADOR CONTA DE CIMA PARA BAIXO, OU SEJA, DE 32000   -->  00000
//         O CONTADOR É DECREMENTANTE.
  
//Define o preescaler:
prescaler = 0x0;	//divisão do clock (divide por 2^0) 
//Define o "modulus"
modulus = 32000;	//Contador começa a partir deste numero E SE DECREMENTA

//PS:
//
//Conta para a frequencia:  Freq = Clock /(modulus * prescaler)
//Com clock = 80000000
//O prescaler pode ser encontrado na referencia /3/ cap 19.
//Esse valor de preescaler e de modulo geram uma onda de 800us

MCF_PIT0_PMR = modulus;	//Decresce apartir deste numero até 0x0000

//Configuração do contador PIT0:
MCF_PIT0_PCSR = (uint16)
 ( MCF_PIT_PCSR_PRE(prescaler) //Define preescaler (divisão do clock)
   | MCF_PIT_PCSR_PIE          //Habilita a geração da interrupção
   | MCF_PIT_PCSR_RLD          //Permite o carregamento automático do modulus
   | MCF_PIT_PCSR_PIF          //Zera flag de interrupção
   | MCF_PIT_PCSR_EN           //Habilita o contador
 ); 

//Definição de prioridade do microprocessador (Nivel 0 como o INT0)
asm {
	  move.w #0x2000, sr
    }

//Apartir daqui, o contador já foi liberado e entrará na função caso estoure a contagem
//Podemos executar qualquer código aqui, e será interrompido ao se obter a onda quadrada

//Uma simples espera:
while(1) {
  printf("(%d)", conta); // esta variável está sendo incrementada na rotina de interrupção
  }
}

Da mesma forma como o roteiro do teclado, precisamos informar que a rotina que vai tratar a interrupção de teclado é a interrupcao_pit0. 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 é /* 119 (0x___) Reserved */, apague asm_exception_handler, e escreva o nome da nossa função de tratamento de interrupção, interrupcao_pit0. O trecho de código resultante será algo assim:
...
asm_exception_handler,           /*  118 (0x___) Reserved */
interrupcao_pit0,                /*  119 (0x___) Reserved */
asm_exception_handler,           /*  120 (0x___) Reserved */
...

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 interrupcao_pit0(); , para que ele saiba que a função existe.


Agora, para a confecção do relatório, podemos utilizar novamente as funções de envio e recebimento da UART0 em C visto no relatório de PWM. Abaixo estão as funções:

#include "uart_support.h"  //Nao se esqueça de colocar este include
...
int main(){
...
uart_init(0,80000,9600);  //Apenas inicialize uma vez o periférico
...
uart_putchar(0,'A');  //Envia um char
...
algum_char = uart_getchar(0);  //Pega um char digitado
...
}

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 o programa exemplo tendando entender exatamente como ele funciona.
  • 2. Utilizando como base o exemplo, construa um programa que:
    • Inicialmente envie a requisição dos dados da onda, da seguinte forma:
#### FEEC - GERACAO DE ONDA QUADRADA ####
ENTRE COM O PREESCALER:
ENTRE COM O MODULO DE CONTAGEM:
    • Deve-se receber pelo programa Hyperterminal - transmissão serial - os dados para geração da onda. Aguarde um <ENTER> depois de cada dado. Ao receber o dado envio-o de volta de modo a formar um eco no hyperterminal.
    • O valor do PREESCALER deve ser de 0 a 15 em decimal (essa será a potência do 2 o qual o clock será dividido /3/ - Cap.19) e o MODULO DE CONTAGEM deve entar no intervalo de 0 a 65536 (2^16).
    • A partir do dado recebido deve-se preparar o programa para enviar a onda, entretanto aguarde o SWA ser pressionado.
    • Além de iniciar a geração de onda deve-se enviar ao hyperterminal o período da onda, da seguinte maneira/5/:
PERIODO:
    • A onda gerada deverá ser observada em um osciloscópio. Faça isto na saída AN2 (conectores da entrada analógica, terra no parafuso de cima). No caso de valores elevados de prescaler e/ou módulo, basta observar o LED da placa ligado em TC0, piscando em baixa frequência.
  • 3. Após executar o código faça um fluxograma do mesmo.
      • DICA: Para fazer a mudança de linha corretamente deve-se usar o "line-feed"(0x0A) seguido do retorno de carro "carriage return"(0x0D).
      • DICA: O <ENTER> recebido serialmente possui código hexadecimal 0x0D.
      • DICA: inicio, msg1, msg2 e msg3 são vetores e cada caractere pode ser acessado separadamente.

- Referências

Ferramentas pessoais