0

I have bluetooth (HC-05) connected on Serial port of Arduino Mega and two TM1637, I am receiving Strings from an Android phone with an app with two Time picker (Fajar and Zohar)see attachment I am sending time which is set by time picker in a formatted way.

The format is

< : Start of number delimiter.

ID : is the number 1 or 2 (1 for Fajar and 2 for Zohar), it indicates from which time picker the data has come.

HH : Hours, set from time picker.

MM : Minutes, set from time picker.

> : End of number delimiter.

See incoming raw data from Bluetooth

Here in the example, first data which comes in is <10320> , which is starting delimiter "<" first digit "1" is the ID from Fajar time picker,03 Hours and 20 minutes and ending delimiter ">". Second data is <21830>, which is from Zohar time picker and vice versa.

I am parsing the incoming string and converting them into integers using the code found on Arduino Forum.

const char startOfNumberDelimiter = '<';
const char endOfNumberDelimiter   = '>';

void setup ()
 { 
 Serial.begin (9600);
 Serial.println ("Starting ...");
 } // end of setup

void processNumber (const long n)
 {
 Serial.println (n);
 }  // end of processNumber

void processInput ()
 {
 static long receivedNumber = 0;
 static boolean negative = false;

 byte c = Serial.read ();

 switch (c)
   {

   case endOfNumberDelimiter:  
     if (negative) 
       processNumber (- receivedNumber); 
     else
       processNumber (receivedNumber); 

   // fall through to start a new number
   case startOfNumberDelimiter: 
     receivedNumber = 0; 
     negative = false;
     break;

   case '0' ... '9': 
     receivedNumber *= 10;
     receivedNumber += c - '0';
     break;

   case '-':
     negative = true;
     break;

   } // end of switch  
 }  // end of processInput

void loop ()
 {

 if (Serial.available ())
   processInput ();

 // do other stuff here
 } // end of loop

with the code above, i can convert string to integers and remove delimiters.

See output of the code in serial monitor. finished data

Problem is : I have to separate ID and Hours and Minutes from that integer and wrap Hours and Minutes that up in

int8_t Digits [] = {1, 2 , 3 , 4 };

Here {1,2,3,4} is {H,H,M,M} Hours and Minutes which displays digits on one of the TM1637.

and also ID with "1" should change the digits on one of the TM167 and the ID with "2" should change digits on another TM1637.

Here is my full code :

#include "TM1637.h"


#define CLK1 2
#define DIO1 3

#define CLK2 4
#define DIO2 5


TM1637 Display1 (CLK1, DIO1);

TM1637 Display2 (CLK2, DIO2);

const char startOfNumberDelimiter = '<';
const char endOfNumberDelimiter   = '>';



void setup ()
{
  Display1.set ();
  Display1.init ();

  Display2.set();
  Display2.init();

  Serial.begin(9600);
  Serial.println ("Starting ...");
}

void loop ()
{
  if (Serial.available ())
    processInput ();
  fajar();
  zohar();
}


void processNumber (const long n)
{
  Serial.println (n);
}  // end of processNumber

void processInput ()
{
  static long receivedNumber = 0;
  static boolean negative = false;

  byte c = Serial.read ();

  switch (c)
  {

    case endOfNumberDelimiter:
      if (negative)
        processNumber (- receivedNumber);
      else
        processNumber (receivedNumber);

    // fall through to start a new number
    case startOfNumberDelimiter:
      receivedNumber = 0;
      negative = false;
      break;

    case '0' ... '9':
      receivedNumber *= 10;
      receivedNumber += c - '0';
      break;

    case '-':
      negative = true;
      break;

  } // end of switch
}  // end of processInput


void fajar ()
{
  int8_t Digits [] = {1, 2 , 3 , 4 };
  Display1.display (Digits);
  Display1.point(POINT_ON);
}

void zohar ()
{
  int8_t Digits [] = {1, 2 , 3 , 4 };
  Display2.display (Digits);
  Display2.point(POINT_ON);
}

Please Help

EDIT : Here is my edited code with Majenko shown technique.

#include "TM1637.h"


#define CLK1 2
#define DIO1 3

#define CLK2 4
#define DIO2 5


uint8_t fajar[4];
uint8_t zohar[4];

uint8_t address = 0;
uint8_t ptr = 0;

TM1637 Display1 (CLK1, DIO1);

TM1637 Display2 (CLK2, DIO2);
void setup ()
{
  Display1.set ();
  Display1.init ();

  Display2.set();
  Display2.init();

  Serial.begin(9600);
}

void loop ()
{
  int c = Serial.read();
  switch (c) {
    case '<': // Start of string - reset everything
      address = 0;
      ptr = 0;
      break;
    case '>': // End of string

       fajartime (); // Edited 
       zohartime (); // Edited

      break;
    default:
      if ((c >= '0') && (c <= '9')) {
        if (address == 0) {
          address = c - '0';
        } else if (ptr < 4) {
          switch (address) {
            case 1:
              fajar[ptr] = c - '0';
              break;
            case 2:
              zohar[ptr] = c - '0';
              break;
          }
          ptr++;
        }
      }
  }
}

void fajartime ()
{

  Display1.display (fajar);
  Display1.point(POINT_ON);
}

void zohartime ()
{

  Display2.display (zohar);
  Display2.point(POINT_ON);
}

Thank you

2

You're thinking the wrong way. At the moment you are receiving individual characters, then combining them into a single integer, and then you want to split that integer back into individual characters. But you start with individual characters already. You don't need, nor want, to convert the string into an integer to then split it again.

If you take each character as it comes in as a separate number and store it separately you have no need for splitting.

For instance, you could have two 4-byte arrays for the two times. You don't need to store the first byte, since it's just an indicator of destination (we can call it a register address if you like).

A simple Finite State Machine for receiving in the correct way will make things easier:

uint8_t fajar[4];
uint8_t zohar[4];
uint8_t address = 0;
uint8_t ptr = 0;

int c = Serial.read();
switch (c) {
    case '<': // Start of string - reset everything
        address = 0;
        ptr = 0;
        break;
    case '>': // End of string
        // Do whatever with the data here
        break;
    default: 
        if ((c >= '0') && (c <= '9')) {
            if (address == 0) {
                address = c - '0';
            } else if (ptr < 4) {
                switch (address) {
                    case 1:
                        fajar[ptr] = c - '0';
                        break;
                    case 2:
                        zohar[ptr] = c - '0';
                        break;
                }
                ptr++;
            }
        }
}

You could simplify things by combining zohar and fajar into a single 2D array keyed on the address (though take care that address never gets an invalid value in that case), or you can reduce memory usage by only having one 4-byte array if you don't care about keeping the data separate at all times (you use it and throw it away as soon as it's arrived).

  • Ahh! i have realized that, the code that i got from an Arduino Forum takes single characters from Serial and make an integer of that, I was thinking in a wrong way! I am new to pointers, i haven't actually used it before - can you please check my code again.. i have edited the question. thank you – Mudassir Hussain Nov 10 '17 at 14:58
  • Using void fajartime (); etc in the middle of your code isn't calling the function - it's defining the function prototype. Lose the void. – Majenko Nov 10 '17 at 15:16
  • ohh! My bad, I have edited that again, Please check – Mudassir Hussain Nov 10 '17 at 15:19
  • Looks reasonable - though I don't know about the functions you use to display - if they take a 4-byte array like that or not. – Majenko Nov 10 '17 at 15:37
  • Also you only really need to update the display for the address you have at the time. – Majenko Nov 10 '17 at 15:38
1

I'm not sure I know what you need help with. You have code that reads a 5 character string from between .

  • If i == 1 you pass the remaining 4 characters to fajar.
  • If i == 2 you pass the remaining 4 characters to zohar.

You then need a function to convert the 4 characters into 4 separate integers. You might need to map these integers onto a code that displays the correct lights or you might have a library to do this already. (You already have the code for this function). All you need to do then is push the number to the display. That might be the problem you have, but how you do that depends on you library and connections.

TM1637 Displays[2] = {(CLK1, DIO1), (CLK2, DIO2)};
void loop()
{
    char buffer[1 + 5 + 1 + 1];
    buffer = readNumber (buffer);
    if (buffer[0] == '1')          // Treating as a character not a number.
        fajar(&(buffer[1]));
    else
        zohar(&(buffer[1]));
}
void fajar(char const* buffer) { displayValue(1, buffer);}
void zohar(char const* buffer) { displayValue(2, buffer);}
void displayValue (const int& displayID, char const* buffer)
{
    int numericValues[4];
    convertToNumbers (buffer, numericValues);  // The code in the switch statement.
    Display[displayID].display (numericValues);
    Display[displayID]..point(POINT_ON);
}

The above code is only a guide, never compiled and it is riddled with issues that could, if bad data was received, cause a major problem. You are going to have to add error and bounds checking before you do anything more than dev test it, but it should work :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.