Está en la página 1de 23

Relatrio de Microprocessadores

2007/2008

Engenharia Fsica Tecnolgica

EXPERINCIA DE BOYLE-MARIOTTE
Projecto Final

Trabalho realizado por:


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

Lisboa, 13 de Dezembro de 2007

Introduo e Objectivos
O objectivo deste trabalho consiste em criar um driver de controlo que faa a ligao entre o
sistema de controlo remoto de experincias E-Lab e o aparato experimental propriamente
dito.
O driver ir ser programado em C tendo em conta o processador PIC18F4550 mas fulcral
sublinhar que se ir abordar o problema de uma perspectiva generalista, estruturando os
algoritmos de controlo que se pretendem implementar em objectos dependentes de um
nmero mximo de variveis independentes do processador e do outro hardware usado.
Neste contexto, torna-se ento obrigatrio criar uma overlayer que consiste em objectos que
geram estas variveis generalistas a partir das parmetros especficos do hardware usado.
Como consequncia desta abordagem dever ser relativamente simples adaptar o programa
a outro hardware, idealmente atravs apenas da alterao dos parmetros especficos uma
vez que toda a maquinaria algortmica estar preparada para suportar estas mudanas.
ainda importante notar que devero ser respeitadas as normas de funcionamento da
mquina de estados do sistema E-Lab relativamente ao I/O. Como guia de implementao
do novo driver iremos usar um antigo em BASIC Stamp facultado pelo docente onde
estaro explcitas as normas supracitadas.
Clarificados os pontos genricos relativos a este trabalho, conveniente descrever a
experincia que se pretende controlar bem como o aparato responsvel pela mesma.
Fisicamente a experincia extremamente simples. O objectivo estudar a relao
constante entre o volume ocupado por um gs e a presso por este exercida nas paredes do
receptculo que o contm. assumido que todo o processo se realiza de forma isotrmica
e como tal no sero efectuadas medies de temperatura (embora seja relevante notar que
a experincia no imune a efeitos adiabticos ainda que estes no faam parte do estudo a
realizar). Em honra dos seus criadores, conhecida como Experincia de Boyle-Mariotte.
Concretamente, o aparato consiste essencialmente numa seringa, um mbolo, um servo
responsvel pelo movimento deste, um sensor de presso ligado na ponta da seringa, um
ADC dual channel ligado a um potencimetro que mede a posio do mbolo na seringa e
tambm ao sensor de presso. disponibilizada uma fotografia do aparato actual bem
como um esquemtico de carcter indicativo.
Finda a contextualizao, e resumidamente, o driver deve deslocar o servo atravs de um
dado nmero de posies equidistantes num dado intervalo. Em cada uma destas posies
dever ler os valores no ADC equivalentes posio (ou volume se preferirmos) e
presso.
Tendo em conta a natureza expositiva e de viso global deste documento, conveniente
consultar o cdigo do programa (disponibilizado em anexo) para detalhes mais tcnicos e
especficos em cada assunto. Notar que a consulta auxiliar do cdigo importante para
compreenso mxima deste texto.

Figura 1 Aparato (fotografia e esquemtico indicativo)

Implementao
ento conveniente comear por analisar os elementos de que se dispe para a execuo
deste projecto antes de se prosseguir para o processo de implementao propriamente dito.
Repare-se que toda a lgica electrnica de controlo e aquisio do aparato se encontra
numa placa construda para esse efeito. No estamos interessados em aprofundar os
detalhes de funcionamento desta placa porque foge ao mbito deste projecto mas fulcral
descrever o I/O da mesma uma vez que isso que nos permite controlar o aparato bem
como saber que ADC se vai utilizar (LTC1298). Temos ento 4 linhas de I/O, trs delas
so relativas ao funcionamento do ADC, clock, chip select e data, e a ltima serve para envio
de pulsos ao servo.
Nota: A linha de dados do ADC concentra em si o I/O do ADC utilizado. Isto implica
que tero que ser tomados cuidados acrescidos aquando do processo de leitura e escrita de
dados no ADC. Sero prestados mais esclarecimentos sobre esta questo quando
conveniente no decurso deste captulo.
O processo de implementao foi ento iniciado com a construo do fluxograma que
traduz a mquina de estados que se pretende implementar no driver.

Figura 2 Fluxograma a implementar

A estrutura escolhida pode ser descrita da seguinte forma: a rotina central estabelece o
curso principal do programa chamando as vrias rotinas auxiliares ou perifricas medida
que vo sendo necessrias. Consequentemente, estas rotinas bem como as variveis mais
relevantes sero alojadas respectivamente em funes e estruturas adequadas. Esta
organizao quase por objectos traz obviamente inmeras vantagens naturais a nvel de
adaptao, organizao, simplicidade e clareza do cdigo.
Passaremos agora a uma explicao faseada do cdigo, abordando cada uma das rotinas
separadamente, concluindo no final com um encaixe global de todos os blocos. Para
facilitao da leitura deste documento, estruturar-se o cdigo em seces.
Nota: O cdigo integral apresentado como anexo no fim deste documento.
Adicionalmente, convm ainda referir (apesar de tal j ter sido feito aquando da
introduo) que se vai adoptar uma filosofia generalista para implementao do driver, para
que este possa ser directamente utilizado ou adaptado com facilidade para outro hardware.
Ficheiro: microfinal.c
Bibliotecas e Declarao de Funes e Variveis
//microfinal.c
//-----------------------------------------------------------------------------//biblioteca dos header files
#include "lib.h"

No ficheiro microfinal.c (ficheiro principal do programa) comea-se ento por incluir um


ficheiro global das bibliotecas usadas (lib.h). Alm das bibliotecas usuais, cuja necessidade
bvia ao longo do cdigo, utilizaram-se quatro bibliotecas prprias (mask.h, union.h,
configure.h, funtion.h).
Ficheiro: mask.h
Nesta biblioteca temos as mscaras usadas em todo o programa. A utilizao de mscaras,
isto , a renomeao de determinadas variveis, parmetros, funes e portas especficos
atravs deste ficheiro que ao fim ao acaba por constituir um mapa dessas renomeaes
um passo fulcral para obteno da generalidade pretendida.
Em concreto definiram-se mscaras para a frequncia de oscilao do cristal usado, para os
factores de calibrao e converso, para os parmetros do USART, para as portas de I/O
(em vrias situaes distintas: ADC, flags e outros) e parmetros de configurao
associados, para os parmetros de controlo de interrupes, para os parmetros do timer
usado e para as funes de delay usadas.
Notar que isto confere extrema acessibilidade no caso de se desejar mudar o I/O nas
diversas situaes. A deciso de mascarar as funes usadas especficas para o CPU usado
bem como os seus parmetros baseou-se no facto de aquando do estudo e consulta do
manual se verificar que estas so vlidas para vrias famlias de CPUs da Microchip e que
noutros CPUs no abrangidos, existem funes similares de igual estrutura e
parameterizao. Neste ltimo caso, bastaria renomear a funo usada e ajustar os
parmetros e no primeiro caso apenas o ajuste dos parmetros suficiente uma vez que as

funes so vlidas. Naturalmente isto confere generalidade e minimiza o esforo de


adaptao em caso de necessidade de mudana.
De notar que no processo de masking se pode denotar alguma redundncia aparente
nomeadamente ao nvel do I/O. Notar que apenas aparente e nada mais. Foi com
conscincia que se seguiu este caminho uma vez que o mesmo I/O usado em situaes
muito distintas e como tal faz sentido especificar no masking estas situaes. Por exemplo,
podem-se usar as mesmas portas no ADC e no flagging e podemos querer apenas mudar as
de um ou outro e a no utilizao desta redundncia obrigaria a manipulao directa do
cdigo para obter o mesmo resultado.
Como crtica podemos referir as funes delay. Poder-se-ia de facto ter construdo uma
funo 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 um
diferente cristal, de criar as funes de delay para o novo caso sem a necessidade de
alterao de uma nica linha de cdigo do driver original. Uma vez se mascarou a frequncia
do cristal, essa funo a adicionar no futuro at pode ser a generalista referida em primeiro
lugar.
Ficheiro: configure.h
Aqui gere-se a configurao primria do I/O, do USART e das interrupes. A reunio das
configuraes neste ficheiro facilita a eventual regulao ou ajuste dos parmetros sem a
necessidade de aceder ao cdigo directamente. Notar que tais regulaes so muito
expectveis no que diz respeito ao USART por exemplo.
Ficheiro: union.h
Aqui esto presentes as estruturas que armazenam as variveis relacionadas com o
funcionamento das interrupes e as variveis relacionadas com o funcionamento da
experincia propriamente dita. A unio relacionada com o funcionamento da experincia
propriamente dita foi construda com dois nveis 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 nvel primrio est relacionado com as operaes que se querem implementar e o nvel
secundrio guarda os diferentes parmetros e resultados relativos a cada uma das
operaes. Desta forma, se quisermos acrescentar operaes especficas ou parmetros s
operaes existentes poderemos faz-lo com relativa simplicidade tendo em conta o
modelo organizacional adoptado. Unidos, os dois nveis constituem um comando.

A experincia a implementar consiste numa s operao, startPV que d incio


experincia. Dentro desta estrutura temos os parmetros de input, parmetros internos de
funcionamento em que se incluem tambm alguns resultados de output:
Input

userPosLow [posio inicial]


userPosHigh [posio final]
nPontos [nmero de pontos a ler]
dt [tempo de espera entre aquisies]

Parmetros Internos
(clculo)
dx [espao entre pontos consecutivos]
PWMposi [posio do servo]
invert e noinvert [traduzem o sentido do pisto]
(medio)
posi [valor de posio lido no ADC]
pressao [valor de presso lido no ADC]
A necessidade e papel destes parmetros explicitada em detalhe na explicao das funes
interpreterStartPV e executeStartPV.
Ficheiro: funtion.h
Aqui temos as funes mais low-level relacionadas com o processo de aquisio, controlo e
flagging primrio, nomeadamente relacionadas com o processo de configurao e leitura no
ADC, pela rotao do servo e com flashing dos leds. Os nomes das trs funes presentes
nesta biblioteca so auto-indicativos.
ADC
Antes de proceder explicao das rotinas relacionadas com a configurao do ADC e
leitura de valores essencial um pequeno prembulo introdutrio ao funcionamento do
ADC escolhido e tambm uma pequena discusso relativa s opes iniciais tomadas na
implementao do processo de configurao e leitura.
O ADC aplicado no aparato um LTC1298. Antes de prosseguir com os detalhes tcnicos
relevantes para a aplicao desejada, conveniente expor a forma como este est ligado na
placa de aquisio e controlo do aparato.
Como se pode ver pela imagem, a linha de dados do ADC concentra em si o I/O do ADC
utilizado numa s linha em vez das tradicionais duas linhas.

Figura 3 ADC LTC1298 e respectivas ligaes no presente contexto


[esquemtico proveniente da datasheet do LTC1298]

De acordo com a datasheet do fabricante deste ADC, esta ligao possvel desde que se
assegure que aps o envio dos bits de configurao pela linha de dados, esta fique de
imediato desocupada pelo controlador usado. Neste contexto, indicada em assembly uma
sugesto de implementao de controlo do ADC na datasheet que serviu de base para a
funo que se construiu.
Poder-se-ia, alternativamente usar o protocolo SPI para controlo do ADC, mas tal no
possvel sem a utilizao de uma resistncia adicional nas portas para impedir a queima das
mesmas o que obviamente confere insegurana a essa opo. Para evitar eventuais
descuidos bem como a recomendao do fabricante neste contexto, optou-se para traduzir
em C a rotina em assembly sugerida na datasheet do ADC.
Explicitando agora o funcionamento do ADC, conveniente antes de prosseguir de expor
uma imagem representativa da linha de dados a implementar:

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


[esquemtico proveniente da datasheet do LTC1298]

Na nossa situao em concreto, com as portas DIN e DOUT sobrepostas numa s linha:

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


[esquemtico proveniente da datasheet do LTC1298]

Notar que durante o quarto flanco ascendente, a linha ter que estar configurada como
input (relativamente ao CPU) para que o LTC1298 tome controlo da linha no quarto flanco
descendente e possa assim fazer o output (relativamente ao ADC).
Clarificado este ponto crucial para a implementao, convm ainda referir que este ADC
tem dois canais, uma resoluo de 12 bits e aguarda 4 bits de configurao. Relativamente

aos 4 bits de configurao, convm apenas saber que o segundo bit escolhe o canal de
leitura. As restantes funes deste componente no so relevantes no contexto deste
trabalho e para mais informaes dever ser consultada a datasheet. mas -nos inidicado pelo
cdigo em Basic STAMP que a configurao dever ter os 3 bits restantes a 1.
Introduzindo por fim, a funo de controlo do ADC LTC1298, comea-se por declarar as
variveis com especial ateno para a varivel config que tem um formato [1 canal 1 1] em
que canal a varivel desta funo, devendo por isso ser 0 ou 1 de acordo com o canal que
queiramos ler.
Notar que todo o processo gerado sequencialmente, at mesmo o relgio do ADC
(OUT_EXT_ADC_CLOCK), notando-se aqui uma forte influncia do cdigo original em
assembly. A funo tem um nico parmetro, canal, relativo ao canal do ADC que
pretendemos 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<<2);

Depois de inicializada a 0 a linha de dados (OUT_EXT_ADC_DATA) e fazendo o turn off


inicial do ADC (OUT_EXT_ADC_CS e notar que este activo a 0) por questes de
segurana, parte-se para a configurao do ADC.
Esta consiste em assegurar antes de mais, que a linha de dados est definida como output
(OUT_EXT_ADC_TRIS) para que se possa enviar os 4 bits de configurao seguida da
activao do ADC.
OUT_EXT_ADC_DATA=0;
OUT_EXT_ADC_CS=1;
IO_EXT_ADC_DATA_TRIS=0;
OUT_EXT_ADC_CLOCK=1;
pause(time);
OUT_EXT_ADC_CS=0;
pause(time);

Inicia-se ento o ciclo de configurao bit a bit do ADC atravs de um ciclo for em quatro
passos. O processo feito atravs de um processo comparativo & na instruo highlighted e
cada um dos bits escolhido atravs de um shift-right no fim do ciclo.
for(i=4;i;i--){
OUT_EXT_ADC_CLOCK=1;
pause(time);
OUT_EXT_ADC_CLOCK=0;
OUT_EXT_ADC_DATA=config&1;
pause(time);
config>>=1;
}

Findo o ciclo de configurao, passamos ao processo de leitura no ADC comeando por


impor a linha como input antes do quarto flanco descendente do clock tal como foi vincado
aquando do prembulo relativo ao ADC usado.
IO_EXT_ADC_DATA_TRIS=1;
OUT_EXT_ADC_CLOCK=1;
pause(time);

Segue-se ento o ciclo de leitura dos 12 bits propriamente dito. Uma vez que se pretende a
obteno de uma sequncia binria e que o C no permite a utilizao directa deste sistema
numrico, h que recorrer a um pequeno truque usando o sistema decimal de inteiros que
se possui para com o auxlio de algumas operaes elementares, construir uma sequncia
pseudo-binria uma vez que sendo constituda por 0 e 1, no C representa um decimal.
Refinamentos matemticos aparte, o processo consiste no seguinte: comeamos por fazer
um shift-left, sendo por isso o lugar preenchido com um 0, depois verifica-se a sada do
ADC (IN_EXT_ADC_DATA) e caso esta esteja a 1, fazemos um incremento unitrio no
bit inicialmente a 0 devido ao shift-left realizado, caso contrrio e o valor da sada do ADC
esteja a 0, o valor permanece inalterado. Fazendo este processo iterativo ciclicamente
conseguimos ler e gerar a sequncia binria que pretendemos.
Nota: apenas para referir um agradecimento ao colega Leonardo Antunes Pedro que nos
auxiliou na elaborao do algoritmo de leitura dos valores no ADC acima descrito e sua
implementao.
for(i=13;i;i--){
OUT_EXT_ADC_CLOCK=0;
read<<=1;
pause(time);
OUT_EXT_ADC_CLOCK=1;
if(IN_EXT_ADC_DATA==1)read++;
pause(time);
}

Por fim, procede-se com o desligar do ADC, e fazendo um pequeno check da sequncia
binria obtida.
OUT_EXT_ADC_CS=1;
read&=4095;
return read;
}

Servo
Depois da funo que rege o funcionamento do ADC, passamos agora aquela que rege a
rotao do servo. Esta funo possui dois parmetros, Npos traduz a posio do servo e dx
traduz o espaamento entre posies consecutivas do servo.
So declaradas as variveis internas i e t. Sendo i uma varivel auxiliar irrelevante para a
compreenso do algoritmo, foquemos as nossas atenes em t, que vai ser o nmero
mnimo de pulsos necessrios para que o servo se possa deslocar entre duas posies
consecutivas para um dado intervalo.

Naturalmente este valor vai depender directamente de dx, isto , o valor que traduz a
largura 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
! obtendo-se assim um valor mnimo para a durao de cada experincia
atravs do valor dx
dependendo claro, apenas do nmero de aquisies a realizar), poder-se ia meramente ter
majorado t independentemente de dx para todo o processo de rotao.
Uma vez que o tempo de paragem em cada aquisio no dominado completamente por t
mas tambm pelo tempo de aquisio propriamente dito e sobretudo pelo tempo de print
dos valores para o terminal, a majorao do valor t no asseguraria razoavelmente de forma
alguma, tempos iguais de durao de cada experincia para qualquer nmero de pontos (o
que aconteceria se no estivssemos condicionados pelo envio de prints).
Desta forma, torna-se bastante vantajoso optimizar o driver atravs da minimizao de t
para cada caso dependendo de dx, reduzindo assim significativamente o tempo necessrio
para realizar a experincia especialmente para um nmero elevado de aquisies (ou
pontos).
No nosso caso em particular, a relao entre o nmero mnimo de pulsos t e dx como se
pode ver no cdigo, igual a um factor 4 em t. Naturalmente este valor depende do servo
usado e dever ser ajustado de acordo com o servo que se tem empiricamente. O papel de
dx relativamente a t apenas de factor de proporo.
Antes de se prosseguir h que referir que este valor de calibrao deveria ter sido
mascarado em mask.h e que tal no foi feito por lapso, mas como bvio, isto pode ser
corrigido em poucos segundos atravs de esforo mnimo no sendo por isso um detalhe
que afecte minimamente a generalidade do cdigo 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 introduo, tem-se o cerne do algoritmo de controlo do servo. O


ciclo envia o nmero mnimo t de pulsos pause com largura correspondente a uma dada
posio Npos no servo equidistantes entre si por um delay pausePisca igual a 10 milissegundos
neste caso em particular.
for(i=t;i;i--){
OUT_SERVO=1;
pause(Npos);
OUT_SERVO=0;
pausePisca(1);
}

Por fim, enviado um pulso adicional de finalizao.


OUT_SERVO=1;
pause(Npos);
OUT_SERVO=0;
}

Leds
conveniente passar revista ainda pelo funcionamento da funo de flagging via leds, a
funo flashLight. Esta funo extremamente simples possuindo trs parmetros: ledpisca
que nos permite escolher em mask.h a combinao de leds que queremos usar, npisca que
rege o nmero de vezes que a combinao de leds escolhida dever piscar e por fim,
delaypisca que rege o nmero de delays pausePisca que queremos entre cada piscadela. No caso
particular, 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 ento a declarao das funes. As funes usadas podem ser dividadas em
subgrupos 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 funes etiquetado por funes de controlo constitudo por cinco
funes (main, mainWait, findCommand, conclusao, reset). Estas funes esto directamente
relacionadas com a sequncia do programa e com a introduo, validao e finalizao de

comandos introduzidos pelo utilizador. Pode-se dizer que constituem um upper layer que faz
a gesto de comandos e controlo.
O segundo grupo, constitudo por quatro funes (interpreterStartPV, executeStartPV,
configPV, notConfigured), est directamente relacionado com a realizao da experincia. Estas
funes so portanto responsveis pela ligao entre os algoritmos do primeiro grupo e o
hardware usado no aparato experimental, sendo por isso, especficas para este. Pode-se dizer
que constituem uma lower layer relativamente ao aparato responsvel pela execuo
experimental.
O funcionamento destes dois grupos de funes ser devidamente explicitado quando for
conveniente ao longo desta exposio.
Por fim, o terceiro grupo (init_cfg, init_buffers, InterruptHandlerHigh) responsvel pelas
configuraes relevantes para esta experincia no PIC utilizado. Configura-se a gesto de
interrupes, as portas I/O e o protocolo USART. Uma vez que estas questes tcnicas j
foram extensivamente abordadas nos trabalhos anteriores, no se requer mais
aprofundamento no presente trabalho.
Por fim, antes de entrar nas rotinas propriamente ditas, segue-se a declarao de variveis
globais.
//microfinal.c
//-----------------------------------------------------------------------------//inicializaccao das variaveis
//principais
char inputstr[80];
char resultado;
int str_pos = 0;
//auxiliares
int i=0;

Aqui podemos considerar variveis principais e auxiliares. As variveis principais em


questo so: inputstr (como o nome indica, contm a string de input onde esto armazenados
os comandos introduzidos pelo utilizador no terminal), str_pos (indica a posio de um
carcter dentro da input string) e resultado (valor lgico que traduz o sucesso ou insucesso da
experincia).
Rotina Principal e Subrotinas Associadas
main
A rotina principal ou funo main consiste portanto em quatro outras subfunes
executadas sequencialmente.
//microfinal.c
//-----------------------------------------------------------------------------void main ()
{
init_cfg();
reset();
notConfigured();
mainWait();
}

init_cfg
Como j foi dito anteriormente, esta funo configura o PIC.
1. A funo ISR_cfg configura os timers relativos s interrupes e outros parmetros
associados.
2. A funo IO_cfg configura os parmetros I/O das portas disponveis.
3. Init_buffers faz clear das variveis 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 cdigo original do driver em BASIC Stamp, esta funo limita-se a lanar
uma flag piscando o led cinco vezes para esse efeito.
notConfigured
Mais uma vez, seguindo letra o driver original em BASIC Stamp. Esta funo envia o
servo para posio inicial e lana uma flag no terminal esperada pelo E-Lab a dizer:
CONFIG_START_NOT_DONE.
mainWait
Esta funo consiste num ciclo infinito de verificao de input. Em modo espera, o
programa faz uma espcie de ping atravs de uma mensagem ELAB_PV no terminal em
que informa o E-Lab que a experincia est viva.

//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 introduo de caracteres pelo teclado e em
particular, ao receber um carriage return verifica se os caracteres anteriormente introduzidos
constituem um comando vlido. Se o comando for vlido e como tal encontrado por
findCommand, chamado por esta e executado. No fim da execuo ou rejeio de
comand por findCommand, a funo conlusao lana um print DONE ou simplesmente
INVALID COMMAND de acordo com o caso encontrado regressando ao modo em
espera.
findCommand
A funo findCommand uma funo genrica de verificao de comandos. No caso do
comando introduzido existir, as operaes consequentes so chamadas.
//microfinal.c
//-----------------------------------------------------------------------------int findCommmand(char * inputstr){
if(strncmppgm2ram(inputstr,"start ",6) == 0){
if(interpreterStartPV(inputstr)){
return executeStartPV();
}
}
return 1;
}

Em particular temos apenas um comando de start. No caso de darmos incio experincia


atravs de um comando com a formatao start [posio inicial] [posio final] [nmero de
pontos] [tempo de espera entre aquisies], a experincia dever ter incio.
interpreterStartPV
Fale-se agora ento da funo interpretadora do comando de start. Aqui torna-se relevante
a natureza dos valores de input, uma vez que se possuem elementos de natureza indirecta
para a posio (userPosHigh e userPosLow) e de natureza directa para o nmero de aquisies
(nPontos) e o tempo de espera entre aquisies (dt).
A partir do momento em que o comando validado pela funo anterior findCommand
entramos na funo interpretadora que comea por efectuar a converso dos valores de
volume (20~50 mL) para valores que o servo possa compreender (valores numricos 0 ~
200). Naturalmente, os valores de natureza directa so armazenados directamente sem
qualquer converso adicional.
O processo de converso propriamente dito consiste numa interpolao linear directa entre
os pontos limite dos intervalos considerados que se traduz na multiplicao. A constante de
interpolao CONVERT foi calculado com a forma usual seguida da multiplicao por um
factor 10 necessrio por causa da impossibilidade de trabalhar com valores fraccionrios.

Posio =

CONVERT
200 $ 0
" Volume + B # CONVERT =
"10
10
50mL $ 20mL

Depois, basta multiplicar o valor de volume pela constante CONVERT, dividir o resultado
! obtido por 10 (necessidade bem explcita na expresso acima) e por fim subtrair a ordenada
na origem B. Este processo feito para as posies inicial e final.
int interpreterStartPV(char *inputstr){
command.startPV.userPosLow
command.startPV.userPosLow
command.startPV.userPosLow
command.startPV.userPosLow
command.startPV.userPosHigh
command.startPV.userPosHigh
command.startPV.userPosHigh
command.startPV.userPosHigh

= atoi(&(inputstr[6]));
= command.startPV.userPosLow * CONVERT;
= command.startPV.userPosLow / 10;
=command.startPV.userPosLow - B;
= atoi(&(inputstr[9]));
= command.startPV.userPosHigh * CONVERT;
= command.startPV.userPosHigh / 10;
= command.startPV.userPosHigh - B;

D-se ento o armazenamento directo dos valores de input para nmero de aquisies e o
tempo de espera entre elas.
command.startPV.nPontos = atoi(&(inputstr[11]));
command.startPV.dt = atoi(&(inputstr[17]));

De seguida h que determinar o sentido do movimento do pisto. Para isso, comparam-se


os dois valores de posio e conforme a relao de ordem entre eles, utiliza-se um conjunto
de duas variveis como mapa booleano. A necessidade do mapa booleano diz respeito ao
clculo da posio do servo e ser convenientemente abordada em executeStartPV.
O j mencionado dx, ou seja, o tamanho de cada passo entre pontos consecutivos de
aquisio ento calculado de forma adequada em cada um dos casos para garantir sempre
que estes valores so positivos uma vez que as funes dependentes deste parmetro esto
preparadas 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 incio execuo da experincia,
resta apenas executar a rotina de configurao inicial configPV seguindo-se de imediato a
funo de execuo executeStartPV.
configPV();
return 1;

configPV
Esta funo consiste apenas no chamamento da funo que rege o servo com valores de
setup para garantir que a experincia est nas condies iniciais.
void configPV(void)
{
printf("CONFIG_START_ACCEPTED\r\n");
pulse(POSIZERO+command.startPV.userPosLow,200);
}

executeStartPV
Chegamos por fim, funo de execuo experimental propriamente dita. Como
perfeitamente expectvel, esta funo consiste basicamente num ciclo em que o nmero de
iteradas corresponde ao nmero de pontos de aquisio introduzidos no input em que
decorrem sequencialmente as seguintes operaes:

1. Clculo da posio actual do mbolo (varivel interna calculada para movimentao


do servo);
2. Envio do servo para a posio seguinte;
3. Tempo de espera adicional dt introduzido pelo utilizador;
4. Leitura do valor da posio (valor lido para output) no ADC;
5. Leitura do valor da presso (valor lido para output) no ADC;
6. printf dos valores para a presso e volume.
Nota: antes do processo anterior, tem lugar o flagging relativo ao incio da experincia. O
mapeamento e papel das instrues relativas a este esto devidamente explicadas ao longo
deste documento quando conveniente.
int executeStartPV(void){
printf("STARTED\r\n");
flashLight(led,10,10);

for(i=0; i<command.startPV.nPontos; i++){

Comea-se ento com o clculo da posio do servo (se traduz j como a largura do
pulso que a determina como se v em pulse) (PWMposi) a introduzir como parmetro
na funo de controlo do servo, a funo pulse.
O clculo base para este valor baseia-se na multiplicao do nmero iterador i (i-sima
aquisio) pela largura de cada passo consecutivo dx.
Aqui torna-se bvia a necessidade do mapa booleano referido em
interpreterStartPV. Quando o movimento ascendente, o mapa booleano anula o
termo subtractivo (porque invert = 0 e noinvert=1) e incrementa iterativamente a
posio do mbolo. Caso contrrio e o movimento seja descendente, o mapa
booleano anula o termo incrementativo (porque invert = 1 e noinvert=0) provocando
assim uma decrementao iterativa na posio do mbolo.
command.startPV.PWMposi=
command.startPV.userPosLow-(command.startPV.invert*(i*command.startPV.dx))+
(command.startPV.noinvert*(i*command.startPV.dx));

Calculado o parmetro necessrio funo de controlo do servo pulse, esta chamada


seguida da funo responsvel pelo tempo de espera adicional entre aquisies.
Nota: a constante POSIZERO um valor emprico de offset relacionado com o servo.
pulse(POSIZERO+command.startPV.PWMposi, command.startPV.dx);
pausePisca(command.startPV.dt);

Segue-se o processo de leitura no ADC dos valores de volume e presso j


extensivamente explicado anteriormente em ADC.
command.startPV.posi = read_ext_ADC(1);
command.startPV.pressao = read_ext_ADC(0);

Nota: os valores lidos e enviados de volume e presso so meramente numricos e


como tal devero ser convertidos para unidades adequadas atravs de processos de
interpolao linear no E-Lab. Optou-se por no incluir os clculos no driver porque
sendo a mquina que aloja o E-Lab muito mais poderosa para clculo, seria muito
questionvel sobrecarregar o PIC com estes clculos quando eles so feitos sempre
posteriori.
printf("PRESSAO %d VOLUME %d\r",command.startPV.pressao, command.startPV.posi);

Chega-se ao fim da rotina de execuo, havendo o return de 0 que nos envia para
DONE.
}
return 0;
}

Nota: sublinhar que as funes PV foram todas feitas em absoluto acordo com o cdigo
do driver original em Basic STAMP.
conclusao
A funo conclusao lana no terminal, uma mensagem de resposta aos comandos
introduzidos 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 experincia for bem sucedida h o lanamento da mensagem


DONE, caso o comando seja invlido temos o lanamento da mensagem INVALID
COMMAND. H que notar que aquando do lanamento da mensagem DONE, o
programa executa as rotinas de reset e notConfigured tal como especificado no driver original
em Basic STAMP regressando rotina mainWait fechando assim o fluxo.
Rotinas Standard de Interrupes
As rotinas de interrupo usadas j foram extensivamente abordadas nos trabalhos
anteriores ao longo do ano e uma vez que foram facultadas como elemento, e j esto
amplamente comentadas, irrelevante no contexto deste documento elaborar
consideraes adicionais sobre estas.

Utilizao e Resultados
Interface
O interface E-Lab para esta experincia consiste na introduo dos valores inicial e final para
a posio do mbolo (em termos de volume) e no nmero de pontos nos quais queremos
fazer a leitura.
Infelizmente, aquando da elaborao deste documento, a experincia estava offline devido a
problemas de hardware e como tal impossvel mostrar aqui um screenshot do interface via
web.
Aqui ficam os valores possveis para a posio e nmero de pontos:
[posio inicial/final] = 20~50 mL

[nmero de pontos] = 0~200

Formato dos Comandos


Atravs do terminal, o formato do comando que d incio experincia o seguinte:
start [posio inicial] [posio final] [nmero de pontos] [tempo de espera entre
aquisies]
Ou usando variveis:
start [userPosLow] [userPosHigh] [nPontos] [dt]
Ou ainda com cardinais que traduzem o nmero de digitos necessrios a cada varivel:
start ## ## ##### ####
Nota: no caso dos parmetros introduzidos serem inferiores em dgitos formatao
indicada, estes devero ser preenchidos com zeros esquerda at obedecerem ao tamanho
inidcado em dgitos (vermelho: incorrecto, verde: correcto).
Exemplo: [posio inicial] = 5 [posio inicial] = 05
[nmero de pontos] = 30 [nmero de pontos] = 00030
O parmetro [tempo de espera entre aquisies] no existe na verso original do driver em
Basic STAMP. A sua incluso foi meramente para facilitar a calibrao da experincia e
oferecer mais generalidade. H que sublinhar que o parmetro pode ser fixado num valor
qualquer desejado no trazendo por isso este pequeno acrescento, qualquer dificuldade
tcnica na implmentao do driver no E-Lab.
[tempo de espera entre aquisies] = 0 ~ 1000 cs (0 ~ 1000 * 10 ms)
Obviamente este tempo apenas um acrescento ao tempo mnimo que o programa demora
a fazer cada aquisio. Entre outros factores, este tempo mnimo depende principalmente
do tempo que demora o printf das aquisies para o terminal.

Flag Mapping
Terminal:
CONFIG_START_NOT_DONE (E-Lab: reset e configurao no recebida)
CONFIG_START_ACCEPTED (E-Lab: configurao aceite)
ELAB_PV (E-Lab: ping)
STARTED (E-Lab: experincia comea)
DONE (E-Lab: experincia termina)
CR DETECTED! (carriage return detectado)
INVALID COMMAND (comando introduzido invlido)
Leds:
Pisca 5 vezes com intervalos de 0,3 segundo: reset.
Pisca 10 vezes com intervalos de 0,1 segundos: setup, executa experincia.
Consideraes Adicionais
O watchdog dever ser desactivado para evitar a possibilidade de um bark ocorrer durante a
execuo experimental, naturalmente crashando o driver. Isto pode ser facilmente conseguido
atravs 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 mquina de estados independente e mais poderosa, espera-se que o controlo de
erros mais pesado seja feito no prprio interface E-Lab atravs da imposio dos limites
indicados neste documento para os valores de input e tambm do impedimento das
situaes disparatadas caso se pretenda ter um sistema prova de ignorncia.
No seu estado actual, o driver no faz esse controlo estando por isso vulnervel a
funcionamento deficiente no caso de introduo de parmetros inadequados.
A inexistncia de um aparato completamente funcional impede que este driver esteja bem
calibrado, nomeadamente em relao ao servo. A instalao de um servo novo no aparato
exigir a recalibrao de alguns parmetros internos atravs das estruturas generalistas
descritas em mask.h e ao longo deste documento.

Resultados
Uma vez que infelizmente, o aparato experimental no se encontrava totalmente funcional
aquando da elaborao deste documento, disponibiliza-se aqui alguns resultados
indicativos:

Figura 6 Sinais de configurao do ADC (CS: amarelo, data: azul, clock: verde)
[notar a alternncia na configurao o que implica a leitura alternada de cada canal]

Figura 6 Detalhe: Sinais de configurao do ADC (CS: amarelo, data: azul, clock: verde)
[notar a alternncia na configurao o que implica a leitura alternada de cada canal]

Pelas imagens podemos verificar com facilidade que o driver se est a comportar de acordo
com o previsto. Infelizmente o ADC utilizado sofreu danos irreversveis devido
electricidade esttica e como tal no possvel apresentar aqui leituras mas foi visvel o seu
funcionamento correcto.
Em anexo esto disponveis dois vdeos que permitem a visualizao do movimento do
servo em paralelo com a introduo de comandos no terminal. Notar que as calibraes
escolhidas foram perfeitamente arbitrrias uma vez que o motor fornecido no era o
adequado ao aparato experimental.
Anexos

2 fotografias com os sinais de configurao e controlo do ADC no osciloscpio


(micro_g3_final_adcconfig_foto1.jpg; micro_g3_final_adcconfig_foto2.jpg);
1 esquemtico 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 esquemtico 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);
Cdigo 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 Experincia de Boyle-Mariotte
Placa de controlo e aquisio para o aparato anterior (baseada no ADC LTC1298)
Osciloscpio digital;
Multmetro;

También podría gustarte