experiência de boyle-mariotte

Upload: andre-b-cunha

Post on 07-Jul-2018

220 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/18/2019 Experiência de Boyle-Mariotte

    1/23

     

    Relatório de Microprocessadores2007/2008

    Engenharia Física Tecnológica

    EXPERIÊNCIA DE BOYLE-M ARIOTTE Projecto Final

    Trabalho realizado por:

     André Cunha, nº53757 João Pereira, nº 55315

    Grupo 3; 5ªfeira 13:00-16:00h

    Lisboa, 13 de Dezembro de 2007

  • 8/18/2019 Experiência de Boyle-Mariotte

    2/23

    Introdução e Objectivos

    O objectivo deste trabalho consiste em criar um driver  de controlo que faça a ligação entre osistema de controlo remoto de experiências E-Lab e o aparato experimental propriamentedito.

    O driver  irá ser programado em C  tendo em conta o processador PIC18F4550 mas é fulcralsublinhar que se irá abordar o problema de uma perspectiva generalista, estruturando osalgoritmos de controlo que se pretendem implementar em objectos dependentes de umnúmero máximo de variáveis independentes do processador e do outro hardware  usado.

    Neste contexto, torna-se então obrigatório criar uma overlayer  que consiste em objectos quegeram estas variáveis generalistas a partir das parâmetros específicos do hardware  usado.

    Como consequência desta abordagem deverá ser relativamente simples adaptar o programaa outro hardware , idealmente através apenas da alteração dos parâmetros específicos uma

     vez que toda a maquinaria algorítmica estará preparada para suportar estas mudanças.

    É ainda importante notar que deverão ser respeitadas as normas de funcionamento damáquina de estados do sistema E-Lab relativamente ao I/O. Como guia de implementaçãodo novo driver   iremos usar um antigo em BASIC Stamp facultado pelo docente ondeestarão explícitas as normas supracitadas.

    Clarificados os pontos genéricos relativos a este trabalho, é conveniente descrever aexperiência que se pretende controlar bem como o aparato responsável pela mesma.

    Fisicamente a experiência é extremamente simples. O objectivo é estudar a relação

    constante entre o volume ocupado por um gás e a pressão por este exercida nas paredes doreceptáculo que o contém. É assumido que todo o processo se realiza de forma isotérmicae como tal não serão efectuadas medições de temperatura (embora seja relevante notar quea experiência não é imune a efeitos adiabáticos ainda que estes não façam parte do estudo arealizar). Em honra dos seus criadores, é conhecida como Experiência de Boyle-Mariotte.

    Concretamente, o aparato consiste essencialmente numa seringa, um êmbolo, um servoresponsável pelo movimento deste, um sensor de pressão ligado na ponta da seringa, um

     ADC dual channel  ligado a um potenciómetro que mede a posição do êmbolo na seringa etambém ao sensor de pressão. É disponibilizada uma fotografia do aparato actual bemcomo um esquemático de carácter indicativo.

    Finda a contextualização, e resumidamente, o driver  deve deslocar o servo através de umdado número de posições equidistantes num dado intervalo. Em cada uma destas posiçõesdeverá ler os valores no ADC equivalentes à posição (ou volume se preferirmos) e àpressão.

     Tendo em conta a natureza expositiva e de visão global deste documento, é convenienteconsultar o código do programa (disponibilizado em anexo) para detalhes mais técnicos eespecíficos em cada assunto. Notar que a consulta auxiliar do código é importante paracompreensão máxima deste texto.

  • 8/18/2019 Experiência de Boyle-Mariotte

    3/23

     

    Figura 1 – Aparato (fotografia e esquemático indicativo)

  • 8/18/2019 Experiência de Boyle-Mariotte

    4/23

    Implementação

    É então conveniente começar por analisar os elementos de que se dispõe para a execuçãodeste projecto antes de se prosseguir para o processo de implementação propriamente dito.

    Repare-se que toda a lógica electrónica de controlo e aquisição do aparato se encontranuma placa construída para esse efeito. Não estamos interessados em aprofundar osdetalhes de funcionamento desta placa porque foge ao âmbito deste projecto mas é fulcraldescrever o I/O da mesma uma vez que é isso que nos permite controlar o aparato bemcomo saber que ADC se vai utilizar (LTC1298). Temos então 4 linhas de I/O, três delassão relativas ao funcionamento do ADC, clock, chip select e data, e a última serve para enviode pulsos ao servo.

    Nota: A linha de dados do ADC concentra em si o I/O do ADC utilizado. Isto implicaque terão que ser tomados cuidados acrescidos aquando do processo de leitura e escrita dedados no ADC. Serão prestados mais esclarecimentos sobre esta questão quando

    conveniente no decurso deste capítulo.

    O processo de implementação foi então iniciado com a construção do fluxograma quetraduz a máquina de estados que se pretende implementar no driver .

    Figura 2 – Fluxograma a implementar

  • 8/18/2019 Experiência de Boyle-Mariotte

    5/23

     A estrutura escolhida pode ser descrita da seguinte forma: a rotina central estabelece ocurso principal do programa chamando as várias rotinas auxiliares ou periféricas à medidaque vão sendo necessárias. Consequentemente, estas rotinas bem como as variáveis maisrelevantes serão alojadas respectivamente em funções e estruturas adequadas. Estaorganização “quase por objectos” traz obviamente inúmeras vantagens naturais a nível de

    adaptação, organização, simplicidade e clareza do código.

    Passaremos agora a uma explicação faseada do código, abordando cada uma das rotinasseparadamente, concluindo no final com um encaixe global de todos os blocos. Parafacilitação da leitura deste documento, estruturar-se o código em secções.

    Nota: O código integral é apresentado como anexo no fim deste documento.

     Adicionalmente, convém ainda referir (apesar de tal já ter sido feito aquando daintrodução) que se vai adoptar uma filosofia generalista para implementação do driver , paraque este possa ser directamente utilizado ou adaptado com facilidade para outro hardware .

    Ficheiro: microfinal c

    Bibliotecas e Declaração de Funções e Variáveis

    //microfinal.c

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

    //biblioteca dos header files

    #include "lib.h" 

    No ficheiro microfinal.c   (ficheiro principal do programa) começa-se então por incluir umficheiro global das bibliotecas usadas (lib.h). Além das bibliotecas usuais, cuja necessidade é

    óbvia ao longo do código, utilizaram-se quatro bibliotecas próprias (mask.h, union.h,configure.h, funtion.h).

    Ficheiro: mask h

    Nesta biblioteca temos as máscaras usadas em todo o programa. A utilização de máscaras,isto é, a renomeação de determinadas variáveis, parâmetros, funções e portas específicosatravés deste ficheiro que ao fim ao acaba por constituir um mapa dessas renomeações éum passo fulcral para obtenção da generalidade pretendida.

    Em concreto definiram-se máscaras para a frequência de oscilação do cristal usado, para os

    factores de calibração e conversão, para os parâmetros do USART, para as portas de I/O(em várias situações distintas: ADC,  flags   e outros) e parâmetros de configuraçãoassociados, para os parâmetros de controlo de interrupções, para os parâmetros do timer  usado e para as funções de delay  usadas.

    Notar que isto confere extrema acessibilidade no caso de se desejar mudar o I/O nasdiversas situações. A decisão de mascarar as funções usadas específicas para o CPU usadobem como os seus parâmetros baseou-se no facto de aquando do estudo e consulta domanual se verificar que estas são válidas para várias famílias de CPUs da Microchip e quenoutros CPUs não abrangidos, existem funções similares de igual estrutura eparameterização. Neste último caso, bastaria renomear a função usada e ajustar os

    parâmetros e no primeiro caso apenas o ajuste dos parâmetros é suficiente uma vez que as

  • 8/18/2019 Experiência de Boyle-Mariotte

    6/23

    funções são válidas. Naturalmente isto confere generalidade e minimiza o esforço deadaptação em caso de necessidade de mudança.

    De notar que no processo de masking   se pode denotar alguma redundância aparentenomeadamente ao nível do I/O. Notar que é apenas aparente e nada mais. Foi com

    consciência que se seguiu este caminho uma vez que o mesmo I/O é usado em situaçõesmuito distintas e como tal faz sentido especificar no masking  estas situações. Por exemplo,podem-se usar as mesmas portas no ADC e no flagging  e podemos querer apenas mudar asde um ou outro e a não utilização desta “redundância” obrigaria a manipulação directa docódigo para obter o mesmo resultado.

    Como crítica podemos referir as funções delay . Poder-se-ia de facto ter construído umafunção generalista que mantivesse os delays  usados para diferentes cristais. Por outro lado,uma vez que se fez o masking   dos delays   usados, bastará no caso de se querer usar umdiferente cristal, de criar as funções de delay   para o novo caso sem a necessidade dealteração de uma única linha de código do driver  original. Uma vez se mascarou a frequência

    do cristal, essa função a adicionar no futuro até pode ser a generalista referida em primeirolugar.

    Ficheiro: configure h

     Aqui gere-se a configuração primária do I/O, do USART e das interrupções. A reunião dasconfigurações neste ficheiro facilita a eventual regulação ou ajuste dos parâmetros sem anecessidade de aceder ao código directamente. Notar que tais regulações são muitoexpectáveis no que diz respeito ao USART por exemplo.

    Ficheiro: union h  

     Aqui estão presentes as estruturas que armazenam as variáveis relacionadas com ofuncionamento das interrupções e as variáveis relacionadas com o funcionamento daexperiência propriamente dita. A união relacionada com o funcionamento da experiênciapropriamente dita foi construída com dois níveis de hierarquia.

    //union.h union 

    {

    struct  startPV {

    int userPosLow;

    int userPosHigh;

    int nPontos;

    int dt;int dx;

    int PWMposi;

    int posi;

    int pressao;

    char invert;

    char noinvert;

    }startPV;

    }command;

    O nível primário está relacionado com as operações que se querem implementar e o nívelsecundário guarda os diferentes parâmetros e resultados relativos a cada uma dasoperações. Desta forma, se quisermos acrescentar operações específicas ou parâmetros àsoperações existentes poderemos fazê-lo com relativa simplicidade tendo em conta omodelo organizacional adoptado. Unidos, os dois níveis constituem um comando.

  • 8/18/2019 Experiência de Boyle-Mariotte

    7/23

     A experiência a implementar consiste numa só operação, startPV   que dá início àexperiência. Dentro desta estrutura temos os parâmetros de input, parâmetros internos defuncionamento em que se incluem também alguns resultados de output :

    Input

    •  userPosLow  [posição inicial] •  userPosHigh  [posição final] •  nPontos  [número de pontos a ler] •  dt [tempo de espera entre aquisições] 

    Parâmetros Internos

    (cálculo) •  dx [espaço entre pontos consecutivos] •  PWMposi [posição do servo] •

     

    invert e noinvert  [traduzem o sentido do pistão] 

    (medição)•   posi  [valor de posição lido no ADC] •   pressao [valor de pressão lido no ADC] 

     A necessidade e papel destes parâmetros é explicitada em detalhe na explicação das funçõesinterpreterStartPV  e executeStartPV .

    Ficheiro:funtion h

     

     Aqui temos as funções mais low-level  relacionadas com o processo de aquisição, controlo e flagging  primário, nomeadamente relacionadas com o processo de configuração e leitura no ADC, pela rotação do servo e com flashing  dos leds . Os nomes das três funções presentesnesta biblioteca são auto-indicativos.

     ADC Antes de proceder à explicação das rotinas relacionadas com a configuração do ADC eleitura de valores é essencial um pequeno preâmbulo introdutório ao funcionamento do

     ADC escolhido e também uma pequena discussão relativa às opções iniciais tomadas naimplementação do processo de configuração e leitura.

    O ADC aplicado no aparato é um LTC1298. Antes de prosseguir com os detalhes técnicosrelevantes para a aplicação desejada, é conveniente expor a forma como este está ligado naplaca de aquisição e controlo do aparato.

    Como se pode ver pela imagem, a linha de dados do ADC concentra em si o I/O do ADCutilizado numa só linha em vez das tradicionais duas linhas.

    Figura 3 – ADC LTC1298 e respectivas ligações no presente contexto[esquemático proveniente da datasheet do LTC1298] 

  • 8/18/2019 Experiência de Boyle-Mariotte

    8/23

    De acordo com a datasheet  do fabricante deste ADC, esta ligação é possível desde que seassegure que após o envio dos bits   de configuração pela linha de dados, esta fique deimediato desocupada pelo controlador usado. Neste contexto, é indicada em assembly  umasugestão de implementação de controlo do ADC na datasheet   que serviu de base para afunção que se construiu.

    Poder-se-ia, alternativamente usar o protocolo SPI para controlo do ADC, mas tal não épossível sem a utilização de uma resistência adicional nas portas para impedir a queima dasmesmas o que obviamente confere insegurança a essa opção. Para evitar eventuaisdescuidos bem como a recomendação do fabricante neste contexto, optou-se para traduzirem C a rotina em assembly  sugerida na datasheet do ADC.

    Explicitando agora o funcionamento do ADC, é conveniente antes de prosseguir de exporuma imagem representativa da linha de dados a implementar:

    Figura 4 – Diagramas temporais às portas do LTC1298 (caso geral)

    [esquemático proveniente da datasheet do LTC1298] 

    Na nossa situação em concreto, com as portas DIN e DOUT sobrepostas numa só linha:

    Figura 5 – Diagramas temporais às portas do LTC1298 (no nosso caso particular)

    [esquemático proveniente da datasheet do LTC1298] 

    Notar que durante o quarto flanco ascendente, a linha terá que estar configurada comoinput  (relativamente ao CPU) para que o LTC1298 tome controlo da linha no quarto flancodescendente e possa assim fazer o output (relativamente ao ADC).

    Clarificado este ponto crucial para a implementação, convém ainda referir que este ADCtem dois canais, uma resolução de 12 bits  e aguarda 4 bits  de configuração. Relativamente

  • 8/18/2019 Experiência de Boyle-Mariotte

    9/23

    aos 4 bits   de configuração, convém apenas saber que o segundo bit   escolhe o canal deleitura. As restantes funções deste componente não são relevantes no contexto destetrabalho e para mais informações deverá ser consultada a datasheet. mas é-nos inidicado pelocódigo em Basic STAMP que a configuração deverá ter os 3 bits restantes a 1.

    Introduzindo por fim, a função de controlo do ADC LTC1298, começa-se por declarar as variáveis com especial atenção para a variável config  que tem um formato [1 canal  1 1] emque canal  é a variável desta função, devendo por isso ser 0 ou 1 de acordo com o canal quequeiramos ler.

    Notar que todo o processo é gerado sequencialmente, até mesmo o relógio do ADC(OUT_EXT_ADC_CLOCK), notando-se aqui uma forte influência do código original em assembly.  A função tem um único parâmetro, canal , relativo ao canal do ADC quepretendemos usar, este pode ser ser 0 ou 1.

    //funtion.h

    int read_ext_ADC(unsigned char canal){

    unsigned char config, time = 50;

    int read;

    int i=0;

    read=0;

    config= 11+(canal=1;

    }

  • 8/18/2019 Experiência de Boyle-Mariotte

    10/23

    Findo o ciclo de configuração, passamos ao processo de leitura no ADC começando porimpor a linha como input  antes do quarto flanco descendente do clock tal como foi vincadoaquando do preâmbulo relativo ao ADC usado. 

    IO_EXT_ADC_DATA_TRIS=1;

    OUT_EXT_ADC_CLOCK=1;

    pause(time);

    Segue-se então o ciclo de leitura dos 12 bits  propriamente dito. Uma vez que se pretende aobtenção de uma sequência binária e que o C não permite a utilização directa deste sistemanumérico, há que recorrer a um pequeno truque usando o sistema decimal de inteiros quese possui para com o auxílio de algumas operações elementares, construir uma sequênciapseudo-binária uma vez que sendo constituída por 0 e 1, no C representa um decimal.

    Refinamentos matemáticos aparte, o processo consiste no seguinte: começamos por fazerum shift-left , sendo por isso o lugar preenchido com um 0, depois verifica-se a saída do

     ADC (IN_EXT_ADC_DATA) e caso esta esteja a 1, fazemos um incremento unitário no

    bit inicialmente a 0 devido ao shift-left  realizado, caso contrário e o valor da saída do ADCesteja a 0, o valor permanece inalterado. Fazendo este processo iterativo ciclicamenteconseguimos ler e gerar a sequência binária que pretendemos.

    Nota: apenas para referir um agradecimento ao colega Leonardo Antunes Pedro que nosauxiliou na elaboração do algoritmo de leitura dos valores no ADC acima descrito e suaimplementação. 

    for(i=13;i;i--){

    OUT_EXT_ADC_CLOCK=0;

    read

  • 8/18/2019 Experiência de Boyle-Mariotte

    11/23

    Naturalmente este valor vai depender directamente de dx , isto é, o valor que traduz alargura de cada passo consecutivo dado por:

    dx =userPosHigh " userPosLow

    nPontos

    ;

    Notar que em vez de se abordar o problema desta forma (i.e. minimizando o valor de t  através do valor dx  obtendo-se assim um valor mínimo para a duração de cada experiênciadependendo é claro, apenas do número de aquisições a realizar), poder-se ia meramente termajorado t  independentemente de dx  para todo o processo de rotação.

    Uma vez que o tempo de paragem em cada aquisição não é dominado completamente por t  mas também pelo tempo de aquisição propriamente dito e sobretudo pelo tempo de  print  dos valores para o terminal, a majoração do valor t  não asseguraria razoavelmente de forma

    alguma, tempos iguais de duração de cada experiência para qualquer número de pontos (oque aconteceria se não estivéssemos condicionados pelo envio de prints  ).

    Desta forma, torna-se bastante vantajoso optimizar o driver   através da minimização de t  para cada caso dependendo de dx , reduzindo assim significativamente o tempo necessáriopara realizar a experiência especialmente para um número elevado de aquisições (oupontos).

    No nosso caso em particular, a relação entre o número mínimo de pulsos t  e dx é como sepode ver no código, igual a um factor 4 em t. Naturalmente este valor depende do servousado e deverá ser ajustado de acordo com o servo que se tem empiricamente. O papel de

    dx  relativamente a t  é apenas de factor de proporção.

     Antes de se prosseguir há que referir que este valor de calibração deveria ter sidomascarado em mask.h  e que tal não foi feito por lapso, mas como é óbvio, isto pode sercorrigido em poucos segundos através de esforço mínimo não sendo por isso um detalheque afecte minimamente a generalidade do código ou sua validade.

    //funtion.h void pulse(unsigned int Npos,unsigned int dx){

    int i,t;

    t= dx/4;if(!t) t=1;

    Depois desta extensa introdução, tem-se o cerne do algoritmo de controlo do servo. Ociclo envia o número mínimo t de pulsos  pause com largura correspondente a uma dadaposição Npos  no servo equidistantes entre si por um delay   pausePisca  igual a 10 milissegundosneste caso em particular. 

    for(i=t;i;i--){

    OUT_SERVO=1;

    pause(Npos);

    OUT_SERVO=0;

    pausePisca(1);

    }

  • 8/18/2019 Experiência de Boyle-Mariotte

    12/23

    Por fim, é enviado um pulso adicional de finalização. 

    OUT_SERVO=1;

    pause(Npos);

    OUT_SERVO=0;

    }

    Leds

    É conveniente passar revista ainda pelo funcionamento da função de  flagging   via leds,  afunção  flashLight. Esta função é extremamente simples possuindo três parâmetros: ledpisca  que nos permite escolher em mask.h   a combinação de leds  que queremos usar, npisca  querege o número de vezes que a combinação de leds   escolhida deverá piscar e por fim,delaypisca que rege o número de delays   pausePisca  que queremos entre cada piscadela. No casoparticular, o valor de pausePisca  vale 10 milissegundos.

    //funtion.h void flashLight(char ledPisca, char nPisca, char delayPisca){

    int i;

    for(i=nPisca;i;i--){

    PortaB = !ledPisca;

    pausePisca (delayPisca);

    PortaB = ledPisca;

    pausePisca (delayPisca);

    }

    }

    Explicitadas as bibliotecas personalizadas e regressando ao ficheiro principal do driver ,segue-se então a declaração das funções. As funções usadas podem ser dividadas emsubgrupos de acordo com a funcionalidade.

    //microfinal.c

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

    //incializaccao das funccoes

    //controlo

    void main (void);

    void mainWait(void);

    int findCommmand(char * inputstr);

    void conclusao(void);

    void reset(void);

    //PV

    int interpreterStartPV(char *inputstr);

    int executeStartPV(void);

    void configPV(void);

    void notConfigured(void);

    //sistema

    void init_cfg(void);

    void init_buffers(void);

    void InterruptHandlerHigh (void); 

    O primeiro grupo de funções etiquetado por funções de controlo é constituído por cinco

    funções (main, mainWait, findCommand, conclusao, reset). Estas funções estão directamenterelacionadas com a sequência do programa e com a introdução, validação e finalização de

  • 8/18/2019 Experiência de Boyle-Mariotte

    13/23

    comandos introduzidos pelo utilizador. Pode-se dizer que constituem um upper  layer  que faza gestão de comandos e controlo.

    O segundo grupo, constituído por quatro funções (interpreterStartPV, executeStartPV,configPV, notConfigured), está directamente relacionado com a realização da experiência. Estas

    funções são portanto responsáveis pela ligação entre os algoritmos do primeiro grupo e ohardware  usado no aparato experimental, sendo por isso, específicas para este. Pode-se dizerque constituem uma  lower layer   relativamente ao aparato responsável pela execuçãoexperimental.

    O funcionamento destes dois grupos de funções será devidamente explicitado quando forconveniente ao longo desta exposição.

    Por fim, o terceiro grupo (init_cfg, init_buffers, InterruptHandlerHigh)  é responsável pelasconfigurações relevantes para esta experiência no PIC utilizado. Configura-se a gestão deinterrupções, as portas I/O e o protocolo USART. Uma vez que estas questões técnicas já

    foram extensivamente abordadas nos trabalhos anteriores, não se requer maisaprofundamento no presente trabalho.

    Por fim, antes de entrar nas rotinas propriamente ditas, segue-se a declaração de variáveisglobais.

    //microfinal.c //------------------------------------------------------------------------------

    //inicializaccao das variaveis

    //principais

    char inputstr[80];

    char resultado;

    int str_pos = 0;

    //auxiliares

    int i=0;

     Aqui podemos considerar variáveis principais e auxiliares. As variáveis principais emquestão são: inputstr  (como o nome indica, contém a string de input  onde estão armazenadosos comandos introduzidos pelo utilizador no terminal), str_pos   (indica a posição de umcarácter dentro da input string) e resultado (valor lógico que traduz o sucesso ou insucesso daexperiência).

    Rotina Principal e Subrotinas Associadas

    main

     A rotina principal ou função main   consiste portanto em quatro outras subfunçõesexecutadas sequencialmente. 

    //microfinal.c //------------------------------------------------------------------------------

    void main ()

    {

    init_cfg();

    reset();

    notConfigured();

    mainWait();

  • 8/18/2019 Experiência de Boyle-Mariotte

    14/23

     

    init_cfg

    Como já foi dito anteriormente, esta função configura o PIC.

    1.   A função ISR_cfg configura os timers relativos às interrupções e outros parâmetrosassociados. 

    2.   A função IO_cfg configura os parâmetros I/O das portas disponíveis. 

    3.  Init_buffers faz clear  das variáveis principais já referidas. 

    4.  USART_cfg  configura o protocolo USART. 

    //microfinal.c

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

    void init_cfg(void)

    {

    ISR_cfg();

    IO_cfg();

    init_buffers();USART_cfg();

    }

    reset

    De acordo com o código original do driver  em BASIC Stamp, esta função limita-se a lançaruma flag  piscando o led   cinco vezes para esse efeito.

    notConfigured  

    Mais uma vez, seguindo à letra o driver original em BASIC Stamp. Esta função envia oservo para posição inicial e lança uma  flag   no terminal esperada pelo E-Lab a dizer:“CONFIG_START_NOT_DONE”.  

    mainWait

    Esta função consiste num ciclo infinito de verificação de input . Em modo espera, oprograma faz uma espécie de ping  através de uma mensagem “ELAB_PV”  no terminal emque informa o E-Lab que a experiência está viva.

  • 8/18/2019 Experiência de Boyle-Mariotte

    15/23

    //microfinal.c //------------------------------------------------------------------------------  

    void mainWait(void){

    while (1){

    if (Flags.Bit.Timeout == 1){

    Flags.Bit.Timeout = 0;

    printf("ELAB_PV\r");

    }

    if (Flags.Bit.Rx == 1) {

    if(inputstr[str_pos - 1] == 0x0D){

    inputstr[str_pos - 1]='\0';

    str_pos = 0;

    printf("CR DETECTED! %s\r", inputstr);

    resultado = findCommmand(inputstr);

    conclusao();

    init_buffers();

    }

    }

    }

    Pode dizer-se que a rotina em espera aguarda a introdução de caracteres pelo teclado e emparticular, ao receber um carriage return  verifica se os caracteres anteriormente introduzidosconstituem um comando válido. Se o comando for válido e como tal encontrado por

     findCommand , é chamado por esta e é executado. No fim da execução ou rejeição decomand por  findCommand , a função conlusao  lança um  print   “DONE”   ou simplesmente“INVALID COMMAND” de acordo com o caso encontrado regressando ao modo emespera.

    f indCommand

     A função  findCommand   é uma função genérica de verificação de comandos. No caso docomando introduzido existir, as operações consequentes são chamadas.

    //microfinal.c //------------------------------------------------------------------------------  int findCommmand(char * inputstr){

    if(strncmppgm2ram(inputstr,"start ",6) == 0){

    if(interpreterStartPV(inputstr)){

    return executeStartPV();

    }

    }

    return 1;

    }

  • 8/18/2019 Experiência de Boyle-Mariotte

    16/23

    Em particular temos apenas um comando de start . No caso de darmos início à experiênciaatravés de um comando com a formatação “start  [posição inicial] [posição final] [número depontos] [tempo de espera entre aquisições]”, a experiência deverá ter início.

    interpreterStartPV

    Fale-se agora então da função interpretadora do comando de start . Aqui torna-se relevantea natureza dos valores de input, uma vez que se possuem elementos de natureza indirectapara a posição (userPosHigh e userPosLow) e de natureza directa para o número de aquisições(nPontos) e o tempo de espera entre aquisições (dt).

     A partir do momento em que o comando é validado pela função anterior  findCommandentramos na função interpretadora que começa por efectuar a conversão dos valores de

     volume (20~50 mL) para valores que o servo possa compreender (valores numéricos 0 ~200). Naturalmente, os valores de natureza directa são armazenados directamente sem

    qualquer conversão adicional.

    O processo de conversão propriamente dito consiste numa interpolação linear directa entreos pontos limite dos intervalos considerados que se traduz na multiplicação. A constante deinterpolação CONVERT  foi calculado com a forma usual seguida da multiplicação por umfactor 10 necessário por causa da impossibilidade de trabalhar com valores fraccionários.

    Posição =CONVERT 

    10"Volume+ B  # CONVERT =

    200$ 0

    50mL $20mL"10  

    Depois, basta multiplicar o valor de volume pela constante CONVERT , dividir o resultadoobtido por 10 (necessidade bem explícita na expressão acima) e por fim subtrair a ordenadana origem B. Este processo é feito para as posições inicial e final.

    int interpreterStartPV(char *inputstr){

    command.startPV.userPosLow = atoi(&(inputstr[6]));

    command.startPV.userPosLow = command.startPV.userPosLow * CONVERT;

    command.startPV.userPosLow = command.startPV.userPosLow / 10;

    command.startPV.userPosLow =command.startPV.userPosLow - B;

    command.startPV.userPosHigh = atoi(&(inputstr[9]));

    command.startPV.userPosHigh = command.startPV.userPosHigh * CONVERT;command.startPV.userPosHigh = command.startPV.userPosHigh / 10;

    command.startPV.userPosHigh = command.startPV.userPosHigh - B;

    Dá-se então o armazenamento directo dos valores de input  para número de aquisições e otempo de espera entre elas. 

    command.startPV.nPontos = atoi(&(inputstr[11]));

    command.startPV.dt = atoi(&(inputstr[17]));

  • 8/18/2019 Experiência de Boyle-Mariotte

    17/23

    De seguida há que determinar o sentido do movimento do pistão. Para isso, comparam-seos dois valores de posição e conforme a relação de ordem entre eles, utiliza-se um conjuntode duas variáveis como mapa booleano. A necessidade do mapa booleano diz respeito aocálculo da posição do servo e será convenientemente abordada em executeStartPV .

    O já mencionado dx , ou seja, o tamanho de cada passo entre pontos consecutivos deaquisição é então calculado de forma adequada em cada um dos casos para garantir sempreque estes valores são positivos uma vez que as funções dependentes deste parâmetro estãopreparadas apenas para valores positivos. 

    if(command.startPV.userPosLow < command.startPV.userPosHigh){

    command.startPV.invert=0;

    command.startPV.noinvert=1;

    command.startPV.dx=

    (command.startPV.userPosHigh-command.startPV.userPosLow)/command.startPV.nPontos;

    }

    else{

    command.startPV.invert=1;command.startPV.noinvert=0;

    command.startPV.dx=

    (command.startPV.userPosLow-command.startPV.userPosHigh)/command.startPV.nPontos;

    }

    Finalmente, e estando agora quase preparados para dar início à execução da experiência,resta apenas executar a rotina de configuração inicial configPV   seguindo-se de imediato afunção de execução executeStartPV . 

    configPV();

    return 1; } 

    configPV

    Esta função consiste apenas no chamamento da função que rege o servo com valores desetup para garantir que a experiência está nas condições iniciais.

    void configPV(void)

    {

    printf("CONFIG_START_ACCEPTED\r\n");

    pulse(POSIZERO+command.startPV.userPosLow, 200);

    executeStartPV

    Chegamos por fim, à função de execução experimental propriamente dita. Como éperfeitamente expectável, esta função consiste basicamente num ciclo em que o número deiteradas corresponde ao número de pontos de aquisição introduzidos no input em quedecorrem sequencialmente as seguintes operações:

  • 8/18/2019 Experiência de Boyle-Mariotte

    18/23

    1.  Cálculo da posição actual do êmbolo (variável interna calculada para movimentaçãodo servo); 

    2.  Envio do servo para a posição seguinte; 

    3.   Tempo de espera adicional dt  introduzido pelo utilizador; 

    4. 

    Leitura do valor da posição (valor lido para output  ) no ADC; 5.  Leitura do valor da pressão (valor lido para output  ) no ADC; 

    6.   printf  dos valores para a pressão e volume. 

    Nota: antes do processo anterior, tem lugar o  flagging  relativo ao início da experiência. Omapeamento e papel das instruções relativas a este estão devidamente explicadas ao longodeste documento quando conveniente.

    int executeStartPV(void){

    printf("STARTED\r\n");

    flashLight(led,10,10);

    for(i=0; i

  • 8/18/2019 Experiência de Boyle-Mariotte

    19/23

    Nota: os valores lidos e enviados de volume e pressão são meramente numéricos ecomo tal deverão ser convertidos para unidades adequadas através de processos deinterpolação linear no E-Lab. Optou-se por não incluir os cálculos no driver  porquesendo a máquina que aloja o E-Lab muito mais poderosa para cálculo, seria muitoquestionável sobrecarregar o PIC com estes cálculos quando eles são feitos sempre à

    posteriori. printf("PRESSAO %d VOLUME %d\r",command.startPV.pressao, command.startPV.posi);

    Chega-se ao fim da rotina de execução, havendo o return  de 0 que nos envia para“DONE”. 

    }

    return 0;

    }

    Nota: sublinhar que as funções PV foram todas feitas em absoluto acordo com o código

    do driver  original em Basic STAMP.

    conclusao

     A função conclusao  lança no terminal, uma mensagem de resposta aos comandosintroduzidos pelo utilizador.

    //microfinal.c //------------------------------------------------------------------------------  void conclusao (void){

    switch(resultado){

    case 0: printf("DONE\r");

    reset();

    notConfigured();

    break;

    case 1: printf("INVALID COMMAND\r");

    break;

    default: break;

    }

    }

    No presente caso, se a experiência for bem sucedida há o lançamento da mensagem“DONE” , caso o comando seja inválido temos o lançamento da mensagem “INVALIDCOMMAND” . Há que notar que aquando do lançamento da mensagem “DONE”, oprograma executa as rotinas de reset  e notConfigured tal como é especificado no driver originalem Basic STAMP regressando à rotina mainWait  fechando assim o fluxo.

    Rotinas Standard  de Interrupções

     As rotinas de interrupção usadas já foram extensivamente abordadas nos trabalhosanteriores ao longo do ano e uma vez que foram facultadas como elemento, e já estão

    amplamente comentadas, é irrelevante no contexto deste documento elaborarconsiderações adicionais sobre estas.

  • 8/18/2019 Experiência de Boyle-Mariotte

    20/23

    Utilização e Resultados

    Inter face

    O interface  E-Lab para esta experiência consiste na introdução dos valores inicial e final paraa posição do êmbolo (em termos de volume) e no número de pontos nos quais queremos

    fazer a leitura.

    Infelizmente, aquando da elaboração deste documento, a experiência estava offline  devido aproblemas de hardware  e como tal é impossível mostrar aqui um screenshot  do interface viaweb.

     Aqui ficam os valores possíveis para a posição e número de pontos:

    [posição inicial/final] = 20~50 mL [número de pontos] = 0~200

    Formato dos Comandos

     Através do terminal, o formato do comando que dá início à experiência é o seguinte:

    “start   [posição inicial] [posição final] [número de pontos] [tempo de espera entreaquisições]”

    Ou usando variáveis:

    “start  [ userPosLow  ] [ userPosHigh  ] [ nPontos  ] [ dt  ]”

    Ou ainda com cardinais que traduzem o número de digitos necessários a cada variável:

    “start  ## ## ##### ####”

    Nota:  no caso dos parâmetros introduzidos serem inferiores em dígitos à formataçãoindicada, estes deverão ser preenchidos com zeros à esquerda até obedecerem ao tamanhoinidcado em dígitos (  vermelho: incorrecto, verde: correcto).

    Exemplo: [posição inicial] = 5 ! [posição inicial] = 05[número de pontos] = 30 ! [número de pontos] = 00030 

    O parâmetro [tempo de espera entre aquisições] não existe na versão original do driver  emBasic STAMP. A sua inclusão foi meramente para facilitar a calibração da experiência e

    oferecer mais generalidade. Há que sublinhar que o parâmetro pode ser fixado num valorqualquer desejado não trazendo por isso este pequeno acrescento, qualquer dificuldadetécnica na implmentação do driver  no E-Lab.

    [tempo de espera entre aquisições] = 0 ~ 1000 cs (0 ~ 1000 * 10 ms)

    Obviamente este tempo é apenas um acrescento ao tempo mínimo que o programa demoraa fazer cada aquisição. Entre outros factores, este tempo mínimo depende principalmentedo tempo que demora o printf  das aquisições para o terminal.

  • 8/18/2019 Experiência de Boyle-Mariotte

    21/23

    Flag Mapping

     Terminal:

    “CONFIG_START_NOT_DONE” (E-Lab: reset e configuração não recebida) 

    “CONFIG_START_ACCEPTED” (E-Lab: configuração aceite) “ELAB_PV” (E-Lab: ping  ) “STARTED” (E-Lab: experiência começa) 

    “DONE” (E-Lab: experiência termina) 

    “CR DETECTED!”  ( carriage return  detectado) “INVALID COMMAND”  (comando introduzido inválido)

    Leds:  

    Pisca 5 vezes com intervalos de 0,3 segundo: reset .

    Pisca 10 vezes com intervalos de 0,1 segundos: setup, executa experiência.

    Considerações Adicionais 

    O watchdog  deverá ser desactivado para evitar a possibilidade de um bark ocorrer durante aexecução experimental, naturalmente crashando o driver. Isto pode ser facilmente conseguidoatravés do programador do CPU e do software  respectivo.

    Sendo software  bastante low-level  e tendo em conta que o interface  E-Lab a usar para este driver  é uma máquina de estados independente e mais poderosa, espera-se que o controlo deerros mais pesado seja feito no próprio interface   E-Lab através da imposição dos limites

    indicados neste documento para os valores de input   e também do impedimento dassituações disparatadas caso se pretenda ter um sistema à prova de ignorância.

    No seu estado actual, o driver não faz esse controlo estando por isso vulnerável afuncionamento deficiente no caso de introdução de parâmetros inadequados.

     A inexistência de um aparato completamente funcional impede que este driver  esteja bemcalibrado, nomeadamente em relação ao servo. A instalação de um servo novo no aparatoexigirá a recalibração de alguns parâmetros internos através das estruturas generalistasdescritas em mask h e ao longo deste documento.

  • 8/18/2019 Experiência de Boyle-Mariotte

    22/23

    Resultados

    Uma vez que infelizmente, o aparato experimental não se encontrava totalmente funcionalaquando da elaboração deste documento, disponibiliza-se aqui alguns resultadosindicativos:

    Figura 6 – Sinais de configuração do ADC (CS: amarelo, data:  azul, c lock : verde)

    [notar a alternância na configuração o que implica a leitura alternada de cada canal]

    Figura 6 – Detalhe: Sinais de configuração do ADC (CS: amarelo, data:  azul, c lock : verde)

    [notar a alternância na configuração o que implica a leitura alternada de cada canal] 

  • 8/18/2019 Experiência de Boyle-Mariotte

    23/23

    Pelas imagens podemos verificar com facilidade que o driver  se está a comportar de acordocom o previsto. Infelizmente o ADC utilizado sofreu danos irreversíveis devido àelectricidade estática e como tal não é possível apresentar aqui leituras mas foi visível o seufuncionamento correcto.

    Em anexo estão disponíveis dois vídeos que permitem a visualização do movimento doservo em paralelo com a introdução de comandos no terminal. Notar que as calibraçõesescolhidas foram perfeitamente arbitrárias uma vez que o motor fornecido não era oadequado ao aparato experimental.

     Anexos

    •  2 fotografias com os sinais de configuração e controlo do ADC no osciloscópio(micro_g3_final_adcconfig_foto1.jpg; micro_g3_final_adcconfig_foto2.jpg);

    •  1 esquemático do aparato (micro_g3_final_aparato_esquematico.pdf);•  2 fotografias do aparato (micro_g3_final_aparato_foto1.jpg;

    micro_g3_final_aparato_foto2.jpg);•  1 comparativo esquemático versus  fotografia

    (micro_g3_final_aparato_fotoesquematico.psd);  •  1 fluxograma do driver  (micro_g3_final_fluxograma.pdf);•  1 datasheet do ADC LTC1298 (micro_g3_final_ltc1298_datasheet);•  2 videos a mostrar o funcionamento do servo(micro_g3_final_servo_video1.avi;

    micro_g3_final_ servo_video2.avi);•  Código fonte (mask.h, union.h, configure.h, funtion.h, lib.h, microfinal.c);

    Material Usado 

     

    MPLAB IDE e compilador de C para este IDE•  SDK PIC184550•   Aparato E-Lab para Experiência de Boyle-Mariotte•  Placa de controlo e aquisição para o aparato anterior (baseada no ADC LTC1298)•  Osciloscópio digital; •  Multímetro;