Bienvenue aux nouveaux arrivants sur FantasPic !

- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.

--- L’équipe FantasPic ---
Commentez, partagez et proposez des Tutos en langage C !
Module Bluetooth RN-41
Jérémy
Administrateur du site
Administrateur du site
Messages : 2112
Âge : 39
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#1 Message par Jérémy » lun. 22 févr. 2016 22:02

Bonjour à tous,
Image

Je vous propose de voir ici le fonctionnement du Bluetooth-click de chez MikroE s’articulant autour du module RN-41 avec interface UART.

Le module sera piloté avec un PIC 18F46K22 posé sur ma carte EasyPIC7.

Pour faire ce Tuto je me suis inspiré de l'exemple de MikroE, que vous pouvez retrouver ici
Code exemple de MikroE
Schéma de connexion du module




Image



Configuration :

- PIC18F46K22
- Module Bluetooth-Click
- Plaque EasyPIC V7
- IDE : MikroC Pro for PIC Version 6.6.2
- Compilateur : Mikro prog suite fo PIC V 2.32





Attention!! Étant un gros fainéant je remplacerais le mot "Bluetooth" par le mot "BT"


Le but :

Dans ce tutoriel nous allons voir comment communiquer entre deux modules Bluetooth. La communication permettra à un PIC de recevoir des ordres du module RN-41 relié en filaire en utilisant l'UART comme protocole de dialogue . De l'autre une application pour device ( tablette ou smartphone) pour le système d'exploitation "android".

Nous allons créer une interface pour paramétrer un chronomètre avec notre application, envoyer les informations à notre module BT RN-41 et les transmettre au PIC pour qu'il agisse en conséquence.
L’arrière pensée de ce travail est la création d'un prise électrique connectée piloter avec un device .(voir dans la catégorie projet du forum).

Comme d'habitude je ne suis pas un expert, mais un passionné donc rien n'est optimisé, mais tout est testé ! La suite de ce tutoriel est ouvert à toute remarques constructives et étayées , pour faire avancer le schmilblick.

Le plus compliqué dans cette présentation n'est pas le programme du PIC en lui même, mais la communication entre les deux modules BT. A savoir la tablette et le Module RN-41.

Voici le schéma de connexion :
Image


1/ Initialisation du module BT
Image

En tout premier lieu, il convient d'initialiser notre Module, c'est à dire lui injecter des paramètres, comme le mot de passe, son nom etc ...
Toute cette configuration se trouve dans un fichier nommé BT_Routines.c que nous prendrons soin de déclarer avec un #include.

Vous trouverez tous le nécessaire pour mieux le configurer à cette adresse (en anglais) : Configuration du RN-41

Après chaque envoi d'un réglage on attend la réponse du module avant de continuer.

idea ! Je vous conseille la première fois de mettre l'allumage d'une LED à la fin des réglages pour voir si tout s'est bien passé. Il m'est arrivé de reste bloquer dans les réglages, et de chercher un moment :evil: .


Attention!! Je vous donne les principaux réglages, qui fonctionne chez moi.

Ceci est à mettre dans un fichier nommé BT_Routines.c de votre projet

► Afficher le code


Une fois la configuration réussie nous allons pouvoir nous connecté à notre BT, et établir un dialogue. Il vous faudra cependant créer une application pour cela sur votre device avec App inventor2 .(voir suite du tutoriel)

Le dialogue entre les deux équipements se constitue comme cela.

2/ Dialogue côté Micro-contrôleur PIC

En émission :
Grâce à l'interruption sur le TIMER0 configurée pour s’exécuter toutes les secondes, nous allons pouvoir envoyé l'état de notre chronomètre à intervalle régulier. L’envoi de cet état nous servira également de fil de vie coté reception tablette, afin de detecter une perte de communication.

toutes les secondes :
==> - Nous mettons notre chrono à jour, seulement si il est lancé.
==> - Nous envoyons l'état de notre chrono ( allumé ou éteint) pour que la tablette puisse l'affiché. Elle recevra des infos en temps réel de l'état du chrono.

L'envoi à la tablette se fait via un petit mot de reconnaissance ici "MAJ".

En reception :
Grâce à l'interruption de l'UART dés que nous recevons quelque chose de la part du BT nous l'enregistrons et le traitons .

==> - Si le début du mot reçu commence par "ch"(pour"chrono"), c'est que nous avons reçu un ordre de lancé le chrono, les bytes suivant seront les valeurs à enregistrées dans nos variable de temps.
==> - Si le début du mot reçu commence par "st" (pour stop), c'est que nous avons reçu l'ordre d’arrêter le chrono.

une fois connecté le module BT , se comporte comme une liaison UART mais sans les fils.

Voici le code du Micro-contrôleur :
[spoil]

Code : Tout sélectionner

/*##################################################################################
Programme de test du module Bluetooth-Click avec RN-41
Fait par Jérémy pour http://www.FantasPic.fr
- Version du "22-02-2016"
- MikroC version 6.6.2
- PIC 18F46K22 FOSC a 32MHZ , Quartz 8Mhz PLL ENable
- Data-Shit du PIC : http://ww1.microchip.com/downloads/en/DeviceDoc/41412F.pdf
#################################################################################*/

#include "BT_Routines.h"

// Constantes pour analyser les réponses
const BT_CMD  = 1;
const BT_AOK  = 2;
const BT_CONN = 3;
const BT_END  = 4;

// Connexion du module LCD
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

sbit LCD_RS at LATB4_bit;
sbit LCD_EN at LATB5_bit;
sbit LCD_D4 at LATB0_bit;
sbit LCD_D5 at LATB1_bit;
sbit LCD_D6 at LATB2_bit;
sbit LCD_D7 at LATB3_bit;
// Fin des connexion du module LCD


//#######################     Déclaration des Variables    #########################
char heure[6]={0};
char minute[6]={0};
char seconde[6]={0};
char txt[20]={0};

unsigned short Index_Buffer, tmp, DataReady, Flag_seconde ;
char CMD_mode, BT_state, response_rcvd, responseID, response = 0 ;
unsigned short Var_Heure, Var_Minute, Var_Seconde, Lancement, compteur, bit_de_vie ;

//###########################     Interruption    ##################################
void interrupt(){
  
  if 
(TMR0IF_bit)              // Interruption sur Timer 0 à 1 seconde
     {
       TMR0IF_bit = 0;        // RAZ du flag
       TMR0H      = 0x0B;     // On recale notre timer pour 1 seconde
       TMR0L      = 0xDC;
       Flag_seconde = 1;      // On signale qu'une seconde s'est écoulée
     }


  if (RCIF_bit == 1) {       // Interruption sur reception UART
    tmp = UART1_Read();      // On enregistre notre byte

    if (CMD_mode){           // Si CMD_mode est égale à 1, l'initialisation n'est pas encore terminée
                             // Tout ce qui arrive sur le buffer est une commande
      switch (BT_state) {
          case  0: {
                    response = 0;                   // Clear response
                    if (tmp == 'C')                 // We have 'C', it could be CMD<cr><lf>  or CONN
                      BT_state = 1;                 // Expecting 'M' or 'N'
                    if (tmp == 'A')                 // We have 'A', it could be AOK<cr><lf>
                      BT_state = 11;                // expecting 'O'
                    if (tmp == 'E')                 // We have 'E', it could be END<cr><lf>
                      BT_state = 31;                // expecting 'N'
                    break;                          // ...
          }
          case  1: {
                    if (tmp == 'M')
                      BT_state = 2;
                    else if (tmp == 'O')
                      BT_state = 22;
                    else
                      BT_state 
= 0;
                    break;
          }
          case  2: {
                    if (tmp == 'D') {
                      response = BT_CMD;           // CMD
                      BT_state = 40;
                    }
                    else
                      BT_state 
= 0;
                    break;
          }
          case 11: {
                    if (tmp == 'O')
                      BT_state = 12;
                    else
                      BT_state 
= 0;
                    break;
          }
          case 12: {
                    if (tmp == 'K'){
                      response = BT_AOK;            // AOK
                      BT_state = 40;
                    }
                    else
                      BT_state 
= 0;
                    break;
          }
          case 22: {
                    if (tmp == 'N')
                      BT_state = 23;
                    else
                      BT_state 
= 0;
                    break;
          }
          case 23: {
                    if (tmp == 'N') {
                      response = BT_CONN;           // SlaveCONNECTmikroE
                      response_rcvd = 1;
                      responseID = response;
                    }
                    BT_state = 0;
                    break;
          }
          case 31: {
                    if (tmp == 'N')
                      BT_state = 32;
                    else
                      BT_state 
= 0;
                    break;
          }
          case 32: {
                    if (tmp == 'D') {
                      response = BT_END;           // END
                      BT_state = 40;
                    }
                    else
                      BT_state 
= 0;
                    break;
          }
          case 40: {
                    if (tmp == 13)
                      BT_state = 41;
                    else
                      BT_state 
= 0;
                    break;
          }
          case 41: {
                    if (tmp == 10){
                      response_rcvd = 1;
                      responseID = response;
                    }
                    BT_state = 0;
                    break;
          }

          default: {
                    BT_state = 0;
                    break;
          }
      }
  }
    else                                // Une fois l'initialisation finie on remplie notre buffer
      {
        if (tmp == 13)                  // Si on recoit un "CR" fin d'une chaine de caractere
           {
              txt[Index_Buffer] = 0;       // Terminateur de string , on rajoute un 0 pour dire "Fin de la chaine"
              DataReady = 1;               // Une donnée à été recue et est prête , on léve le drapeau
           }
        else                               // Sin on a pas recu de "CR"
           {
              txt[Index_Buffer] = tmp;     // On place la donnée recue dans le tableau txt[] à l'endroit de l'index
              Index_Buffer++;              // Incremente l'index du tableau pour palcer la lettre suivante
           }
        RCIF_bit = 0;                     // Ré-arme le flag
      }
  }
}

// Get BlueTooth response, if there is any   ???? je sais pas trop, désolé ??????
char BT_Get_Response() {                  // Il doit s'agir de la reponse du module en fonction de la question
  if (response_rcvd) {
    response_rcvd = 0;
    return responseID;
  }
  else
    return 0
;
}

//##################################################################################
//#########################     PROGRAMME PRINCIPAL     ############################
//##################################################################################

void main() {
  // Configuration des PORTs
  ANSELC = 0;
  ANSELD = 0 ;
  TRISD = 0;
  PORTD = 0;

  // Initialisation des variables
  CMD_mode = 1;
  BT_state = 0;
  response_rcvd = 0;
  responseID = 0;
  response = 0;
  tmp = 0;
  DataReady = 0;

  //--------  Interruption sur reception UART   ------------------------
  GIE_bit  = 1;         // Enable Global interrupt, active toutes les interruptions
  PEIE_bit = 1;         // Enable Peripheral interrupt, active l'interruption sur les
  PIE1.RC1IE = 1;       // Enable UART RX interrupt
  PIR1.RC1IF = 0;       // Drapeau d'interrutpion
//--------------------------------------------------------------------

//--------  Interruption sur Timer 0  ------------------------
  T0CON         = 0x86;   // timer 0 activé + prescaler mis à 1/128
  TMR0H         = 0x0B;   // réglage de la valeur du TMR0 pour 1 seconde exact
  TMR0L         = 0xDC;
  TMR0IE_bit    = 1;      // Interrpution Activée
//--------------------------------------------------------------------

  UART1_init(115200);           // Initialise UART1 pour module /!\ NE PAS CHANGER  /!\ //
  delay_ms(100);
  
  Lcd_Init
();                   // Initialise le  Lcd
  delay_ms(100);
  Lcd_Cmd(_LCD_CLEAR);          // Efface LCD
  Lcd_Cmd(_LCD_CURSOR_OFF);     // Eteint le curseur

  // Messages de bienvenue
  Lcd_Out(1,1,"BlueTooth-Click!");
  Lcd_Out(2,1,"www.FantasPic.fr");
  Delay_ms(1500);

  // Configure le module BlueTooth-Click
  BT_Configure();  // Envoi la configuration au BT au démarrage via le fichier BT_Routines.c

  // Messages pour signaler qu'on attend la connexion entre les devices
  Lcd_Cmd(_LCD_CLEAR);
  Lcd_Out(1,1,"Connexion !");
  Lcd_Out(2,1,"SVP, attendez...");

  while (BT_Get_Response() != BT_CONN);    //  Tant que le BT n'est pas connecté on reste ici
  
  GIE_bit 
= 0;                  // Désactive les INT
  CMD_mode = 0;                 // On arrete le mode de commande car le BT est configuré et Connecté

  LCD_Cmd(_LCD_CLEAR);          // efface l'écran
  Lcd_Out(1,1,"Connexion OK !");// Affiche un message de connexion reussie
  Delay_ms(2000);
  
  Lcd_Cmd
(_LCD_CLEAR);          // efface l'écran
  Lcd_Out(1,1,"Reception...");  // Affiche un message

  GIE_bit = 1;                  // On ré-Active les INT

  DataReady = 0;                // RAZ du flag
  Index_Buffer = 0;             // RAZ dde l'index
  Flag_seconde = 0;             // RAZ du flag seconde
  Lancement = 0;                // RAZ du flag Lancement



//###################################################################################
 while (1) {

    if (DataReady)              // Si une donnée est recue
       {
         GIE_bit  = 0;               // Interdit les Interutpions le temps du traitement
         DataReady = 0;              // Réarme le flag
         Index_Buffer = 0;           // Raz l'index du buffer


//---------------  Reception des valeurs du chrono  ---------------------------
         if ( txt[0] == 'c' & txt[1] == 'h') // on verifie le mot de commande "ch" correspondant à chrono
            {
               Var_Heure = txt[3];    // On enregistre les valeurs du chrono recues dans les variables
               Var_Minute = txt[5];
               Var_Seconde = txt[7];

               Lancement = 1;   // On met le flag à 1 pour signaler le Lancement du chrono
            }


//---------------  Reception de l'arret du chrono  ---------------------------
         else if ( txt[0] == 's' & txt[1] == 't')  // on verifie le mot de commande "st" correspondant à stop
            {
               Lancement = 0;   // On met le flag à 0 pour signaler l'arret du chrono
            }
         Lcd_Out ( 2,1,txt);
        GIE_bit = 1;                // On ré-active les INT
       }

    if ( Flag_seconde == 1)        // Toute les secondes ont envoie les infos pour tenir le fil de vie
          {
            if ( Lancement == 1 )  // Si le Lancement à été effetué
               {                   // On effectue le décompte des secondes et on envoie les valeurs par BT
                  Var_Seconde--;   // On décremente une seconde

                  if (Var_Seconde > 59 )   // Quand la secondes passe de 0 à 255
                     {
                        Var_Seconde = 59;
                        Var_Minute--;      // On décremente une minute
                        if (Var_Minute> 59 )
                           {
                              Var_Minute = 59;
                              Var_Heure--;

                              if (Var_Heure > 59 )  // Si le Compte à rebours arrive à zéro
                                 {
                                   Lancement = 0;   // On arrete le chrono
                                   Var_Heure = Var_Minute = Var_Seconde = 0;  // On RAZ les valeurs
                                 }
                            }
                      }
                  PORTD = Var_Seconde;   // me permet de verifier que le chrono tourne sur la carte easypic.  A supprimer apres test
               }

             UART1_Write_text("MAJ"); // Mot de reconnaisance pour la tablette
             UART1_Write(Lancement);  // On indique que le chrono tourne ou non
             UART1_Write(Var_Heure);  // On indique la variable pour MAJ de la tablette
             UART1_Write(Var_Minute);
             UART1_Write(Var_Seconde);

             Flag_seconde = 0;    // Réarme le flag
          }
  }
[/spoil]


3/ Dialogue côté tablette et app invetor2 :

Le principe est quasiment le même qu'avec le PIC, mais faites de manière différente avec app inventor2.

En émission :
L'application de la tablette n'as pas besoin d'envoyer de ligne de vie à notre PIC car , il n'y a rien à effectué en cas de perte de communication. Bien sur c'est tout de même envisageable, avec l'envoi également d'une info toute les secondes.

- Envoie des données, sur l'appui du bouton "START". la trame envoyée se constitue du préambule avec les lettres "ch" , suivie de séparateurs, puis des valeurs rentrées sur la tablette dans les cases correspondantes et enfin d'un "CR" .
- Envoie des données, sur l'appui du bouton "STOP". La trame envoyée est seulement constituée du mot "st" et d'un "CR".

En reception :
Souvenez vous , la tablette reçoit des infos toutes les secondes envoyées par le PIC et le Timer0.

- Elle vérifie le que le mot "MAJ" soit bien reçu en préambule, si c'est le cas , elle enregistre et affiche les valeurs envoyé par le PIC( notre chrono).
- Elle regarde aussi la ligne de vie . En effet à chaque informations reçue, elle RAZ un compteur pour ne pas qu'il déborde . Si le compteur déborde c'est que la tablette n'as pas reçu de mise à jour plusieurs secondes, donc que la communication à été perdue . Elle le signale par un message et propose de se reconnecter .

Voici les images de app invetor2 : (Attention ça pique les yeux ! )
[spoil]Image[/spoil]


En conclusion :

Avec App inventor2 la mise en forme du programme complique énormément les choses. En effet de simple chose sur la papier comme :
==> - Pour ne pas envoyer de texte vide.
==> - Cacher/afficher tel ou tel image.
==> - Empêche l'envoi si un nombre est trop grand etc ....

font de lourdes taches à gérer et beaucoup de choses à modifier.

Voila grâce à ce tutoriel j’espère que vous réussirez à faire dialoguer votre module BlueTooth-Click( RN-41) avec un autre device fonctionnant en BlueTooth.
Il vous suffit de bien configurer vôtre module, une application pour tablette/Smartphone, et hop le tour est joué !!

Résultat en vidéo:


Le programme à été légèrement modifié pour la vidéo afin de voir clairement ce que l'on reçoit dans le buffer du PIC sur le LCD . A savoir le mot de reconnaissance et les valeurs du chrono.
Les leds du port D , sont les secondes du chrono, quand elles changent c'est que le chrono tourne !
http://www.dailymotion.com/video/x3tzntj


A très vite j’espère !!
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Module Bluetooth RN-41
paulfjujo
Avatar de l’utilisateur
Expert
Expert
Messages : 1028
Âge : 67
Enregistré en : juillet 2015
Localisation : 01120
Contact :

#2 Message par paulfjujo » mar. 23 févr. 2016 11:01

bonjour Jeremy,


- Cacher/afficher tel ou tel image.


La supperposition d'image ne marche pas ,(ou je n'ai pas trouvé/compris l'astuce ?) avec le parametre visible/non visible,
c'est quand meme dommage !
et la seule solution que j'ai trouvé est d'utiliser les SPRITES ..contenus dans un canvas (grafique).

Module Bluetooth RN-41
Jérémy
Administrateur du site
Administrateur du site
Messages : 2112
Âge : 39
Enregistré en : juillet 2015
Localisation : Dans le sud
Contact :

#3 Message par Jérémy » mar. 23 févr. 2016 11:08

et la seule solution que j'ai trouvé est d'utiliser les SPRITES ..contenus dans un canvas (grafique).

effectivement ça doit être lourd de faire ça .

En faite la superposition n'existe pas en mode designer(ou je ne l'ai pas trouvé non plus). Il faut masquer une image et en rendre une autre visible .ensuite faut inverser. Mais tout dépend de la complexité que tu souhaite faire.

Par exemple pour mon image de LED .
en mode designer les deux leds sont cote à cote.
en mode Blocks, J'initialise l'écran avec la led grise visible et la rouge non-visible. Comme ca je ne vois qu'une led. Ensuite j'inverse tout simplement et la led grise s'efface et la rouge prends ca place . on a l'impression qu'elle sont superposées
C'est en faisant des erreurs, que l'on apprend le mieux !!!

Module Bluetooth RN-41
AchileT
Membre
Membre
Messages : 17
Enregistré en : septembre 2015

#4 Message par AchileT » dim. 22 mai 2016 09:58

Salut

:bravo: pour ce tuto bien utile !


Retourner vers « Langage C »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité