Shop OBEX P1 Docs P2 Docs Learn Events
SimpleIDE C function problem — Parallax Forums

SimpleIDE C function problem

RsadeikaRsadeika Posts: 3,837
edited 2016-02-28 22:54 in Propeller 1
Data Bytes: 2
signed
The current in milliamps (mA) flowing into or out of Create’s
battery. Negative currents indicate that the current is flowing
out of the battery, as during normal running. Positive currents
indicate that the current is flowing into the battery, as during
charging.
Range: -32768 – 32767
The above tech note is what I am trying to get to work, using SimpleIDE simpletools. When compiled, it does not have any errors, but the value displayed is not what I am expecting. When I have a draw on the battery, I am expecting to see a negative value, but I do not see any negative sign when the value is displayed. Anybody have any ideas as to what I got wrong with my function?

Thanks

Ray
void CRcurrent()
{
  fdserial_txChar(create,142);
  fdserial_txChar(create,23);  // Current
  int highbyte = fdserial_rxChar(create);
  pause(50);
  int lowbyte =  fdserial_rxChar(create);
  pause(50);
  //writeDec(rpi,highbyte);  // 255
  //writeStr(rpi,"\n");
  //writeDec(rpi,lowbyte);    // 93
  //writeStr(rpi,"\n");
  float tempbyte = ((highbyte << 8) + lowbyte);
  writeFloat(rpi,(tempbyte/1000));   // 63.0xxx
  writeStr(rpi," Current\n");
  tempbyte=0;
}          

Comments

  • ersmithersmith Posts: 6,053
    edited 2016-02-28 23:47
    If you want to treat a 16 bit quantity as a signed value, you'll have to "sign extend" it to 32 bits, otherwise it will be treated as an unsigned value.

    There are a number of ways to do this, but they all come down to the same thing (copying the high bit of the 16 bits you read into the upper word of the 32 bit register). The simplest and probably clearest is to let the compiler do it for you:
    #include <stdint.h> // make sure you include this at the start of your program
    ...
    int16_t current = ((highbyte<<8) | lowbyte);
    writeFloat(rpi, (float)current/1000.0f);
    
    This declares the current to be a signed 16 bit quantity (int16_t), so when you cast it to float later the sign extension will happen automatically.

    If you don't do this, the calculation of (( highbyte << 8 ) | lowbyte) will happen in normal int precision, which is 32 bits, and since the resulting value will never exceed the positive range of a 32 bit integer it will appear positive. You could also sign extend by hand:
    int current32 = ((highbyte << 8) | lowbyte); // value between 0 and 65536
    current32 = (current32<<16)>>16;             // extend sign of lower 16 bits; value is now between -32768 and 32767
    
  • You can also use the casting method to take an existing 32 bit value and sign extend it:

    current32 = (int16_t)current32;

    It's functionally the same as the double shift, but it tells the compiler (and whoever reads your code) a little more explicitly what you're trying to do
  • RsadeikaRsadeika Posts: 3,837
    edited 2016-02-29 14:17
    I just tried out the new code adjustments, for the function, in the previous post, and it is working as expected.

    Now, the question I have is, why is the function below working as expected, or maybe it's not, and I am getting values that are close enough, but not really? I used used this function as a basic start for the function in the previous post, but now I am curious as to what the code difference is, in the function below, compared to the previous function, that makes this one work, and the other one not work as expected?

    Ray
    Data Bytes: 2
    unsigned
    This code indicates the voltage of Create’s battery in
    millivolts (mV).
    Range: 0 – 65535
    void CRvolts()
    {
      fdserial_txChar(create,142);
      fdserial_txChar(create,22);  //Voltage
      int highbyte = fdserial_rxChar(create);
      pause(50);
      int lowbyte =  fdserial_rxChar(create);
      pause(50);
      float tempbyte = ((highbyte << 8)  + lowbyte);
      writeFloat(rpi,tempbyte/1000);
      writeStr(rpi," Volts\n");
      tempbyte=0;
    }
    
  • In the second case you *want* the positive range (0-65535) so no sign extension is necessary; the default behavior works fine. Technically I suppose it might be clearer to the readers if you put in an explicit cast to "16 bit unsigned integer" (uint16_t).

    In both cases you're reading 16 bits, but in case 1 you want to treat those 16 bits as signed (-32768-32767) and in case 2 you want them treated as unsigned (0-65536). That's why C has different signed and unsigned integer types.
  • float tempbyte = ((highbyte << 8)  + lowbyte);
    
    In the previous post code block, the '+' sign was not showing up, I fixed it. In the CRcurrent function it is using '|', that is for a 'bitwise OR', not sure I understand what that is doing in regards to:
    int16_t current = ((highbyte<<8) | lowbyte);
    

    Ray
  • Heater.Heater. Posts: 21,230
    Well, (highbyte<<8) will always produce a result with the lower 8 bits set to zero.

    So using "+" or "|" to set those low bits makes no difference.

    There is a reason why in boolean logic they use "." or AND and '+' for OR.

    Personally I would rather use the "|".

  • Pin - 3
    Power control toggle.
    Turns Create on or off on a low-to-high
    transition.
    Using the the tech note above, what would be the preferred way, in C, to accomplish this?
    Using P24 on the Propeller board, which would be connected to Pin 3, would I just:
    low(24)
    high(24)
    or is there a better way to do this. Of course this will be in its own little function.

    Ray
Sign In or Register to comment.