Pages: 1 [2]   Go Down
Author Topic: An LED bar graph tachometer  (Read 4801 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 0
Posts: 204
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The IR beam is just triggering the LED pins ON/OFF. I get a blink each time a hole in the disc comes around.  It's actually not doing much but I wanted to start by having the IR beam trigger some kind of output...

I need to figure out how to have the chip calculate RPM based on the pulses over a given time and output to different blocks of pins based in that info. I think...
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, you need to measure or calculate the RPM, certainly. If you have an input that is pulsing once per revolution, measuring RPM is just a matter of timing or counting those pulses.

Outputting the RPM value on your LEDs is an unrelated and much easier problem.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Full Member
***
Karma: 0
Posts: 204
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yep, 1 pulse per rev. I figure I need to sample it over time and then store that value and output it some way. I'm guessing the sample time will dictate how rapidly the display updates.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 204
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well, I finally got the HE sensors in and figured out how to wire them up. Pretty neat little devices!

Code:
//-----------------------------------------------
 volatile byte rpmcount;
 unsigned int rpm;
 unsigned long timeold;
 void setup()
 {
   Serial.begin(9600);
   attachInterrupt(0, rpm_fun, RISING);
   rpmcount = 0;
   rpm = 0;
   timeold = 0;
 }
 void loop()
 {
   if (rpmcount >= 20) {
     //Update RPM every 20 counts, increase this for better RPM resolution,
     //decrease for faster update
     rpm = 30*1000/(millis() - timeold)*rpmcount;
     timeold = millis();
     rpmcount = 0;
     Serial.println(rpm,DEC);
   }
 }
 void rpm_fun()
 {
   rpmcount++;
   //Each rotation, this interrupt function is run twice
 }
//-----------------------------------------------

I've been puttering with this code some and I imagine it holds the key to what I'm trying to accomplish.

Any hints, pointers?  I'd like to get something sort of working this weekend.

Thanks.

I also found this:

http://www.hobbytronics.co.uk/arduino-tutorial11-hall-effect

At least I have input to the Arduino with an HE sensor...
« Last Edit: June 10, 2012, 01:16:41 pm by hoff70 » Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 204
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Not much action here but I've been making baby steps:

Code:
//code by Crenn from http://thebestcasescenario.com
//project by Charles Gantt from http://themakersworkbench.com


/*To disable interrupts:
 cli();                // disable global interrupts

and to enable them:  
 sei();                // enable interrupts
*/


                                   //Varibles used for calculations
int NbTopsFan;
int Calc;

                                  //The pin location of the sensor
int hallsensor = 2;
int ledPin = 4;           //$$STUFF I ADDED$$


                        
typedef struct{                  //Defines the structure for multiple fans and their dividers
  char fantype;
  unsigned int fandiv;
}fanspec;

//Definitions of the fans
fanspec fanspace[3]={{0,1},{1,2},{2,8}};

char fan = 1;   //This is the varible used to select the fan and it's divider, set 1 for unipole hall effect sensor
               //and 2 for bipole hall effect sensor


void rpm ()      //This is the function that the interupt calls
{
 NbTopsFan++;
}

              //This is the setup function where the serial port is initialised,
             //and the interrupt is attached
void setup()
{
 pinMode(hallsensor, INPUT);
 Serial.begin(9600);
 attachInterrupt(0, rpm, RISING);
 pinMode(ledPin, OUTPUT);    ////$$STUFF I ADDED$$$
}
void loop ()
{
   NbTopsFan = 0; //Set NbTops to 0 ready for calculations
   sei(); //Enables interrupts
   delay (1000); //Wait 1 second
   cli(); //Disable interrupts
   Calc = ((NbTopsFan * 60)/fanspace[fan].fandiv); //Times NbTopsFan (which is apprioxiamately the fequency the fan is spinning at) by 60 seconds before dividing by the fan's divider
   Serial.print (Calc, DEC); //Prints the number calculated above
   Serial.print (" rpm\r\n"); //Prints " rpm" and a new line
  
   //$$STUFF I ADDED$$/////////////////////////////////////////////////////////////////////////////
   if (Calc > 40)
   {
     digitalWrite (4, HIGH);
     delay (500);
   }
   if (Calc < 40)
   {
     digitalWrite (4, LOW);
   }
}

I didn't do much but I am getting serial output of RPM to the serial monitor and I'm getting a single LED to turn ON/OFF with RPM changes. My RPM measurement doesn't seem to be accurate but it is proportional so I figure I can tinker with the code to get it working. I guess the numbers really don't matter as long as I can get the output to register correctly. I'm not going to be using the serial data anyway.

I did get the hall effect sensor working after learning that I needed a resistor between the pos and signal  smiley-roll-sweat

Just one sad little LED for output but it's a start:



No little magnets to mount on my test rig so I'm stuck waving a big one over the HE sensor for now... I considered using a PC fan 3rd wire for input but I want to stick with what I'm going to use in the final build so I don't complicate things.

Would someone mind explaining what's going on in the code? Especially this line:

fanspec fanspace[3]={{0,1},{1,2},{2,8}};

Thanks.


More stuff:

Code:
//code by Crenn from http://thebestcasescenario.com
//project by Charles Gantt from http://themakersworkbench.com


/*To disable interrupts:
 cli();                // disable global interrupts

and to enable them:  
 sei();                // enable interrupts
*/


                                   //Varibles used for calculations
int NbTopsFan;
int Calc;

                                  //The pin location of the sensor
int hallsensor = 2;
int ledPin = 4;           //$$STUFF I ADDED$$
int ledPin1 = 5;
int ledPin2 = 6;
int ledPin3 = 7;

                        
typedef struct{                  //Defines the structure for multiple fans and their dividers
  char fantype;
  unsigned int fandiv;
}fanspec;

//Definitions of the fans
fanspec fanspace[3]={{0,1},{1,2},{2,8}};

char fan = 1;   //This is the varible used to select the fan and it's divider, set 1 for unipole hall effect sensor
               //and 2 for bipole hall effect sensor


void rpm ()      //This is the function that the interupt calls
{
 NbTopsFan++;
}

              //This is the setup function where the serial port is initialised,
             //and the interrupt is attached
void setup()
{
 pinMode(hallsensor, INPUT);
 Serial.begin(9600);
 attachInterrupt(0, rpm, RISING);
 pinMode(ledPin, OUTPUT);////$$STUFF I ADDED$$$
 pinMode(ledPin1, OUTPUT);
 pinMode(ledPin2, OUTPUT);
 pinMode(ledPin3, OUTPUT);
}
void loop ()
{
   NbTopsFan = 0; //Set NbTops to 0 ready for calculations
   sei(); //Enables interrupts
   delay (1000); //Wait 1 second
   cli(); //Disable interrupts
   Calc = ((NbTopsFan * 60)/fanspace[fan].fandiv); //Times NbTopsFan (which is apprioxiamately the fequency the fan is spinning at) by 60 seconds before dividing by the fan's divider
   Serial.print (Calc, DEC); //Prints the number calculated above
   Serial.print (" rpm\r\n"); //Prints " rpm" and a new line
  
   //$$STUFF I ADDED$$/////////////////////////////////////////////////////////////////////////////
   if (Calc > 40)
   {
     digitalWrite (4, HIGH);
     delay (100);
   }
   if (Calc < 40)
   {
     digitalWrite (4, LOW);
   }
   if (Calc > 100)
   {
     digitalWrite (5, HIGH);
     delay(100);
   }
   if (Calc < 100)
   {
     digitalWrite (5, LOW);
   }
   //////
    if (Calc > 240)
   {
     digitalWrite (6, HIGH);
     delay(100);
   }
   if (Calc < 240)
   {
     digitalWrite (6, LOW);
   }
   /////
    if (Calc > 300)
   {
     digitalWrite (7, HIGH);
     delay(100);
   }
   if (Calc < 300)
   {
     digitalWrite (7, LOW);
   }
  
  
  
}

It's clunky but it seems to work!

Also, If all goes well, (And it looks like it very well may  smiley) I would like to do a permanent install. I don't want to use my UNO for it but rather build a bare bones chip setup. Any input on this? I suppose I would at least need a crystal as well as a power supply. Would be neat to (Try to) build!
« Last Edit: June 10, 2012, 05:11:51 pm by hoff70 » Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 204
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just another update. I will get this finished some day...

I want this to be a "stand alone" project so I started fooling with ATtiny 85's. Thanks to the kind and patient folks here I've made some progress on that front.

I believe I may be able to run this project with an ATtiny 85. I found this code which runs well on it:

Code:
void setup() {                     //nothing to do in setup
}

byte t = 0;                         //used for looping between LED's in a knight rider kind of fashion
void loop() {
  for (t = 0; t < 10; t++) {
    charliePlex(t);               //switch on LED number T
    delay(75);                     // Wait a bit
  }
  for (t = 9; t >= 0; t--) { // Reverse the run
    charliePlex(t);                // switch on LED number T
    delay(60);                      // delay a bit
  }
  charliePlex(10);               //switch off all LEDs I only had 9, so if you try to switch on any
                                         //bigger number, they would all be off.
  delay(500);                      //big delay before we do it all over again
}

void charliePlex(byte i) {   // This function switches on one of the LED's. Due to the way I
                                        // laid out my circuit, the pins are not exactly in a logical order,
                                        // but if you understand the concept, it's easy to tune it for your circuit.
  for (int t = 0; t < 4; t++) pinMode(t, INPUT); // I used IO ports 0-4. the ATTINY85 only has 5
                                                                    //(or 6 if you sacrifice reset) GPIO's. This loop will switch
                                                                    // off all the LED's, because it sets the IO ports to input
                                                                    // (high impedance) mode.
  switch (i) {                                       //decide which LED we want to switch on
    case 0: charlieSwitch(2, 0);            //The first LED is wired from Pin 2 to Pin 0
     break;
    case 1: charlieSwitch(0, 2);            // the second LED is the reverse of the LED above
     break;
    case 2: charlieSwitch(1, 0);
     break;
    case 3: charlieSwitch(0, 1);
     break;
    case 4: charlieSwitch(1, 2);
     break;
    case 5: charlieSwitch(2, 1);
     break;
    case 6: charlieSwitch(3, 2);
     break;
    case 7: charlieSwitch(2, 3);
     break;
    case 8: charlieSwitch(3, 1);
     break;
   }
}

void charlieSwitch(byte pin1, byte pin2) {            //This function merely sets the ports as output,
                                                                      // and drives the first one HIGH and the Second one LOW
     pinMode(pin1, OUTPUT);
     pinMode(pin2, OUTPUT);
     digitalWrite(pin1, HIGH);
     digitalWrite(pin2, LOW);
}

It uses 4 pins to charlieplex 9 LED's leaving 1 pin for input. I'm hoping I can use the last pin for input from the HE sensor but I was wondering if I may need an external clock like a crystal to get it working.  It's not going to be a high precision instrument so maybe the chip alone will do it?

Any input would be most welcome!
Logged

Pages: 1 [2]   Go Up
Jump to: