1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

(solved)Tidier/smaller/easier code for vu-meter

Discussion in 'Arduino' started by fezder, Dec 19, 2015.

  1. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Now that i managed to get ag's circuit to work at last, i figured it would be good excersice to create pair of lm3915's with code.
    The circuit is that i feed peak detectors output to arduino's ADC input that then lights leds needed via two daisy chained 74595 shift registers. Main thing that bothers is that i had to manually calculate voltages for each led (3db difference between each led so logharitmic) and that procedure makes code perhaps too long and complicated.....
    arduino's ADC seemed to perform well enought, only smallest resolution is 5mv, but i have 12-bit version too (external) but i don't feel confortable using it as of yet. I can also add schematic if that is needed
    So, here comes uglee code, it works but could be better, i have that feeling:

    Code (c):
    int datapin = 2;
    int latchpin = 3;
    int clockpin = 4;

    int val = 0;


    void setup()
    {
    DDRD = DDRD | B11111100;
    }

    void loop()
    {
    val = analogRead (A0);
    float voltage = val * (5.0 / 1023.0);

    if ( voltage > 2.0)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    PORTD = B00001000;
    }

    else if (voltage > 1.414000)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B01111111);
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    PORTD = B00001000;
    }

    else if (voltage > 0.999698)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00111111);
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    PORTD = B00001000;
    }

    else if (voltage > 0.706786)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00011111);
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    PORTD = B00001000;
    }

    else if (voltage > 0.499698)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00001111);
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    PORTD = B00001000;
    }

    else if (voltage > 0.353287)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000111);
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    PORTD = B00001000;
    }

    else if (voltage > 0.249774)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000011);
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    PORTD = B00001000;
    }

    else if (voltage > 0.176590)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000001);
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    PORTD = B00001000;
    }

    else if (voltage > 0.124849)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    shiftOut(datapin, clockpin, MSBFIRST, B11111111);
    PORTD = B00001000;
    }


    else if ( voltage > 0.088268)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    shiftOut(datapin, clockpin, MSBFIRST, B01111111);
    PORTD = B00001000;
    }

    else if (voltage > 0.062406)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    shiftOut(datapin, clockpin, MSBFIRST, B00111111);
    PORTD = B00001000;
    }

    else if (voltage > 0.044121)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    shiftOut(datapin, clockpin, MSBFIRST, B00011111);
    PORTD = B00001000;
    }

    else if (voltage > 0.031193)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    shiftOut(datapin, clockpin, MSBFIRST, B00001111);
    PORTD = B00001000;
    }

    else if (voltage > 0.022054)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    shiftOut(datapin, clockpin, MSBFIRST, B00000111);
    PORTD = B00001000;
    }

    else if (voltage > 0.015592)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    shiftOut(datapin, clockpin, MSBFIRST, B00000011);
    PORTD = B00001000;
    }

    else if (voltage > 0.011024)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    shiftOut(datapin, clockpin, MSBFIRST, B00000001);
    PORTD = B00001000;
    }

    else if (voltage < 0.005)
    {
    PORTD = B00000000;
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    shiftOut(datapin, clockpin, MSBFIRST, B00000000);
    PORTD = B00001000;
    }




    }
     
    Last edited: Feb 15, 2016
  2. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    You could use a switch....

    Code (c):

    int datapin = 2;
    int latchpin = 3;
    int clockpin = 4;

    int val = 0;

    void send(unsigned int v)
       {
       PORTD = B00000000;
       shiftOut(datapin, clockpin, MSBFIRST, (unsigned char)(v>>8));
       shiftOut(datapin, clockpin, MSBFIRST, (unsigned char) v);
       PORTD = B00001000;
       }

    void setup()
       {
       DDRD = DDRD | B11111100;
       }

    void loop()
       {
       val = analogRead (A0);
       float voltage = val * (5.0 / 1023.0);
       switch(voltage)
         {
         case > 2:           Send(65535); break;
         case > 1.414:       Send(32767); break;
         case > 0.999698:    Send(16383); break;
         case > 0.706786:    Send(8191); break;
         case > 0.499698:    Send(4095); break;
         case > 0.353287:    Send(2047); break;  
         case > 0.249774:    Send(1023); break;
         case > 0.176590:    Send(511); break;
         case > 0.124849:    Send(255); break;  
         case > 0.088268:    Send(127); break;
         case > 0.062406:    Send(63); break;
         case > 0.044121:    Send(31); break;  
         case > 0.031193:    Send(15); break;
         case > 0.022054:    Send(7); break;
         case > 0.015592:    Send(3); break;  
         case > 0.031193:    Send(1); break;
         case < 0.005:       Send(0); break;
         }  
       }
     
     
    • Thanks Thanks x 1
  3. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Ah! well now, bit more easier than i thought, much tidier. I checked other sketches online and there were used quite complicated things without documentary...then again, even mine code didn't have documentation, oops. Thanks again Ian!
     
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland

    If i got it right, this value is biggest what can be stored in unsigned int? what is used after this if i need someday chain even 3 shift registers?
     
  6. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    unsigned char (byte) is 8 bit as you know.. 0~255
    unsigned int (word) is 16 bits 0 ~ 65535
    unsigned long ( doubleword ) is 32 bits 0 ~ 42946927295

    There isn't a 24 bit.... so if you have a 20bit ADC you would use a 32 bit register

    MSByte = (unsigned char ) (32bitReg>>16)
    NSByte = (unsigned char ) (32bitReg>>8)
    LSByte = (unsigned char ) 32bitReg

    Note*** when casting there is a trap.... This works..
    MSByte = (unsigned char ) (32bitReg>>16)
    This doesn't..
    MSByte = (unsigned char ) 32bitReg>>16

    This is because the second reduces the size of the register first then shifts.... All data destoyed
    The first shifts the data first THEN resizes the data type...
     
    • Thanks Thanks x 1
  7. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Phew, 20 bit adc, that must have some serious resolution! i have only 10 bit on arduino and 12 bit as an external IC (mcp3208 IIRC, 8-channels plus reference for it)
     
  8. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Hmm, i compiled that code Ian and got error saying
    Code (c):
    Arduino: 1.6.5 (Windows 7), Board: "Arduino Pro or Pro Mini, ATmega328 (5V, 16 MHz)"

    sketch_dec25a.ino: In function 'void loop()':
    sketch_dec25a:24: error: switch quantity not an integer
    sketch_dec25a:26: error: expected primary-expression before '>' token
    sketch_dec25a:26: error: 'Send' was not declared in this scope
    sketch_dec25a:27: error: expected primary-expression before '>' token
    sketch_dec25a:28: error: expected primary-expression before '>' token
    sketch_dec25a:29: error: expected primary-expression before '>' token
    sketch_dec25a:30: error: expected primary-expression before '>' token
    sketch_dec25a:31: error: expected primary-expression before '>' token
    sketch_dec25a:32: error: expected primary-expression before '>' token
    sketch_dec25a:33: error: expected primary-expression before '>' token
    sketch_dec25a:34: error: expected primary-expression before '>' token
    sketch_dec25a:35: error: expected primary-expression before '>' token
    sketch_dec25a:36: error: expected primary-expression before '>' token
    sketch_dec25a:37: error: expected primary-expression before '>' token
    sketch_dec25a:38: error: expected primary-expression before '>' token
    sketch_dec25a:39: error: expected primary-expression before '>' token
    sketch_dec25a:40: error: expected primary-expression before '>' token
    sketch_dec25a:41: error: expected primary-expression before '>' token
    sketch_dec25a:42: error: expected primary-expression before '<' token
    switch quantity not an integer

      This report would have more information with
      "Show verbose output during compilation"
      enabled in File > Preferences.
     
    according to arduino forums, switch can't be float or expression. Pity :/
     
    Last edited: Feb 15, 2016
  9. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    The switch statement in the Arduino environment doesn't support floats..

    You may ave to multiply by 1000 and cast to integer!! ( I haven't got an Arduino environment at home, so I can't test the code )
    Code (c):

    switch((int)(voltage*1000))
         {
         case > 2000:  Send(65535); break;
         case > 1410:   Send(32767); break;
         case > 998:    Send(16383); break;
         case > 701:    Send(8191); break;
         case > 499:    Send(4095); break;
         case > 353:    Send(2047); break;
         case > 249:    Send(1023); break;
         case > 176:    Send(511); break;
         case > 124:    Send(255); break;
         case > 88:    Send(127); break;
         case > 62:    Send(63); break;
         case > 44:    Send(31); break;
         case > 31:    Send(15); break;
         case > 22:    Send(7); break;
         case > 15:    Send(3); break;
         case > 11:    Send(1); break;
         case < 5:       Send(0); break;
         }
     
     
    • Thanks Thanks x 1
  10. Ian Rogers

    Ian Rogers Super Moderator Most Helpful Member

    Joined:
    Mar 28, 2011
    Messages:
    9,310
    Likes:
    914
    Location:
    Rochdale UK
    The switch statement may not like the ">" operator.... If this be the case just use if!!

    if( voltage > XXXX) send(xxx);
     
    • Thanks Thanks x 1
  11. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    ah, so does ''normal'' c-language support float?
    I compiled with that integer multiplier and now it only whined about expressions

    seems i'm stuck with if/else stuff, thanks anyway Ian!
     
  12. misterT

    misterT Well-Known Member Most Helpful Member

    Joined:
    Apr 19, 2010
    Messages:
    2,697
    Likes:
    368
    Location:
    Finland
    Old thread, but I have couple of points.

    - Some embedded C programmers think that "switch case" should be avoided because the syntax is error-prone. use if and else if instead. The result is practically the same.
    - Using floats will explode your code size, increase calculation times and decrease accuracy. In this case you are only doing linear scaling to your adc values. You do not need to convert to volts if you are only comparing values. You can use the raw adc-result.
    - Use standard integer types to make sure your variables are exactly what you want them to be. Uint8_t, uint16_t, uint32_t, int8_t, int16_t etc.
    - http://www.electro-tech-online.com/...rect-and-adc-1023-is-just-plain-wrong.132570/
    Code (C):
    #include <stdint.h> // Standard Integer Type definitions

    uint16_t val; // 16-bit unsigned integer.
    val = analogRead(A0); // Read raw adc value

    // Conversion from raw value to voltage.
    // float voltage = val * (5.0 / 1024.0);

    // Conversion from voltage to raw value
    // raw = voltage * (1024.0 / 5.0);

    if ( val > 410) // 2.0 volts
    {
        // Action...
    }

    else if (val > 290) // 1.414000 volts
    {
        // Action...
    }

    // Etc..
    I would not use the floating point voltage value internally at all. Only if I need to print the value for human to read.. or if I need to do some "advanced" math where I need the math-library.
     
    Last edited: Jan 21, 2016
    • Informative Informative x 1
  13. fezder

    fezder Well-Known Member

    Joined:
    Dec 11, 2011
    Messages:
    1,665
    Likes:
    100
    Location:
    Mikkeli, Finland
    Thanks for those, was good information! Every bit of code optimization is welcome.
     

Share This Page