Mren_5

Autor: Renan Rodrigues Fioritti
Data: 26/05/2010

Programa de piscar LED

Como esperado, as placas montadas estão funcionando. Sendo assim, programou-se quatro maneiras de piscar o LED, sendo que duas (a primeira utilizando o oscilador interno a partir de um laço simples, e a outra utilizando o cristal externo e temporizador). Os dois outros projetos são desenvolvidos pelo outro integrante da dupla.

Sendo assim, o código do programa que pisca o LED a partir de um laço simples é mostrado logo abaixo:

#include <hidef.h> /* for EnableInterrupts macro */
#include "derivative.h" /* include peripheral declarations */

int i; // declaração da variável i

void main(void) {

  PTFDD = 0x80; // inicializa PTB7 como saída de dados
  PTFD = 0;  // zera PTB

  for(;;){              // loop eterno para piscar o led
    for (i=1;i<100000;i++) {        // loop utilizando o clock interno da CPU
      __RESET_WATCHDOG();   // reseta watchdog para o programa não terminar
    }
    PTFD_PTFD7 = ~PTFD_PTFD7;   // inverte o sinal da porta F, fazendo o led piscar

  }
}

É importante salientar que este programa é bastante desvantajoso, pois mantém a CPU totalmente ocupada para fazer o LED piscar. Em compensação, ao se carregar o código no microcontrolador, o led piscará a uma taxa de algumas frações de segundo, cabendo ao usuário ajustar o limite da variável i no código de tal forma a acompanhar a velocidade de piscagem do led.

A outra implementação do projeto de piscar o LED é utilizando o temporizador e o cristal externo. Sendo assim, As configurações seguintes foram aplicadas: Primeiramente iniciou-se um novo projeto no Processor Expert. Em seguida, ajustou-se, em “Component Inspector” os seguintes parâmetros:

  • Desabilitou-se o clock interno de referência;
  • Habilitou-se o clock externo, configurando de modo em que fique o cristal externo como fonte de relógio;
  • A freqüência do mesmo foi ajustada para 32678Hz.

Os parâmetros modificados se encontram na figura abaixo:

/media/Attachments/courseEA079_1S2010/Mren_5/cristal_config.JPG

Figura 1: Modificações que foram realizadas no ajuste de clock

Em seguida, clicou-se em Init MTIM no canto inferior esquerdo da figura, abrindo uma nova janela de “Component Inspector”. O intuito agora é utilizar o módulo temporizador MTIM. Com isso, os seguintes parâmetros foram modificados:

  • A freqüência de clock foi fixada;
  • Foi ajustado Prescaler e Modulo Register de tal modo que o programa consiga contar até 1 segundo.

Sendo assim, essas configurações possibilitam ao programador gerar um código tal que faça um led apagar e acender a cada 1 segundo que se passa. A figura abaixo ilustra as modificações realizadas:

/media/Attachments/courseEA079_1S2010/Mren_5/cristal_config2.JPG

Figura 2: Modificações para o módulo temporizador MTIM.

Nota-se que as interrupções estão desabilitadas, sendo que a parte em que se usa interrupção está desenvolvida pelo outro integrante da dupla.

Clica-se em “generate code” na aba “Processor Expert” na parte superior da tela para gerar assim os códigos a serem desenvolvidos utilizando as especificações já configuradas até então. O programa principal se encontra na pasta “User Modules” e possui o mesmo nome do projeto criado anteriormente, com a extensão .c. O programa “vazio” se encontra deste jeito:

void main(void)
{
/* Write your local variable definition here */
/*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
 PE_low_level_init();
/*** End of Processor Expert internal initialization. ***/
/* Write your code here */
/* For example: for(;;) { } */
/*** Don't write any code pass this line, or it will be deleted during code generation. ***/
/*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
for(;;){}
/*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

Nota-se que existe uma função chamada de PE_low_level_init(), na qual dentro dela pode-se verificar o seguinte código:

void PE_low_level_init(void)
{
  /* SCGC1: MTIM1=1,TPM2=1,TPM1=1,ADC=1,IIC2=1,IIC1=1,SCI2=1,SCI1=1 */
  setReg8(SCGC1, 0xFF);
  /* SCGC2: SCI3=1,FTSR=1,IRQ=1,KBI2=1,KBI1=1,RTC=1,SPI2=1,SPI1=1 */
  setReg8(SCGC2, 0xFF);
  /* SCGC3: PTH=0,PTG=1,PTF=1,PTE=1,PTD=1,PTC=1,PTB=1,PTA=1 */
  setReg8(SCGC3, 0x7F);
  /* SCGC4: ??=1,??=1,??=1,MTIM2=1,MC=1,MB=0,FEC=1,PTJ=1 */
  setReg8(SCGC4, 0xFB);
  /* Common initialization of the CPU registers */
  /* PTASE: PTASE7=0,PTASE6=0,PTASE5=0,PTASE4=0,PTASE3=0,PTASE2=0,PTASE1=0,PTASE0=0 */
  setReg8(PTASE, 0x00);
  /* PTBSE: PTBSE7=0,PTBSE6=0,PTBSE5=0,PTBSE4=0,PTBSE3=0,PTBSE2=0,PTBSE1=0,PTBSE0=0 */
  setReg8(PTBSE, 0x00);
  /* PTCSE: PTCSE7=0,PTCSE6=0,PTCSE5=0,PTCSE4=0,PTCSE3=0,PTCSE2=0,PTCSE1=0,PTCSE0=0 */
  setReg8(PTCSE, 0x00);
  /* PTDSE: PTDSE7=0,PTDSE6=0,PTDSE5=0,PTDSE4=0,PTDSE3=0,PTDSE2=0,PTDSE1=0,PTDSE0=0 */
  setReg8(PTDSE, 0x00);
  /* PTESE: PTESE7=0,PTESE6=0,PTESE5=0,PTESE4=0,PTESE3=0,PTESE2=0,PTESE1=0,PTESE0=0 */
  setReg8(PTESE, 0x00);
  /* PTFSE: PTFSE7=0,PTFSE6=0,PTFSE5=0,PTFSE4=0,PTFSE3=0,PTFSE2=0,PTFSE1=0,PTFSE0=0 */
  setReg8(PTFSE, 0x00);
  /* PTGSE: PTGSE3=0,PTGSE2=0,PTGSE1=0,PTGSE0=0 */
  clrReg8Bits(PTGSE, 0x0F);
  /* PTJSE: PTJSE1=0,PTJSE0=0 */
  clrReg8Bits(PTJSE, 0x03);
  /* PTADS: PTADS7=1,PTADS6=1,PTADS5=1,PTADS4=1,PTADS3=1,PTADS2=1,PTADS1=1,PTADS0=1 */
  setReg8(PTADS, 0xFF);
  /* PTBDS: PTBDS7=1,PTBDS6=1,PTBDS5=1,PTBDS4=1,PTBDS3=1,PTBDS2=1,PTBDS1=1,PTBDS0=1 */
  setReg8(PTBDS, 0xFF);
  /* PTCDS: PTCDS7=1,PTCDS6=1,PTCDS5=1,PTCDS4=1,PTCDS3=1,PTCDS2=1,PTCDS1=1,PTCDS0=1 */
  setReg8(PTCDS, 0xFF);
  /* PTDDS: PTDDS7=1,PTDDS6=1,PTDDS5=1,PTDDS4=1,PTDDS3=1,PTDDS2=1,PTDDS1=1,PTDDS0=1 */
  setReg8(PTDDS, 0xFF);
  /* PTEDS: PTEDS7=1,PTEDS6=1,PTEDS5=1,PTEDS4=1,PTEDS3=1,PTEDS2=1,PTEDS1=1,PTEDS0=1 */
  setReg8(PTEDS, 0xFF);
  /* PTFDS: PTFDS7=1,PTFDS6=1,PTFDS5=1,PTFDS4=1,PTFDS3=1,PTFDS2=1,PTFDS1=1,PTFDS0=1 */
  setReg8(PTFDS, 0xFF);
  /* PTGDS: PTGDS7=0,PTGDS6=0,PTGDS5=0,PTGDS4=0,PTGDS3=1,PTGDS2=1,PTGDS1=1,PTGDS0=1 */
  setReg8(PTGDS, 0x0F);
  /* PTJDS: ??=0,??=0,PTJDS5=0,PTJDS4=0,PTJDS3=0,PTJDS2=0,PTJDS1=1,PTJDS0=1 */
  setReg8(PTJDS, 0x03);
  /* PTAIFE: PTAIFE7=0,PTAIFE6=0,PTAIFE5=0,PTAIFE4=0,PTAIFE3=0,PTAIFE2=0,PTAIFE1=0,PTAIFE0=0 */
  setReg8(PTAIFE, 0x00);
  /* PTBIFE: PTBIFE7=0,PTBIFE6=0,PTBIFE5=0,PTBIFE4=0,PTBIFE3=0,PTBIFE2=0,PTBIFE1=0,PTBIFE0=0 */
  setReg8(PTBIFE, 0x00);
  /* PTCIFE: PTCIFE7=0,PTCIFE6=0,PTCIFE5=0,PTCIFE4=0,PTCIFE3=0,PTCIFE2=0,PTCIFE1=0,PTCIFE0=0 */
  setReg8(PTCIFE, 0x00);
  /* PTDIFE: PTDIFE7=0,PTDIFE6=0,PTDIFE5=0,PTDIFE4=0,PTDIFE3=0,PTDIFE2=0,PTDIFE1=0,PTDIFE0=0 */
  setReg8(PTDIFE, 0x00);
  /* PTEIFE: PTEIFE7=0,PTEIFE6=0,PTEIFE5=0,PTEIFE4=0,PTEIFE3=0,PTEIFE2=0,PTEIFE1=0,PTEIFE0=0 */
  setReg8(PTEIFE, 0x00);
  /* PTFIFE: PTFIFE7=0,PTFIFE6=0,PTFIFE5=0,PTFIFE4=0,PTFIFE3=0,PTFIFE2=0,PTFIFE1=0,PTFIFE0=0 */
  setReg8(PTFIFE, 0x00);
  /* PTGIFE: PTGIFE3=0,PTGIFE2=0,PTGIFE1=0,PTGIFE0=0 */
  clrReg8Bits(PTGIFE, 0x0F);
  /* PTJIFE: PTJIFE1=0,PTJIFE0=0 */
  clrReg8Bits(PTJIFE, 0x03);
  /* PTDPF1: D6=0,D5=3,D4=3 */
  clrSetReg8Bits(PTDPF1, 0x30, 0x0F);
  /* PTCPF2: C3=0 */
  clrReg8Bits(PTCPF2, 0xC0);
  /* SOPT3: CS=0,PCS=0 */
  clrReg8Bits(SOPT3, 0x1F);
  /* ### Shared modules init code ... */
  /* ### Init_MTIM "MTIM3" init code ... */
  MTIM3_Init();
  /* INTC_WCR: ENB=1,??=0,??=0,??=0,??=0,MASK=0 */
  setReg8(INTC_WCR, 0x80);
  /* Set initial interrupt priority 0 */
  asm {
    move.w SR,D0;
    andi.l #0xF8FF,D0;
    move.w D0,SR;
  }
}

A grosso modo, a função inicializa as configurações realizadas no processor expert, tais como o cristal externo e o módulo temporizador. Na parte em assembly, a idéia básica desses três comandos é de mascaramento dos bits 8,9 e 10 do registrador de status (SR) do microcontrolador, alocando zeros nesses bits.

Finalmente, o programa que pisca o led foi realizado da seguinte forma:

void main(void)
{
  PE_low_level_init();
  PTBDD = 0x80; // inicializa PTB7 como saída de dados
  PTBD = 0;  // zera PTB
  MTIM1SC_TRST = 1;
  MTIM1SC_TSTP = 0; // Inicializa módulo temporizador

  for(;;){
  if(MTIM1SC_TOF==1){

    PTFD_PTFD7=~PTFD_PTFD7;  // Barra valor da porta F
    MTIM1SC_TOF = 0;         //Zera registrador TOF
  }
}

Percebe-se pelo código acima que foram utilizados alguns registradores, tais como MTIM1SC_TRST, MTIM1SC_TSTP e MTIM1SC_TOF. Ambos os registradores são declarados da seguinte forma:

/*** MTIM1SC - MTIM Clock Configuration Register; 0xFFFF82A0 ***/
typedef union {
  byte Byte;
  struct {
    byte             :1;
    byte             :1;
    byte             :1;
    byte             :1;
    byte TSTP        :1;                                       /* MTIM Counter Stop */
    byte TRST        :1;                                       /* MTIM Counter Reset */
    byte TOIE        :1;                                       /* MTIM Overflow Interrupt Enable */
    byte TOF         :1;                                       /* MTIM Overflow Flag */
  } Bits;
} MTIM1SCSTR;
extern volatile MTIM1SCSTR _MTIM1SC @0xFFFF82A0;
#define MTIM1SC                         _MTIM1SC.Byte
#define MTIM1SC_TSTP                    _MTIM1SC.Bits.TSTP
#define MTIM1SC_TRST                    _MTIM1SC.Bits.TRST
#define MTIM1SC_TOIE                    _MTIM1SC.Bits.TOIE
#define MTIM1SC_TOF                     _MTIM1SC.Bits.TOF

#define MTIM1SC_TSTP_MASK               0x10
#define MTIM1SC_TRST_MASK               0x20
#define MTIM1SC_TOIE_MASK               0x40
#define MTIM1SC_TOF_MASK                0x80

Percebe-se primeiramente que esses registradores são parte de uma estrutura de dados MTIM1SC, localizado no endereço 0xFFFF82A0 da memória. Ambos os registradores possuem 1 byte de tamanho, sendo que MTIM1SC_TRST é o contador de reset do módulo temporizador, MTIM1SC_TSTP é o contador de parada e MTIM1SC_TOF é o contador de overflow. Partindo deste princípio, no programa de piscar o led, o contador de reset foi setado a fim de iniciar a contagem do temporizador. O contador de parada foi zerado a fim de que o contador não pare de contar. Sendo assim, ao entrar no loop infinito, o programa irá executar a inversão do valor lógico do led se, e somente se o contador de overflow obtiver valor 1. Ou seja, o led irá trocar de valor se o contador do temporizador atingir um certo valor no qual setou o contador de overflow. Ao atingir esse valor, o mesmo é zerado, para que o temporizador continue contando até atingir overflow novamente, piscando o led novamente. Tendo em vista essas noções teóricas, o programa principal foi carregado no microcontrolador, observando assim a piscagem do led a cada 1 segundo aproximadamente, como previsto. Nota-se que ainda sim o programa é desvantajoso, pois a não utilização de interrupção acarreta em ocupação extrema de espaço de memória da CPU. Uma das vantagens deste programa em relação ao outro é de que o tempo de oscilação já é previamente calculado em segundos, cabendo ao programador ajustar a frequência de operação de seu programa em tempos mais usuais.

Interface RS-232

A interface RS-232 é uma porta serial, ou seja, ela transmite e recebe dados de forma assíncrona. RS é uma abreviação de “Recommended Standard”. Ela relata uma padronização de uma interface comum para comunicação de dados entre equipamentos. Antigamente, utilizava-se linha telefônica para a troca de dados digitais, sendo necessário um modem para decodificação de sinais. Sendo assim, criou-se o padrão RS-232. Ele especifica as tensões, temporizações e funções dos sinais, um protocolo para troca de informações, e as conexões mecânicas. As maiores dificuldades encontradas pelos usuários na utilização da interface RS232 incluem pelo menos um dos seguintes fatores:

  • A ausência ou conexão errada de sinais de controle, resultam em estouro do buffer (“overflow”) ou travamento da comunicação.
  • Função incorreta de comunicação para o cabo em uso, resultam em inversão das linhas de Transmissão e Recepção, bem como a inversão de uma ou mais linhas de controle (“handshaking”).

O RS-232 atribui funções particulares aos fios em um cabo serial. Além de dois  condutores usados para dados, vários outro são necessários para handshaking de  hardware e para fazer com que tudo funcione corretamente. A interface a ser estudada aqui é o conector de 9 pinos (DB-9), no qual sua especificação elétrica se encontra logo abaixo:

/media/Attachments/courseEA079_1S2010/Mren_5/9_PIN_PIN_OUT.JPG

Figura 3: Pinagem da porta serial DB-9.

Onde: 1- Detecção de portadora (CD) 2- Recepção de dados (RXD) 3- Transmissão de dados (TXD) 4- Terminal de dados pronto (DTR) 5- Terra do Sinal (GND) 6- Data set ready (DSR) 7- Solicitação de envio (RTS) 8- Pronto para enviar (CTS) 9- Indicador de chamada (RI)

Deve-se estar atento ao pino 5 (GND), pois é nele que os sinais de dados realizam um caminho de retorno. Ao ligar no computador, o pino 7 fica ligado na carcaça da CPU, onde é o terra comum de toda a circuitaria do computador.

A especificação RS-232 inclui dois fios dedicados a revelar se há um dispositivo conectado a outra ponta da conexão, e se ele está ligado. O sinal no pino 4 chama-se Data Terminal Ready, ou simplesmente DTR. É uma voltagem positiva enviada do dispositiva enviada do dispositivo DTE para indicar que o dispositivo está conectado, ligado e pronto para iniciar a comunicação. O sinal complementar aparece no pino 6. Ele se chama Data Set Ready, ou DST; uma tensão positiva nessa linha indica que o DCE está ligado e pronto para fazer o seu trabalho. Em uma conexão serial RS-232 normal, os dois sinais devem estar presentes para que algo mais aconteça. O DTE envia o sinal DTR ao DCE, e o DCE envia o sinal DSR ao DTE. Os dois dispositivos, então, saberão que o outro está pronto. Para a interface RS-232, a taxa máxima para a transmissão de dados é de 19200 bps (bits por segundo). A maioria dos equipamentos digitais utilizam níveis TTL ou CMOS. Portanto, o primeiro passo para conectar um equipamento digital a uma interface RS232 é transformar níveis TTL (0 a 5 volts) em RS232 e vice-versa. Isto é feito por conversores de nível. Existe uma variedade grande de equipamentos digitais que utilizam o driver 1488 (TTL => RS232) e o receiver 1489 (RS232 => TTL). Estes CIs contém 4 inversores de um mesmo tipo, sejam drivers ou receivers. O driver necessita duas fontes de alimentação +7,5 volts a +15 volts e –7,5 volts a –15 volts. Isto é um problema onde somente uma fonte de +5 volts é utilizada. Um outro CI que está sendo largamente utilizado é o MAX232 (da Maxim). Ele inclui um circuito de “charge pump” capaz de gerar tensões de +10 volts e –10 volts a partir de uma fonte de alimentação simples de +5 volts, bastando para isso alguns capacitores externos. Este CI também tem 2 receivers e 2 drivers no mesmo encapsulamento. Nos casos onde serão implementados somente as linhas de transmissão e de recepção de dados, não seria necessário 2 chips e fontes de alimentação extras. A figura abaixo mostra um circuito de comunicação utilizando o MAX232:

/media/Attachments/courseEA079_1S2010/Mren_5/max232.JPG

Figura 4: Utilização do max232.

Para finalizar, provavelmente utilizaremos este CI para realizar a comunicação serial entre o microcontrolador e a CPU, sendo de suma importância o entendimento deste dispositivo em questão.