Continue to Site

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.

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

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

Status
Not open for further replies.

fezder

Well-Known Member
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:

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:
You could use a switch....

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;
     }  
   }
 
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!
 
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?
case > 2: Send(65535); break;
 
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...
 
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)
 
Hmm, i compiled that code Ian and got error saying
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:
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 )
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;
     }
 
The switch statement in the Arduino environment doesn't support floats..
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!
 
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.
- https://www.electro-tech-online.com...rect-and-adc-1023-is-just-plain-wrong.132570/
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:
Thanks for those, was good information! Every bit of code optimization is welcome.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top