Unexpected Multiplication result from function - math

I am working on a piece of code that calls a function and passes a number < 2 ** 16. The function only returns the number * 1000:
#pragma GCC optimize("Os")
unsigned long getVal(unsigned short val) {
return val * 1000 ;
}
void setup() {
Serial.begin(9600) ;
}
void loop() {
Serial.println(getVal(200)) ;
}
Now, if I send 200 to getVal(), I should get 200000, but it returns 3392! But if I modify the function like this:
unsigned long getVal(unsigned short val) {
return val * 1000000 ;
}
I get 200000000 back, which is expected.
I can't literally multiply numbers with 1000, but 100,000 works just fine.
I already tried disabling the Optimization with O0, which doesn't fix the problem either.
I am not getting what's going on. I am on Arduino Nano.

val * 1000000 performs a long multiplication, because one of the terms (1000000) is a long
val * 1000 does an int multiplication, because both terms are int. Arduino Nano int is 16 bit wide only, so the result is truncated before it is turned into the desired long return value.
unsigned long getVal(unsigned short val) {
return val * 1000UL ;
}
is what you are looking for.

Related

Converting char starting with "0b" or "0B" to unsigned long

I am working on a project for a client so I am given a lot of code I cannot modify. I am stuff in a weird situation because of this problem. Nonetheless, I have a char with 34 indexes that I need to convert into an unsigned long type. I have seen numerous methods to accomplish this such as strtout, atol, etc. None have worked because the string starts with "0b" (ie "0b10000010000010000010000010000000"). Without the "0b", the rest of the code will not function properly. I tested with varying beginning 2 chars but nothing has led to a successful trial. Is there a function or code available that can convert the previously mentioned string into unsigned long? Any help is greatly appreciated.
You can combine the fact that a character - '0' is the number of that digit and use bit shifting to build the number up from the string:
unsigned long binaryToUL(String numberString){
int i;
unsigned long answer = 0;
if(numberString.startsWith("0b"))
for(i = 2; i<numberString.length(); i++)
answer = (answer << 1) + (numberString[i] - '0');
return answer;
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
unsigned long test;
String testString = "0b10000010000010000010000010000000";
test = binaryToUL(testString);
Serial.println(testString);
Serial.println(test,BIN);
Serial.println(test);
while(true)
;
}
To convert a string a string representation of a binary that started with a "0b" or "0B", you need to remove the header first, then convert to the an unsigned long (uint32_t). Depend on what is the original string type (char[], char*) but an Arduino String in this case would make it easier to work with.
String myStr = "0b10000010000010000010000010000000";
void setup(){
Serial.begin(115200);
myStr.toUpperCase();
myStr.replace("0B", "");
uint32_t ul = strtoul(myStr.c_str(), NULL, 2);
Serial.println(ul, BIN);
}
void loop(){
}

using an integer function return value to return a pointer

I am writing a serial command interpreter. The user will send a text string to the interpreter and it will do stuff and return an integer (either data or a code depending on what the user requested). But I want to expand the interpreter and allow the user to get an array of data or other structure in response to their query.
Can I use the integer return value to return a pointer to EEPROM (or global variable) address? And have the user follow the pointer to the memory location? Based on the query they sent, they would know if the return value is a pointer or data integer.
for example if I want to return
struct curve_t {
int type; // (2 bytes) calibration type indicator
int ref[2]; // (4 bytes) calibration reference point2
float param[11]; // (11*4 bytes) curve fitting parameters
} theCurve;
can I use a function like this?
int serialResponse(char * command) {
// interpret command here
return &theCurve;
}
Can you send a memory address through serial interface?
YES
Can your user access EEPROM through serial interface, using that address?
Not directly. Your MCU has to relay the data between your user and the EEPROM.
I wrote a small test program and confirmed that it is possible. I can pass the address from the function as an integer and then re-cast it in my calling function. It needs to address a global variable or at least on that is available in the calling function.
char res[10];
void loop {
b = function();
Serial.println((char *)b);
}
int function() {
return int(&res[0]);
}
I would not recommend casting a pointer into an integer because it won't work on computer architectures where an int has fewer bits than a pointer.
Lexical Parsers - like what you're writing - often arrange to return a token type, and place the token value in a union that the caller can access. The nice thing about structuring your code in that way is that it's extensible to whatever data types you want, and it will work no matter what C++ platform you're running on.
Here's an example of a token parser that can parse integers and your curve_t:
struct curve_t {
int type; // (2 bytes) calibration type indicator
int ref[2]; // (4 bytes) calibration reference point2
float param[11]; // (11*4 bytes) curve fitting parameters
};
union TokenValue {
int i; // type = TOKEN_TYPE_INT
struct curve_t *pCurve; // type = TOKEN_TYPE_P_CURVE
};
enum TokenType {
TOKEN_TYPE_UNKNOWN = 0,
TOKEN_TYPE_INT,
TOKEN_TYPE_P_CURVE
};
curve_t theCurve;
TokenValue tokenValue;
/*
* Parses the given command,
* setting the parsed value in tokenValue,
* returning the type of value (a TOKEN_TYPE_*).
*/
TokenType serialResponse(char * command) {
if (command[0] == 'a') { // TO DO: your code will test something else.
// We want to return an integer
tokenValue.i = 1234; // TO DO: in your code, instead set the integer value from command
return TOKEN_TYPE_INT;
}
if (command[0] == 'b') { // TO DO: your code will test something else.
// We want to return a pointer to theCurve.
// TO DO: Fill in the values of theCurve, for example theCurve.param[0]
tokenValue.pCurve = &theCurve;
return TOKEN_TYPE_P_CURVE;
}
// Else
return TOKEN_TYPE_UNKNOWN;
}
void setup() {
//TO DO: move this code to where it belongs in your Sketch
//TO DO: parse a command
char command[10] = "and so...";
// TO DO: read the command.
// Process the command
enum TokenType t;
t = serialResponse(command);
if (t == TOKEN_TYPE_INT) {
// The command result is an integer
int i = tokenValue.i;
// TO DO: process the integer.
} else if (t == TOKEN_TYPE_P_CURVE) {
// The command result is a curve
curve_t *pCurve = tokenValue.pCurve;
// TO DO: process the Curve.
} else {
// unrecognized command. TO DO: handle the error.
}
}
void loop() {
// put your main code here, to run repeatedly:
}
If you insist on using the cast of an int to a pointer (which I admit is a lot simpler), you could add a test for int size problems to your setup():
void setup() {
Serial.begin(9600);
if (sizeof(int) < sizeof(curve_t *)) {
Serial.println("cast won't work");
for (;;) {} // hang here forever.
}
}

Run two functions at once

This program is a simple program designed to plot at the same time both your & Uc on the serial monitor. Arduino runs through the first for loop & plot the F1 function and after that does the same with F2. My objective is to plot them both at the same time.
My idea is to actually take a small fraction of time, let's say 10 ms, to plot F1 & the next 10 ms to plot F2, but I don't know how to write this down. I think the millis function is the solution, but I'm not quite sure how to implement it.
const short int R = 5000;
const float C = 0.0005;
const float TE = 0.1;
const float Tau = R*C;
const short int E = 5;
float t, Tinit,Tfin;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
//F1
for ( t = 0; t <= 20; t = t+TE)
{
float Ur = E*exp(-t/Tau);
Serial.println (Ur);
}
//F2
for ( t = 0; t <= 20; t = t+TE)
{
float Uc = E*(1-exp(-t/Tau));
Serial.println (Uc);
}
}
Thread can be used to solve your problem . It has a huge documentation , it is widely used library for Arduino(unofficial).
Give it a try.
It will be easy for you, if you see these :
Example - 1 (thread instance example)
Example - 2 (callback example)
Example - 3 (It is still buggy , but I think it will help)
If you want to do it without libraries , then you need to create two functions , without those loops . Like
void f1()
{
float Ur = E*exp(-t/Tau);
Serial.println (Ur);
}
void f2()
{
float Uc = E*(1-exp(-t/Tau));
Serial.println (Uc);
}
Now inside "void loop()" you can implement the basic logic of threading , which will be pretty rough , but fulfill your requirements. Like :
void loop() {
unsigned long now = millis();
static unsigned long last_finger_update;
if (now - last_finger_update >= FINGER_UPDATE_PERIOD) {
last_finger_update = now;
f1();
}
static unsigned long last_wrist_update;
if (now - last_wrist_update >= WRIST_UPDATE_PERIOD) {
last_wrist_update = now;
f2();
}
}
You have to declare two variables
const unsigned long FINGER_UPDATE_PERIOD = 1000;
const unsigned long WRIST_UPDATE_PERIOD = 1000;
All time units are in milliseconds. This strategy is collected from internet.
The most deterministic way of handling this is simply:
for (t = 0; t <= 20; t = t + TE) {
float Ur = E*exp(-t/Tau);
float Uc = E*(1-exp(-t/Tau));
Serial.println (Ur);
Serial.println (Uc);
}
More generally, you can implement a primitive resource scheduler:
while (true) {
task_one();
task_two();
}
You can do that Easily if you run RTOS in MCU as you know other solutions will also be sequential...
I've been using TridentTD_EasyFreeRTOS library it has easy way of having multiple tasks and controlling them in different sketch files..

Using long ints with Arduino Uno

I am trying to take a number between 100,000 and 10,000, and push each individual number into a queue.
I use a modulus function to do this. However, I am running into issues with the Uno's 16 bit ints, which a cap at 32,767. I have tried using long ints, unsigned ints, and unsigned long ints, but the program still only pushes 0s onto the queue after 32,767. Should I try a char/string approach, or am I missing a solution?
void fill_que(unsigned int b) {
int price = b;
while(price > 0) {
queue.push(price%10);
Serial.print(price%10);
price/=10;
}
}
int main() {
unsigned int price1 = 36111;
fill_que(price1);
}
I will make a guess and say, you forgot to change the type of the variable price.
It should be:
void fill_que(unsigned long b)
{
unsigned long price = b;
while(price > 0)
{
queue.push(price%10);
Serial.print(price%10);
price/=10;
}
}
int main()
{
unsigned long price1 = 36111;
fill_que(price1);
}

How to correctly use sscanf

I have to write an Arduino function to look up a number in the phone book. My code doesn't work because of the condition using sscanf. What am I doing wrong?
//read the phone book and put the good value in the string
void Read_ADMIN_PHONE_NUMBER(){
String ADMIN_PHONE_NUMBER;
delay(1000);
sendATcommand("AT+CPBS=\"SM\"", 500) ; //Select the SIM phonebook
sendATcommand("AT+CPBR=1,99", 100) ; // To read ALL phonebook +CPBR: 1,"690506990",129,"ANDROID"---- exemple de reponse copier du serial monitor
if (1 == sscanf(fonaInBuffer, "+CPBR: %*s", &ADMIN_PHONE_NUMBER)) {
Serial.println(F("*****"));
Serial.println(ADMIN_PHONE_NUMBER);
} else {
Serial.println(F("**bad***"));
}
delay(2000);
}
My problem come from the sscanf.I can't put fonaInBuffer in ADMIN_PHONE_NUMBER
void Read_ADMIN_PHONE_NUMBER(){
String ADMIN_PHONE_NUMBER;
delay(1000);
sendATcommand("AT+CPBS=\"SM\"", 500) ; //Select the SIM phonebook
sendATcommand("AT+CPBR=1,99", 100) ; // To read ALL phonebook like example: +CPBR:1,"690506990",129,"ANDROID"
if (1 == sscanf(fonaInBuffer, "+CPBR: %*s", &ADMIN_PHONE_NUMBER)) {
Serial.println(ADMIN_PHONE_NUMBER);
} else {
Serial.println(F("**bad***"));
}
delay(2000);
The * in %*s means 'do not assign', and such conversion specifications are not counted in the number of successful conversions. Therefore, the sscanf() call will return 0 always (unless the scanned string is empty; then it returns EOF) because there is no active conversion.
Remove the *, or replace it with a suitable number. If the ADMIN_PHONE_NUMBER is a char ADMIN_PHONE_NUMBER[123];, then the number you use should be (at most) 122: %122s — because sscanf() writes a null after the 122 characters if it reads 122 characters in a single 'word'. It is not clear what String ADMIN_PHONE_NUMBER; means — more precise advice cannot be given because of that.
Reducing your code to close to an MCVE (How to create a Minimal, Complete, and Verifiable Example?):
#include <stdio.h>
int main(void)
{
char buffer[] = "+CPBR: 1,\"690506990\",129,\"ANDROID\"";
char number[64];
int n = sscanf(buffer, "+CPBR: %63s", number);
printf("n = %d: number = [%s]\n", n, number);
n = sscanf(buffer, "+CPBR: %*d , \" %63[^\"]", number);
printf("n = %d: number = [%s]\n", n, number);
return 0;
}
Sample output:
n = 1: number = [1,"690506990",129,"ANDROID"]
n = 1: number = [690506990]
Take your pick as to which you want to use. I've been liberal with allowed white space in the sscanf conversion specifications. You can be less liberal if you prefer.

Resources