Hi everyone,
Hope this is not a duplicate, but I need some help with my project.
I want to have a lock that I can unlock both with a pin and from the blynk app. I have struggled to do the checking of key inputs which should be instantaneous together with blynk, and as a result want to use two arduinos (one MKRGSM1400 and one uno) in a master/slave setup. The uno should be doing the real time events while the mkr is handling the connection.
All I want to do is pass the the code from a numeric field in the app to the slave, but whenever I change the value the connection stops.
Master code is below. Any help would be greatly appreciated
Thanks
#define BLYNK_PRINT Serial
// Arduino MKR GSM 1400 uses U-blox modem
#define TINY_GSM_MODEM_UBLOX
// Include the required Wire library for I2C
#include <Wire.h>
#include <TinyGsmClient.h>
#include <BlynkSimpleTinyGSM.h>
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// Your GPRS credentials
// Leave empty, if missing user or pass
char apn[] = "hologram";
char user[] = "";
char pass[] = "";
//setup parts for the coderecognition
int c=0;
int code[] = {0,0,0,0,0,0};
int code_int = 0;
int multiplier;
int right_code = 3333;
int led_pin = 7;
TinyGsm modem(SerialGSM);
//blynktimer
BlynkTimer timer;
//setup map widget
WidgetMap myMap(V0);
//setup pin check
BLYNK_WRITE(V1){
int x = param.asInt();
right_code = x;
//let slave know the set code
Serial.println(right_code);
Wire.beginTransmission(9); // transmit to device #9
Wire.write(right_code); // sends the right code to the arduino
Wire.endTransmission(); // stop transmitting
}
void setup() {
// Debug console
Serial.begin(9600);
Wire.begin();
pinMode(led_pin, OUTPUT);
digitalWrite(led_pin,LOW);
//Establish GSM connection
delay(10);
// Set GSM module baud rate
SerialGSM.begin(115200);
pinMode(GSM_DTR, OUTPUT);
digitalWrite(GSM_DTR, LOW);
delay(5);
// Turn on the GSM module by triggering GSM_RESETN pin
pinMode(GSM_RESETN, OUTPUT);
digitalWrite(GSM_RESETN, HIGH);
delay(100);
digitalWrite(GSM_RESETN, LOW);
delay(1000);
// Restart takes quite some time
// To skip it, call init() instead of restart()
Serial.println("Initializing modem...");
modem.restart();
// Unlock your SIM card with a PIN
//modem.simUnlock("1234");
Blynk.begin(auth, modem, apn, user, pass);
}
void loop() {
Blynk.run();
//timer.run();
}
You’re using blocking code inside BLYNK_WRITE(), and the result is being disconnected.
You can set a flag inside BLYNK_WRITE() and use a timer calling a function to read the flag. That function will send the data.
Use something like this code:
// New flag
bool newDataToSend = false;
// and new timer
BlynkTimer timer;
void sendData(void)
{
if (newDataToSend)
{
Wire.beginTransmission(9); // transmit to device #9
Wire.write(right_code); // sends the right code to the arduino
Wire.endTransmission(); // stop transmitting
// resetting flag
newDataToSend = false;
}
}
//setup pin check
BLYNK_WRITE(V1){
right_code = param.asInt();
//let slave know the set code
Serial.println(right_code);
// set flag here if receiving new data
newDataToSend = true;
}
// 500ms = 0.5 s
#define CHECK_INTERVAL_MS 500
void setup() {
....
Blynk.begin(auth, modem, apn, user, pass);
// Call sendData to check the flag every 0.5s
timer.setInterval(CHECK_INTERVAL_MS, sendData);
}
void loop() {
Blynk.run();
timer.run();
}
Thanks a lot!
I did half of what you suggested before I saw the reply and had moved sending the data into a separate function, however, I didn’t have the flag, and still had issues.
Is there a problem with using “blocking code” (I don’t know what this is to be fair), too often? I would also like to receive data back and am wondering if this is going to break it if I check too much.
Re. Blocking functions
Currently, you’re using Arduino / ESP single-task and single-thread system. That means if you monopolize the CPU by doing something such as:
// And connect never happens
while(this->connect() != true) {}
or
do {
xxx();
} while(be_true_very_long_time);
or
delay(very_long_time);
none of other critical instructions can be executed, unless hardware interrupt service routines (ISR), which have highest priority when there is an interrupt.
The Blynk’s Blynk.run(), timer.run() as well as many other functions (such as Software WatchDog timer, Soft Timer, etc.), need to be run so that the system can function normally.
This problem could be addressed if you’re using preemptive multi-tasking Real-Time OS (RTOS), so that it your task behaves bad, other higher priority can preempt bad task. Certainly, if your bad task, (assigned with very high priority) behaves bad, you still have same issue.
To receive data, you can do something similar as sendData() by polling it with a timer. But it’s better to use certain kind of interrupt, which I believe Wire / TWI library is currently using.
You can use this kind of code to receive
#define I2C_ADDRESS 9
void sendData(void)
{
if (newDataToSend)
{
Wire.beginTransmission(I2C_ADDRESS); // transmit to device I2C_ADDRESS = 9
Wire.write(right_code); // sends the right code to the arduino
Wire.endTransmission(); // stop transmitting
// resetting flag
newDataToSend = false;
}
}
// function executed whenever data is received from master
void readData(void)
{
while (Wire.available())
{
// Do whatever you need with received data
// Received byte as a character
char c = Wire.read();
// For example, just print out to Serial to test
Serial.print(c);
}
}
void setup()
{
....
// join I2C bus with I2C_ADDRESS = 9
Wire.begin(I2C_ADDRESS);
Wire.onReceive(readData); // register event
Blynk.begin(auth, modem, apn, user, pass);
// Call sendData to check the flag every 0.5s
timer.setInterval(CHECK_INTERVAL_MS, sendData);
}