• Nenhum resultado encontrado

Trabalho 3 - Interrupções

N/A
N/A
Protected

Academic year: 2023

Share "Trabalho 3 - Interrupções"

Copied!
6
0
0

Texto

(1)

1- Tradução do programa de controlo para C

Depois de ter a versão assembly do programa de controlo do voltímetro digital a funcionar, este deve ser convertido para linguagem C. Só depois de completar o debug desta última versão é que deve passar aos pontos seguintes.

Ambiente de programação em C

Como o compilador de C que vamos usar é o TurboC, o qual corre apenas em ambiente DOS, é necessário ter em atenção o seguinte:

a) Ao criar-se o ficheiro source (extensão .c) com o vim, deve executar-se no editor o comando

[ESCAPE]

:set fileformat=dos

antes de fazer o save (:wq), para que o ficheiro assuma o formato do DOS. Caso contrário a compilação subsequente termina sempre com erro. Isto tem que ver com as mudanças de linha nos ficheiros de texto, que diferem entre o DOS e o linux.

b) Para compilar o programa em C, proceder do seguinte modo:

i) Entrar no emulador de DOS do linux:

Dosemu

Poucos depois aparece o prompt tradicional do DOS (C:\>).

O vosso directório pessoal do linux está mapeado no directório seguinte dentro do "dosemu":

C:\AC2\AULAS\AC2PttGn

o que significa que os vossos ficheiros podem ser acedidos quer directamente do linux, quer dentro do emulador.

ii) Para compilar o programa escrito em C é usado um script que, por sua vez, invoca o TC seguido do utilitário que converte o ficheiro objecto no formato binário do Kit Det188:

makec <nome do ficheiro s/ extensão .c>

que cria o <ficheiro.kit> (ou ‘z’).

iii) Para sair do emulador de DOS:

exitemu

Para trabalharem de maneira eficiente recomenda-se que abram sempre três terminais no linux:

- um para editar o ficheiro fonte (para evitar de sair do vim para compilar);

- um para compilar o programa e onde vai estar sempre a correr o dosemu (do qual não precisam de sair);

- um para executar o linterm (que pode também estar sempre a correr).

2- Atendimento à ADC por interrupção

Nesta fase do trabalho vamos incluir uma rotina de interrupção que será activada sempre que a ADC termina uma conversão. Das duas entradas de interrupção presentes na ficha de expansão do kit Det188 vamos usar a INT1 que ligaremos ao sinal EOC\ da ADC, depois de invertido.

Para que a rotina de interrupção seja executada sempre que o sinal INT1 é activado, é preciso:

• Inicializar o ponteiro correspondente a esta interrupção na Tabela de Endereços de Interrupção (TEI);

• Programar no Controlador de Interrupções interno (PIC) o registo de controlo correspondente a este sinal;

• No fim da rotina de interrupção, enviar para o PIC comando de fim de interrupção.

2.1- Inicialização do ponteiro de interrupção

A localização base deste ponteiro na TEI é determinada multiplicando o vector correspondente ao INT1 (vector type, 13) por 4. Assim, os 16 bits do offset do ponteiro localizam-se nas posições de memória cujos endereços são 13x4=52=34h e 35h; o segmento está localizado logo a seguir, ou seja em (13x4)+2=54=36h e 37h (fig. 1).

A inicialização do ponteiro correspondente à interrupção é

Práticas de Arquitectura de Computadores II

Trabalho 3 - Interrupções

Vector INT1 = 13 0

3 4 7

34h 37h 4Ch 4Fh

Div. Error Exception Single Step

Interrupt

INT1

Timer2 (offset)

(seg) (seg)

(seg)

(seg) (offset)

(offset)

(offset)

Vector Timer2 = 19

Fig. 1 - Tabela de Endereços de Interrupção

(2)

realizada em C usando as funções FP_OFF() e FP_SEG(), juntamente com a função poke() de escrita em memória (16 bits).

Exemplo: Inicialização do ponteiro correspondente ao INT1 para a rotina de serviço int1_isr:

poke(0, 13*4, FP_OFF(int1_isr));

poke(0, 13*4+2, FP_SEG(int1_isr));

2.2- Programação do registo de controlo no PIC A fig. 2 representa o registo de controlo do sinal de interrupção INT1. Valores possíveis para cada um dos campos deste registo são:

SFNM=C=0: configura a interrupção em fully nested mode (o modo de funcionamento mais simples que usaremos sempre);

LTM=0: configura a entrada INT1 para ser activa ao flanco;

MSK=0: desactiva a máscara, ou seja, activa a interrupção;

PR[2:0]=111: Atribui ao INT1 a prioridade 7 (mais baixa).

O que se traduz no valor 0007.

A programação do registo de controlo do INT1 resume-se pois à instrução:

outport(0xFF3A, 0x07);

2.3- Comando de fim de interrupção

Imediatamente antes de sair, a rotina de serviço à interrupção deverá enviar para o registo EOI (fig. 3) um comando de fim de interrupção. Este destina-se a desactivar o bit correspondente ao INT1 no registo In-Service, de forma a permitir o reconhecimento de interrupções subsequentes (neste sinal de interrupção ou em outros de prioridade inferior).

Os valores a usar nos campos do comando EOI são os seguintes:

SPEC/NSPEC=0: indica que o comando é do tipo específico, ou seja, a interrupção a que se refere é identificada explicitamente;

S[4:0]=Vector do INT1=13: Identifica a interrupção pelo seu vector.

O comando EOI é enviado com a instrução:

outport(0xFF22, 13);

2.4- Organização do programa

Na sua versão sem interrupções, o programa do voltímetro digital executa sucessivamente as acções seguintes:

1- Inicialização (prog. PCS3\, etc.);

2- Comanda ADC para iniciar conversão;

3- Testa se fim de conversão;

4- Lê ADC;

5- Rotina chgscale;

6- Rotina h2d;

7- Envio resultado displays;

8- Goto 2;

Com a introdução de uma rotina de atendimento à interrupção INT1 (ADC), sugere-se a estruturação do software como indicado na fig. 4.

A rotina de atendimento à interrupção e o programa principal executam as seguintes acções:

Rotina de serviço à interrupção INT1:

1- Lê ADC;

2- Rotina chgscale;

3- Escreve resultado em VadcS;

4- adcON=0;

5- Envia comando EOI para o PIC;

Programa principal:

1- Disable das interrupções;

2- Inicialização (prog. PCS3\, inicial.

ponteiro de interrupção, prog. PIC, etc.);

3- Enable das interrupções;

4- adcON=1;

5- Comanda ADC para iniciar conversão;

6- Espera até adcON=0;

7- Lê VadcS;

8- Rotina h2d;

9- Envio resultado displays;

10- Goto 4;

A comunicação e sincronização entre os dois módulos é assegurada por duas variáveis globais: VadcS e adcON. A primeira é usada para transferir o valor da ADC (já na escala 0-5.0V) entre a rotina de interrupção e o programa principal. A variável binária adcON é usada para validar o valor em VadcS e para garantir que os comandos de início de conversão (enviados pelo main) ocorrem apenas depois da ADC terminar a conversão anterior.

Note-se que a rotina chgscale foi incluída na rotina de serviço à interrupção e a rotina h2d no programa principal.

Esta opção (que é apenas uma entre outras possíveis) justifica-se pelo facto de se entender a mudança de escala como uma adaptação da saída da ADC aos requisitos do sistema, sendo por isso um processamento que deve estar encapsulado na rotina da ADC. Por outro lado o processamento correspondente à rotina h2d (assim como a multiplexagem que é preciso efectuar para alimentar os dois displays) tem a haver com as características da saída, não devendo por isso ser incluído na rotina de interrupção.

Em linguagem C, isto traduz-se por:

SFNM PR0

0 0 . . . . C LTM MSK PR2 PR1 0 1 2 3 4 5 6 15

Fig. 2 – Registo de controlo do INT1 (FF3Ah)

SPEC/

NSPEC 0 0 . . . . . 0 S4 S3 S2 S1 S0 0 1 2 3 4 15

Fig. 3 – Registo EOI (FF22h)

INT1

0

(var globais) VadcS adcON

8 8

Programa principal(main) 1 ADC

Rotina interrupção

INT1 (int1_isr)

Fig. 4 – Organização do software do voltímetro

(3)

/* Programa do voltímetro digital com atendimento à ADC por interrupções */

/* Constantes*/

#define ADC ADD 0x2081

#define IO_ADD 0x2080

#define EOI_ADD 0xFF22

#define INT1_VECT 13

#define INT1_CR_ADD 0xFF3A

#define INT1_CR_VAL 0x0007

/* Variáveis globais */

char VadcS, adcON;

/* Rotina de serviço da ADC */

void interrupt int1_isr(void) {

int ValADC;

...

ValADC = inportb(ADC_ADD);

...

VadcS = .... ; adcON = 0;

/* Envio de comando EOI para o PIC */

outport(EOI_ADD , INT1_VECT);

}

/* Programa main */

void main (void) {

disable(); /* disable interrupts*/

/* Inicialização do vector de interrup. */

poke(0, INT1_VECT*4, FP_OFF(int1_isr));

poke(0, INT1_VECT*4+2, FP_SEG(int1_isr));

/* Programação do PIC */

outport(INT1_CR_ADD, INT1_CR_VAL);

enable(); /* enable interrupts*/

...

adcON = 1;

outportb(ADC ADD, 0); /* start conv*/

...

}

3- Utilização do Timer2 para controlar a actualização do display

Nesta fase do trabalho vamos utilizar um timer do 80C188 para controlar a actualização (refresh) dos dígitos do display. O timer será programado para gerar uma interrupção (a cada 20ms) sendo necessário pois incluir a rotina de serviço correspondente a esta interrupção.

Assim, o código do main será aumentado com as seguintes inicializações:

• Inicialização do ponteiro de interrupção do Timer2 na Tabela de Endereços de Interrupção (TEI);

• Programação do registo de controlo correspondente aos timers no Controlador de Interrupções interno (PIC);

• Programação dos registos do Timer2.

A rotina de interrupção do Timer2 deve terminar com o envio para o PIC do comando de fim de interrupção.

3.1- Inicialização do ponteiro de interrupção

O procedimento é idêntico ao indicado em 2.1. O vector correspondente ao Timer2 é 19 (ver fig. 1) pelo que os 16 bits do offset do ponteiro localizam-se nas posições de endereços 19x4=76=4Ch e 4Dh, e o segmento nas posições (19x4)+2=78=4Eh e 4Fh.

3.2- Programação do registo de controlo no PIC O PIC possui um único registo de controlo para os três timers do 80C188 (fig. 5).

Valores possíveis a programar em cada um dos campos deste registo são:

MSK=0: desactiva a máscara de interrupção dos timers;

PR[2:0]=111: Atribui às interrupções dos timers a prioridade 7 (mais baixa).

O valor a programar será portanto 0007.

3.3- Programação do Timer2 Consiste na

• inicialização do registo MaxCountA (endereço FF62h);

• programação do registo de controlo deste timer.

O timer2 gera uma interrupção sempre que o seu contador atinge o valor de MaxCountA. Dado que pretendemos ter uma interrupção a cada 20ms e a frequência de relógio dos timers é de 1.25 MHz (0.8 μs), o valor a programar em MaxCountA será 20000/0.8=25000.

Os valores possíveis a programar nos campos do registo de controlo do timer2 (fig. 6) são:

EN=1: activa o timer;

INH\=1: valida o valor o bit EN;

INT=1: activa interrupções do timer;

MC=X: bit maximum count;

CONT=1: funcionamento continuo.

O valor a programar será portanto E001h.

3.4- Comando de fim de interrupção

O comando de fim de interrupção a enviar para o registo EOI (fig. 3) é idêntico ao usado para o caso do INT1. A única diferença reside na identificação da interrupção no campo S[4:0]. Como o PIC tem apenas um in-service bit para as interruções dos três timers, basta que o comando EOI indique que se trata de uma destas interrupções, sem

PR0

0 0 . . . . 0 MSK PR2 PR1

0 1 2 3 4 15

Fig. 5 – Registo de controlo dos três timers (FF32h)

CONT

EN INH . . . MC 0 0 0 0

0 1 2 3 4 5 15

INT 0

14 12 13

Fig. 6 – Registo de controlo do Timer2 (FF66h)

(4)

especificar qual. O código a usar em qualquer uma das interrupções dos timers é S[4:0]=8 (correspondente ao vector do Timer0). O comando EOI tem portanto o valor 8.

3.5- Organização do programa

Com a introdução da rotina de atendimento à interrupção do Timer2 passamos a ter o software do voltímetro organizado como se indica na fig. 7.

As rotinas de interrupção e o programa principal executam as seguintes acções:

Rotina de serviço à interrupção INT1 (igual à anterior):

1- Lê ADC;

2- Rotina chgscale;

3- Escreve resultado em VadcS;

4- adcON=0;

5- Envia comando EOI para o PIC;

Rotina de serviço à interrupção do Timer2:

1- Lê VadcS;

2- Rotina h2d;

3- Envia resultado displays (Em cada activação a rotina actualiza ora um, ora outro dígito);

4- Envia comando EOI para o PIC;

Programa principal:

1- Disable das interrupções;

2- Inicialização (prog. PCS3\, inicial.

ponteiros de interrupção, prog. PIC, prog.

timer2, etc.);

3- Enable das interrupções;

4- adcON=1;

5- Comanda ADC para iniciar conversão;

6- Espera até ADC_ON=0;

7- Goto 4;

Em linguagem C, isto traduz-se por:

/* Programa do voltimetro digital com atendimento à ADC por interrupções e refresh do display*/

/* Constantes*/

#define ADC ADD 0x2081

#define IO_ADD 0x2080

/* Vectores de interrupção */

#define INT1_VECT 13

#define TIMER2_VECT 19

/* Constantes referentes ao PIC */

#define EOI_ADD 0xFF22

#define INT1_CR_ADD 0xFF3A

#define INT1_CR_VAL 0x0007

#define TIMERs_CR_ADD 0xFF32

#define TIMER2_CR_VAL 0x0007

#define TIMERs_EOI_VAL 8

/* Constantes referentes ao Timer2 */

#define TIMER2_MAXCA_ADD 0xFF62

#define TIMER2_MAXCA_VAL 25000

#define TIMER2_CTRL_ADD 0xFF66

#define TIMER2_CTRL_VAL 0xE001

/* Variáveis globais */

char VadcS, adcON;

/* Rotina de serviço da ADC */

void interrupt int1_isr(void) {

int ValADC;

...

ValADC = inportb(ADC_ADD);

...

VadcS = .... ; adcON = 0;

/* Envio de comando EOI para o PIC */

outport(EOI_ADD , INT1_VECT);

}

/* Rotina de serviço ao Timer 2 */

void interrupt timer2_isr(void) {

v=VadcS; /* lê valor VadcS */

...

/* Envio de comando EOI para o PIC */

outport(EOI_ADD , TIMERs_EOI_VAL);

}

/* Programa main */

void main (void) {

disable(); /* disable interrupts*/

/* Inicialização do vector do INT1 */

poke(0, INT1_VECT*4, FP_OFF(int1_isr));

poke(0, INT1_VECT*4+2, FP_SEG(int1_isr));

/* Inicialização do vector do TIMER 2 */

poke(0, TIMER2_VECT*4, FP_OFF(timer2_isr));

poke(0, TIMER2_VECT*4+2, FP_SEG(timer2_isr));

/* Programação do PIC (INT1 e TIMER 2) */

outport(INT1_CR_ADD, INT1_CR_VAL);

outport(TIMER2_CR_ADD, TIMER2_CR_VAL);

INT1

0

(var globais) VadcS adcON

8 8

1 ADC Programa principal (main)

Rotina interrupção

INT1 (int1_isr) INT_TIMER2

Rotina interrupção

TIMER2 (timer2_isr)

Fig. 7 – Organização do software do voltimetro

(5)

/* Programação do Timer 2 */

outport(TIMER2_CTRL_ADD, TIMER2_CTRL_VAL);

outport(TIMER2_MAXCA_ADD, TIMER2_MAXCA_VAL);

enable(); /* enable interrupts*/

...

adcON = 1;

outportb(ADC ADD, 0); /* start conv*/

...

}

4- Utilização do Timer 1 para controlar a frequência de amostragem

Nesta fase final do trabalho vamos programar o Timer1 de maneira a gerar interrupções à frequência de 8Hz (125 ms).

Estas interrupções deverão desencadear o início de conversão na ADC, pelo que esta será a frequência de amostragem do sinal de entrada.

De forma semelhante ao ponto anterior, o código do main terá de incluir as seguintes inicializações:

• Inicialização do ponteiro de interrupção do Timer1 (vector type 18) na TEI;

• Programação dos registos do Timer1.

Note-se que a programação do registo de controlo dos timers, no PIC é feita uma única vez para todos os timers.

4.1- Programação do Timer1

Esta programação é idêntica à que fizemos antes para o Timer2. Neste caso o valor a escrever no registo MaxCountA (endereço FF5Ah) seria 125ms/0.8μs = 156250, número esse que excede largamente o máximo que é possível ter nos timers (de 16bits) do 80C188. Assim sugere-se uma de entre as duas soluções descritas nos pontos 4.1.1 e 4.1.2.

4.1.1- Interrupções do Timer1 a 3x8Hz

Nesta solução o timer1 é programado para gerar interrupções à frequência de 3x8Hz mas a rotina de serviço correspondente desencadeia o início de conversão na ADC apenas de 3 em 3 invocações. Desta forma o valor a programar em MaxCountA é de 156250/3≈52083.

Os valores a programar nos campos do registo de controlo do timer1 (fig. 8) são:

EN=1: activa o timer;

INH\=1: valida o valor o bit EN;

INT=1: activa interrupções do timer;

RIU=X: este bit é read-only;

MC=X: bit maximum count ignorado;

RTG=0: timer conta desde que T1IN=1;

P=0: prescaler não usado;

EXT=0: relógio interno usado;

ALT=0: apenas MaxCountA usado;

CONT=1: funcionamento continuo.

O valor a programar será portanto E001h.

4.1.2- Utilização do relógio de 50Hz do Timer2

Outra solução para o problema será fazer funcionar o timer1, não a partir do relógio interno do processador (1.25MHz), mas sim a partir do sinal de 50Hz gerado pelo timer2. O timer2 continua a gerar as interrupções para a rotina de refresh do display e ao mesmo tempo funciona como prescaler do timer1. Neste caso o valor a escrever em MaxCountA é de 125/20=6.25≈6, ao que corresponderá uma frequência de 8.33Hz (120ms).

Os valores a programar nos campos do registo de controlo do timer1 (fig. 8) são os mesmos da solução anterior, excepto o bit P (prescaler) que neste caso é 1. O valor a programar será portanto E009h.

4.2- Organização do programa

Com a introdução da rotina de atendimento à interrupção do Timer1 passamos a ter o software do voltímetro organizado como se indica na fig. 9.

Admitindo que adoptamos a solução indicada em 4.1.2, as rotinas de interrupção e o programa principal executam as seguintes acções:

Rotina de serviço à interrupção INT1:

1- Lê ADC;

2- Rotina chgscale;

3- Escreve resultado em VadcS;

4- Envia comando EOI para o PIC;

Rotina de serviço à interrupção do Timer2 (igual à anterior):

1- Lê VadcS;

2- Rotina h2d;

3- Envia resultado displays (Em cada activação a rotina actualiza ora um, ora outro dígito);

4- Envia comando EOI para o PIC;

Rotina de serviço à interrupção do Timer1 (secção 4.1.2):

1- Comanda ADC para iniciar conversão;

2- Envia comando EOI para o PIC;

Programa principal:

1- Disable das interrupções;

2- Inicialização (prog. PCS3\, inicial.

ponteiros de interrupção, prog. PIC, prog.

timer2, prog. timer1, etc.);

3- Enable das interrupções;

4- Ciclo infinito;

INT1 VadcS

8 8

ADC Programa

principal (main)

Rotina interrupção

INT1 (int1_isr) INT_TIMER2

Rotina interrupção

TIMER2 (timer2_isr)

INT_TIMER1 Rotina interrupção

TIMER1 (timer1_isr) start

conv

Fig. 9 – Versão final do software do voltimetro

CONT EN INH . . . MC RTG P EXT ALT

0 1 2 3 4 5 15

INT RIU

14 12 13

Fig. 8 – Registo de controlo do Timer1 (FF5Eh)

(6)

Note-se que agora o programa principal apenas executa as inicializações necessárias, ficando depois em ciclo infinito sem fazer nada. Como o comando de início de conversão da ADC é agora enviado sob o controlo do timer1, já não precisamos da variável global adcON.

Em linguagem C teremos:

/* Programa do voltimetro completamente interrupt- driven*/

/* Constantes*/

#define ADC ADD 0x2081

#define IO_ADD 0x2080

/* Vectores de interrupção */

#define INT1_VECT 13

#define TIMER2_VECT 19

#define TIMER1_VECT 18

/* Constantes referentes ao PIC */

#define EOI_ADD 0xFF22

#define INT1_CR_ADD 0xFF3A

#define INT1_CR_VAL 0x0007

#define TIMERs_CR_ADD 0xFF32

#define TIMERs_CR_VAL 0x0007

#define TIMERs_EOI_VAL 8

/* Constantes referentes ao Timer2 */

#define TIMER2_MAXCA_ADD 0xFF62

#define TIMER2_MAXCA_VAL 25000

#define TIMER2_CTRL_ADD 0xFF66

#define TIMER2_CTRL_VAL 0xE001

/* Constantes referentes ao Timer1 */

#define TIMER1_MAXCA_ADD 0xFF5A

#define TIMER1_MAXCA_VAL 6

#define TIMER1_CTRL_ADD 0xFF5E

#define TIMER1_CTRL_VAL 0xE009

/* Variáveis globais */

char VadcS;

/* Rotina de serviço da ADC */

void interrupt int1_isr(void) {

int ValADC;

...

ValADC = inportb(ADC_ADD);

...

VadcS = .... ;

/* Envio de comando EOI para o PIC */

outport(EOI_ADD , INT1_VECT);

}

/* Rotina de serviço ao Timer 2 */

void interrupt timer2_isr(void) {

v=VadcS; /* lê valor VadcS */

...

/* Envio de comando EOI para o PIC */

outport(EOI_ADD , TIMERs_EOI_VAL);

}

/* Rotina de serviço ao Timer 1 */

void interrupt timer1_isr(void) {

outportb(ADC ADD, 0); /* start conv.*/

/* Envio de comando EOI para o PIC */

outport(EOI_ADD , TIMERs_EOI_VAL);

}

/* Programa main */

void main (void) {

disable(); /* disable interrupts*/

/* Inicialização do vector do INT1 */

poke(0, INT1_VECT*4, FP_OFF(int1_isr));

poke(0, INT1_VECT*4+2, FP_SEG(int1_isr));

/* Inicialização do vector do TIMER 2 */

poke(0, TIMER2_VECT*4, FP_OFF(timer2_isr));

poke(0, TIMER2_VECT*4+2, FP_SEG(timer2_isr));

/* Inicialização do vector do TIMER 1 */

poke(0, TIMER1_VECT*4, FP_OFF(timer1_isr));

poke(0, TIMER1_VECT*4+2, FP_SEG(timer1_isr));

/* Programação do PIC (INT1 e TIMERs 2 e 1) */

outport(INT1_CR_ADD, INT1_CR_VAL);

outport(TIMER2_CR_ADD, TIMERs_CR_VAL);

/* Programação do Timer 2 */

outport(TIMER2_CTRL_ADD, TIMER2_CTRL_VAL);

outport(TIMER2_MAXCA_ADD, TIMER2_MAXCA_VAL);

/* Programação do Timer 1 */

outport(TIMER1_CTRL_ADD, TIMER1_CTRL_VAL);

outport(TIMER1_MAXCA_ADD, TIMER1_MAXCA_VAL);

enable(); /* enable interrupts*/

while(1);

}

Referências

Documentos relacionados

As IMagens e o texto da Comunicação (com as legendas incluídas) devem ser enviadas por correio eletrônico. Comitê

No entanto, maiores lucros com publicidade e um crescimento no uso da plataforma em smartphones e tablets não serão suficientes para o mercado se a maior rede social do mundo

esta espécie foi encontrada em borda de mata ciliar, savana graminosa, savana parque e área de transição mata ciliar e savana.. Observações: Esta espécie ocorre

Dessa forma, os níveis de pressão sonora equivalente dos gabinetes dos professores, para o período diurno, para a condição de medição – portas e janelas abertas e equipamentos

O valor da reputação dos pseudônimos é igual a 0,8 devido aos fal- sos positivos do mecanismo auxiliar, que acabam por fazer com que a reputação mesmo dos usuários que enviam

Sendo os resultados experimentais (verde) obtidos nas amostras sem desvolatilizacão da Figura 37, fizeram-se a descrição feita acima onde a media final serviu

A solução, inicialmente vermelha tornou-se gradativamente marrom, e o sólido marrom escuro obtido foi filtrado, lavado várias vezes com etanol, éter etílico anidro e

No primeiro dia das atividades, com o intuito de explorar a ideia de Frações através do evento da Copa do Mundo foram feitas as seguintes perguntas aos alunos:?.  O que é a