Hey, I'm working on a project that requires me to build a connected pill dispenser.
Both sides have an Arduino Uno, one for the pill dispenser and the other for the connected watch.
I'm on the pill dispenser side and I have :
- Serial Bluetooth v3.0 module (Use to send "1" to the watch, causing it to vibrate and remind the user to take a pill)
- Arduino GSM Shield V2 (Send an SMS to a family member if he does not take the pill.)
- 4x4 Keypad (Write the number)
- 16x2 LCD (Show the number, and heartbeat)
- DS1307 RTC module (So that we can send the vibration or SMS at a specific time. )
- Xbee that I yet have to implement (Receive heartbeat from the watch)
In the project, we don't really care if the person takes the pills or not, we don't do that part. If he has to take it at 10h00, we send the reminder to the watch at 9h55, and the SMS to a familly member at 10h05
1. GSM and Keypad library :
I tried to implement the GSM library on top of the Keypad library. Lots of error appeared during the compilation, so I changed in 2 or 3 file inside the Keypad library every IDLE, PRESSED enum with srbIDLE, srbPRESSED and so on.
Even if I still have some errors I can compile the program
I tried doing this GSM and Keypad conflit with namespace, but it didn't work, maybe I did something wrong. I did put the namespace, when I created Keypad.cpp (He didn't precise how to call the .cpp file) and I try to compile, I had something like "Key.cpp was not found"
Again, by changing the enums in the Keypad library, even if I have some error it seems to compile.
2. GSM and SoftwareSerial library (HELP) :
Now that Keypad & GSM seems to be fixed, I'm trying to add the SoftwareSerial library for the bluetooth module and again, some things are in conflit with each other.I tried to modify SoftwareSerial.cpp and GSM3SoftSerial.cpp but I have the same error. So I reverted the modification.
Any way to fix this ?
Pin 2-3 are for the GSM TX-RX, 4 to 11 is for the Keypad, 12 and 13 for the Bluetooth module. Xbee module not implemented yet.
I commented out the bluetooth part so I can try adding the SoftwareSerial library and see if it compile or not but you can see what command I use just to send "1".
#include <Wire.h>
#include "RTClib.h"
#include "rgb_lcd.h"
#include <Keypad.h>
//#include <SoftwareSerial.h>
#include <GSM.h>
rgb_lcd lcd;
RTC_DS3231 rtc;
// Initialisation du Keypad 4x4 //
const byte ROWS = 4; // Définie la longeur du tableau [rangée]
const byte COLS = 4; // Définie la longueur du tableau [colonne]
byte rowPins[ROWS] = {11, 10, 9, 8}; // Définile les pins associé pour les [rangées]
byte colPins[COLS] = {7, 6, 5, 4}; // Définie les pins associé pour les [colonnes]
char Jour_Lettre[7][4] = {"Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"}; // Tableau des jours de la semaine
char hexaKeys[ROWS][COLS] = { // Tableau pour associer chaque touche du keypad à un(e) chiffre/lettre
{'1', '2', '3', 'C'},
{'4', '5', '6', 'D'},
{'7', '8', '9', 'E'},
{'A', '0', 'B', 'F'}
};
Keypad keypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); // Accepte uniquement des valeurs contenu dans des const byte / byte [Keypad = library && keypad nom donné à la fonction]
//////// FONCTIONS / VARIABLES KEYPAD && LCD ////////
////////////////////////////////////////////////////
char Numero[10]= ""; // Permet de stocker le numéro lors de la confirmation | ^
char NumeroTemp[11]= ""; // Stock le numéro saisi temporairement | Il sera stocké dans Numero lors de la confirmation |
char NumeroUndo[11]= ""; // Stock le numéro écrit afin de l'afficher à nouveau si effacé
int pos = 3; // pos = position du curseur LCD
int pos_num = 0; // pos_num = position dans le tableau --> char NumeroTemp && NumeroUndo
bool verif = 0; // Permet de rentrer dans le while() de la confirmation
long Temps_Precedent = 0; // Stock le temps écoulé, sera MàJ à chaque action et servira de nouvelle référence pour "Saisi réinitialisé automatiquement || F"
//////// GERE LA DURÉE (millisecondes) //////// // Gère la durée d'affiche de messages et met à jour Temps_Precedent par rapport à ce délai
#define DELAI_Eff_Undo 50 // Définie le temps à attendre dans la fonction "Effacer" && "Undo"
#define DELAI_Confirmation 600 // "Confirmation" && "Enregistrement" && "Modification" && "Réinitialisation"
#define DELAI_Proche 2000 // "Afficher le proche à contacter"
//////// COULEUR BACKLIGHT LCD ////////
enum {BLEU,BLANC,ROUGE,VERT}; // Enum permet d'associer un mot à une constante, en commençant par la gauche et par 0
void Couleur_RGB(int couleur){ // Si on écrit Couleur_RGB(un mot définit dans enum) int couleur prendra sa variable
switch(couleur){ // Selon la variable un cas va s'exécuter
case BLEU : // case 0
lcd.setRGB(0, 115, 180);
break;
case BLANC : // case 1
lcd.setRGB(255, 255, 255);
break;
case ROUGE : // case 2
lcd.setRGB(255, 0, 0);
break;
case VERT : // case 3
lcd.setRGB(0, 255, 0);
break;
default : // Si aucune variable ne correspond à un case, il exécutera "default"
lcd.setRGB(255, 255, 255);
break;
}
}
void Reset_Pos(){
pos = 3; // On remet la position du curseur LCD à 3
pos_num = 0; // On remet la position du tableau à 0
}
void Reset_Char(){
memset(NumeroTemp, 0, 11); // memset permet de remplir les n premiers octets de la zone mémoire pointé par s avec c
memset(NumeroUndo, 0, 11); // memset(s, c ,n). Ici par 0, soit NULL, on efface tout
}
void Avancer_Pos(){ // On incrémante 1 pour avancer l'affichage LCD et dans le tableau
pos ++;
pos_num ++;
}
//////// EFFACE LE DERNIER CHIFFRE ////////
void Effacer(){
pos --;
pos_num --;
NumeroTemp[pos_num] = '\0'; // On efface dans le tableau NumeroTemp, à x position, le numéro auparavant enregistré grace à \0
lcd.setCursor(pos, 0);
lcd.print(' ');
Couleur_RGB(ROUGE);
delay(DELAI_Eff_Undo);
Couleur_RGB(BLANC);
}
//////// UNDO "EFFACE LE DERNIER CHIFFRE" ////////
void Undo(){
if (NumeroUndo[pos_num] != 0){ // Si dans la position du tableau il y a une valeur différente de NULL, donc s'il y a un chiffre
NumeroTemp[pos_num] = NumeroUndo [pos_num];
lcd.setCursor(pos, 0);
lcd.print(NumeroTemp[pos_num]);
Avancer_Pos();
Couleur_RGB(VERT);
delay(DELAI_Eff_Undo);
Couleur_RGB(BLANC);
}
}
//////// CONFIRME LE NUMÉRO SAISI ////////
void Confirmation(){
Couleur_RGB(VERT);
lcd.clear(); // On efface tout l'affichage
lcd.setCursor(3, 0); // On affiche (colonne 3, ligne 1)
lcd.print("Enregistre"); // "" Enregistre ""
lcd.setCursor(3, 1);
lcd.print(NumeroTemp);
delay(DELAI_Confirmation);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Non : B Oui : F");
lcd.setCursor(3, 1); // On affiche (colonne 3, ligne 2) : le numéro de téléphone enregistré pendant 5 secondes
lcd.print(NumeroTemp); // Le numéro de téléphone tapé pendant 3.5 secondes
verif = 1;
}
//////// ENREGISTRE LE NUMÉRO SAISIE ////////
void Enregistrement(){
strcpy (Numero, NumeroTemp); // !!!! On place le numéro tapé dans dans NumeroTemp au sein de la variable Numero (qui nous servira pour le GSM)!!!!
Reset_Char();
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("Enregistrement");
lcd.setCursor(4, 1);
lcd.print("effectue");
delay(DELAI_Confirmation);
lcd.clear();
Couleur_RGB(BLANC);
verif = 0;
Reset_Pos();
}
//////// MODIFICATION DU NUMÉRO SAISI ////////
void Modification(){
Couleur_RGB(ROUGE);
lcd.clear();
lcd.setCursor(3, 0);
lcd.print("Annulation");
lcd.setCursor(1, 1);
lcd.print("enregistrement");
delay(DELAI_Confirmation);
Afficher_a_Nouveau();
verif = 0;
}
//////// AFFICHE LE PROCHE A CONTACTER ////////
void Afficher_Proche(){
Couleur_RGB(BLEU);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Pers a contacter");
lcd.setCursor(3, 1);
lcd.print(Numero);
delay(DELAI_Proche);
}
//////// AFFICHE DE NOUVEAU LE NUMÉRO SAISI ////////
void Afficher_a_Nouveau(){
lcd.clear();
lcd.setCursor(3, 0);
lcd.print(NumeroTemp);
lcd.setCursor(pos, 0);
Couleur_RGB(BLANC);
}
//////// SAISI RÉINITIALISÉ AUTOMATIQUEMENT || F ////////
void Reinitialisation(){
lcd.clear();
Couleur_RGB(ROUGE);
lcd.setCursor(0, 0);
lcd.print("Reinitialisation");
lcd.setCursor(4, 1);
lcd.print("en cours");
delay(DELAI_Confirmation);
lcd.clear();
Couleur_RGB(BLANC);
Reset_Char();
Reset_Pos();
}
//////// AFFICHE DATE && HEURE ////////
void Afficher_Date(){
int Jour; // Stock le jour
int Mois; // Stock le mois
int Annee; // Stock l'année
int Seconde; // Stock les secondes
int Minute; // Stock les minutes
int Heure; // Stock les heures
String jSem; // Stock le jour de la semaine
String maDate; // Stock : Le jour de la semaine(écrit) jour de la semaine(chiffre) / mois / année
String monTps; // Stock : Heure / Minute / Seconde
DateTime now = rtc.now();
Jour = now.day();
Mois = now.month();
Annee = now.year();
Seconde = now.second();
Heure = now.hour();
Minute = now.minute();
jSem = Jour_Lettre[now.dayOfTheWeek()];
maDate = maDate +jSem+ " "+ Jour + "/" + Mois + "/" + Annee;
monTps = monTps + Heure +":"+ Minute +":" + Seconde;
lcd.setCursor(2,0);
lcd.print(maDate);
lcd.setCursor(4,1);
lcd.print(monTps);
maDate = "";
monTps = "";
delay(1000);
}
int decompte = 0; // Utilisé pour faire le décompte dans la boucle while pour afficher la date & heure pendant 5 secondes
/*//////// FONCTIONS / VARIABLES BLUETOOTH ////////////
////////////////////////////////////////////////////
bool Activer_Vibration = 1;
#define Rx 12
#define Tx 13
SoftwareSerial blueToothSerial(Rx,Tx);
void Bluetooth(){
blueToothSerial.begin(9600);
blueToothSerial.print("AT+DEFAULT"); // Restore all setup value to factory setup
blueToothSerial.print("AT+NAMEPilulier"); // set the bluetooth name as "Pilulier" ,the length of bluetooth name must be less than 12 characters.
blueToothSerial.print("AT+ROLEM"); // set the bluetooth work in master mode
blueToothSerial.print("AT+CLEAR"); // Clear connected device mac address
}*/
///////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
void setup(){
Serial.begin(9600);
lcd.begin(16, 2); // Initialise le LCD en 16x2
rtc.begin(); // Démarre le module RTC
//pinMode(Rx, INPUT); // Rappel, Rx = pin 12
//pinMode(Tx, OUTPUT); // Rappel, Tx = pin 13
//Bluetooth();
}
void loop(){
long Temps_Actuel = millis(); // millis() permet de voir le temps écoulé depuis que le système est en marche
char keyPress = keypad.getKey(); // STOCK la touche appuyé dans la variable keyPress //
DateTime now = rtc.now();
lcd.setCursor(0, 1);
lcd.print("Saisir le numero");
//////// ON ÉCRIT UN CHIFFRE ////////
if (isdigit(keyPress) && pos < 13) {
lcd.setCursor(pos, 0); // Affiche le numéro appuyé (colonne, ligne 1)
lcd.print(keyPress); // On affiche la touche appuyé
NumeroTemp[pos_num] = keyPress; // Commence à écrire à partir de la position 0 dans le tableau NumeroTemp
NumeroUndo[pos_num] = NumeroTemp [pos_num];
Avancer_Pos();
Temps_Precedent = Temps_Actuel;
}
//////// EFFACE LE DERNIER CHIFFRE ////////
if (keyPress == 'E' && pos > 3){
Effacer();
Temps_Precedent = Temps_Actuel +DELAI_Eff_Undo;
}
//////// UNDO "EFFACE LE DERNIER CHIFFRE" ////////
if (keyPress == 'B' && pos < 13){
Undo();
Temps_Precedent = Temps_Actuel +DELAI_Eff_Undo;
}
//////// CONFIRMER LE NUMÉRO SAISI ////////
if (keyPress == 'C' && pos_num == 10){ // Si on confirme (C) et qu'on est arrivé à bout du tableau (10) et donc qu'on a écrit le numéro complet
Confirmation();
while (verif == 1){
char keyPress = keypad.getKey();
long Temps_Actuel = millis() +DELAI_Confirmation;
if (keyPress == 'F'){
Enregistrement();
Temps_Precedent = Temps_Actuel;
}
else if (keyPress == 'B'){
Modification();
Temps_Precedent = Temps_Actuel;
}
}
}
/*//////// AFFICHE LE PROCHE À CONTACTER ////////
if (keyPress == 'A'){
Afficher_Proche();
Afficher_a_Nouveau();
Temps_Precedent = Temps_Actuel +DELAI_Proche;
}*/
//////// AFFICHE DATE && HEURE ////////
if (keyPress == 'D'){
Couleur_RGB(BLEU);
decompte = 5;
lcd.clear();
while (decompte > 0, decompte--){ // Permet de faire le décompte dans la boucle pour afficher la date & heure pendant 5 secondes
Afficher_Date();
}
Afficher_a_Nouveau();
Temps_Precedent = Temps_Actuel +5000;
}
//////// SAISI RÉINITIALISÉ AUTOMATIQUEMENT || F////////
if (keyPress == 'F' || Temps_Actuel - Temps_Precedent >= 20000){
Reinitialisation();
Temps_Precedent = Temps_Actuel +DELAI_Confirmation;
}
/*//////// VIBRATION BRACELET ////////
if(keyPress == 'A'){
blueToothSerial.print(Activer_Vibration);
}
/// TEST ///
/*if(now.minute() == 59 && now.second() == 30){
lcd.setRGB(255, 0, 0);
delay(60000);
lcd.setRGB(255, 255, 255);
}*/
}