Pages: [1]   Go Down
Author Topic: Help with strtoul() function.  (Read 2523 times)
0 Members and 1 Guest are viewing this topic.
Scunthorpe, UK
Offline Offline
Full Member
***
Karma: 0
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello all.

New to world of Arduino and as a electronic hardwear engineer this programing side is all new to me but learning fast thanks to the forums  smiley.

Ok, i would like to use the function strtoul() but i don't fully understand how to use it so would like your help in understanding how to use the function correctly.

I have a ASCII string for example,

"41 05 1C 7B" (received over the serial)

but i'm only interested in the "1C 7B" and would like to convert it to HEX to get something like "0x1C7B" stored to a unsigned long. So if anyone could show/explain this to me it will be a great help.

Look forward to your replies, thanks.
« Last Edit: April 06, 2012, 05:34:54 am by Pavilion1984 » Logged

Germany
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
Walking on Nails
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The following code assumes that you save the whole ASCII string into a character array (reading from serial is usually a slow process with characters arriving one after another).

Code:
char buffer[12]; //your message with a trailing '\0'

// read from serial and maybe check if message has the correct length

char * pch;
uint32_t nResult= 0;
byte nPos= 0;
pch= strtok(buffer, " ");
while(pch)
{
  if(nPos > 1) // ignore first and second hex value
  {
    nResult= (nResult << 8) | (strtoul(pch, NULL, 16) & 0xff);
  }
  nPos++;
  pch= strtok(NULL, " ");
}
The code is not efficient or fail save. Basically your string is divided into smaller substrings and in the loop the first two "bytes" are skipped and the following bytes are combined to the result by reading a single byte (result from stroul is 32 bit, hence the mask to 8 bit) and shifting the previous value of the result by 8 bits and placing the read byte into this now free space.

Another approach would be to modify the buffer directly to get those two bytes of interest together without the space in between and then use strtoul().
Logged

loved the 68000 assembler back then and now I have to deal with THIS 8 bit thingy

'round the world...
Offline Offline
Faraday Member
**
Karma: 42
Posts: 3283
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Something like this?
Code:
char str[] = {'4','1','0','5','1','C','7','B','\0'};
unsigned long result = strtoul(str, NULL, 16);
unsigned int result_int;
result = result &0xFFFF; //getting rid of 0x4105
//OR
result_int = result &0xFFFF; //getting rid of 0x4105

Should work. smiley
I haven't compiled it... so chances are that this may put out some errors.
Logged

Eu não sou o teu criado. Se respondo no fórum é para ajudar todos mediante a minha disponibilidade e disposição. Responder por mensagem pessoal iria contra o propósito do fórum e por isso evito-o.
Se realmente pretendes que eu te ajude por mensagem pessoal, então podemos chegar a um acordo e contrato onde me pagas pela ajuda que eu fornecer e poderás então definir os termos de confidencialidade do meu serviço. De forma contrária toda e qualquer ajuda que eu der tem de ser visível a todos os participantes do fórum (será boa ideia, veres o significado da palavra fórum).
Nota também que eu não me responsabilizo por parvoíces escritas neste espaço pelo que se vais seguir algo dito por mim, entende que o farás por tua conta e risco.

Dito isto, mensagens pessoais só se forem pessoais, ou seja, se já interagimos de alguma forma no passado ou se me pretendes convidar para uma churrascada com cerveja (paga por ti, obviamente).

Scunthorpe, UK
Offline Offline
Full Member
***
Karma: 0
Posts: 129
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the replies an will have a look at them. From searching around i came up with the below, whould that not work do you think?

#define NULL '\0'

char serialrx[16];
char buffer[8];

void setup() {
  Serial.begin(9600);
  Serial.flush();
}

void loop() {
  byte i = 6;
  serialrx[6];                                                     //start conversion from the 6th byte
  while(serialrx != NULL)
  buffer[i++] = strtoul (serialrx, NULL, 16);
  i = 6;

}
« Last Edit: April 06, 2012, 07:08:58 am by Pavilion1984 » Logged

Germany
Offline Offline
Jr. Member
**
Karma: 0
Posts: 89
Walking on Nails
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Please use the code tags (button # above the smilies).

Concerning the code you posted:
Code:
#define NULL '\0'
This one is not necessary.
Code:
char serialrx[16];
char buffer[8];

void setup() {
  Serial.begin(9600);
  Serial.flush();
}
Serial.flush() changed in Arduino 1.0. Before it cleared the receive buffer. Since v1.0 it waits for the transmit buffer to be empty / the transmission to be finished. Not really necessary in setup().
Code:
void loop() {
  byte i = 6;
  serialrx[6];                                                     //start conversion from the 6th byte
This line does nothing.
Code:
  while(serialrx != NULL)
  buffer[i++] = strtoul (serialrx, NULL, 16);
  i = 6;
}
And this code is bogus. serialrx is a pointer to an array of characters. serialrx[pos] means one of the characters in the array. This looks like a try in using pointer arithmetics or maybe some very old code for reading the serial receive buffer. The way it is now serialrx is never NULL because it is defined as a global array - the pointer to the array stored in serialrx is not NULL.

From my point you need to learn some of the C programming basics and some C++ to use libraries supplied with Arduino.

Lets go through all step by step. Let us assume all input via serial connection looks like your example string - four hex coded values with spaces between and at the end of the command an "return" ("\n" or "\n\r"). First step is to get the input from Serial. All data arrives bytewise and the ATmega328 on the Arduino is a lot faster than the transmission via Serial. You could use a buffer for the incoming data and when a "return" arrives the whole string is evaluated. While reading data you could filter the spaces out and ignore any '\r' only looking for '\n'. This helps for the second step using strtoul like bubulindo did in his post. For the reading you need some kind of a loop which collects and filters incoming data.
Code:
  boolean bWaitingInput= true;
  while(bWaitingInput)
  {
    uint8_t nBufferPos= 0; // position in the array where a new character is saved
    if(nBufferPos >= BUFFER_MAX) // is the buffer full?
    {
      serialrx[BUFFER_MAX - 1]= '\0'; // make a valid string by setting the last buffer character to '\0'
      Serial.print("buffer overflow: ");
      Serial.println(serialrx); // transmit what the buffer holds for debugging
      nBufferPos= 0; // reset the buffer
    }
    if(Serial.available()) // something arrived via serial connection?
    {
      char c= Serial.read(); // read the new character
      switch(c)
      {
        case '\r':
        case ' ':
          break; // do nothing with space or '\r'
        case '\n':
          serialrx[nBufferPos++]= '\0'; // a string must have 0 at the end, so we add it here
          bWaitingInput= false; // we have data for evaluation
          break;
        default: // all other characters go into the buffer
          serialrx[nBufferPos++]= c;
    }
  }
  Serial.print("received: ");
  Serial.println(serialrx);
Now strtoul could be used on serialrx (no spaces to interfere are in the buffer). BUFFER_MAX is a define for the buffer size. Search for "post increment" to understand the filling of the buffer with the position variable. This is for a start. If you have no idea what's going on then use Serial.println() to show you results in the serial monitor. PaulS proposes to use a pen and paper and think of what you would do step by step to get your problem solved - I like this idea.
Logged

loved the 68000 assembler back then and now I have to deal with THIS 8 bit thingy

Pages: [1]   Go Up
Jump to: