Arduino hex to string decoder not working - arduino

I'm creating a HEX -> STR decoder using an LCD screen (display the HEX as well as the decoded values), a keypad (to input the HEX code), and a button (to press for it to decode the HEX values). The decoder works sometimes but sometimes it glitches out and presents unexpected values.
#include <Keypad.h>
#include<LiquidCrystal.h>
String hex; // store the hex values
String text; // store the decoded text
int calcButton = 0;
const byte ROWS = 4;
const byte COLS = 4;
char hexaKeys[ROWS][COLS] = {
{'1', '2', '3', 'F'},
{'4', '5', '6', 'E'},
{'7', '8', '9', 'D'},
{'A', '0', 'B', 'C'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {13, 12, 11, 10};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
LiquidCrystal lcd(5, 4, 3, 2, A0, A1);
char nibble2c(char c) {
if ((c>='0') && (c<='9'))
return c-'0' ;
if ((c>='A') && (c<='F'))
return c+10-'A' ;
if ((c>='a') && (c<='a'))
return c+10-'a' ;
return -1 ;
}
char hex2c(char c1, char c2) {
if(nibble2c(c2) >= 0)
return nibble2c(c1)*16+nibble2c(c2) ;
return nibble2c(c1) ;
}
// resets string values and clears screen
void erase() {
hex = "";
Serial.println(hex);
text = "";
lcd.clear();
lcd.setCursor(0,0);
}
// decode the hex values
String calculate(String hex) {
if (hex.length()%2 != 0) {
lcd.setCursor(0,0);
lcd.print("No of characters");
lcd.setCursor(0,1);
lcd.print("needs to be even");
delay(2000);
erase();
}
else {
for (int i = 0; i < hex.length() - 1; i+=2){
for (int j = 1; j < hex.length(); j+=2){
text += hex2c(hex[i], hex[j]);
}
}
}
}
void setup() {
pinMode(A2, INPUT);
lcd.begin(16, 2);
lcd.setCursor(0,0);
Serial.begin(9600);
}
void loop() {
calcButton = digitalRead(A2); // decode button
char customKey = customKeypad.getKey();
// if keypad is pressed, add hex values to str
if (customKey){
lcd.print(customKey);
hex += customKey;
Serial.println(hex);
}
// if button is pressed, decode
if (calcButton == 1) {
lcd.clear();
calculate(hex);
hex = "";
lcd.print(text);
text = "";
delay(1500);
lcd.clear();
}
}
I input 49 and get I (which is correct) but when I input 4949 I expect the output to be II but it outputs IIII and when I input 6F expecting o the entire screen blurs and glitches.

The problem is here:
for (int i = 0; i < hex.length() - 1; i+=2){
for (int j = 1; j < hex.length(); j+=2){
text += hex2c(hex[i], hex[j]);
}
}
Notice that you iterate over the hex string length()*length()/4 times, combining every even hex character from the string with every odd character in the string, not just the one immediately following it. For two-digit hexadecimal strings this works because there only is one odd- and one even-indexed character; for longer strings you get wrong results.
4949 will combine 4 (#0) and 9 (#1), then 4 (#0) and 9 (#3) (wrong!), then 4 (#2) and 9 (#1) (wrong!), then 4 (#2) and 9 (#3), which gives you the result that 49494949 should give instead of 4949.
What you want is just:
for (int i = 0; i < hex.length() - 1; i+=2){
text += hex2c(hex[i], hex[i+1]);
}

Related

Arduino is giving a weird output when using toInt()

I'm trying to convert a string to an integer (which is actually a binary number) so that I can output the DEC value, but where the answer SHOULD be 63 (00111111), it's giving me -19961 as an output? It would be great if someone can help me correctly convert the string to an int :)
// C++ code
//
const int button = 13;
int buttonPressed = 0;
int counter = 0;
int myInts[] = {0, 0, 1, 1, 1, 1, 1, 1};
void setup()
{
Serial.begin(9600);
pinMode(button, INPUT);
}
void loop()
{
buttonPressed = digitalRead(button);
if (buttonPressed == HIGH){
counter = count();
//rial.println(counter);
}
else{
Serial.println("Button not pressed");
}
delay(1000);
}
int count()
{
String myString = ""; //Empty string for constructing
int add = 0;
int i = 0;
//Should add all the values from myInts[] into a string
while(i < 8){
myString = String(myString + myInts[i]);
Serial.println(add);
delay(1000);
add++;
i++;
}
Serial.println(myString);
int myNumber = myString.toInt(); //Convert the string to int
Serial.println(myNumber, DEC); //Should print 63 in this case
return add;
}
Your code currently does the following:
Concatenates all your integers together to make a string "00111111"
Attempts to convert it (as a string holding a base 10 integer) to the integer 111,111 (one hundred eleven thousand, one hundred eleven)
Hits integer overflow. The range of an Arduino int is -32768 to 32767 (65536 possible values), so the number you really have is 111111 - 2*65536 = -19961.
I don't believe that there's an overload of Arduino's ToInt that converts a binary string to an integer. Depending on the C++ support in Arduino, you may be able to use std::stoi as described here.
Instead, you may choose to do the conversion yourself - you can keep track of a number sum, and at each loop iteration, double it and then add the next bit:
int sum = 0;
for(int i = 0; i < 8; i++) {
sum *= 2;
sum += myInts[i];
// print and delay if you want
}
Over the eight iterations, sum ought to have values 0, 0, 1, 3, 7, 15, 31, and finally 63

Redeclared as different kind of symbol in Arduino

I'm currently working on a school project. I want the servo to move according to the number of coins selected. I keep getting the error " 'void servoOne()' redeclared as different kind of symbol " I know this has been asked but I'm not sure how to fix this.
Here is my code.
#include <LiquidCrystal.h>
#include <Keypad.h>
#include <Servo.h>
Servo servoOne;
String sharp="";
int piso=0;
int lima=0;
int sampu=0;
String input="";
String remlast = "";
LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);//RS,EN,D4,D5,D6,D7
const byte Rows= 4; //number of rows on the keypad i.e. 4
const byte Cols= 3; //number of columns on the keypad i,e, 3
//we will definne the key map as on the key pad:
char keymap[Rows][Cols]={
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
byte rPins[Rows]= {3,4,5,6}; //Rows 0 to 3
byte cPins[Cols]= {7,8,9}; //Columns 0 to 2
Keypad kpd= Keypad(makeKeymap(keymap), rPins, cPins, Rows, Cols);
void setup() {
// put your setup code here, to run once:
lcd.begin(20,4);
servoOne.attach(10);
}
void loop() {
char key2 = kpd.getKey();
if (key2 != NO_KEY)
{
lcd.print(key2);
if (sharp == "")
{
input+=key2;
remlast = input;
remlast.replace("*","");
remlast.replace("#","");
piso = remlast.toInt();
}
else if (sharp == "five")
{
input+=key2;
remlast = input;
remlast.replace("*","");
remlast.replace("#","");
lima = remlast.toInt();
}
else if (sharp == "ten")
{
input+=key2;
remlast = input;
remlast.replace("*","");
remlast.replace("#","");
sampu = remlast.toInt();
}
if(key2=='*' && sharp!=NULL)
{
lcd.rightToLeft();
sharp="";
piso=0;
lima=0;
sampu=0;
input="";
remlast="";
}
if (sharp=="ten" && key2=='#')
{
sharp = "out";
lcd.clear();
lcd.print(piso);
lcd.print(lima);
lcd.print(sampu);
servoOne();
}
else if (sharp=="five" && key2=='#')
{
lcd.clear();
lcd.print("10-peso=");
lcd.setCursor(0,1);
lcd.print("(*)Erase (#)Enter");
lcd.setCursor(8,0);
sharp="ten";
input = 0;
}
else if (key2=='#')
{
lcd.clear();
lcd.print("5-peso=");
lcd.setCursor(0,1);
lcd.print("(*)Erase (#)Enter");
lcd.setCursor(7,0);
sharp="five";
input = 0;
}
if (key2=='*')
{
lcd.clear();
lcd.print("1-peso=");
lcd.setCursor(0,1);
lcd.print("(*)Erase (#)Enter");
lcd.setCursor(7,0);
}
}
}
//--------------------SERVO ONE--------------------//
void servoOne()
{
servoOne.write(70);
delay(10);
while(piso>0)
{
int x = piso;
while(x>0)
{
servoOne.write(170);
delay(200);
servoOne.write(40);
delay(200);
x--;
}
}
}
It occurs as it clashes between servoOne in Servo servoOne; and void servoOne(). Please replace servoOne in void servoOne() by some other name.
(don't forget to replace the function name in function call by your new function name)

why the output not follow the setcursor?

Why is the output of the function does not follow the lcd.setCursor position? When type in, the output pops out at a different position instead of the determined setcursor. I need to use this function multiple times for different variables that hold a different number for a different purpose. However, I need the display of the numbers on the LCD according to the set position.
Here is the code:
#include <Keypad.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the
LCD I2C address
const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] =
{
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'*', '0', '#'}
};
byte rowPins[ROWS] = {9,8,7,6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5,4,3}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
void setup()
{
Serial.begin(9600);
lcd.begin(20,4);
}
void loop()
{
lcd.setCursor(2,0);
int stage1speed = getnumber();
lcd.setCursor(5,0);
lcd.print("sv");
lcd.setCursor(2,1);
int stage1time = getnumber();
lcd.setCursor(5,1);
lcd.print("sec");
lcd.setCursor(2,2);
int stage2speed = getnumber();
lcd.setCursor(5,2);
lcd.print("sec");
lcd.setCursor(2,3);
int stage2time = getnumber();
lcd.setCursor(5,3);
lcd.print("sec");
}
int getnumber()
{
static char buffer[4];
static byte i = 0;
char key = keypad.getKey();
// i < 3: prevent buffer overflow
if ('0' <= key && key <= '9' && i < 3)
{
buffer[i] = key;
++i;
} else if (key == '#' && i > 0)
{
buffer[i] = '\0'; // null-terminate buffer
int value = atoi(buffer);
lcd.print(buffer);
i = 0;
}
}

Arduino - Adafruit 16-channel board, how to properly control all channels with less delay?

I am trying to control a few (8 for now) servo motors using this 16-channel board. I am running to some issues about accuracy, for example, when moving a couple of motors do draw a diagonal line, because of the delay between each servo, each motor will move in different timing resulting in incorrect drawings.
I am not sure about how to drive the motors in the fastest way in therms of code.
Where to set delays, the baud rate settings for this application, etc. I couldn't find a good example using all channels with minimum delay. In my case, messages are coming from serial, as explained in the code comment.
Is this the right way to drive this board channels?
I am using an arduino uno, but I would like to check if using a Teensy 3.2 results in best performances for this application.
Thanks in advance for any suggestions.
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
//#define SERVOMIN 150
//#define SERVOMAX 600
// temporary setting pins for 4 lights - it will be controlled by some decade counter...
//#define L1 4
//#define L2 7
//#define L3 8
//#define L4 10
#define L1 9
#define L2 10
#define L3 11
#define L4 12
/*
* a "pointer" device includes a light and 2 servos. Parameters from serial are:
* index,light,servo1,servo2; <- parameters separated by ',' end of pointer is ';'
*
* example of how serial is coming containing instructions for 4 pointers;
0,0,180,180;1,0,0,0;2,0,180,180;3,0,0,0;
0,0,90,90;1,0,90,90;2,0,90,90;3,0,90,90;
**most of the time these instructions doesn't come all for 4 pointers.
ex:
1,0,12,12;4,255,100,100;
**sometimes it comes only id and light parameter.
0,255;1,0;
(instructions only to turn light on/off)
*/
//values for 8 servos:
const uint8_t SERVOMIN[] = {150, 130, 150, 130, 150, 130, 150, 130};
const uint8_t SERVOMAX[] = {600, 500, 600, 500, 600, 500, 600, 500};
//boards (for now, only one board = 16 servos)
Adafruit_PWMServoDriver pwm [] = {
Adafruit_PWMServoDriver(0x40)
};
uint8_t servonum = 0;
uint8_t activeServos = 4; //not being used now
char buf [4]; //maybe too long
uint16_t currentPointer [4]; //index//light//servo1//servo2
byte lightPin [4] = {L1, L2, L3, L4};
uint8_t lightstatus [4] = {0, 0, 0, 0};
//debug
String inputString = ""; // a string to hold incoming data
boolean stringComplete = false; // whether the string is complete
boolean feedback = false;
void setup() {
//temporally as digital outputs
pinMode(L1, OUTPUT);
pinMode(L2, OUTPUT);
pinMode(L3, OUTPUT);
pinMode(L4, OUTPUT);
Serial.begin(115200);//230400 //115200 //57600 //38400 ?
for ( uint8_t i = 0; i < sizeof(pwm); i++) {
pwm[i].begin();
pwm[i].setPWMFreq(60);
}
}
void loop() {
reply();
}
void reply() {
if (stringComplete) {
if (feedback) Serial.println(inputString);
// clear the string:
inputString = "";
stringComplete = false;
for ( int i = 0; i < sizeof(buf); ++i ) buf[i] = (char)0;
}
}
void serialEvent() {
static byte ndx = 0;
static int s = 0;
while (Serial.available()) {
char rc = (char)Serial.read();
inputString += rc;
//(2) setting pointer parameter
if ( rc == ',') {
setPointer(s);
s++;
for ( int i = 0; i < sizeof(buf); ++i ) buf[i] = (char)0;
ndx = 0;
}
//(3) end of this pointer instruction
else if (rc == ';') {
setPointer(s);
//executePointer(); //plan B
ndx = 0;
s = 0;
for ( int i = 0; i < sizeof(buf); ++i ) buf[i] = (char)0;
}
//(4) end of command line
else if (rc == '\n') {
//p = 0;
s = 0;
stringComplete = true;
}
//(1) buffering
else {
buf[ndx] = rc;
ndx++;
}
}
}
void setPointer(int s) {
//index//light//servo1//servo2
int value;
value = atoi(buf);
//index
if (s == 0) {
if (feedback) {
Serial.print("index:");
Serial.print(value);
Serial.print(", buf:");
Serial.println(buf);
}
currentPointer[0] = value;
}
//light
else if (s == 1) {
int index = currentPointer[0];
currentPointer[s] = value;
//Serial.println(index);
digitalWrite(lightPin[index], (value > 0) ? HIGH : LOW);
// analogWrite( lightPin[currentPointer[0]], currentPointer[1]); // implement later
if (feedback) {
Serial.print("light: ");
Serial.println(value);
}
//servos
} else {
int index = currentPointer[0];
if (feedback) {
Serial.print("servo ");
Serial.print(index * 2 + s - 2);
Serial.print(": ");
Serial.println(value);
}
uint16_t pulselen = map(value, 0, 180, SERVOMIN[index], SERVOMAX[index]);
currentPointer[s] = pulselen;
pwm[0].setPWM(index * 2 + (s - 2), 0, pulselen); //current pointer id * 2 + s (s is 2 or 3)
//delay(20);
}
}
// this was plan B - not using
void executePointer() {
int index = currentPointer[0];
analogWrite( lightPin[index], currentPointer[1]);
pwm[0].setPWM(index * 2, 0, currentPointer[2]);
pwm[0].setPWM(index * 2 + 1, 0, currentPointer[3]);
delay(20);
}

Arduino Calculator (Multiple Button Pressing)

We're currently making a 4x3 calculator using Arduino and LCD. We're lacking buttons so instead of one button per operation, there's only one button for all operations. So far, it only does addition. How do you do the thing wherein if I pressed the OPERATION button once, it does addition, if twice, subtraction, etc.
#include <Keypad.h>
#include <LiquidCrystal.h> //import lcd library
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //lcd pins
//LiquidCrystal lcd(5,4,3,2,1,0);
const byte ROWS = 4; // four rows
const byte COLS = 3;
//define the keymap
char keys [ROWS] [COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
{'+', '0', '='}
};
byte rowPins[ROWS] = {
9 ,8 ,7 ,6}; //connect keypad ROW1, ROW2, ROW3, ROW4 to these arduino pins
byte colPins[COLS] = {
13, 10, 1};
//create the keypad
Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
//variables declaration
boolean valOnePresent = false;
boolean next = false;
boolean final = false;
String num1, num2;
int ans;
char op;
void setup(){
lcd.begin(16,2);
lcd.setCursor(2,0);
lcd.print("Calculator");
delay(2500);
lcd.clear(); //clears the LCD screen and positions the cursor in the upper-left corner.
}
void loop(){
char key = myKeypad.getKey();
if (key != NO_KEY && (key=='1'||key=='2'||key=='3'||key=='4'||key=='5'||key=='6'||key=='7'||key=='8'||key=='9'||key=='0')){
if (valOnePresent != true){
num1 = num1 + key;
int numLength = num1.length();
lcd.setCursor(15 - numLength, 0); //to adjust one whitespace for operator
lcd.print(num1);
}
else {
num2 = num2 + key;
int numLength = num2.length();
lcd.setCursor(15 - numLength, 1);
lcd.print(num2);
final = true;
}
}
else if (valOnePresent == false && key != NO_KEY && (key == '/' || key == '*' || key == '-' || key == '+')){
if (valOnePresent == false){
valOnePresent = true;
op = key;
lcd.setCursor(15,0);
lcd.print(op);
}
}
else if (final == true && key != NO_KEY && key == '='){
if (op == '+')
{
ans = num1.toInt() + num2.toInt();
}
else if (op == '='){
ans = num1.toInt() + num2.toInt();
}
/* else if (op == '+')
{
answ = num1.toInt() - num2.toInt();
}
*/
lcd.clear();
lcd.setCursor(15,0);
lcd.autoscroll();
lcd.print(ans);
lcd.noAutoscroll();
}
}
You could use an array in order to accomplish this. By implementing a while loop with a small delay you can keep iterating through the positions in the array every time the button is pushed until the array times out. Here's an example of some could you could use to implement it.
char ops [4] = {'+','-','/','*'};
int del = 2500;
int strt = millis();
int location = 0;
while (millis() - strt < del) {
key = myKeypad.getkey();
if (key == '+') {
if (loc == 3) {
location = 0;
}
else {
location += 1;
}
strt = millis();
}
}
op = ops(location);

Resources