Hello,
I'm new here and this is my first post, be kind if I made something wrong.
I'm conducting a project with the aim to snd information from my MKR wifi1010 to my smartphoen through a BLE connection with app like LightBlue or BlueFruit Connect
I'm able to see the name of the Arduino and to connect but i'm not able to see the information that should be send to the Smartphone via Serial.print
Do you have any experience or any idea how can i send information to the smartphone via BlueART in order to send the information to run the test.
Thank you, here is the code
// #include <Iono.h>
/*
This code uses Sferalab's Iono MKR pinout map,
but not the specific libraries.
There is a direct correspondence to Arduino's own pins.
For information, see:
https://www.sferalabs.cc/
*/
#include <Button.h>
#include <HardwareBLESerial.h>
HardwareBLESerial &bleSerial = HardwareBLESerial::getInstance();
/* ---------- options ---------- */
const bool recordAccel = false; // option to record the accelerometer data from accelPin
const int recLenAccel = 2000; // length of the stored accelerometer history (# samples)
const bool printAccel = false; // option to print the raw acceleration data
// const bool recordTouch = true; // directly monitor the closed circuit between carrier and anvil
/* ---------- numeric constants ---------- */
const float stubHeight = 25.0; // height of the sample holder part [mm]
const float gravityAcc = 9.81; // gravitational acceleration [m/s^2]
const int interrDeb = 10; // interrupt debounce [us]
const int maxADC_V = 30; // If using the iono shield, the voltage read by ADC is 0.0-30.0[V]
const float accelSens = 100.0; // Accelerometer sensitivity [mV/g]
const float accelRange = 50.0; // Max value readable by accelerometer [g]
const int measPeriod = 100; // time between accel measurements [us]
const int avgPeriod = 20; // Acceleration - moving average parameter - # samples
const int timeTouchComp = -6; // Compensation of the touch time [us], measure with oscilloscope
const int respTime_PS = 500; // Panasonic EX11 photoswitch declared response time [us]
const float beamD_PS = 1.0; // Panasonic EX11 photoswitch declared beam diameter [mm]
/* ---------- pins declaration ---------- */
// IONO pin;
const int photoSwitch = A2; // DI2; // Photoelectric switch pin. It must have interrupt.
const int magnetPin = 3; // DO1; // The magnet is on this pin. It is a relay output.
const int anvilSwitch = 7; // DI5; // Switch (or switches in &&) on the anvil. It must have interrupt.
const int accelPin = A1; // AV1; // Accelerometer, it is connected through 2-wire 0-20mA connection.
const int buttonPinA = A3; // DI3;
const int buttonPinB = A4; // DI4;
const int LEDPinB = A6; // DO3; // LED mounted on Button B
const int sensorPowerPin = 2; // DO2; // Give power to the sensors (relay)
const int anvilTouch = 5; // DI6; // Detect connection between anvil and stub
/* ---------- counters and storage variables ---------- */
int recordedAccel[recLenAccel];
uint64_t timeRecAccel;
const int recLen = 4;
volatile uint64_t recordedTimes[recLen];
volatile uint64_t recordedTimes_PS[recLen];
volatile uint64_t recordedTimes_A[recLen];
volatile uint64_t recordedTimes_T[recLen];
volatile int timesIndex = 0;
volatile int timesIndex_T = 0;
// volatile uint64_t dt = 0;
/* ---------- runtime management ---------- */
bool prepared = false;
bool loaded = false;
bool armed = false;
short tested = 0; // used for basic error codes
bool sent = false;
uint64_t armedTime;
uint64_t blinkTimer;
int i = 0;
/* ---------- buttons ---------- */
Button buttonA(buttonPinA, 1000);
Button buttonB(buttonPinB, 1000);
short resultA = 0;
short resultB = 0;
bool longPressA = false;
bool longPressB = false;
const int buttonSyncTol = 300;
uint64_t buttonSyncTime = 0;
const int doubleClickTol = 500;
bool shortB = false;
uint64_t whenShortB = 0;
/* -------- setup -------- */
void setup() {
pinMode(photoSwitch, INPUT);
pinMode(anvilSwitch, INPUT);
//pinMode(buttonPinA, INPUT);
//pinMode(buttonPinB, INPUT);
pinMode(LEDPinB, OUTPUT);
pinMode(magnetPin, OUTPUT);
pinMode(sensorPowerPin, OUTPUT);
// Fast ADC setup
//using values 0-4096 (12 bit)
analogReadResolution(12);
Serial.begin(9600);
if (!bleSerial.beginAndSetupBLE("KATest")) {
while (true) {
Serial.println("failed to initialize HardwareBLESerial!");
delay(1000);
}
}
attachInterrupt(digitalPinToInterrupt(photoSwitch), photoSwitchISR, CHANGE);
attachInterrupt(digitalPinToInterrupt(anvilSwitch), anvilSwitchISR, CHANGE);
attachInterrupt(digitalPinToInterrupt(anvilTouch), anvilTouchISR, CHANGE);
}
/* -------- main loop -------- */
void loop() {
if(!prepared){
prepared = prepare();
}
bleSerial.poll();
if(!loaded && prepared){
armed = false;
buttonSyncTime = 0;
loaded = loadSample();
}
/* -------- Arming routine -------- */
while(loaded && !armed){
resultA = buttonA.checkPress();
resultB = buttonB.checkPress();
// Simultaneous press A and B goes on to armed
if(resultA == -1 || resultB == -1){
if(millis()-buttonSyncTime > buttonSyncTol){
buttonSyncTime = millis();
longPressA = (resultA == -1);
longPressB = (resultB == -1);
}else{
if(resultA == -1){
longPressA = true;
}
if(resultB == -1){
longPressB = true;
}
}
}
if (longPressA && longPressB && loaded){
longPressA = false;
longPressB = false;
digitalWrite(sensorPowerPin,HIGH);
armed = true;
armedTime = millis();
bleSerial.println("Sensors ON");
bleSerial.println("/* ------------- ARMED ------------ */");
bleSerial.println("/* short press A | B to cancel */");
}
// Double click B returns to loading
if(resultB == 1){
if(!shortB){
shortB = true;
whenShortB = millis();
}else if(millis() - whenShortB < doubleClickTol){
loaded = false;
shortB = false;
bleSerial.println("canceled");
}else{
shortB = false;
}
}
bleSerial.poll();
}
/* -------- Countdown and then test -------- */
if(loaded && armed){
bleSerial.poll();
if(millis()-armedTime < 5000){
if(millis()-blinkTimer > 250){
blinkTimer = millis();
digitalWrite(LEDPinB,!digitalRead(LEDPinB));
//bleSerial.println(map(5000 - (millis()-armedTime),0,5000,0,5));
}
resultA = buttonA.checkPress();
resultB = buttonB.checkPress();
if(millis()-armedTime < 200){
resultA = 0;
resultB = 0;
}
if(resultA == 1 || resultB == 1){
loaded = false;
armed = false;
bleSerial.println("Disarmed");
digitalWrite(LEDPinB, LOW);
digitalWrite(sensorPowerPin,LOW);
}
}else{
tested = measureLoop();
armed = false;
digitalWrite(sensorPowerPin,LOW);
bleSerial.println("Sensors OFF");
}
}
if(tested > 0){
sent = sendThroughBLESerial();
}else if(tested == -1){
bleSerial.println("TEST CANCELED - disturbed signals");
prepared = false;
loaded = false;
armed = false;
tested = 0;
sent = false;
}
if(tested != 0 && sent){
prepared = false;
loaded = false;
armed = false;
tested = 0;
sent = false;
}
delay(100);
}
/* -------- state functions -------- */
boolean prepare(){
bleSerial.println("/* ---------- PREPARATION --------- */");
if(!bleSerial){
Serial.print("Waiting for BLE UART connection... ");
while (!bleSerial) {
delay(700); // on Mbed-based Arduino boards, delay() makes the board enter a low-power sleep mode
digitalWrite(LEDPinB,!digitalRead(LEDPinB));
}
while(resultB == 0){
bleSerial.poll();
resultB = buttonB.checkPress();
digitalWrite(LEDPinB,!digitalRead(LEDPinB));
delay(250);
}
if(bleSerial){
Serial.println("CONNECTED");
Serial.println("kineticAdhesionTest - Lorenzo Pedrolli, 2022");
bleSerial.println("/* ----- kineticAdhesionTest ------ */");
bleSerial.println("/* --- Lorenzo Pedrolli, 2022 ----- */");
bleSerial.println("/* */");
}
}else{
bleSerial.println("bleSerial OK");
}
bleSerial.poll();
return true;
}
boolean loadSample(){
bleSerial.println("/* -------- LOADING SAMPLE -------- */");
bleSerial.println("/* long press */");
bleSerial.println("/* A to hold/release magnet */");
bleSerial.println("/* B to confirm sample positioning */");
bleSerial.poll();
digitalWrite(LEDPinB, LOW);
uint64_t beginTime = millis();
bool loading = true;
while(loading){
bleSerial.poll(); // needed because of blocking while loop!!!
resultA = buttonA.checkPress();
resultB = buttonB.checkPress();
if(resultA == -1 && digitalRead(buttonPinB) == 0){
digitalWrite(magnetPin,!digitalRead(magnetPin));
bleSerial.print("Magnet: ");
if(digitalRead(magnetPin)){
bleSerial.println("ON");
}else{
bleSerial.println("OFF");
}
}else if(digitalRead(buttonPinA) == 0 && resultB == -1 && digitalRead(magnetPin)>0 ){
loading = false;
digitalWrite(LEDPinB, HIGH);
bleSerial.println("sample loaded");
bleSerial.println("/* long press A & B to test */");
bleSerial.poll();
return true;
}else if(millis()-beginTime > 1000000){
bleSerial.println("loading timeout");
return false;
}
delay(100);
}
}
short measureLoop(){
int ret = 0;
digitalWrite(LEDPinB,LOW);
bleSerial.println("/* ------------ TESTING ----------- */");
bleSerial.poll();
delay(10);
attachInterrupt(digitalPinToInterrupt(photoSwitch), photoSwitchISR, CHANGE);
attachInterrupt(digitalPinToInterrupt(anvilSwitch), anvilSwitchISR, CHANGE);
attachInterrupt(digitalPinToInterrupt(anvilTouch), anvilTouchISR, CHANGE);
// Initialize Acceleration values array
if(recordAccel){
for(i = 0; i < recLenAccel; i++){
recordedAccel[i] = 0;
}
}
// Initialize time values to all zeros
for(i = 0; i < recLen; i++){
recordedTimes[i] = 0;
recordedTimes_PS[i] = 0;
recordedTimes_A[i] = 0;
recordedTimes_T[i] = 0;
}
timesIndex = 0;
timesIndex_T = 0;
volatile bool stillMeasuring = true;
delay(100);
if(timesIndex != 0){
// this error should arise if the sensors are misfiring
return -1;
}
loaded = false;
digitalWrite(magnetPin, LOW);
recordedTimes[0] = micros();
timesIndex++;
while(stillMeasuring==true){
if(recordAccel && timesIndex>1){
Serial.println("this is bad");
timeRecAccel = micros();
for(int k=0; k<recLenAccel; k++){
recordedAccel[k] = analogRead(accelPin);
delayMicroseconds(measPeriod);
}
timeRecAccel = micros()-timeRecAccel;
}
if(timesIndex >= recLen){
stillMeasuring = false;
ret = 1;
}
if((micros()-recordedTimes[0])>10000000){
stillMeasuring = false;
ret = 2;
}
}
detachInterrupt(digitalPinToInterrupt(photoSwitch));
/*detachInterrupt(digitalPinToInterrupt(anvilSwitch));
detachInterrupt(digitalPinToInterrupt(anvilTouch));*/
return ret;
}
bool sendThroughBLESerial(){
char buffer[20]; // this is used to translate the numbers, bleSerial is not working well with uint64_t
int timeoutCounter = 0;
while (!bleSerial && timeoutCounter < 1000) {
delay(500);
digitalWrite(LEDPinB,!digitalRead(LEDPinB));
resultB = buttonB.checkPress();
bleSerial.poll();
timeoutCounter ++;
}
if(timeoutCounter >= 999){
Serial.println("ERROR: ble not available.");
return false;
}
//bleSerial.flush();
bleSerial.poll();
bleSerial.println("/* --------- SENDING DATA --------- */");
bleSerial.println("INTERRUPT RAW DATA");
bleSerial.println("Recorded times [us]:");
bleSerial.println("general ; photoSwitch ; anvil ; touch");
for(i = 0; i<recLen; i++){
sprintf(buffer,"%d",recordedTimes[i]);
bleSerial.print(buffer);
bleSerial.print(" ; ");
sprintf(buffer,"%d",recordedTimes_PS[i]);
bleSerial.print(buffer);
bleSerial.print(" ; ");
sprintf(buffer,"%d",recordedTimes_A[i]);
bleSerial.print(buffer);
bleSerial.print(" ; ");
sprintf(buffer,"%d",recordedTimes_T[i]);
bleSerial.print(buffer);
bleSerial.println(" ");
bleSerial.poll();
}
if(recordAccel){
int accelVoltage = 0;
float accelSlow = (float)map(recordedAccel[0],0,4096,0,maxADC_V*1000);
float maxVal = -1.0;
if(printAccel){
bleSerial.println("RECORDED ACCELEROMETER VALUES");
bleSerial.print("Total recorded time [us]: ");
sprintf(buffer,"%d",timeRecAccel);
bleSerial.println(buffer);
//bleSerial.println(timeRecAccel);
bleSerial.println("Values from accelerometer:");
bleSerial.println("Index , time[ms] , value[mV]");
}
for(i=0; i<recLenAccel; i++){
accelVoltage = (float)map(recordedAccel[i],0,4096,0,maxADC_V*1000); // mVolts
// finding the peak acceleration value.
accelSlow = (accelSlow*(avgPeriod-1)+accelVoltage)/avgPeriod; // mVolts
maxVal = max(maxVal, fabs(accelVoltage-accelSlow)); // mVolts
if(printAccel){
// Print the index
sprintf(buffer,"%5d",i);
bleSerial.print(buffer);
bleSerial.print(" , ");
// print the time in ms
sprintf(buffer, "%.3f", i*(float)(timeRecAccel/recLenAccel)*0.001);
bleSerial.print(buffer);
bleSerial.print(" , ");
// print the recorded acceleration in mV
sprintf(buffer,"%d",accelVoltage);
bleSerial.print(buffer);
bleSerial.println("");
}
if(i%10==0){
bleSerial.poll();
}
}
maxVal = gravityAcc * maxVal/accelSens; // peak acceleration [m/s^2]
bleSerial.print("Peak acceleration ANVIL: ");
sprintf(buffer, "%.5f", maxVal);
bleSerial.print(buffer);
bleSerial.print(" m/s^2 = ");
sprintf(buffer, "%.5f", maxVal/gravityAcc);
bleSerial.print(buffer);
bleSerial.println(" g");
bleSerial.println("SAMPLE accel.: a_s = a_a * (m_a / m_s)");
if(maxVal/gravityAcc > accelRange){
bleSerial.println("WARNING: accelerometer overload");
}
bleSerial.poll();
}
bleSerial.println("IMPACT VELOCITY");
float passT_12 = (float)(recordedTimes_PS[2] - recordedTimes_PS[1]) * 1e-6;
float passV_1 = (1e-3 * (stubHeight+2*beamD_PS)) / passT_12 - 0.5 * gravityAcc * passT_12; // m/s
sprintf(buffer, "%.5f", passV_1);
bleSerial.print("At PhotoSwitch: ");
bleSerial.print(buffer);
bleSerial.println(" m/s");
if(recordedTimes_A[3] > 0){
float passT_1A = (float)(recordedTimes_A[3] - recordedTimes_PS[1] + respTime_PS) * 1e-6;
float impV_A = passV_1 + gravityAcc * passT_1A;
sprintf(buffer, "%.5f", impV_A);
bleSerial.print("Impact velocity (1 2 A): ");
bleSerial.print(buffer);
bleSerial.println(" m/s");
}
if(recordedTimes_T[0] > 0){
float passT_1T = (float)(recordedTimes_T[0] - recordedTimes_PS[1] + respTime_PS) * 1e-6;
float impV_T = passV_1 + gravityAcc * passT_1T;
sprintf(buffer, "%.5f", impV_T);
bleSerial.print("Impact velocity (1 2 T): ");
bleSerial.print(buffer);
bleSerial.println(" m/s");
float Dt_in = (float)(recordedTimes_T[0] - recordedTimes_PS[2] + respTime_PS) * 1e-6;
float Dt_out = (float)(recordedTimes_PS[4] - recordedTimes_T[1] - respTime_PS) * 1e-6;
if(recordedTimes_A[3] == 0){
Dt_out = (float)(recordedTimes_PS[4] - recordedTimes_T[1] - respTime_PS) * 1e-6;
}
float rebV_T = (impV_T * Dt_in + gravityAcc * 0.5 * (Dt_out*Dt_out-Dt_in*Dt_in))/Dt_out;
sprintf(buffer, "%.5f", rebV_T);
bleSerial.print("Rebound vel. (2 T1/T2 3): ");
bleSerial.print(buffer);
bleSerial.println(" m/s");
float passT_0T = (float)(recordedTimes_T[0] - recordedTimes[0]) * 1e-6;
float impV_0T = gravityAcc * passT_0T;
sprintf(buffer, "%.5f", impV_0T);
bleSerial.print("Impact velocity (0 T): ");
bleSerial.print(buffer);
bleSerial.println(" m/s");
}
bleSerial.poll();
bleSerial.print("Touch time: ");
sprintf(buffer, "%d", recordedTimes_T[1] - recordedTimes_T[0] + timeTouchComp);
bleSerial.print(buffer);
bleSerial.println(" us");
bleSerial.poll();
bleSerial.println("MESSAGES");
if(tested == 2){
bleSerial.println("INVALID TEST: timeout");
}
bleSerial.println("/* ------------- END -------------- */");
bleSerial.println(" ");
bleSerial.poll();
return true;
}
/* -------- interrupt runtimes for measurement -------- */
void photoSwitchISR(){
recordedTimes_PS[timesIndex] = micros();
if( (recordedTimes_PS[timesIndex] - recordedTimes_PS[timesIndex-1]) > interrDeb){
timesIndex++;
}
}
void anvilSwitchISR(){
/*recordedTimes_A[timesIndex] = micros();
dt = (recordedTimes_A[timesIndex]-recordedTimes_PS[timesIndex-1]);
if(dt > interrDeb && dt < 500000){
detachInterrupt(digitalPinToInterrupt(anvilSwitch));
timesIndex++;
}else{
recordedTimes_A[timesIndex] = 0;
}*/
if(timesIndex == 3){
recordedTimes_A[3] = micros();
timesIndex++;
detachInterrupt(digitalPinToInterrupt(anvilSwitch));
}
}
void anvilTouchISR(){
recordedTimes_T[timesIndex_T] = micros();
if(timesIndex_T==0){
if((recordedTimes_T[timesIndex_T]-recordedTimes_PS[2])>interrDeb){
timesIndex_T++;
}
}else if((recordedTimes_T[timesIndex_T]-recordedTimes_T[timesIndex_T-1])>interrDeb){
timesIndex_T++;
if(timesIndex_T >= recLen){
detachInterrupt(digitalPinToInterrupt(anvilTouch));
}
}
}
Have a good day,