Você está na página 1de 16

Relatrio de Microprocessadores 2007/2008

Engenharia Fsica Tecnolgica

PROGRAMAO DE UM MICROPROCESSADOR EM C PARA CONTROLO DE LEDS ATRAVS DE


UMA CONSOLA E COMUNICAO EM SRIE
Laboratrio II

Trabalho realizado por: Andr Cunha, n53757 Joo Pereira, n 55315 Grupo 3; 5feira 13:00-16:00h

Lisboa, 10 de Outubro de 2007

Introduo e Objectivos O objectivo ltimo deste trabalho laboratorial consiste em controlar os leds da placa includa no SDK atravs de uma consola no PC utilizando a porta srie para efectuar as comunicaes. Devero ainda, ser feitas algumas consideraes acerca das vantagens e desvantagens das comunicaes assncronas tendo em conta o caso em estudo, a porta srie. Implementao e Procedimento A implementao dever ser atingida naturalmente atravs da introduo de interrupes. Tendo como base um pequeno programa facultado no enunciado que envia mensagens peridicas para a consola de acordo com um timer acendendo um led aquando do envio e gera uma interrupo sempre que um carriage return (CR) detectado na consola acendendo um led aquando do mesmo. 1 sesso de laboratrio Material utilizado: MPLAB IDE SDK PIC184550 Comeou-se por tentar perceber o funcionamento do programa de exemplo fornecido pelo docente. Os comentrios adicionais esto colocados abaixo:
//============================================================================ // Filename: MAIN.C //============================================================================ // Author: // Company: // Date: Mike Garbutt Microchip Technology Inc. 04/26/2001

// Revision: 1.00 //============================================================================ // Compiled using MPLAB-C18 V1.00.31 // Include Files: P18C452.H V1.14.2.2 //============================================================================ // // Example code to generate a TMR0 interrupt and toggle LEDs on pins RB0 and // RB7. Toggles RB0 in the interrupt routine and sets RB7 to match RB0 in the // main routine. This demonstrates that code is executing in both routines. // //============================================================================ //---------------------------------------------------------------------------//incluso das bibliotecas #include #include #include #include <p18f4550.h> <stdio.h> <usart.h> <string.h>

//----------------------------------------------------------------------------

void main (void); void InterruptHandlerHigh (void); union { struct { unsigned Timeout:1; unsigned Rx:1; unsigned None:6; } Bit; unsigned char Byte; } Flags; //---------------------------------------------------------------------------// Main routine char inputstr[80]; char str_pos = 0; void main () { int i = 0; Flags.Byte = 0; INTCON = 0x20; INTCON2 = 0x84; TMR0H = 0; TMR0L = 0; T0CON = 0x82; INTCONbits.GIEH = 1; TRISB = 0xF0; //inicia //opes USART que permite a //disable global and enable TMR0 interrupt //TMR0 high priority //clear timer //clear timer //set up timer0 - prescaler 1:8 //enable interrupts //permite a utilizao das portas B como output comunicao atravs da porta srie com as seguintes //construo de uma estrutura que // uma palavra de 8 bits dos quais s //vamos usar dois //flag to indicate a TMR0 timeout //flag to indicate a Rx interrupt

OpenUSART(

USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH, 25 );

//envio de interrupes off //recepo de interrupes on //modo assncrono //utilizao de palavras de 8 bits //recepo continuada //modo de funcionamento para baud rates //altas em palavras de 8 bits //factor que regula a baud rate usada

while (1) { if (Flags.Bit.Timeout == 1) { Flags.Bit.Timeout = 0;

//timeout? //clear timeout indicator //escreve a string no buffer

printf("MicroProc Grupo %d\r", i++) // de destino. }

if (Flags.Bit.Rx == 1) //foi inserido um caracter? { if(inputstr[str_pos - 1] == 0x0D) //o ltimo caracter foi o ENTER? { printf("CR detected! %s\r", inputstr); //print commando //detectado str_pos = 0; //reset da posio na string de buffer LATBbits.LATB2 = !LATBbits.LATB2; //toggle LED on RB2 } } //neste caso envia para a porta serie }//fim do ciclo while infinito } //o seguinte bloco de cdigo representa a gesto de interrupes.

//h um salto para uma zona da memria endereada por 0x08 sempre que ocorre uma //interrupo de alta prioridade //em geral, o pragma vai permitir a activao de opes especficas de compilao //neste caso vai permitir que tenhamos interrupes disponveis e subsequente gesto //das mesmas, algo que de outra forma impossvel usando apenas o C //---------------------------------------------------------------------------// High priority interrupt vector #pragma code InterruptVectorHigh = 0x08 void InterruptVectorHigh (void) { _asm goto InterruptHandlerHigh //jump to interrupt routine _endasm }

//rotina que gere uma interrupo de alta prioridade //---------------------------------------------------------------------------// High priority interrupt routine #pragma code #pragma interrupt InterruptHandlerHigh void InterruptHandlerHigh () { if (INTCONbits.TMR0IF) { INTCONbits.TMR0IF = 0; Flags.Bit.Timeout = 1; LATBbits.LATB0 = !LATBbits.LATB0; } if (PIR1bits.RCIF) //check RX interrupt { PIR1bits.RCIF = 0; //ento mete a varivel de interrupo a 0 Flags.Bit.Rx = 1; //a flag Rx vai a 1 inputstr[str_pos] = getcUSART(); //vai buscar a inputstr porta srie //caracter a caracter (em cada iterada) str_pos++; if(str_pos == 80){str_pos = 0;} //incrementa a posio de escrita na //string de destino //verifica se a string de 80 caracteres //est cheia e caso o esteja faz reset da //posio de escrita na string a 0 //permite interrupes feitas por //perifricos //clear interrupt flag //indicate timeout //toggle LED on RB0

//check for TMR0 overflow

INTCONbits.PEIE=1; } }

//----------------------------------------------------------------------------

Antes de introduzir os fluxogramas que descrevem a rotina do programa propriamente dito bem como a rotina de gesto de interrupes conveniente explcitar alguns aspectos mais tcnicos do cdigo. utilizada uma estrutura que prev a existncia de interrupes de alta prioridade, no incio do programa, o protocolo de comunicaes atravs da porta srie configurado para modo continuado de recepo de dados (interrupes via porta srie), assincronamente utilizando palavras de 8 bits e baud rates elevadas. O envio de interrupes est desactivado.

Nota: os fluxogramas podem ser consultados em anexo no final do documento. 2 sesso de laboratrio MPLAB IDE e compilador de C para este IDE SDK PIC184550 Na segunda sesso procedeu-se ento elaborao do programa de acordo com os objectivos expressos tendo como base o cdigo supracitado. Desta forma, fez-se um highlight apenas do corpo de cdigo relevante para os objectivos, uma vez que existe cdigo repetido relacionado com as interrupes, preparao do protocolo de comunicaes, a prpria estrutura do programa, etc.
//Microprocessadores, Trabalho Laboratorial n 2 //Andr Cunha, n 53757, LEFT //Joo Pereira, n 55315, LEFT // // Programa que permite ligar e desligar os leds atravs da introduo de // comandos on, off e toggle numa consola cujas funes so explcitas // //============================================================================ //---------------------------------------------------------------------------//incluso das bibliotecas #include #include #include #include <p18f4550.h> <stdio.h> <usart.h> <string.h>

//---------------------------------------------------------------------------void main (void); void InterruptHandlerHigh (void); union { Struct { unsigned Timeout:1; unsigned Rx:1; unsigned None:6; } Bit; unsigned char Byte; } Flags; //---------------------------------------------------------------------------// Main routine char inputstr[80]; char str_pos = 0; void main () { int i = 0; Flags.Byte = 0; INTCON = 0x20; INTCON2 = 0x84; TMR0H = 0; TMR0L = 0; T0CON = 0x82; //disable global and enable TMR0 interrupt //TMR0 high priority //clear timer //clear timer //set up timer0 - prescaler 1:8 //construo de uma estrutura que // uma palavra de 8 bits dos quais s //vamos usar dois //flag to indicate a TMR0 timeout //flag to indicate a Rx interrupt

INTCONbits.GIEH = 1; TRISB = 0xF0; //inicia //opes USART que permite a

//enable interrupts //permite a utilizao das portas B como output comunicao atravs da porta srie com as seguintes

//inicializar os leds LATBbits.LATB0 = 0; LATBbits.LATB1 = 0; LATBbits.LATB2 = 0; LATBbits.LATB3 = 0; OpenUSART( USART_TX_INT_OFF & USART_RX_INT_ON & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX & USART_BRGH_HIGH, 25 ); //inicio do ciclo infinito while (1) { if (Flags.Bit.Timeout == 1) //detecta se houve timeout interrupt { Flags.Bit.Timeout = 0; //clear timeout indicator printf("G3 QUINTA %d\r", i++); //escreve a string no buffer de //destino. } //verifica se foi feita uma interrupo pelo teclado if (Flags.Bit.Rx == 1){ //verifica se o caracter "enter" existe no ultimo input da string if (inputstr[str_pos - 1] == 0x0D) { //altera o caracter "enter" por um caracter "NULL" = '\0' //no ultimo input da string //desde modo a string fecha-se e fica s com o tamanho do nmero //de caractres introduzidos na string inputstr[str_pos - 1]='\0'; //inicializa o str_pos para uma nova string que gravada no array // inputstr str_pos = 0; //print, d o alarme de deteccao e //comando fornecido pelo utilizador printf("COMMAND DETECTED! %s\r", inputstr); //compara o inputstr com um comando valido "led t x" onde x um //numero entre 0 e 3 para fazer o toggle do led correnpondente x, //se nao introduzirmos um valor x, faz o toggle a todos leds if(strncmppgm2ram(inputstr,"led t ",6)==0){ //vai buscar o caracter que ocupa a sexta posiccao na string para //executar os case correspondentes switch(inputstr[6]){ case '0': printf("TOGGLE LED 0 \r"); //print LATBbits.LATB0 = !LATBbits.LATB0; //toggle led 0 break; case '1':printf("TOGGLE LED 1 \r"); //print LATBbits.LATB1 = !LATBbits.LATB1; //toggle led 1 break; o print do //envio de interrupes off //recepo de interrupes on //modo assncrono //utilizao de palavras de 8 bits //recepo continuada //modo de funcionamento para baud rates //altas em palavras de 8 bits //factor que regula a baud rate usada

case '2':printf("TOGGLE LED 2 \r"); //print LATBbits.LATB2 = !LATBbits.LATB2; //toggle led 2 break; case '3':printf("TOGGLE LED 3 \r"); //print LATBbits.LATB3 = !LATBbits.LATB3; //toggle led 3 break; default : printf("TOGGLE ALL LEDS \r"); //toggle todos os leds LATBbits.LATB0 LATBbits.LATB1 LATBbits.LATB2 LATBbits.LATB3 break; } } //compara o inputstr com um comando valido "led on x" onde x um numero entre 0 e 3 //para acender do led correnpondente x, se nao introduzirmos um valor x,acende todos //leds if(strncmppgm2ram(inputstr,"led on ",7)==0){ //vai buscar o caracter que ocupa a setima posiccao na string para executar os case //correspondentes switch(inputstr[7]){ case '0': printf("LED 0 ON \r"); LATBbits.LATB0 = 1; break; case '1': printf("LED 1 ON \r"); LATBbits.LATB1 = 1; break; case '2': printf("LED 2 ON \r"); LATBbits.LATB2 = 1; break; case '3': printf("LED 3 ON \r"); LATBbits.LATB3 = 1; break; //print //acende led 0 //print //acende led 1 //print //acende led 2 //print //acende led 3 = = = = !LATBbits.LATB0; !LATBbits.LATB1; !LATBbits.LATB2; !LATBbits.LATB3; //print

default : printf("ALL LEDS ON \r"); //print //acende todos os leds LATBbits.LATB0 = 1; LATBbits.LATB1 = 1; LATBbits.LATB2 = 1; LATBbits.LATB3 = 1; break; } } //compara o inputstr com um comando valido "led off x" onde x um numero entre 0 e 3 //para apagar do led correnpondente x, se nao introduzirmos um valor x , apaga todos //leds if(strncmppgm2ram(inputstr,"led off ",8)==0){ //vai buscar o caracter que ocupa a oitava posiccao na string para executar os case //correspondentes switch(inputstr[8]){ case '0': printf("LED 0 OFF \r"); LATBbits.LATB0 = 0; break; //print //apaga led 0

case '1': printf("LED 1 OFF \r"); LATBbits.LATB1 = 0; break; case '2': printf("LED 2 OFF \r"); LATBbits.LATB2 = 0; break; case '3': printf("LED 3 OFF \r"); LATBbits.LATB3 = 0; break; default :

//print //apaga led 1 //print //apaga led 2 //print //apaga led 3 //print

printf("ALL LEDS OFF \r");

//apaga todos os leds LATBbits.LATB0 LATBbits.LATB1 LATBbits.LATB2 LATBbits.LATB3 break; } } } } } //fim do ciclo while infinito} //o seguinte bloco de cdigo representa a gesto de interrupes. //h um salto para uma zona da memria endereada por 0x08 sempre que ocorre uma //interrupo de alta prioridade //em geral, o pragma vai permitir a activao de opes especficas de compilao //neste caso vai permitir que tenhamos interrupes disponveis e subsequente gesto //das mesmas, algo que de outra forma impossvel usando apenas o C //---------------------------------------------------------------------------// High priority interrupt vector #pragma code InterruptVectorHigh = 0x08 void InterruptVectorHigh (void) { _asm goto InterruptHandlerHigh //jump to interrupt routine _endasm } = = = = 0; 0; 0; 0;

//rotina que gere uma interrupo de alta prioridade //---------------------------------------------------------------------------// High priority interrupt routine #pragma code #pragma interrupt InterruptHandlerHigh void InterruptHandlerHigh () { if (INTCONbits.TMR0IF) { INTCONbits.TMR0IF = 0; Flags.Bit.Timeout = 1; LATBbits.LATB0 = !LATBbits.LATB0; } if (PIR1bits.RCIF) //check RX interrupt { PIR1bits.RCIF = 0; //ento mete a varivel de interrupo a 0 Flags.Bit.Rx = 1; //a flag Rx vai a 1 inputstr[str_pos] = getcUSART(); //vai buscar a inputstr porta srie //caracter a caracter (em cada iterada) //clear interrupt flag //indicate timeout //toggle LED on RB0

//check for TMR0 overflow

str_pos++; if(str_pos == 80){str_pos = 0;}

//incrementa a posio de escrita na //string de destino //verifica se a string de 80 caracteres //est cheia e caso o esteja faz reset da //posio de escrita na string a 0 //permite interrupes feitas por //perifricos

INTCONbits.PEIE=1; } }

//----------------------------------------------------------------------------

Nota: os fluxogramas podem ser consultados em anexo no final do documento.

Anlise e Consideraes Adicionais Tendo em conta o estudo do mtodo de comunicaes usado, a porta srie, resolveu-se ento de acordo com as exigncias do enunciado fazer uma pequena anlise do mesmo. A porta srie do PC dispe de um conjunto de baud rates (bits por segundo) standard. Desse conjunto escolhe-se um valor de acordo com as necessidades para uma dada aplicao. Por sua vez, o CPU usado possui uma tambm um conjunto restricto de valores de baud rate possveis que depende intrnsecamente do CPU usado bem como do prprio cristal oscilador utilizado. Aps a consulta da documentao do CPU, chegou-se a uma frmula que relaciona um parmetro X de configurao do CPU (que um inteiro) com a baud rate desejada. Naturalmente, se impusermos uma baud rate e obtermos o parmetro X a partir desta, arredondamentos sero impostos neste factor (de forma a ser um inteiro) o que se traduz numa diferena entre a baud rate standard e a baud rate real do nosso CPU.

Sabendo que o CPU utilizado avalia o valor lgico de um dado bit tendo em conta uma mdia ponderada em trs momentos equidistantes dentro de um dado perodo, se a diferena entre a baud rate no PC e a aquela que temos aproximada no CPU for demasiada, o assincrosnismo pode gerar corrupo de dados no processo de trasnmisso de dados o que obviamente se pretende evitar a todo o custo. Desta forma, utilizando a frmula para calcular as baud rates do CPU a usar em cada um dos casos do conjunto standard de baud rates, assumiu-se um erro mximo de 33% (por causa do mtodo de avaliao do valor lgico de cada bit acima explicado). Desta forma construiu-se uma expresso que traduz o tempo mximo e mnimo para o envio de cada palavra de 8 bits. Seja T o perodo do sinal tem-se que:

A motivao para esta expresso simples, ao fim de uma palavra de 8 bits, impomos um desvio mximo de T/3 no oitavo bit para garantirmos a viabilidade e a certeza de que no temos alteraes no valor lgico lido na sequncia. Com algumas operaes simples possvel calcular as baud rates correspondentes. Como a palavra tem 8 bits, divide-se a expresso anterior por 8 e fazendo o inverso da expresso obtida, pode-se ento calcular o baud rate correspondente. E construiu-se uma tabela com o conjunto standard das baud rates mais o desvio mximo (para cima e para baixo) permitido bem como o baud rate permitido pelo CPU e ver quando que prevemos ter problemas. Experimentalmente, verificou-se que existia corrupo na transmisso de dados para os valores previstos (baud rates superiores a 19200 bits por segundo a vermelho na tabela 1)

mas inesperadamente tambm para valores inferiores a 1200 bits por segundo (a laranja na tabela 1). Aps a consulta da documentao, verificou-se que ao impormos na configurao do protocolo, a utilizao de baud rates elevadas atravs do parmetro USART_BRGH_HIGH, que impossibilitamos a utilizao de baud rates iguais ou inferiores a 300 bits por segundo tal como se verificou nos resultados experimentais. Para acedermos a esses baud rates, seria necessrio configurar o CPU atravs da flag indicada acima, para baud rates baixos.
BRstd(b/s) Xarred BRmin(b/s) BRmax(b/s) BRreal(b/s)

110 300 1200 2400 9600 19200 38400 57600 115200 230400 460800 921600

2272 832 207 103 25 12 6 3 1 0 0 0

105.6 288 1152 2304 9216 18432 36864 55296 110592 221184 442368 884736

115 313 1252 2504 10017 20035 40070 60104 120209 240417 480835 961670

110 300 1202 2404 9615 19231 35714 62500 125000 250000 250000 250000

Tabela 1 Valores tericos e reais mais o desvio mximo e mnimo dos baud rates testados

Ao consultar os valores tabelados nas pginas 243 e 244 do manual, verificou-se tambm que os resultados obtidos fazem sentido dentro daquilo que assegurado pelo fabricante. Comentrios e Concluses A grande vantagem das comunicaes assncronas est explcita na sua natureza assncrona. O facto do protocolo assncrono nos permitir estabelecer comunicao entre dispositivos sem a necessidade de sincroniz-los aquando do envio de um pacote de dados, permite-nos poupar uma linha de dados que de outra forma teria obrigatoriamente que ser usada para sincronizar o clock dos dispositivos envolvidos no protocolo. Como desvantagens, podemos notar que se pretendermos estabelecer comunicao entre vrios dispositivos (no s dois como neste caso) utilizando um protocolo genericamente assncrono, o controlo do erro pode ser mais complicado que no presente caso dependendo naturalmente da natureza das linhas e dispositivos envolvidos. Outra desvantagem possivelmente quando se pretende alta preciso no processo de comunicao como por exemplo num qualquer processo de aquisio em tempo real, em

que fulcral assegurar que os dispositivos de envio e aquisio esto sincronizados de forma muito precisa. Outra desvantagem que me parece possvel talvez ao trabalhar com palavras muito extensas porque o erro entre as baud rates standard e as baud rates reais cumulativo e como tal cresce com o aumento do nmero de bits. Logo quanto maior for a palavra envolvida, mais cuidado teremos que ter ao efectuar a transferncia de dados. Olhando para a expresso de durao mxima e mnima de cada palavra e extrapolando-a para palavras maiores, imediato que o factor de erro permitido se torna menor (em termos relativos) porque o factor que multiplica T aumenta.

BRstd(b/s)

Tstd(s) 9,091E03 3,333E03 8,333E04 4,167E04 1,042E04 5,208E05 2,604E05 1,736E05 8,681E06 4,340E06

FactorX 2272 832 207 103 25 12 6 3 1 0

BRreal/b/s) 109,99 300,12 1201,92 2403,85 9615,38 19230,77 35714,29 62500,00 125000,00 250000,00

Treal(s) 9,09E03 3,33E03 8,32E04 4,16E04 1,04E04 5,20E05 2,80E05 1,60E05 8,00E06 4,00E06

Md.Assinc.8bit(s) 0,000008727 0,000010667 0,000010667 0,000005333 0,000001333 0,000000667 0,000015667 0,000010889 0,000005444 0,000002722

Md.Assinc.Mx.(s) 0,000378788 0,000138889 0,000034722 0,000017361 0,000004340 0,000002170 0,000001085 0,000000723 0,000000362 0,000000181

BRmin(b/s) 106 288 1152 2304 9216 18432 36864 55296 110592 221184

BRmax(b/s) 115 313 1252 2504 10017 20035 40070 60104 120209 240417

110 300 1200 2400 9600 19200 38400 57600 115200 230400

Tabela 2 Valores tericos e reais mais o desvio mximo e mnimo dos baud rates mais valores temporais respectivos

Figura 1 Fluxograma para a rotina principal do programa de exemplo facultado na aula

main

Flag timeout ?

Print

Flag Rx ?

Y Y N

Input Enter?

print

Toggle led

Figura 2 Fluxograma para a rotina principal do programa realizado para cumprir os objectivos

main

Flag timeout ?

Print

Flag Rx ?

Y Y N * Compara o input com os comandos validos no programa (toggle, on, off) Executa as operaes para cada led correspondente n ={0,1,2,3} Y

Input Enter?

Print command detected

Compare * commands

Toggle LEDn

Acende LEDn

Apaga LEDn

Figura 3 Fluxograma do inter ruption handler, comum a ambos os programas

Main

Interrup?

TMR0 overflow?

Clear flag indicate timeout Toggle led0

Check Rx ?

Clear flag indicate flag Rx Write input string