Go Down

### Topic: Shift what? (Read 3420 times)previous topic - next topic

#### DanielIt

##### Dec 12, 2011, 11:48 am
Hello guys.I have been on this forum for some time now and i am learning the programming doing different sketches.I found some lines of code in the free code of the Multiwii copter that i am interested in and i do not understand what is going on there.
Code: [Select]
`#define VBAT              // comment this line to suppress the vbat code#define VBATSCALE     126 // change this value if readed Battery voltage is different than real voltage #define VBATLEVEL1_3S 103 // 10,3Vstatic uint32_t vbatRaw = 0;       //used for smoothing voltage readingstatic uint8_t vbat;               //battery voltage in 0.1V stepsstatic uint8_t buzzerFreq;         //delay between buzzer ring#if defined(VBAT)    vbatRaw = (vbatRaw*15 + analogRead(V_BATPIN)*16)>>4; // smoothing of vbat readings      vbat = vbatRaw / VBATSCALE;                          // result is Vbatt in 0.1V steps         if (vbat>VBATLEVEL1_3S) {      buzzerFreq = 0; buzzerState = 0; BUZZERPIN_OFF;    else      buzzerFreq = 4;`
what i cant understand is after getting the value from the analogRead,what is the >>4 doing there? I know it should be shift right with 4 elements but where?inside the value?The other part of the code i get it all.
Thank you
Daniel

#### dxw00d

#1
##### Dec 12, 2011, 11:57 am
The expression inside the brackets would be evaluated and the result right-shifted.

#### PaulS

#2
##### Dec 12, 2011, 11:57 am
The >>4 is equivalent to dividing by 16. The previous average is multiplied by 15, the new reading is multiplied by 16 and added, and the result is divided by 16 to produce a new average.

#### DanielIt

#3
##### Dec 12, 2011, 12:43 pm
I am still having trouble understanding the equation.So bare with me please and correct me where i am wrong.
Suppose i have the analogRead to 1023(5V to the input pin).
First time i get vbatRaw=0
so ((0 x 15)+(1023 x 16) >>4  that makes (16368)>>4 3
so the shift what does here? it takes the point 4 times to the left? Is the result 1.6368 ?
Thank you for patience and understanding.
Daniel

#4

#### DanielIt

#5
##### Dec 12, 2011, 01:02 pm
ok i understood it is divided again by 16.But with every cycle the value of vbarRaw increase,even if i have constant analogRead of my analog pin.
Is it suppose to be like this or i am still missing something?

#### PaulS

#6
##### Dec 12, 2011, 01:10 pm
I'm not sure why the current reading is multiplied by 16. It doesn't look like it should be. (15 times the previous value + the current value) divided by 16 would yield a new average. Looks like a flaw in that code.

#### DanielIt

#7
##### Dec 12, 2011, 01:41 pm
well there still is something spookie in this formula.The real thing is that in testing it works.I have a 5V power supply connected to A0 pin.I defined the VBATSCALE 50 (as it say in 0.1V steps). i can see the analogRead function reading correctly the pin.I have initialized the led on pin 13 and VBATLEVEL1_3S to 45.
With the potmeter if i turn down the supply to less than 4.5Volts on the analog pin the led start blinking.i tryed different voltage levels and it works perfectly.I just dont understand the math under that formula.Still must be something with that shift.

#### DanielIt

#8
##### Dec 12, 2011, 02:12 pm
Here is the complete code i am using.Using Analog3 as input on Arduino Pro mini,16Mhz and 5V supply.
Digital 8 as output to my led(the code is using a buzzer but i dont have one).The entire code is working,just i still not understand the math of how it retrieves the voltage in 0.1V steps.I perfectly understand the map function of the arduino but i dont get this.ANy help is appreciated.
Code: [Select]
`#define BUZZERPIN_PINMODE          pinMode (8, OUTPUT);#define BUZZERPIN_ON               PORTC |= 1<<6;#define BUZZERPIN_OFF              PORTC &= ~1<<6;#define VBAT              // comment this line to suppress the vbat code#define VBATSCALE     50 // change this value if readed Battery voltage is different than real voltage #define VBATLEVEL1_3S 45 // 4.5V#define V_BATPIN 3static uint32_t currentTime;static uint32_t vbatRaw = 0;       //used for smoothing voltage readingstatic uint8_t vbat;               //battery voltage in 0.1V stepsstatic uint8_t buzzerFreq;         //delay between buzzer ringstatic uint8_t  buzzerState = 0;static uint32_t buzzerTime;void setup(){   BUZZERPIN_PINMODE  }void loop(){currentTime = micros(); #if defined(VBAT)    vbatRaw = (vbatRaw*15 + analogRead(V_BATPIN)*16)>>4; // smoothing of vbat readings      vbat = vbatRaw / VBATSCALE;                          // result is Vbatt in 0.1V steps         if (vbat>VBATLEVEL1_3S)     {      buzzerFreq = 0; buzzerState = 0; BUZZERPIN_OFF;    }     else         buzzerFreq = 1;     if (buzzerFreq)       {         if (buzzerState && (currentTime > buzzerTime + 250000) )           {             buzzerState = 0;BUZZERPIN_OFF;buzzerTime = currentTime;           }         else if ( !buzzerState && (currentTime > (buzzerTime + (2000000>>buzzerFreq))) )           {             buzzerState = 1;BUZZERPIN_ON;buzzerTime = currentTime;           }      }      #endif }    `
Thank you!
Daniel

#### AWOL

#9
##### Dec 12, 2011, 02:28 pm
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

#### Grumpy_Mike

#10
##### Dec 12, 2011, 02:44 pm
The generation of the average reading is fine but the line:-
Code: [Select]
`vbat = vbatRaw / VBATSCALE; `
Is not going to work given that VBATSCALE = 50, and you have a 5V reference voltage and no potential divider on the input.
However is one of those things is different we need to know so we can explain where it goes right.

At the moment suppose you had an input voltage of 2.5V then the reading (smoothed or not) would be 512. If you then do an integer division by 50 you get 10 not the 25 you say you are getting.

#### wildbill

#11
##### Dec 12, 2011, 02:51 pm

That would make perfect sense. But actually, it looks like you're taking your current average and taking fifteen sixteenths of it, then adding in sixteen sixteenths of your most recent reading. The raw reading will continuously increase (until it overflows)- looks like a bug.

#### Grumpy_Mike

#12
##### Dec 12, 2011, 03:08 pm
Quote
The raw reading will continuously increase (until it overflows)

Don't forget this is an integer division we are talking about, so you are not going to accumulate errors like that because an integer division truncated the result.

#### DanielIt

#13
##### Dec 12, 2011, 03:15 pm
You are perfectly right Myke.The original code is using a resistor divider to get the voltage of a 12V battery reading.It divides so that at 12.6Volts it gets 5V at analog pin.I just took the part of the code so i could read 5V directly in input.However the code using the divider it works perfectly fine.The VBATSCALE is defined 126 and i use VBATLEVEL_1 to define the voltage i want to monitor,for example 90 if the voltage drop below 9Volt.
But in my case i want to use the same code to measure a real 5V input,and trigger the led if it drops below 3V for example.I know i could already use the map function or something more simple,but i just wanted to understand how is this math used in this equation,especially the sift to the right.

#### Grumpy_Mike

#14
##### Dec 12, 2011, 06:28 pm
It works like this:-
The analogue to digital converter has a reference voltage which defines the full scale reading. By default this is the 5V supply of the arduino. If you put 5V into the analogue input you get a reading of 1023 "units" therefore each of these units corresponds to :-
5 / 1024 = 4.88 mV (note 1024 because there are 1024 intervals between readings of 0 to 1023)
So if you want to convert this number into a voltage in volts then multiply the reading by 0.00488 or divide by 204.8
However that code uses integer division and that truncates the values.
Supposed you want the units to be 0.1V then divide by 20.48, in practice this will be dividing by 20 and getting a value roughly in 0.1V units.

Hope that helps.

Go Up