Pages: [1] 2   Go Down
Author Topic: Shift what?  (Read 1439 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 43
Even a broken clock is right twice a day!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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,3V

static uint32_t vbatRaw = 0;       //used for smoothing voltage reading
static uint8_t vbat;               //battery voltage in 0.1V steps
static 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
Logged

Gosport, UK
Offline Offline
Faraday Member
**
Karma: 19
Posts: 3114
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The expression inside the brackets would be evaluated and the result right-shifted.
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 551
Posts: 46266
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 43
Even a broken clock is right twice a day!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 551
Posts: 46266
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I suggest that you re-read reply # 4.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 43
Even a broken clock is right twice a day!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 551
Posts: 46266
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 43
Even a broken clock is right twice a day!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 43
Even a broken clock is right twice a day!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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 3

static uint32_t currentTime;
static uint32_t vbatRaw = 0;       //used for smoothing voltage reading
static uint8_t vbat;               //battery voltage in 0.1V steps
static uint8_t buzzerFreq;         //delay between buzzer ring
static 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
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 240
Posts: 24466
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You're taking your current average and taking fifteen sixteenths of it, then adding in one sixteenth of your most recent reading.
Logged

"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.

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 514
Posts: 31555
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

The generation of the average reading is fine but the line:-
 
Code:
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.
Logged

New Jersey
Online Online
Faraday Member
**
Karma: 50
Posts: 3435
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You're taking your current average and taking fifteen sixteenths of it, then adding in one sixteenth of your most recent reading.
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.
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 514
Posts: 31555
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 43
Even a broken clock is right twice a day!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
I hope i dont make anyone mad about this,but making all the math into paper get me always to the overflow.
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 514
Posts: 31555
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Pages: [1] 2   Go Up
Jump to: