[Ovmsdev] 3 bytes to char
Nikolay Shishkov
nshishkov at yahoo.com
Thu Jul 2 17:51:16 HKT 2015
Thank you all for the help with this. It was difficult for me to bend my mind around this.I was not able to test Brian's suggestion, but after many tests (printing bytes values and intermediate results) I ended up with something very similar.Thanks again,Nikolay
On Thursday, June 25, 2015 8:52 AM, Mark Webb-Johnson <mark at webb-johnson.net> wrote:
^this.
Nice ;-)
Mark.
> On 25 Jun, 2015, at 2:47 pm, HONDA S-2000 <s2000 at audiobanshee.com> wrote:
>
> First, 0x07DCC0 is supposed to be 515264, not 520264. Looks like you added 5000 in your spreadsheet.
>
> Second, you don't show your declarations for sv1 & sv2, which could be part of the problem.
>
>
> Personally, I would start with the following code (on a 32-bit machine):
>
> unsigned long sv = (unsigned)can_databuffer[4];
> sv <<= 8;
> sv |= (unsigned)can_databuffer[5];
> sv <<= 8;
> sv |= (unsigned)can_databuffer[6];
> car_SOC = (sv + 5000) / 10000UL;
>
> or, if you want to follow Mark's general advice, the last line would be:
>
> car_SOC = ((sv + 5000) * 3355) >> 25;
>
> The 25 bit shift is exactly the same as dividing by 33554432, so multiplying by 3355 before shifting is the same as multiplying by 0.00009998679161 or dividing by 10001.321 (with only 0.0132% error).
>
>
> I'm just not sure whether 32-bit math is efficient on this platform. Since you're converting a 20-bit number to 7-bit (0%..100%), then I assume you could leave off the 3rd byte, can_databuffer[6], and still be accurate enough.
>
> unsigned short sv = (unsigned)can_databuffer[4];
> sv <<= 8;
> sv |= (unsigned)can_databuffer[5];
> car_SOC = ((sv + 33) * 13) >> 9;
>
> Note that the 16-bit value jump by about 40 for every 1% SOC, so I was adding 20 to round off. The actual value would be 19.53125 if float were efficient. That doesn't quite reach 100%, so I fudged by adding 33 instead. That's not enough to round up the lowest values too much, because 1% will still be 1%.
>
> The second code example above was a bit tricky, because lopping off the last byte divides the input by 256, but combining that with the original 1/10000 scaling means you need to divide by 39.0625 (I just did some calculations on an envelope to come up with the code above, but tested it with values of 100%, 99%, 2%, and 1% to make sure it's close enough). I can't quite calculate the percent error of dropping a byte and then using multiply/shift instead of divide. Maybe someone else can review this.
>
> Brian
>
>
> On Jun 24, 2015, at 4:35 PM, Nikolay Shishkov <nshishkov at yahoo.com> wrote:
>> I seem to not been able to grasp the idea and would appreciate a code example.
>> For example byte1=0x07, byte2=0xDC, byte3=0xC0
>> If I put these in excel and calculate 7*256*256 + 220*256 + 192 I get 520264.
>> Then when I divide this by 10000, I get 52.0264. And this matches the 52% shown by the car.
>>
>> Currently my code for this conversion is:
>> sv1 = (unsigned long)can_databuffer[4];
>> sv1 = sv1*65536UL;
>> sv2 = (unsigned long)can_databuffer[5];
>> sv2 = sv2*256UL;
>> sv3 = (unsigned long)can_databuffer[6];
>> sv3 = sv3;
>>
>> car_SOC = (char)((unsigned long)(sv1 + sv2 + sv3 + 5000UL)/10000UL);
>>
>> And the result for car_SOC is 49.
>> How is this possible?
>> And what would be the correct way to put these 3 bytes together and divide them by 10000 to get to the final value in char?
>>
>> Thanks in advance,
>> Nikolay
>>
> _______________________________________________
> OvmsDev mailing list
> OvmsDev at lists.teslaclub.hk
> http://lists.teslaclub.hk/mailman/listinfo/ovmsdev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openvehicles.com/pipermail/ovmsdev/attachments/20150702/478740fa/attachment.htm>
More information about the OvmsDev
mailing list