User Interface, Using A buffer with a module

Hi!
I have a TEA5767 radio module, with breakout board.
I also have a PS2 keyboard, and ps2 keyboard adapter, along with corresponding libraries.

The ps2 keyboard output is gathered through the "keyboard.read()" function.
The radio module's frequency is SET through the "radio.setFrequency()" function.

Here is what I want. The user inputs a number onto the keyboard, and the module is set to that frequency number. However, keyboard.read() only reads one character at a time, and the full frequency is 4 characters long.

So, how do I make the user able to enter a full 4 character "thing" of text, then set that thing as the frequency for the radio module????

Some example code would be epic!
Thanks in advance! :slight_smile:

P.S. Please let me know if you need the libraries in order to help. I will gladly attempt to gather them for you.

So, how do I make the user able to enter a full 4 character “thing” of text, then set that thing as the frequency for the radio module?

How were you able to get your computer to wait until you finished typing to post?

You store the data each time you detect a key press, unless the key is the one that means “OK, NOW let’s use the data”. If it is, then you use the data, and clear the buffer and reset the index for the next set of data.

PaulS:
How were you able to get your computer to wait until you finished typing to post?

You store the data each time you detect a key press, unless the key is the one that means “OK, NOW let’s use the data”. If it is, then you use the data, and clear the buffer and reset the index for the next set of data.

Yes I understand the concept, but how do I write that into my C++ arduino program?

Thanks for the reply! :slight_smile:

Here is my draft code for the buffer:

void app_Radio() {
  char freq0 = ' ';
  char freq1 = ' ';
  char freq2 = ' ';
  char freq3 = ' '; 

  tft.fillScreen(BLUE);
  tft.setCursor(10, 10);
  tft.setTextColor(GREEN);
  tft.setTextSize(2);
  tft.print("Enter Frequency");
  tft.println();
  tft.setTextSize(3);
  tft.print(freq0);
  tft.print(freq1);
  tft.print(freq2);
  tft.print(freq3);
  int radioentry;
  radioentry = keyboardps2.read();
      freq0 = '_';
  while (freq0 == '_') {
    if (keyboardps2.available) {
    radioentry = freq0;
    freq1 = '_';
    }
  } //While
  while (freq1 == '_') {
    if (keyboardps2.available) {
    radioentry = freq1;
    freq2 = '_';
    }
  } //While
  while (freq2 == '_') {
    if (keyboardps2.available) {
    radioentry = freq2;
    freq3 = '_';
    }
  }
    while (freq3 == '_') {
    if (keyboardps2.available) {
    radioentry = freq3;
char finalfreq[4];
finalfreq[0] = freq0;
finalfreq[1] = freq1;
finalfreq[2] = freq2
finalfreq[3] = freq3;

radio.setFrequency(finalfreq[4]);
    }
  }
  //While
}

Any suggestions?

There is no real difference between any read method (serial, file, ...). So I suggest that you read (possibly again) Serial Input Basics - updated; saves me a lot of typing ;). Example 2 will probably be a good option.

You also have to look at what the TEA5767 Module is expecting as a representation of the frequency.
Have you a code sample of feeding the TEA a specific frequency ?

I’m just looking at something I found/wrote some time ago now.
The frequency is calculated in an unsigned integer and then is split into two unsigned characters.
There may be other ways of doing the same thing.

  Wire.beginTransmission(0x60);   //writing TEA5767
  Wire.write(frequencyH);  // unsigned char
  Wire.write(frequencyL);  // unsigned char
  (bHLSI) ? (Wire.write(0x10)) : (Wire.write(0x00)) ;
  Wire.write(0x10);   // XTAL
  Wire.write(0x00);
  Wire.endTransmission();

Edit:
I found it here . . .
https://www.electronicsblog.net/arduino-fm-receiver-with-tea5767/

sterretje:
There is no real difference between any read method (serial, file, …). So I suggest that you read (possibly again) Serial Input Basics - updated; saves me a lot of typing ;). Example 2 will probably be a good option.

Ok. I read through Example 2. I didn’t really understand it (Could you explain it to me? It confused me :confused: ) Anyways, I editied to the best of my ability. I basically replaced “Serial.read()” with “Keyboard.read()” so it would be reading from the keyboard, not the Serial Receive Buffer. I kept Serial.print() though. Here is my modified code:

#include <PS2Keyboard.h> //Keyboard

// Example 2 - Receive with an end-marker

const int DataPin = 18;
const int IRQpin =  19;

PS2Keyboard keyboard;

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

boolean newData = false;

void setup() {
    Serial.begin(9600);
      keyboard.begin(DataPin, IRQpin);
    Serial.println("<Arduino is ready>");
}

void loop() {
    recvWithEndMarker();
    showNewData();
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
    
    while (keyboard.available() > 0 && newData == false) {
        rc = keyboard.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

When I run this code, it compiles. On the serial monitor, it says “Arduino is Ready.” However, when I type something on the PS2 keyboard, nothing happens!!
Could someone please explain this to me??
I love all the help so far! :slight_smile:

Every iteration of loop(), the code checks if there are characters available and if so it reads them and adds it to a buffer ‘receivedChars’. When a ‘\n’ (linefeed) is received, it replaces it with the string terminator ‘\0’ and places that in the buffer. ‘ndx’ (index) indicates where the character must be placed in the buffer; it starts with 0 and increments every time a character is received.

+-----+-----+-----+-----+-----+-----+-----
| 'a' | 'b' | 'c' | '\0'|     |     |
+-----+-----+-----+-----+-----+-----+-----

When the ‘\n’ is received, a flag is set to indicate that the message is complete and sets ‘ndx’ to 0 for the next time that one needs to read data.

The flag is used in showNewData() and it will show the new text if the flag was set. It will clear the flag to indicate that there is no longer new data (it was processed).

I think that you need to add some debug statements to your recvWithEndMarker.

  while (keyboard.available() > 0 && newData == false)
  {
    Serial.println("characters available");
    rc = keyboard.read();
    Serial.print(rc, HEX);

    if (rc != endMarker)
    {
      ...
      ...
    }
    else
    {
      Serial.println("  endMarker received");
      ...
      ...
    }
}

This way you can follow what was received. On your keyboard, type some characters like ‘a’, ‘b’ etc and press .

Tell us what you typed and what the result in the serial monitor is.

For a ‘a’, you should see 61, for a ‘b’ 62 and so on. For a ‘0’ you should see ‘30’, for ‘1’ you should see ‘31’ etc. See asciitable.com

If you see different data in the serial monitor, you get raw keyboard output instead of ascii characters. Please provide links to the libraries that you use and the hardware that you use to connect the PS keyboard to the Arduino. Also, which Arduino do you use?

sterretje:
When the ‘\n’ is received, a flag is set to indicate that the message is complete and sets ‘ndx’ to 0 for the next
For a ‘a’, you should see 61, for a ‘b’ 62 and so on. For a ‘0’ you should see ‘30’, for ‘1’ you should see ‘31’ etc. See asciitable.com

Great! I will try to get the library for you… It was so long ago I can’t remember where I got it.

Hardware:

  1. Arduino MEGA

  2. Ps2 Adapter: https://www.amazon.com/gp/product/B00XRRNV4A/ref=oh_aui_detailpage_o00_s00?ie=UTF8&psc=1

  3. Keyboard: https://www.amazon.com/gp/product/B0075W8C8S/ref=oh_aui_detailpage_o01_s00?ie=UTF8&psc=1

Ok. So I ran this code:

// Example 2 - Receive with an end-marker

#include <PS2Keyboard.h> //Keyboard

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data

const int DataPin = 18;
const int IRQpin =  19;

boolean newData = false;

PS2Keyboard keyboard;

void setup() {
    Serial.begin(9600);
    keyboard.begin(DataPin, IRQpin);
    Serial.println("<Arduino is ready>");
}

void loop() {
    recvWithEndMarker();
    showNewData();
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\n';
    char rc;
    
   while (keyboard.available() > 0 && newData == false)
  {
    Serial.println("characters available");
    rc = keyboard.read();
    Serial.print(rc, HEX);

    if (rc != endMarker)
    {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
    }
    else
    {
      Serial.println("  endMarker received");
receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
    }
}
}

void showNewData() {
    if (newData == true) {
        Serial.print("This just in ... ");
        Serial.println(receivedChars);
        newData = false;
    }
}

On the serial monitor, I got this:

<Arduino is ready>
characters available
63characters available
67characters available
61characters available
64characters available
64characters available
65characters available
61characters available
65characters available
72characters available

61 was infact the letter A!
The letter B was 62!

When I hit ENTER on the keyboard, it prints the letter “D”

Where should I go from here? With this current code, are all the values being stored into the buffer? Can I just print the buffer and have all the numbers displayed on the same line, in the same thing?

Thanks SO much for the help so far!

'D' is actually 0D and if you look it up at asciitable.com, it's a carriage return (and not a linefeed). Change your endmarker to '\r' (or 0x0D) and it should work.

sterretje:
‘D’ is actually 0D and if you look it up at asciitable.com, it’s a carriage return (and not a linefeed). Change your endmarker to ‘\r’ (or 0x0D) and it should work.

YES! I got it working! The program is alive at last!

I have now created this new program that will later be interfaced into my main code.
This new code incorporates a TFT LCD, and the radio module that I am trying to set the frequency.

//Required Libraries

#include "TouchScreen.h" //Screen Library
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library
#include "Wire.h" //Uno to Mega communication library
#include <PS2Keyboard.h> //Keyboard
#include <TEA5767Radio.h>

//TFT Needed Data

#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
#define LCD_RESET A4
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

//Setting up the devices

PS2Keyboard keyboard;
TEA5767Radio radio = TEA5767Radio();
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

//Buffer Variable Stuff

const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;

//Keyboard Pins
const int DataPin = 18;
const int IRQpin =  19;

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = '\r';
    char rc;

   while (keyboard.available() > 0 && newData == false)
  {
    Serial.println("characters available");
    rc = keyboard.read();
    Serial.print(rc, HEX);

    if (rc != endMarker)
    {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
    }
    else
    {
      Serial.println("  endMarker received");
receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
    }
}
}

void setup() {
  //Initializing various devices
  
  tft.reset();
  uint16_t identifier = tft.readID();
    tft.begin(identifier);
      Wire.begin();
  Serial.begin(9600);
    keyboard.begin(DataPin, IRQpin);
    
    //Setting Up The on screen visuals
    
tft.fillScreen(BLUE);
tft.setTextColor(WHITE);
tft.setTextSize(2);
tft.print("FM Radio");
tft.setTextSize(1);
tft.println("Enter Station");
tft.println();


}

void loop() {
recvWithEndMarker();
    if (newData == true) {
    tft.fillScreen(BLUE);
    tft.print("You are listening to");
        tft.println(receivedChars);
          radio.setFrequency(receivedChars[32]);
        newData = false;
}
}

However, when I enter the frequency and hit ENTER, the radio does not go to the frequency?
What could be wrong?

I speculate that radio is not accepting the Buffer array as a proper frequency, that can be inputted into the TEA5767 module!

What can I do about this???

Thank you, thank you, thank you for all the help so far!!! :slight_smile: :slight_smile: :slight_smile:

stupid-questions:
I speculate that radio is not accepting the Buffer array as a proper frequency, that can be inputted into the TEA5767 module!

What I now believe from studying my TEA5767 library, is that it accepts floats, not chars (or in that case, char arrays)
Would you guys on the forums tend to agree? Or is it a different problem with my code? (See my previous reply)

I just compressed my ps2 keyboard library, and my TEA5767 library. The .zip files are attached to this reply.

PS2Keyboard.zip (10.1 KB)

TEA5767Radio.zip (2.82 KB)

Hi. I don't mean to bump the thread with so many consecutive posts, but I was curious.
I changed the "char" when declaring the array to act as the buffer, into "float"
I got a compiling error when running the program! The error was when I was printing the buffer to the TFT LCD, but NOT when I was printing to the radio module? I don't understand!
Here was the error:

call of overloaded 'print(float [32])' is ambiguous

How strange! Any explanations?

"overloaded" means there are many different versions of the print() function. There's one that prints single characters, there's one that prints strings, there's one that prints String objects.

"ambiguous" means it found two different versions that might do what you want but it's not able to tell exactly which one. The compiler can't guess which one you wanted. It has to stop and ask you to be unambiguous.

Printing an array of floats is probably not what you wanted. If you have 1.23 and 4.56 in an array, do you want it to print "1.234.56"? You should probably print only one of the values in the array at a time. Then print a comma or space between each one. Use a for() loop.

stupid-questions:
What I now believe from studying my TEA5767 library, is that it accepts floats, not chars (or in that case, char arrays)
. . .

Here is an example which appears to use the same library for the TEA5767 as you are using. Clear is that the frequency is a float:

void setFrequency(float frequency) Sets the frequency in MHz.

You have also to decide how the user is going to enter the frequency through the keyboard, for example, are you going to require the decimal point as in '101.3' or is the user simply to enter '1013' and the decimal point is assumed ? You probably don't want more then 2 decimal places but that depends on the FM channels in your area.

Once you have decided that, then you can look for a routine to convert the text input into a float number.

radio.setFrequency(receivedChars[32]);

That will never work; no idea what it will do though. Why do you use a different approach as to

tft.println(receivedChars);

??

Anyway, you need to convert the text to a float. See man atof and man strtod; the former does not do error checking, the latter does.

void loop()
{
  float frequency;

  recvWithEndMarker();
  if (newData == true)
  {
    tft.fillScreen(BLUE);
    tft.print("You are listening to");
    tft.println(receivedChars);


    frequency = atof(receivedChars);
    radio.setFrequency(frequency);

    newData = false;
  }
}

I suggest that you use strtod (I'm a little lazy) and implement some error checking if it fails (tell the user that he's an idiot if he enters 'abc' instead of '123.45').

Note:
the above is based on the code in your reply #10.

6v6gt:
You have also to decide how the user is going to enter the frequency through the keyboard, for example, are you going to require the decimal point as in ‘101.3’ or is the user simply to enter ‘1013’ and the decimal point is assumed ?

Well, I don’t really know what method I would use. I mean, when I had tested my PS2 >> TEA567 Code, I was typing the decimal point. So, I was assuming the user would type the decimal point. However, if the other method is somehow better, then I am definatly willing to use it. I guess if both methods are really the same, I would go with the user typing the decimal. But if not, I would go with whatever option is better!

Thanks for the help! :slight_smile:

stupid-questions:
Well, I don't really know what method I would use. I mean, when I had tested my PS2 >> TEA567 Code, I was typing the decimal point. So, I was assuming the user would type the decimal point. However, if the other method is somehow better, then I am definatly willing to use it. I guess if both methods are really the same, I would go with the user typing the decimal. But if not, I would go with whatever option is better!

Isn't programming fun? You write a little bit of code to read user input and next you have to write five or ten times as much to validate that user input. Your code needs to validate what the user enters; e.g it needs to be in the format 123.45 or it needs to be 12345. Up to you.

Note
I once added one variable to a C# program configuration and had to add 150 lines of validation (about 30 checks, including telling the user that there were mistakes); you're warned :smiley:

sterretje:
Note
I once added one variable to a C# program configuration and had to add 150 lines of validation (about 30 checks, including telling the user that there were mistakes); you're warned :smiley:

Well, I was saved from that experience by one line of code (that I got from your post, post #15):

float frequency = atof(receivedChars);

This created a float called frequency, and computed recievedChars into the float! From there I just printed frequency to the module!

IT WORKKKKEEEEEDDD!

I can't say how much I appreciate all the help on this topic. With that being said, I have a new issue with this project, related to this topic. (Que: slow, sarcastic applause from other forum posters)
Here is the new issue. (In the same project, different "area" of the project.)

I have an arduino mega, plugged into a TFT LCD, a radio module, and a good PS2 keyboard. (Sound familiar?) Now. An Arduino UNO is plugged into the Mega, communicating with two jumpers over Software Serial. Plugged in to the Arduino Uno, there is a GSM Phone module. Here is what I want to go down:

  1. The user enters a phone number on the PS2 keyboard
  2. The phone number is relayed to the uno through software serial
  3. The uno then tells the GSM module to voice call the phone number

Here are my thoughts. When the user starts up the program on the arduino mega, it sends "s" to the uno, priming it for data reception.
Idea #1. From there, each time the user enters a number on the keyboard, the number is printed to the TFT lcd, then printed to the Arduino uno. Then, the uno stores each incoming byte in a char array. The user hits enter, and "f" is printed to the Arduino Uno. This tells the uno to send the entire char array to the GSM module.
Idea #2. The user begins to type into the ps2 keyboard. Each thing is stored in a char array. When the user hits enter, the char array is sent to the UNO, where it is then sent to the GSM module. The only problem is, I have no idea how to receive a full char array over software serial, so how could I make the uno get the full char array and print it to the GSM module!

EDIT: Forgot this last part:
So which idea would be better?
Again, thanks for the wondrous help so far, it is really awesome! :smiley:

Well, I was saved from that experience by one line of code (that I got from your post, post #15):

I doubt that; enter a value like 'abc' and see which frequency you get; I think it will be 0.00. With strtod(), you can at least check if it's a valid float value by checking the endpointer.

Next not every frequency is valid for your radio. Let's say your radio is an FM radio; valid FM frequencies range from 88MHz to 108MHz (if I'm not mistaken). So you should basically check if the user entered a value between those two. Your radio might also be able to do SW, MW and LW. Different frequency ranges and you need to validate that the values are within that range.