DTMF decoding

Really pretty simple but I hit a road block. building a DTMF decoder using a MT8877 board.
decodes fine but i need it to decode a string of digits before it does what I want. so rigth now I send it DTMF 4 and it turns a relay on. what I need it to do is what for a string of digits so maybe something like 141 to turn on and 140 to turn off. just and example. I took a couple stabs at writing a little code to do this but got now where.

seems like I need a time varable that makes the code what for the number of digits I need.

eventually i would like to have a code which I would have to enter that would then allow me to send addition codes to turn things on and off. then after a predetermined amount of time the master code times out without activity and resets.

ideas?

//Global variables-----------------------------------------------------------------------------------------

byte DTMFread;            // The DTMFread variable will be used to interpret the output of the DTMF module.
const int STQ = A0;        // Attach DTMF Module STQ 
 const int Q4 = A4;        // Attach DTMF Module Q4  
 const int Q3 = A3;        // Attach DTMF Module Q3  
 const int Q2 = A2;        // Attach DTMF Module Q2  
 const int Q1 = A1;        // Attach DTMF Module Q1  

 int R1 = 4;
 int R2 = 5;
 int R3 = 6;
 int R4 = 7;

 unsigned long lastDTMFtime = 0;


/*=========================================================================================================

========================================================================================================== */
void setup() {
 Serial.begin(57600);
  pinMode(STQ, INPUT);
  pinMode(Q4, INPUT);
  pinMode(Q3, INPUT);
  pinMode(Q2, INPUT);
  pinMode(Q1, INPUT);
  pinMode(R1, OUTPUT);
  pinMode(R2, OUTPUT);
  pinMode(R3, OUTPUT);
  pinMode(R4, OUTPUT);
  digitalWrite(R1, LOW);
  digitalWrite(R2, LOW);
  digitalWrite(R3, LOW);
  digitalWrite(R4, LOW);
  
}

void adjust() 
{ 
if(digitalRead(STQ)==HIGH){       //When a DTMF tone is detected, STQ will read HIGH for the duration of the tone.
    DTMFread=0;
    if(digitalRead(Q1)==HIGH){      //If Q1 reads HIGH, then add 1 to the DTMFread variable
      DTMFread=DTMFread+1;
    }
    if(digitalRead(Q2)==HIGH){      //If Q2 reads HIGH, then add 2 to the DTMFread variable
      DTMFread=DTMFread+2;
    }
    if(digitalRead(Q3)==HIGH){      //If Q3 reads HIGH, then add 4 to the DTMFread variable
      DTMFread=DTMFread+4;
    }
    if(digitalRead(Q4)==HIGH){      //If Q4 reads HIGH, then add 8 to the DTMFread variable
      DTMFread=DTMFread+8;
    }
    Serial.println(DTMFread);
  }
  {
    int DTMFstring = DTMFread
    unsigned long timeNow = millis();
  }
}
void loop() {
 adjust();
  {

  if (DTMFread == 4) {
     digitalWrite(R4, HIGH);
  }
   else {
    digitalWrite(R4, LOW);
   }
  }
  
}

Put every { on a new line. Use Tools + Auto Format to properly indent the code.

Then, get rid of the useless curly braces, and post the code again.

But, before you do that, adjust() does not even begin to describe what that function does. Give the function a decent name.

  {
    int DTMFstring = DTMFread
    unsigned long timeNow = millis();
  }

Why would anyone with an IQ above 10 use string in the name of an int?
Why is there not a ; at the end of that line?
Why are you defining local variables that immediately go out of scope?

Why does adjust() not return a value? If it did, you could build an array of values, and then operate on the array.

Hey paul,
String for us in the 2 way LMR PS world refers to the string of DTMF tone sent to activate something, ie an alarm. Some times we say we stack tones when refering to toning out fire stations etc.
I agree the sketch needs to be cleaned up. it is a lot of cut and paste.

I started to try and figure out the adjust() but hit a mental wall

TNX JK

W7OWC:
String for us in the 2 way LMR PS world refers to the string of DTMF tone sent to activate something, ie an alarm.

But that refers to a string of tones, thus it should be called a tone (at the very least). Although I wouldn’t have phrased my criticism in the same way, it is an extremely important point that he made. The variable name as it stands, is misleading. Good code explicitly expresses the intent of the programmer, and clearly describes the characteristics of the data.

Why not use the hash ‘#’ (or the star) key to mark the end of the input?
40# for relay 4 off
41# for relay 4 on
When a # is detected, your sketch will know it’s the end of the input sequence, like a full stop tells you that it’s the end of a sentence.

I did so more work on the sketch. I am very new to this, writing a sketch is a steep learning curve. I am muttling through. By no means is the following correct. I am just trying to figure it out. I did put in some notation to try and explain what I am doing the adjust() is hardly started. I am trying out how to first get the DTMFread to convert to a series numbers to be able to turn the right relay on and off.

is there some binary library that would be use full for this?

//Global variables

byte DTMFread;            // The DTMFread variable will be used to interpret the output of the DTMF module.
const int STQ = A0;        // Attach DTMF Module STQ 
 const int D4 = A4;        // Attach DTMF Module D4  
 const int D3 = A3;        // Attach DTMF Module D3  
 const int D2 = A2;        // Attach DTMF Module D2  
 const int D1 = A1;        // Attach DTMF Module D1  

#define RELAY1 4 //
#define RELAY2 5 //
#define RELAY3 6 //
#define RELAY4 7 //
 DTMFread(11) = "*"; // Decode for #
 DTMFread(12) = "#"; // Decode for *
 DTMFread(13) = "A"; // Decode for A
 DTMFread(14) = "B"; // Decode for B
 DTMFread(15) = "C"; // Decode for C
 DTMFread(0) = "D";  // Decode for D
 DTMFcode("10#"); // Turn off RELAY1
 DTMFcode("11#"); // Turn on RELAY1
 DTMFcode("20#"); // Turn off RELAY2
 DTMFcode("21#"); // Turn on RELAY2
 DTMFcode("30#"); // Turn off RELAY3
 DTMFcode("31#"); // Turn on RELAY3
 DTMFcode("40#"); // Turn off RELAY4
 DTMFcode("41#"); // Turn on RELAY4
 DTMFcode("12341*"); // Master Lock
 DTMFcode("12340#"); // Master Unlock

 unsigned long lastDTMFreadtime = 0;

void setup() {
 Serial.begin(57600);
  pinMode(STQ, INPUT);
  pinMode(Q4, INPUT);
  pinMode(Q3, INPUT);
  pinMode(Q2, INPUT);
  pinMode(Q1, INPUT);
  pinMode(RELAY1, OUTPUT);
  pinMode(RELAY2, OUTPUT);
  pinMode(RELAY3, OUTPUT);
  pinMode(RELAY4, OUTPUT);
  digitalWrite(RELAY1, LOW);
  digitalWrite(RELAY2, LOW);
  digitalWrite(RELAY3, LOW);
  digitalWrite(RELAY4, LOW);
  
}

void adjust() 
{ 
if(digitalRead(STQ)==HIGH){       //When a DTMF tone is detected, STQ will read HIGH for the duration of the tone.
    DTMFread=0;
    if(digitalRead(Q1)==HIGH){      //If Q1 reads HIGH, then add 1 to the DTMFread variable
      DTMFread=DTMFread+1;
    }
    if(digitalRead(Q2)==HIGH){      //If Q2 reads HIGH, then add 2 to the DTMFread variable
      DTMFread=DTMFread+2;
    }
    if(digitalRead(Q3)==HIGH){      //If Q3 reads HIGH, then add 4 to the DTMFread variable
      DTMFread=DTMFread+4;
    }
    if(digitalRead(Q4)==HIGH){      //If Q4 reads HIGH, then add 8 to the DTMFread variable
      DTMFread=DTMFread+8;
    }
    DTMFcode=DTMFread &
    Serial.println(DTMFread);
  }
  {
    int DTMFcode = ;// this needs to be each DTMF value decoded over a set period of time (10sec). 
    unsigned long timeNow = millis();
    int discard = DTMFread;  // if predetermined amount of time has been reached since last recieved DTMF then erease code.
    if (timeNow - lastDTMFreadtime >= 10000) {
     discard;  //junk the previuos DTMFcode
    }
  }
  void adjust (int RELAYa, DTMFcode, unsigned long &lastDTMFreadtime)// create a prameter where when the correct DTMFcode is recieved the correct relay is either switched on or off.
{{
  if (DTMFcode) { // The correct DTMFcode to turn on the correct relay ie DTMFcode(21) RELAY2 ON
     digitalWrite(RELAYa, HIGH);
  }{
      if (DTMFcode == ) {  // The correct DTMFcode to turn off the correct relay ie DTMFcode(20) RELAY2 OFF
     digitalWrite(RELAYa, LOW);
  }}}}}

void loop() {
adjust(DTMFcode(21)RELAY1,lastDTMFreadtime); // change the state of the relay.
  }
  
}

You get points for not using the String class. Your code blocks are hopeless. Even after formatting, they are a mess. You have a function adjust() which is declared inside a function adjust(), along with the loop() function. Really, it's clear that you need to learn the C code constructs before you can proceed any further with this.

Your code formatting ("pretty-printing") would earn you scorn and derision not only here, but in any C programming venue. It isn't good when formatting is a mess, but you can't fool the compiler into reading your mind. You have to speak its language. Also, it appears that you are trying to learn by trial and error. That won't work.

Sorry, but that's just how it is.

well, like I said I am learning this. This is not what I do for a living it is a hobby and as such I devote time as I can to learn the programming.

Why would anyone want to scorn me for trying to understand something? that seems really ignorant on their part. If I scorn people for trying to learn in my profession people get hurt and die. that is the way it is I am not blowing this out of proportion. If have a brother needing help I help them.

That is how I approach life. So please before you jump all over me for putting function adjust() inside a function adjust or my pretty-printing isn't up to par in a C programming venue tell why this doesnt work, teach me. I have spent nearly my entire life gaining knowledge and passing it onto others.

I have read a few books to get and understanding but I have a long way to go. the few sketch I have scraped together and had the help of others to get running have taught me lots.

Lets be constructive about this.

Thank you,
Jim

I am trying to be constructive. You can't get the help you need here, well, not only here. I can't imagine how I could have learned it without studying it. I started with the old fashioned K&R book. I tried simple examples and gradually built up from that. I asked a friend for help, but I had simple, specific questions for him. I systematically worked my way around different features of the language. That was way before the cornucopia of information we call the internet came to be. Even so, I can't imagine learning it from scratch in a place like a forum.

Have you investigated the specific issues that I mentioned, and addressed them? You see, I love to help people. There are lots more people here with that attitude. But it is cumbersome and unproductive to try to explain the entire subject of programming in C in short little posts. Even if it is a dialogue. It just isn't a practical venue.

If you do have a long way to go, I suggest that you back off and try some simpler projects that have a chance of actually working, so that you can get positive feedback and have something to "play" with.

fundamentally, you’ll have trouble detecting multiple button presses unless you can tell the difference between two presses and one long press - you need to detect “tone stop” as well as “tone start”:

uint8_t read_tone() {
   while (digitalRead(STQ)==LOW)       // Wait for tone detect
      ; // spin while waiting
   /* Tone detected; read it in */
    DTMFread=0;
    if(digitalRead(Q1)==HIGH){      //If Q1 reads HIGH, then add 1 to the DTMFread variable
      DTMFread=DTMFread+1;
    }
        : // (going to assume this code was correct
    if(digitalRead(Q4)==HIGH){      //If Q4 reads HIGH, then add 8 to the DTMFread variable
      DTMFread=DTMFread+8;
    }
   while (digitalRead(STQ)==HIGH)       // Wait for tone to end
      ; // spin while waiting
   return DTMFread;
}

Ok; this will yield a number from 0 to 11; essentially base 12 (unless you have a 16-key pad?) Hexadecimal maybe without all the values used, so you can fit up to 8 “digits” in a long, which will be easier to compare than a string. So we need to assemble individual keypresses into a single long that has all the presses, terminated with # or *…

/* read a touchtone string terminated by a non-numeric
   if the string is too long, just discard.
   return as a string of hex digits, including the terminator
*/
uint32_t read_tt_string() {
  uint8_t digit;		/* assembled string */
  uint32_t ttstr = 0;
  do {
    digit = read_tone();
    ttstr = (ttstr<<4) | digit; // shift left and or in the new digit
  } while (digit <= 9);  // until a "terminator"
  return ttstr;
}

Now, we need some way to specify the hex strings so we can do comparisons. They’re ALMOST hex strings, except for the terminators that happen only at the end of numbers, so we can do it manually adding special values to hex numbers (note that we start with the value shifted to make room for the terminator.):

#define DTMF_SPLAT 11 /* * */
#define DTMF_SHARP 12 /* # */

#define RELAY1_OFF (0x100 + DTMF_SHARP)   /* 10# */
#define RELAY1_ON  (0x110 + DTMF_SHARP)   /* 11# */
#define RELAY2_OFF (0x200 + DTMF_SHARP)   /* 20# */
#define RELAY2_ON  (0x210 + DTMF_SHARP)   /* 21# */
#define RELAY3_OFF (0x300 + DTMF_SHARP)   /* 30# */
#define RELAY3_ON  (0x310 + DTMF_SHARP)   /* 31# */
#define RELAY4_OFF (0x400 + DTMF_SHARP)   /* 40# */
#define RELAY4_ON  (0x410 + DTMF_SHARP)   /* 41# */
#define MAST_LOCK    (0x123410 + DTMF_SPLAT)  /* 12341* */
#define MAST_UNLOCK  (0x123400 + DTMF_SHARP)  /* 12340# */

Now, you main loop can just read in these longs, and compare (or decompose) them however it wants:

void loop() {
  uint32_t command = read_tt_string();
  if (command & 0xF != DTMF_SHARP) {
    /* Only command that ends in other than # is LOCK */
    if (command == MAST_UNLOCK) {
      // la de da..
    }
  } else {
    switch(command) {
    case RELAY1_ON:
      //click
      break;
    case RELAY1_OFF:
      //unclick
      break;
      :
    }
  }
}

(a switch/case statement is not really a good way to do this, but it should work.)

You’d have to make rather substantial changes to avoid stopping everything else in read_tone(), but this should give you a general strategy…

Was this sketch completed by anyone. I would love to use it.