LusoRobótica - Robótica em Português
Sistemas específicos => Arduino / AVR => Tópico iniciado por: almamater em 04 de Agosto de 2010, 00:28
-
Hello!
Estou a programar uma pequena aplicação em VB para se conectar ao arduino e obter informação da eeprom, consigo que funcione mas tenho um problema..
Só consigo obter resposta do Arduino (mesmo com a ligação série efectuada / open) se fizer Reset manual nele, isto apenas acontece qdo antes ele foi utilizado tb por um serial monitor como o que vem no software de upload do Arduino...
A minha questão é, pq é que ao ligar o Serial Monitor da aplicação do Arduino ele faz Auto-Reset e através da minha aplicação ele não o faz, se fizesse ia ficar com este problema resolvido..
Estou a usar:
clsSerial.BaudRate = 9600
clsSerial.DataBits = 8
clsSerial.Parity = 0
clsSerial.StopBits = 1
clsSerial.GetPorts()
clsSerial.PortNumber = 6
Há alguma forma de "forçar" o reset ao arduino durante esta ligação?
Se ligar o Arduino e utilizar logo a minha aplicação funciona bem, mas se usar antes a porta série dele a seguir já me acontece o que referi :-[
-
Bom dia,
VB .net ou VB6?
Penso que esse problema pode ser devido a teres a ligação da porta de serie já aberta, terias de verificar se já existe uma ligação aberta e fecha-la manualmente (não sei se é possivel).
Acho que quando fazes um reset, fechas as ligações com a porta de serie actuais e abres as novas ligações, dai ele funcionar nessa altura.
-
Bom dia,
VB .net ou VB6?
Penso que esse problema pode ser devido a teres a ligação da porta de serie já aberta, terias de verificar se já existe uma ligação aberta e fecha-la manualmente (não sei se é possivel).
Acho que quando fazes um reset, fechas as ligações com a porta de serie actuais e abres as novas ligações, dai ele funcionar nessa altura.
Vb .net 2008 e 2010, pois deve ser isso.. já tentei encontrar alguma opção para forçar o fecho das ligações da COM do arduino mas sem resultados.. grr foi um filme para perceber o envio/recepção para o arduino e consegui, agora reparei neste pormenor!
-
Se perceberes de C# posso-te enviar o que uso para a comunicação. Sendo .net podes inclusive colocar como um projecto em paralelo na solução.
-
Se perceberes de C# posso-te enviar o que uso para a comunicação. Sendo .net podes inclusive colocar como um projecto em paralelo na solução.
OK, gracias! pode ser que resolva o meu problema! podes enviar para aqui (almamater@mail.telepac.pt) sff
-
Dá uma vista de olhos aqui também: http://bravomofo.blogspot.com/2010/03/serial-talk.html (http://bravomofo.blogspot.com/2010/03/serial-talk.html)
Comigo funcionou sem problemas até ao momento.
-
humm estranho, estava a testar agora a mesma coisa mas num Computador com Windows XP e funciona tudo bem :o, estabelecendo ligação com a minha aplicação em VB o Arduino faz reset.. coisa que em Windows 7 não faz.. será dos drivers FTDI?
-
Bom.. outra dúvida.. a questão anterior tem de se resolver com um Reset ao Arduino sempre que acontece.
Agora estou com outra situação, como é que posso enviar o valor por exemplo "155" e o Arduino não ler linha a linha:
1
5
5
mas sim um valor inteiro 155 ? ::)
A função que estou a usar em VB para o envio é:
Dim WithEvents serialPort As New IO.Ports.SerialPort
Public Function Send(ByVal txtMsg As String) As Boolean
Try
txtMsg += vbCrLf
serialPort.Write(txtMsg)
Return True
Catch ex As Exception
Return False
End Try
End Function
-----------------------------------
Private WithEvents clsSerial As New Serial
'ENVIO:
clsSerial.Send("155")
-
Tens que usar a função atoi, que converte ASCII ou seja strings em inteiros.
Para usares essa função tens de passar a string a usar, não sei como lhe chamas no teu programa, portanto imaginemos que se chama String_recebida, para converteres para um int fazes o seguinte no teu programa:
meu_inteiro = atoi(String_recebida);
-
Bom.. tentei de diversas formas implementar isso no programa do arduino mas sem sucesso.. algo me está a escapar :-\
Peguei no exemplo do site do arduino para tentar perceber:
int incomingByte = 0; // for incoming serial data
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
Enviado para o Arduino o valor "255" ele recebe isto (http://img535.imageshack.us/img535/3969/001ejg.png):
I received: 50
I received: 53
I received: 53
Ok, apresenta segundo a tabela Aschii, colocando a função atoi "int meu_inteiro = atoi(incomingByte);" tenho um erro:
error: invalid conversion from 'int' to 'const char*
Já pesquisei e já testei definir com char* incomingByte [0];
mas nunca dá!
é que eu precisava mesmo de obter o valor certo definido, pq quero guardar na eeprom várias varáveis e cada uma delas vai ter um valor de 0 a 255 recebido pela porta série, como o Arduino recebe linha a linha tenho possivelmente de fazer um ciclo para juntar as leituras todas para me fazer 1 número: 255 em vez de 3 números: 2, 5, 5
-
Não estás a perceber ... o problema não está no arduino :P
Tens de converter de string para inteiro ... ou melhor provavelmente não precisas de fazer isso, se, como argumento da função send, em vez de uma string, aceitares um inteiro, e o enviares.
Assim, quando fazes:
clsSerial.Send(155)
(nota a falta de aspas), envias o INTEIRO (que será o carácter de acordo com a tabela ASCII :P).
Ou então, dentro da função, usas o atoi.
Usando síntaxe de C (não gosto do de VB xD e não estou habituado), a tua função seria uma coisa assim:
int Send(int intMsg) {
return serialPort.Write((char)intMsg); } // Considerando que retorna falso quando falha e vice-versa.
No entanto, isto tem a desvantagem de aceitar apenas números entre 0 e 255, já que o arduino recebe byte a byte ... a outra opção, é alterar o código do arduino de forma a que ele receba cada dígito do número, e os transforme em inteiros (postei há pouco tempo uma função que faz isso! xD).
Vê este tópico: http://lusorobotica.com/index.php?topic=2633.0 (http://lusorobotica.com/index.php?topic=2633.0)
Apenas tens de enviar um carácter para o arduino saber que tem de parar de ler o número :P, usando a função getnumber()
-
Obrigado pela explicação.
Neste caso enviado o 255 dá o seguinte:
(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fimg827.imageshack.us%2Fimg827%2F2125%2F001wj.th.png&hash=e0fd2f9c9fd24980aaf4c4894343adb8faacddf1) (http://img827.imageshack.us/i/001wj.png/)
Está certo assim não está?
-
O metRo_ uma vez andou a pedir-me ajuda num código para exactamente isso.
O cliente que está a receber o serial tem que processar a informação, já que a transmissão serial é sempre byte a byte
Das duas uma. Ou fazes um software para quem está a enviar os dados, que converte o número que colocas na letra ascii com esse valor, e podes mandar valores de 0 a 256 (equivalente a 1 byte de comunicação), ou quem recebe os dados, sabe que vai receber vários números ascii e vai multiplicado por 10 para shiftar de forma decimal até obter um caracter terminador, ou x bytes pré configurados.
-
Ok, podem chamar-me burro :-X
Tenho 3 processos que podem ser executados de acordo com o que é recebido via serial.read, tenho tudo a funcionar menos a parte de receber o valor inteiro e por inteiro
Em VB tenho as seguintes funções:
Envia Strings:
Public Function Send(ByVal txtMsg As String) As Boolean
Try
' // txtMsg += vbCrLf
serialPort.Write(txtMsg)
Return True
Catch ex As Exception
Return False
End Try
End Function
Para enviar o valor Inteiro (já testei as Byte e as Integer):
Public Function Send2(ByVal txtMsg2 As Byte) As Boolean
Try
serialPort.Write(txtMsg2)
Return True
Catch ex As Exception
Return False
End Try
End Function
No lado do Arduino tenho:
byte com; //lê string recebido
byte Posicao; //saber a posição na eeprom
byte ValorExtra; //para gravar valor na eeprom
int ValorEeprom; //para ler valor de eeprom
void loop()
{
if (Serial.available() > 0)
{
com = Serial.read();
delay(50);
if (com== 103){ //se receber a letra "g"
Posicao= Serial.read();
delay(50);
ValorExtra= Serial.read();
delay(50);
}
if (com== 103){ // letra "g"
if (Posicao== 97){ // letra "a"
EEPROM.write(0,ValorExtra);
Serial.print("VALOR 1 GUARDADO: ");
Serial.println(EEPROM.read(0));
delay(100);
}
if (Posicao== 98) { // letra "b"
EEPROM.write(1,ValorExtra);
Serial.print("VALOR 2 GUARDADO: ");
Serial.println(EEPROM.read(1));
delay(100);
}
etc.
Ou seja, o "g" representa a condição para gravar na eeprom e dentro desta tenho vários IFs que identificam a posição pretendida..
No meu programa em VB estou a fazer assim:
clsSerial.Send("ga") '//Usa a função SEND para enviar as letras "g" e "a" [ciclo gravar e na posição/IF 'a']
clsSerial.Send2(145) '//Usa a função SEND2 para enviar o valor a gravar na eeprom que pode ser de 0-255
O arduino de facto detecta o "g", detecta o "a" mas quando vai a gravar na eeprom grava apenas o número correspondente em ascii do 1º digito que recebeu, neste caso do 1 e grava o valor 49 em vez do 145
-----------------
Estive o dia todo a inventar e alterar coisas e juro que já tinha conseguido receber o valor por inteiro de uma só vez.. mas sinceramente já dei tanta volta que me baralhei e tou assim neste momento.
-
Mas a função atoi faz isso e devia funcionar devidamente..
Lê sobre ela.
-
Hum, isso devia ter funcionado ... só se houver algum problema com a forma como a função Serial.write está a processar o número :S E em vez de o processar como um valor de um byte, transforma numa string (o que, sinceramente, acho uma grande estupidez xD).
De qualquer forma, aconselho-te então a usar ou a função que te mostrei: http://lusorobotica.com/index.php?topic=2633.0 (http://lusorobotica.com/index.php?topic=2633.0)
Ou então, guarda o número numa string, e usa o atoi (vai dar ao mesmo xD). De qualquer forma, tens de enviar um carácter de fim de número.
Por exemplo, alterar o código que mostraste, de forma a mandar um número, terminado de S (ps: não precisas de dois if(comm==103), por isso tomei a liberdade de tirar o segundo :P):
Public Function Send(ByVal txtMsg As String) As Boolean
Try
' // txtMsg += vbCrLf
serialPort.Write(txtMsg)
Return True
Catch ex As Exception
Return False
End Try
End Function
byte com; //lê string recebido
byte Posicao; //saber a posição na eeprom
byte ValorExtra; //para gravar valor na eeprom
int ValorEeprom; //para ler valor de eeprom
void loop()
{
if (Serial.available() > 0)
{
com = Serial.read();
delay(50);
if (com== 103){ //se receber a letra "g"
Posicao= Serial.read();
delay(50);
ValorExtra= Serial.read();
delay(50);
}
if (com== 103){ // letra "g"
if (Posicao== 97){ // letra "a"
EEPROM.write(0,ValorExtra);
Serial.print("VALOR 1 GUARDADO: ");
Serial.println(EEPROM.read(0));
delay(100);
}
if (Posicao== 98) { // letra "b"
EEPROM.write(1,ValorExtra);
Serial.print("VALOR 2 GUARDADO: ");
Serial.println(EEPROM.read(1));
delay(100);
}
etc.
long getnumber(char stop_character) {
int cs;
long i = 0;
while(1) {
while(!Serial.available())
delay(100); // Verifica a cada 100 ms -- para não esforçar demais o CPU -- se recebeu dados
cs = Serial.read();
if(stop_character == (char)cs) break; // Recebe os dados e compara-os com o carácter de paragem. Se for igual, pára de receber dados.
if(cs < '0' || cs > '9') continue; // Se não for um dígito ignoramos
i *= 10;
i += (cs-'0'); } // O número resultado avança uma casa decimal para cima, e adiciona o dígito lido (para obter o dígito decimal a partir do caracter, basta subtrair o caracter '0'.
return i; }
clsSerial.Send("ga145S") '//Usa a função SEND para enviar as letras "g" e "a" [ciclo gravar e na posição/IF 'a'] e o número 145 (letra S usada para terminar o número)
Atenção, como a variável usada para guardar o número recebido é um byte, só suporta entre 0 e 255, apesar de poderes enviar números maiores para a função getnumber, apenas os primeiros 8 bits serão usados.
Prefiro usar uma função como a que mostrei aqui, em vez do atoi, pois o atoi obrigaria a usar processamento e armazenamento extra: receber a string por serial, guardá-la, e depois passá-la para o atoi processá-la carácter a carácter. Assim, processamos cada byte do serial logo.
Ou fazes isto, ou então fazes o que provavelmente é o melhor: estuda melhor o VB, e vê se percebes porque é que o teu byte 145 está a ser convertido para uma string, e como podes evitar isso. Ou então muda de linguagem :P, para uma em que isso não acontece sem tu saberes ...
-
Humm ok! Tenho pensar adoptar o C# / c.net ;D
Obrigado pela paciência antes de mais!
Acho que não foram publicadas as alterações referidas na parte do com= serial.read (), tenho apenas de colocar desta forma com = getnumber('S'); certo?
void loop()
{
com = getnumber('S');
delay(50);
if (com== 103){
Posicao= Serial.read();
delay(50);
ValorExtra= Serial.read();
}
//GRAVAR VALORES EEPROM:
if (Posicao== 97){ // letra "a"
EEPROM.write(0,ValorExtra);
Serial.print("VALOR 1 GUARDADO: ");
Serial.println(EEPROM.read(0));
delay(100);
}
if (Posicao== 98) { // letra "b"
EEPROM.write(1,ValorExtra);
Serial.print("VALOR 2 GUARDADO: ");
Serial.println(EEPROM.read(1));
delay(100);
}
etc
}
long getnumber(char stop_character) {
int cs;
long i = 0;
while(1) {
while(!Serial.available())
delay(100); // Verifica a cada 100 ms -- para não esforçar demais o CPU -- se recebeu dados
cs = Serial.read();
if(stop_character == (char)cs) break; // Recebe os dados e compara-os com o carácter de paragem. Se for igual, pára de receber dados.
if(cs < '0' || cs > '9') continue; // Se não for um dígito ignoramos
i *= 10;
i += (cs-'0'); } // O número resultado avança uma casa decimal para cima, e adiciona o dígito lido (para obter o dígito decimal a partir do caracter, basta subtrair o caracter '0'.
return i; }
-
Humm ok! Tenho pensar adoptar o C# / c.net ;D
Obrigado pela paciência antes de mais!
Acho que não foram publicadas as alterações referidas na parte do com= serial.read (), tenho apenas de colocar desta forma com = getnumber('S'); certo?
void loop()
{
com = getnumber('S');
delay(50);
if (com== 103){
Posicao= Serial.read();
delay(50);
ValorExtra= Serial.read();
}
//GRAVAR VALORES EEPROM:
if (Posicao== 97){ // letra "a"
EEPROM.write(0,ValorExtra);
Serial.print("VALOR 1 GUARDADO: ");
Serial.println(EEPROM.read(0));
delay(100);
}
if (Posicao== 98) { // letra "b"
EEPROM.write(1,ValorExtra);
Serial.print("VALOR 2 GUARDADO: ");
Serial.println(EEPROM.read(1));
delay(100);
}
etc
}
long getnumber(char stop_character) {
int cs;
long i = 0;
while(1) {
while(!Serial.available())
delay(100); // Verifica a cada 100 ms -- para não esforçar demais o CPU -- se recebeu dados
cs = Serial.read();
if(stop_character == (char)cs) break; // Recebe os dados e compara-os com o carácter de paragem. Se for igual, pára de receber dados.
if(cs < '0' || cs > '9') continue; // Se não for um dígito ignoramos
i *= 10;
i += (cs-'0'); } // O número resultado avança uma casa decimal para cima, e adiciona o dígito lido (para obter o dígito decimal a partir do caracter, basta subtrair o caracter '0'.
return i; }
Não alteres o que disseste que alteravas xD
O com serve para receberes letras, ou seja, lê carácter a carácter do serial, normalmente. O getnumber('S') lê todos os dígitos do serial (ignorando assim as letras 'g' e 'a'), até chegar à letra 'S'. Logo, tens inicialmente de ler o 'g' (para saberes que vais receber o número) e o 'a' (para saberes onde guardar) através do serial.read(). Depois é que lês o número :P
PS: Não conheço o C# por isso não posso comentar. No entanto, recomendaria que tentasses aprender uma linguagem diferente e universal (no sentido de ser suportada por vários sistemas operativos), como python, perl, C/C++ ou java (recomendo mais o C/C++, pois se vais fazer projectos com o arduino, ou mesmo outros microcontroladores, provavelmente vais usar essa linguagem, por isso é importante que compreendas bem o seu sintaxe/funcionalidade).
-
:D
Muito obrigado a todos pela ajuda! em especial ao Cynary que nesta fase final não estava mesmo a perceber o porquê de não chegar um inteiro ao Arduino mas com a função Getnumber é uma maravilha!! ;)
Obrigado!
-
Bom, aproveitando este tópico pq o assunto é o mesmo.. e fui eu que o criei :P
Estive ontem a testar a ligação com o Arduino em VB .net com o Firmata e funcionou bem, a ligação é estabelecida sem problemas e fica logo 'sincronizado' com a aplicação, com os exemplos que disponibilizam (http://firmata.org/wiki/Main_Page (http://firmata.org/wiki/Main_Page)) consigo ligar/desligar os pinos e obter valores analógicos.
Eu estava a pensar em monitorizar sensores (temperatura / distância / etc) numa aplicação, acho que a melhor forma é o Arduino obter o valor do sensor e calcular o resultado e enviar o mesmo para a aplicação (serial).. com o Firmata não percebi ainda muito bem como enviar/receber strings..
Como costumam fazer? a minha alternativa ao Firmata é estabelecer uma ligação série normal e ler/filtrar tudo o que chega vindo do Arduino..