French communication B4A vers Arduino et visversa avec Bluethooth ou GPS

Henrig

Member
Licensed User
Longtime User
Mon idée est de commander un maximum de sortie en High/Lowe d’un Arduino Méga, selon la porté(loin, très loin) c’est un GSM Sim900 qui dialogue et si je suis prêt ce sera le Bluetooth
Jusqu'à présent j’en commande une bonne cinquantaine mais tous ceci n’est qu’un exercice de style et tous passe bien avec un GSM Sim900, a voir ici :
http://forum.arduino.cc/index.php?topic=252733.msg1830283#msg1830283
j’en suis donc à la partie Bluetooth qui prendra le relais quand il sera à porté , peut être utiliserai-je le WIFI aussi

J’ai utilisé un exemple de communication <<Module bluetooth JY-MCU V1.04 pour Arduino>> entre Arduino et mon Smartphone,
le code de bluetooth.zip vers Arduino fonctionne correctement, mais pas celui Arduino/Smartphone je n’arrive pas à l’implémenter sur mon Smartphone
en fait les trois dernière ligne font dépairer le SmartPhone et plante,
Le code Arduino Méga :

B4X:
//**********************************************
// Module bluetooth HC06 avec envoi de commandes AT
// et affichage de la réponse du module
// code de  http://nicolasz68.blogspot.fr/2012/09/module-bluetooth-jy-mcu-v104-pour.html
// pour les resistances  http://42bots.com/tutorials/hc-06-bluetooth-module-datasheet-and-configuration-with-arduino/
//***********************************************/* 
#include <SoftwareSerial.h>  //Software Serial Port
#include <String.h>
#include <print.h>
#include <serial.h>
#define RxD 10  //Pin 10 pour RX (pin0=serial) vert    19
#define TxD 11   //Pin 11 pour TX, on peut changer noir 18
SoftwareSerial BTSerie(RxD,TxD); 
 
String msg = String("");
void setup() 
{ 
  Serial.begin(9600);    //115200 si on veut
  delay(500); 
  Serial.println("Bonjour - Pret pour les commandes AT"); 
  // Configuration du bluetooth 
  pinMode(RxD, INPUT); 
  pinMode(TxD, OUTPUT); 
  BTSerie.begin(9600);  //57600
  delay(500);  //1200
  BTSerie.print("AT+VERSION");  //Demande le N° de version
  delay(500); 
  BTSerie.print("\n"); 
} 
 
void loop() 
{ 
  //On lit caractere par caractere sur le BTSerie et on affice sur le Terminal Serie
  char recvChar;
  String msg ;
 
  if (BTSerie.available()) { 
   while(BTSerie.available()) { // While there is more to be read, keep reading.
     recvChar = (unsigned char)BTSerie.read(); 
     msg += String(recvChar);
   }
     Serial.print(msg);
     Serial.println("");
     msg ="";
  } 
 
  //if (BTSerie.available()) {
  //while(BTSerie.available()) { // While there is more to be read, keep reading.
  //msg += (unsigned char)BTSerie.read();
  //}
 
  if (Serial.available()) { 
    recvChar = Serial.read(); 
    BTSerie.write(recvChar);
    //BTSerie.write(Serial.read());
  } 
     //Serial.print(msg);
}

coté B4A j'ai bluetooth.zip

Je sais pas trop quoi mettre comme fonction pour réceptionner les caractères sur la parti B4A, et pourtant le code et simple et fonctionne parfaitement
Merci de votre intérêt si vous me donnez une piste
Cordialement
Henri
 

Attachments

  • Bluetooth.zip
    466.3 KB · Views: 599

nico78

Active Member
Licensed User
Longtime User
Je travaille dessus, je posterais bientôt un code!
 

nico78

Active Member
Licensed User
Longtime User
Je me suis dis au départ que c'étais facile à faire mais en réalité non, j'ai passé plusieurs nuits à debugger et faire des corrections à cause du préfixe lors de l'envoi dans le code basic4android. Il est possible de se passer du préfixe mais il est beaucoup mieux de le garder, cela permet d'être sûr de recevoir la chaine en une seule fois. De plus j'ai dû apporter des corrections dans le code basic4android pour empêcher d'envoyer une chaine de caractères supérieure à 60, si c'est le cas, la chaine est systématiquement tronqué dans mon exemple mais on peut tout simplement ne pas l'envoyer.
Cette restriction est dû à la librairie SoftwareSerial qui ne peut pas traiter plus de 64 octets à la fois donc 4 bytes pour la longueur de la chaine (préfixe) + 60 octets pour la chaine mais il est possible d'augmenter ce chiffre en modifiant le fichier SoftwareSerial.h et en passant la valeur #define _SS_MAX_RX_BUFF 64 à 128 ou 256, si des modifications sont faites dans ce fichier, il faudra alors modifier le code présenté ci dessous.
Un autre problème constaté est le fait que le programme basic4android n'attend pas de réponse de l'arduino pour savoir s'il est prêt pour recevoir un deuxième message. Ce qui fait que dans la boucle de traitement des données, lorsque qu'on fait un read on libère de l'espace et cet espace est rempli par d'autres octets si on renvoie un message de l'appli android avant que le code arduino n'est fini de réceptionner le premier message.

Bien pensé à sélectionner retour chariot dans le moniteur série!

La carte Mega dispose de 4 port série, Serial, Serial1, Serial2 et Serial3, il aurait été plus simple de raccorder le module bluetooth sur le Serial1 par exemple, cela aurait évité la restriction des 64 bits en réception.

Tout cela a été pris en compte et tester avec une carte arduino mega 2560 et un module bluetooth HC05, voici le code [update du 05/11/14 à 19H53]:
B4X:
#include <SoftwareSerial.h>
#define RxD 10  //Pin 10 raccorder le TX du module bluetooth
#define TxD 11  //Pin 11 raccorder le RX du module bluetooth

SoftwareSerial BTSerie(RxD, TxD);

String msg;
byte test;
byte value;
char SerialCaracteres;
unsigned int Caracteres;
unsigned int NombreCaracteres;
unsigned int ValeurTampon;

void setup()
{
  Serial.begin(9600);
  BTSerie.begin(9600);
}

void loop()
{
  if (BTSerie.available() > 3) {
    NombreCaracteres = 0;
    Caracteres = 0;
    msg = "";

    // On récupère les 4 premiers octets qui indique la longueur de la chaine
    // qui suit sans prendre en compte les 4 premiers octets
    // qui va du byte le plus fort au byte le plus faible
    // parce que c'est programmé de cette façon dans le code basic4android
    // mais on aurait pu traiter du byte le plus faible au byte le plus fort
    // en modifiant le code source basic4android dans cette ligne:
    // AStream.Initializeprefix(Main.serial1.InputStream, True, Main.serial1.OutputStream, "AStream")
    // il suffit de passer la valeur true à false
    for (int i = 3; i > -1; i--) {
      ValeurTampon = 0;
      ValeurTampon = BTSerie.read();
      NombreCaracteres = (NombreCaracteres + (ValeurTampon  << (8 * i)));
    }

    // on vérifie que la longueur est inférieur à 61 car
    // la librairie SoftwareSerial ne peut traiter quun maximum de 64 bits à la fois
    // mais il est possible de modifier cette valeur dans le fichier:
    // SoftwareSerial.h
    // se trouvant ici:
    // C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\SoftwareSerial
    // en modifiant cette ligne:
    // #define _SS_MAX_RX_BUFF 64 // RX buffer size --> on voit bien ici la valeur 64
    // mais ensuite il faudra bien sûr modifier le code présenté
    // donc 4 byte pour la longueur et 60 byte max pour la chaine = 64
    if (NombreCaracteres < 61) {
      //Serial.println(String(NombreCaracteres));
      // ce delay est très important, il permet d'être sûr d'avoir reçu
      // tous les octets avant l'extraction
      delay(60);
      // vérification que la chaine dans le buffer est bien égale
      // au nombre de caractère attendu sinon on vide le buffer
      if (BTSerie.available() == NombreCaracteres ) {
        while (NombreCaracteres != Caracteres) {
          if (BTSerie.available() > 0) {
            msg += (char)BTSerie.read();
            Caracteres += 1;
            //delay(100);
            //Serial.println(String(Caracteres));
          }
        }
        Serial.println(msg);
        msg = "";
        // très important on vide le buffer de SoftwareSerial car le nombre
        // de caractère attendu ne correspond pas à celui présent dans le buffer
      } else {
        while (BTSerie.available() > 0) {
          //Serial.println("Erase");
          BTSerie.read();
        }
      }
    }
  }

  // on vérifie si des données sont présentes à la réception
  // du port série Serial
  if (Serial.available() > 0) {
    NombreCaracteres = 0;
    SerialCaracteres = char(0);
    msg = "";
    test = 1;
    // la lecture s'arrête dès que le retour chariot est reçu
    // donc sélectionner retour chariot dans le moniteur série
    // de l'IDE arduino
    while (SerialCaracteres != char(13)) {
      if (Serial.available() > 0) {
        SerialCaracteres = (char)Serial.read();
        if (SerialCaracteres != char(13)) {
          NombreCaracteres += 1;
          msg += SerialCaracteres;
          // delay nécessaire pour ralentir la lecture des données
          delay(1);
        }
      // Si on n'a pas reçu le retour chariot, on quitte la boucle
      } else {
        test = 0;
        msg = "";
        //Serial.println("Cancel");
        break;
      }
    }

    if (test == 1) {
      // on envoie la longueur de la chaine en premier
      // du byte le plus fort au byte plus faible
      value = 0;
      value = (byte)(NombreCaracteres >> 24);
      BTSerie.write(value);

      value = (byte)(NombreCaracteres >> 16);
      BTSerie.write(value);

      value = (byte)(NombreCaracteres >> 8);
      BTSerie.write(value);

      value = (byte)(NombreCaracteres);
      BTSerie.write(value);

      // on envoie la chaine de caractères
      BTSerie.print(msg);
      msg = "";
    }
  }
}


La modification à faire dans le fichier bluetooth, dans la partie ChatActivity:
B4X:
Sub btnSend_Click
    Dim texte As String
    If txtInput.text.Length > 60 Then
        texte = txtInput.text.SubString2(0,60)
    Else
        texte = txtInput.text
    End If
    Log(texte)
    AStream.Write(texte.GetBytes("UTF8"))
    txtInput.SelectAll
    txtInput.RequestFocus
    LogMessage("Me", txtInput.Text)
End Sub
 
Last edited:

Henrig

Member
Licensed User
Longtime User
Bonsoir Nico78
En fait j'essaye un peu de pousser les cartes Mega avec cette combine : http://forum.arduino.cc/index.php?topic=252733.msg1830283#msg1830283
si le code vous intéresse il est bien sur à vous, mais c'est de toute façon c'est loin d’être terminé.
je n'ai pas de but vraiment précis là dessus, juste pour voir si Arduino et B4A faisait bon ménage, faut se creuser un peu la tête mais OUI
pour de petite distance j'ai quelque projets qui intègre le bluetooth d'ou ma recherche et il n'y a pas grand chose en fait !
votre réflexion sur les serials est évidente, mais je n'ai rien trouvé d'autre comme modèle que le broche 10 et 11, j'ai bien sur essayé les serial1...4 mais sans succès et ceci me déçoit un peu
mon Arduino Mega est déjà connecté a un gsm SIM900 (un premier prix chinois, mais qui marche bien) et tout les exemples que j'ai trouvé se connecte avec les sortie 51, 52 je sais pas si ceci a une conséquence sur l'utilisations des autre serials, jusque là j'ai pas trouvé mieux et c'a fonctionne bien
je suis loin de mon domicile, mais dés le WE j'essayerai votre code,
je suis aussi en galère en ce moment pour utiliser B4A sur un portable(64bit et Windows 7), ce qui m'aurai permis d'avancer plus
il faut dire aussi que je commence juste à mettre le pied à l’étrier sur Arduino.

En tout cas Merci de vos réponses et l'interet que vous y portez
Henri
 

Henrig

Member
Licensed User
Longtime User
En fait il ne fonctionnait pas car je ne sélectionnais le bon API dans Android.SDK (api18 ! ! !)
maintenant c'est OK (pour cette parti)
j'ai testé un exemple en l’envoyant par mail sur mon smartphone et c'est OK car je n'ai ni bluetooth et je n'y arrive pas par le câble relié a ce portable.
En fait je ne sais plus comment me servir de Babridge et BA4 designer par câble, peut-être avez-vous une suggestion ?


Merci Klaus
 

nico78

Active Member
Licensed User
Longtime User
Concernant le câble, il faut coché usb debugging dans le smartphone et que le driver soit installé je crois; pour le driver, il suffit en général d'installer le soft du constructeur s'il existe bien sûr sinon je ne sais pas.

Pour le Serial1, je viens de faire des tests et apparemment il y a aussi un buffer de 64 bit alors que j'ai lu qu'il y aurait un buffer de 128 bit, mystère mais bon cela n'est pas un problème pour envoyer des commandes, cela reste suffisant.

Il suffit donc de remplacer BTSerie par Serial1 ou celui de votre choix et de supprimer ces lignes:
#include <SoftwareSerial.h>
#define RxD 10 //Pin 10 raccorder le TX du module bluetooth
#define TxD 11 //Pin 11 raccorder le RX du module bluetooth

SoftwareSerial BTSerie(RxD, TxD);
 

nico78

Active Member
Licensed User
Longtime User
J'ai mis à jour le code en utilisant des instructions spécifiques aux Serial:

B4X:
char msgrecu[60];
char msgenvoye[60];
unsigned int recu;

unsigned int value;
unsigned int NombreCaracteres;
unsigned int ValeurTampon;

void setup()
{
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop()
{
  if (Serial1.available() > 3) {
    NombreCaracteres = 0;
    ValeurTampon = 0;
    // on remplit avec des 0 le tableau de char
    for (int i = 0; i < 60; i++) {
      msgrecu[i] = char(0);
    }
    // On récupère les 4 premiers octets qui indique la longueur de la chaine
    // qui suit sans prendre en compte les 4 premiers octets
    // qui va du byte le plus fort au byte le plus faible
    // parce que c'est programmé de cette façon dans le code basic4android
    // mais on aurait pu traiter du byte le plus faible au byte le plus fort
    // en modifiant le code source basic4android dans cette ligne:
    // AStream.Initializeprefix(Main.serial1.InputStream, True, Main.serial1.OutputStream, "AStream")
    // il suffit de passer la valeur true à false

    for (int i = 3; i > -1; i--) {
      ValeurTampon = Serial1.read();
      NombreCaracteres = (NombreCaracteres + (ValeurTampon  << (8 * i)));
      // ligne qui suit pour le debug
      Serial.println(String(NombreCaracteres));
    }
    //38
    if (NombreCaracteres < 61) {
      recu = Serial1.readBytes(msgrecu, NombreCaracteres);
      if (recu == NombreCaracteres) {
        Serial.print("Message recu: ");
        Serial.println(msgrecu);
      }
    }
    // s'il reste des caracteres, pon vide le buffer
    delay(1);
    while (Serial1.available() > 0) {
      Serial1.read();
      delay(1);
      // ligne qui suit pour le debug
      Serial.println("Erase Serial1");
    }
  }

  // on vérifie si des données sont présentes à la réception
  // du port série Serial
  if (Serial.available() > 0) {
    NombreCaracteres = 0;
    // on remplit avec des 0 le tableau de char
    for (int i = 0; i < 60; i++) {
      msgenvoye[i] = char(0);
    }

    // la lecture s'arrête dès que le retour chariot est reçu
    // donc sélectionner retour chariot dans le moniteur série
    // de l'IDE arduino

    NombreCaracteres = Serial.readBytes(msgenvoye, 60);
    Serial.println(String(NombreCaracteres));

    // on vérifie que le dernier caractère est bien un retour chariot
    if (msgenvoye[(NombreCaracteres - 1)] == char(13)) {
      // on envoie la longueur de la chaine en premier
      // du byte le plus fort au byte plus faible
      value = 0;
      value = (byte)(NombreCaracteres >> 24);
      Serial1.write(value);

      value = (byte)(NombreCaracteres >> 16);
      Serial1.write(value);

      value = (byte)(NombreCaracteres >> 8);
      Serial1.write(value);

      value = (byte)(NombreCaracteres);
      Serial1.write(value);

      // on envoie la chaine de caractères
      Serial1.print(msgenvoye);

      // les deux lignes qui suivent sont pour le debug
      Serial.print("Message envoye: ");
      Serial.println(msgenvoye);
    }
    // S'il reste des caracteres, on le vide
    while (Serial.available() > 0) {
      Serial.read();
      delay(1); 
      // ligne qui suit pour le debug
      Serial.println("Erase Serial");
    }
  }
}
 

nico78

Active Member
Licensed User
Longtime User
L'avantage en wifi lorsque vous ferez des tests, c'est que vous n'aurez pas besoin de créer une appli android, il suffira juste d'utiliser votre navigateur web habituel sur le PC ou sur votre mobile mais si vous le souhaitez vous pourrez faire une interface spécifique.

Vous avez un exemple ici qu'il faudra adapter:
http://arduino.cc/en/Tutorial/WebServer
 
Top