Conectar o pic ao mundo via serial

Software e Hardware para uC PIC

Moderadores: andre_luis, 51, guest2003, Renie

Conectar o pic ao mundo via serial

Mensagempor ze » 28 Jan 2015 12:10

...pra atrair sua atenção

olás. estou querendo capturar o peso de uma balança cuja palavra é esta
Código: Selecionar todos
STX C C C C C C P P P P P R R R R R R T T T T T T ETX
......................................|...|.|.|......

STX=start = 0x02
ETX=stop = 0x03
O peso em g está nos T´s indicados p[17],p[19],p[20]e p[21]. No caso, aguardo STX, aguardo RCIF, incremento i até 23 (p[i]) e localizo a informação. Pareço ter tido sucesso com isso mas com a instabilidade mencionada abaixo. Caso tenha alguma ideia melhor, não se acanhe! sinta-se a vontade em expô-la!
Mas como nem tudo são flores: o mc tem que fazer isso pra mostrar ao vivo num display 7 segmentos que são multiplexados. Ou seja, não pode parar de multiplexar pra receber o dado e vice versa. Além de ter que tomar alguma decisões em função do peso e tal...
Tentei
-usar interrupçoes do timer junto com interrupçao da serial mas parece que uma atrapalha a outra. O mc (pic16f883) não tem o lance de prioridade de interrupção.
-fazer uma rotina de receber dados por fora dentro do loop principal mas está meio instável. A interrupt do timer parece zoar o barraco

ah sim 4 displays, interrupt a 400Hz, baud 2400, a balança envia a palavra o tempo todo

Vc tem algo pra aliviar meu sofrimento? Alguma ideia? Me lembro que o amigo xuts mencionou algo a respeito. e alguém falou algo sobre decodificador em anel ou algo assim... cara memória fraca...

porque não no forum pic??....o boteco parece ser melhor frequentado. Sr moredador, se um dia pretender mover pra lá, troque o título. Mas não perca seu tempo...deixa por aqui mesmo por enquanto

agradeço a voce, caro bom e velho amigo querido leitor ocasional.
Ah sim, talvez vc não saiba mas tento ajudar a molecada neste e em outros foruns. Bom .. acho que isso não te motiva em nada.. foi só pra desabafar mesmo...
Editado pela última vez por andre_luis em 10 Mar 2015 20:51, em um total de 2 vezes.
Razão: movido da seção 'Boteco' para seção 'PIC' / Titulo alterado sob demanda do autor
Avatar do usuário
ze
Dword
 
Mensagens: 1655
Registrado em: 05 Jun 2007 14:32

Re: Não consigo pensar num título melhor...

Mensagempor Maffeis » 28 Jan 2015 12:25

A interrupção da serial apenas salva o valor em uma fila.

A interrupção do timer incrementa uma variável de certo em certo tempo.

no loop principal do programa vc coloca uma maquina de estados, vendo variável de tempo e atualizando os displays.

vc coloca na maquina de estados um estado para verificar a fila de tempos em tempos isso vai atualizar os valor que será mostrado no display.

Ou vc utiliza um sistema operacional de tempo real, por exemplo o FreeRTOS.
Maffeis
Word
 
Mensagens: 501
Registrado em: 07 Ago 2010 19:10

Re: Não consigo pensar num título melhor...

Mensagempor Red Neck Guy » 28 Jan 2015 12:26

Eu faria assim:
- Criaria uma int de rx
- Criaria um buffer de N posições para colocar os dados recebidos da balança
- Dentro da int de RX quando recebesse STX setaria o ponteiro para o inicio do buffer e quando recebesse ETX calcularia o peso e colocaria numa variavel global
- Na verdade eu criaria uma lista e colocaria as últimas medidas nele, para poder fazer médias e tudo mais.
ASM51 descanse em paz!
Avatar do usuário
Red Neck Guy
Dword
 
Mensagens: 1968
Registrado em: 12 Out 2006 22:24

Re: Não consigo pensar num título melhor...

Mensagempor brasilma » 28 Jan 2015 12:58

Fique tranquilo, tenho inúmeras aplicações assim e a capacidade de um controlador da familia '51 (rodando a 2MHz) dá tranquilo (os Z80 dos primeiros computadores pessoais varriam todo o vídeo 30 telas/s (gerando sincronismo), liam teclado, e quando sobrava tempo ainda processavam o programa do usuário, rsrsrs).

Por uma questão de segurança e sincronismo trabalhe com duas rotinas controladas por interrupção uma para a leitura da serial - com maior prioridade - e outra para a multiplexação, o programa principal, onde são tratados os dados e o cliente entra com outros opera no tempo que sobrar (coloque a rotina de varredura de teclado dentro da interrupção com menor prioridade).
" A Teoria orienta e a Prática decide" ;-)
Avatar do usuário
brasilma
Dword
 
Mensagens: 3621
Registrado em: 11 Out 2006 15:39
Localização: Planeta Terra

Re: Não consigo pensar num título melhor...

Mensagempor ze » 28 Jan 2015 13:28

-mafeis: obrigado. Atualizar display no loop principal? bom parece que (me) perco um pouco o controle. O objetivo seria pouco processamento na interrupt do timer pra não zoar a da serial?

-aquino: tentei algo assim. mas tem o lance da interrupt do timer da varredura encavalar na da serial (e vice versa). acho que esta é a essência do problema

-brasilma: o ideal é mesmo duas interrupts. com outro mc que tem como definir prioridade já tive algum sucesso no passado. na verdade deixava a de multiplexação como prioritária (errado?). neste pic não tem isso. ele só tem um vetor. Digamos p.ex que recebe um dado no momento em que o display está apagado, tenho que colocar o byte no buffer[], ver se é STX, etc, e o display ficará um tempinho a+ apagado e vai dar (deu) uma piscadela irritante. De fato tentei não fazer nada na interrupt da serial a não ser pôr o byte no {buffer[i++]; if (i>23) i=0;} (a piscadela é causada por este processo!!) mas estou com dificuldade em achar os dados entre STX e ETX por fora. Estou no caminho certo? como separar/achar os dados dentro deste "anel" sendo ele rotativo? (não sei se me entende) Preciso sincronizar as coisas e a mente...? Ah sim tem teclado mesmo. este leio na varredura dos anodos comuns dos displays...
Avatar do usuário
ze
Dword
 
Mensagens: 1655
Registrado em: 05 Jun 2007 14:32

Re: Não consigo pensar num título melhor...

Mensagempor Red Neck Guy » 28 Jan 2015 13:35

Tu deve estar ficando muito tempo dentro das interrupções do timer, tente fazer as coisas o mais rápido possível na int e usar o processamento na thread principal.
Tenho inumeras aplicações assim, onde leio de protocolos diferentes, processo, informo na ihm e não tenho perda alguma de dados.
ASM51 descanse em paz!
Avatar do usuário
Red Neck Guy
Dword
 
Mensagens: 1968
Registrado em: 12 Out 2006 22:24

Re: Não consigo pensar num título melhor...

Mensagempor xultz » 28 Jan 2015 13:49

Zé, uma interrupção não encavala a outra. O importante é que quando você entrar numa ISR, desabilite as interrupções, trate, habilite e saia. Se estiver tratando a serial e o timer gerar flag de interrupção, ele vai ficar lá esperando sair da serial prá tratar o display.
Assim, as ISR precisam ser muito, muito enxutas. Prá ISR de serial, eu geralmente faço uma máquina de estados bem simples, mas ou menos como o Aquino sugeriu. Cria uma variável chamada de estado (ou outro nome mais criativo), e inicializa com 0.
Quando entrar na ISR da seria, verifica se o recebido é STX. Se sim, muda prá 1.
Se estado for 1, incrementa um contador. Se contador chegar a 17 (pelo que entendi, são bytes que você recebe mas ignora), muda estado para 2.
Se estado for 2, pega byte, guarda na primeira posição de um buffer de 4 posições, muda estado prá 3.
Se estado for 3, pega byte, guarda na segunda posição do buffer, muda estado prá 3
E faz assim até chegar no último estado, onde confere se recebeu um ETX. Se sim, seta uma variável global chamada flag_serial, e muda estado para zero. Se não recebeu ETX, recebeu lixo, muda estado prá zero e não seta flag_serial.

Na tua ISR do timer, você vai ler uma variável que tem o peso, converte prá 7 segmentos, escreve nos pinos, e cai fora.

Na tua main, você fica num loop infinito, que se flag_serial estiver setada, zera ela, converte o valor recebido do buffer de 4 posições e escreve na variável global de peso.

Vai por mim, desse jeito funciona de boa.
98% das vezes estou certo, e não estou nem aí pros outros 3%.
Avatar do usuário
xultz
Dword
 
Mensagens: 3001
Registrado em: 13 Out 2006 18:41
Localização: Curitiba

Re: Não consigo pensar num título melhor...

Mensagempor brasilma » 28 Jan 2015 14:06

Zé, a rotina de interrupção serial é muito rápida (curta) e serve apenas para retirar o byte (recebido) do buffer de recepção para não perdê-lo (retira e coloca numa área de memória para ser tratado pela rotina principal), sendo assim não causa nenhum problema a sua rotina de varredura.

Capici?
" A Teoria orienta e a Prática decide" ;-)
Avatar do usuário
brasilma
Dword
 
Mensagens: 3621
Registrado em: 11 Out 2006 15:39
Localização: Planeta Terra

Re: Não consigo pensar num título melhor...

Mensagempor Maffeis » 28 Jan 2015 14:17

Sobre maquina de estados

O Exemplo é justamente um protocolo desse tipo.

http://sergioprado.org/maquina-de-estados-em-c/
Maffeis
Word
 
Mensagens: 501
Registrado em: 07 Ago 2010 19:10

Re: Não consigo pensar num título melhor...

Mensagempor ze » 28 Jan 2015 16:09

-brasilma foi isso que pensei... mas segundo o conceito do xults, será que devo fazer isso tudo dentro da isr ? realmente vai tomar um tempinho
nos comentários, os do xults. amigo se desejares, podes conferir?
Código: Selecionar todos
if (RCIF)
   {
   if (RCREG==_stx) estado=1; //Quando entrar na ISR da serial, verifica se o recebido é STX. Se sim, muda prá 1
   if (estado==1) x++; //Se estado for 1, incrementa um contador.
   if (x==17)       {estado=2;} //Se contador chegar a 17 (pelo que entendi, são bytes que você recebe mas ignora), muda estado para 2.
   if (estado==2) {buffer[0]=RCREG;estado=3;}//Se estado for 2, pega byte, guarda na primeira posição de um buffer de 4 posições, muda estado prá 3.
   if (estado==3) {buffer[1]=RCREG;estado=4;}//Se estado for 3, pega byte, guarda na segunda posição do buffer, muda estado prá ...
   if (estado==4) {buffer[2]=RCREG;estado=5;}
   if (estado==5) {buffer[3]=RCREG;estado=6;}//E faz assim até chegar
   if (estado==6) {buffer[4]=RCREG;estado=7;}// no último estado,
   if (estado==7) {//onde
                  if (RCREG==_etx) ////confere se recebeu um ETX.Se sim,
                     {
                     flag_serial=1; //seta uma variável global chamada flag_serial,
                     estado=x=0;//e muda estado para zero
                     }
                  else estado=x=0;//Se não recebeu ETX, recebeu lixo, muda estado prá zero e não seta flag_serial.
                  }
   }

teria eu que fazê-lo no loop principal? mas aí não seria interrupção
no loop faço assim
Código: Selecionar todos
//etc...
if (flag_serial) {flag_serial=0;peso=balanca();} //balanca retorna buffer[0,2,3,4] num int
display(peso);
//...


De fato ainda não tive sucesso. Devo estar fazendo uma cagadinha básica. Não está compondo o buffer[] direito
Tipo a rotina de timer varredura não pode ser totalmente enxuta pois leio teclas nela p.ex.
ôu... e agora? quem poderá me ajudar?
ah sim.. obrigado mafeis. lê-lo-ei
Avatar do usuário
ze
Dword
 
Mensagens: 1655
Registrado em: 05 Jun 2007 14:32

Re: Não consigo pensar num título melhor...

Mensagempor MOR_AL » 28 Jan 2015 23:24

Bom.
Se o dado vai para um display de 7 segmentos, então você pode dispensar algumas (muitas) transmissões.
Imagine que você aceite uma taxa de atualização dos dados no display de, digamos, 4 vezes por segundo.
Aí você poderia aceitar a continuar processar 4 dados por segundo. Os outros você simplesmente despreza.
Aí vai dar tempo para fazer tudo.
Não sei se ajudei. Na verdade li as postagens rapidamente.
Se não tiver nada a ver, desconsidere.
MOR_AL
"Para o triunfo do mal só é preciso que os bons homens não façam nada." Edmund Burke.
"Nunca discutas com pessoas estúpidas. Elas irão te arrastar ao nível delas e vencê-lo por possuir mais experiência em ser ignorante". Mark Twain
Avatar do usuário
MOR_AL
Dword
 
Mensagens: 2934
Registrado em: 19 Out 2006 09:38
Localização: Mangaratiba - RJ

Re: Não consigo pensar num título melhor...

Mensagempor KrafT » 29 Jan 2015 00:48

Concordo, com os colegas: Esse tratamento todo é trivial para o PIC, ainda mais com esse baudrate baixíssimo.

Uma coisa é certa, você tem que atender o display pelo menos umas 30x por segundo, para não dar flicker. Por que vc usa 400Hz?

Tem cara que vc não está apagando alguma flag de interrupção ao sair...

Por outro lado, essa tua aplicação (devido à velocidade da serial ser baixa), até pode rodar completamente no main, só usa a int do timer para gerar uma tick de 1ms. O flag da serial vc pode ler por pooling.

Outra coisa que eu penso, é que vc tá recebendo lixo na serial e não tá tratando os flags de erro da UART. Tenta ver se esses flags não tão gerando uma int não tratada.

Qual é a frequência de clock do PIC?
"..."Come to the edge," he said. And so they came. And he pushed them. And they flew."― Guillaume Apollinaire
Avatar do usuário
KrafT
Dword
 
Mensagens: 2228
Registrado em: 11 Out 2006 14:15
Localização: Blumenau -SC

Re: Não consigo pensar num título melhor...

Mensagempor xultz » 29 Jan 2015 08:01

Zé, aquele monte de if não é muito interessante.
O ideal é fazer um switch. Por exemplo
Código: Selecionar todos
unsigned char leitura;

leitura = RCREG;

switch(estado)
{
case 0:
  if(leitura == 'STX')
  {
      estado = 1;
      contador = 0;
   }
   break;

case 1:
   contador++;
   if(contador == 17)
      estado = 2;
   break;

case 2:
   buffer[0] = leitura;
   estado = 3;
   break;


e assim por diante. Desta forma, o código compara o estado, desvia praquele ponto, executa 2 ou três linhas, e retorna, é muito otimizado.
98% das vezes estou certo, e não estou nem aí pros outros 3%.
Avatar do usuário
xultz
Dword
 
Mensagens: 3001
Registrado em: 13 Out 2006 18:41
Localização: Curitiba

Re: Não consigo pensar num título melhor...

Mensagempor andre_luis » 29 Jan 2015 08:25

Concordo, e fica mais fácil de debugar depois.
"Por maior que seja o buraco em que você se encontra, relaxe, porque ainda não há terra em cima."
Avatar do usuário
andre_luis
Dword
 
Mensagens: 5447
Registrado em: 11 Out 2006 18:27
Localização: Brasil - RJ

Re: Não consigo pensar num título melhor...

Mensagempor ze » 29 Jan 2015 10:28

-moris ajudou muito! de fato absolutamente tudo a ver! não tinha pensado nisso

-andre, concordo discordando. pra um pic com pouca memória, creia-me: if´s ocupam menos espaço. Passei por isso quando num projeto um mc de 1k ocupou 1022 bytes. Bom, não é o caso deste mas quis manter os princípios 'mãos de vaca'

-xuts, discordo concordando. realmente o break foi o separador de águas (quase que literalmente). Note que coloquei o return fazendo algo semelhante ao break. Durante a madrugada tive este insight, portanto antes destas tuas sábias palavras. Notaste as anteriores nos comentários?
Código: Selecionar todos
if (RCIF)
   {
   if (RCREG==_stx) estado=1; //Quando entrar na ISR da serial, verifica se o recebido é STX. Se sim, muda prá 1
   if (estado==1) x++; //Se estado for 1, incrementa um contador.
   if (x==18)       {estado=2;x=0;return;} //Se contador chegar a 17 (pelo que entendi, são bytes que você recebe mas ignora), muda estado para 2.
   if (estado==2) {buffer[0]=RCREG;estado=3;return;}//Se estado for 2, pega byte, guarda na primeira posição de um buffer de 4 posições, muda estado prá 3.
   if (estado==3) {buffer[1]=RCREG;estado=4;return;}//Se estado for 3, pega byte, guarda na segunda posição do buffer, muda estado prá ...
   if (estado==4) {buffer[2]=RCREG;estado=5;return;}
   if (estado==5) {buffer[3]=RCREG;estado=6;return;}//E faz assim até chegar
   if (estado==6) {buffer[4]=RCREG;estado=7;return;}// no último estado,
   if (estado==7) {//onde
                  if (RCREG==_etx) ////confere se recebeu um ETX.Se sim,
                     {
                     flag_serial=1; //seta uma variável global chamada flag_serial,
                     estado=0;//e muda estado para zero
                     x=0;
                     }
                  x++;
                  if (x>3) {estado=x=0;}//Se não recebeu ETX, recebeu lixo, muda estado prá zero e não seta flag_serial.
                  }
   }


-kraft pode ser trivial pro pic mas não pra um idoso com pouca intimidade com a inteligência (vulgo burro véio) tipo este que vos escreve.
Sim são 400Hz mas são 4 displays então vai dar '100Hz' cada um. Além do que um contador no timer me dá 0.01 segundos a cada varrida nos 4, facilita a matemática pra esta mula véia (não, não troquei de sexo neste parágrafo) pra uma temporização qualquer.
Quanto a zerar flag o hw faz isso pra mim. Basta ler o RCREG.... buffer[0]=RCREG. mc a 8MHz.
Rodar no main() é uma ideia desafiadora curiosa mas parece que dá uma sensação de... solidão. É legal sentir a presença de um 'coprocessador' da interrupt. Sei lá.. nem tente entender. Mas quiçá num projeto próximo considerá-lo-ei

Devo considerar o lance dos case swich sim e ainda promover alguma melhoria na apresentação e otimização do código. Mas primeiro vou soltar alguns foguetes

Bom resumindo, agradeço às manifestação dos jovens amigos velhos de guerra cuja sabedoria contribuiu para mais um caso de sucesso (parcial pois ainda não testei na prática).

Um forte abraço em cada 1 e 1 bj nas muiés do 6.

E se precisar de algo, conta comigo : 1....2...3....4.... !
Avatar do usuário
ze
Dword
 
Mensagens: 1655
Registrado em: 05 Jun 2007 14:32

Próximo

Voltar para PIC

Quem está online

Usuários navegando neste fórum: Nenhum usuário registrado e 1 visitante

x