Go Down

Topic: tachometer programming help needed (Read 865 times) previous topic - next topic

kazimier

hi

just been working for a bit with trying to get a optical tachometer to control a range of parameters, so the faster an object spins the higher the pitch, the brighter the lights etc. I am almost there - but I just can't get past a syntax error - whenever I compile the code below I get the error message:

error: expected unqualified-id before 'else

i know it must be something really easy but I have been staring at the screen for a while with no luck - does anyone have any suggestions?

Code: [Select]
/*
* Optical Tachometer
*
* Uses an IR LED and IR phototransistor to implement an optical tachometer.
* The IR LED is connected to pin 13 and ran continually. A status LED is connected
* to pin 12. Pin 2 (interrupt 0) is connected across the IR detector.
*
*
*/
//#define DEBUG      

int ledPin = 13;                // IR LED connected to digital pin 13
int statusPin = 12;
int lightPin = 11;// LED connected to digital pin 12
int brightness = 0;
int delay_time = 40; // delay for this amount each write cycle.
int noteDown = LOW;
byte MIDI_channel = 0;
byte cc_number = 0;
byte incomingByte;
byte button;
byte note;
byte printing_byte = 0;
int Value = 0;
int midi_pitch = 0;
int mappedrpm = 0;
int state=0;
#ifdef DEBUG
const int DEBUG_RATE = 9600;        // Serial debugging communicates at 9600 baud
const int SERIAL_PORT_RATE = DEBUG_RATE;
#else
const int MIDI_BAUD_RATE = 31250;   // MIDI communicates at 31250 baud
const int SERIAL_PORT_RATE = MIDI_BAUD_RATE;
#endif



volatile byte rpmcount;
volatile int status;

unsigned int rpm;

unsigned long timeold;

void rpm_fun()
{
  //Each rotation, this interrupt function is run twice, so take that into consideration for
  //calculating RPM
  //Update count
     rpmcount++;
     
  //Toggle status LED  
  if (status == LOW) {
    status = HIGH;
  } else {
    status = LOW;
  }
  digitalWrite(statusPin, status);
}

void setup()
{
    state = 0;
   
  Serial.begin(SERIAL_PORT_RATE);
  //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
  //Triggers on FALLING (change from HIGH to LOW)
  attachInterrupt(0, rpm_fun, FALLING);
 
  //Turn on IR LED
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);
 
  //Use statusPin to flash along with interrupts
  pinMode(statusPin, OUTPUT);

  rpmcount = 0;
  rpm = 0;
  timeold = 0;
  status = LOW;


}

void loop()
{
  //Update RPM every second
  delay(800);
  //Don't process interrupts during calculations
  detachInterrupt(0);
  //Note that this would be 60*1000/(millis() - timeold)*rpmcount if the interrupt
  //happened once per revolution instead of twice. Other multiples could be used
  //for multi-bladed propellers or fans
  rpm = 3*1000/(millis() - timeold)*rpmcount;
  timeold = millis();
  rpmcount = 0;
 
 brightness = map(rpm, 0, 50, 0, 255);
 analogWrite(lightPin, brightness);

  if(rpm > 127) {
   printing_byte = 127;
 
  }

}
void checkButton(){    
 printing_byte = map(rpm, 0, 50, 0, 127);{
 if(printing_byte >= 120) noteSend(0x90, 65, 0); else noteSend(0x90, 65, 127);
 }
}


else
{

#ifdef DEBUG
 Serial.println(rpm, DEC);
#else
 noteSend(MIDI_channel, cc_number, printing_byte);
#endif
  //Write it out to serial port
  //Restart the interrupt processing
attachInterrupt(0, rpm_fun, FALLING);
}

void noteSend(byte MIDI_channel, byte cc_number, byte printing_byte)
{
Serial.print(B10110000 + MIDI_channel,BYTE);
Serial.print(cc_number,BYTE);
Serial.print(printing_byte,BYTE);
}

   

DaveK

#1
Aug 12, 2009, 02:16 am Last Edit: Aug 12, 2009, 02:48 am by DaveK Reason: 1
Reformat your code with a standard indention style and you will discover the source of your problem.

Edit: I should point you to the Auto Format menu option in the Tools menu :)

DaveK

#2
Aug 12, 2009, 02:19 am Last Edit: Aug 12, 2009, 02:47 am by DaveK Reason: 1
Incidentally, blocking problems of this sort are extremely common for new programmers. I've put an issue into the Arduino issues list on GoogleCode requesting some attention to this problem.

The Tools|AutoFormat feature helps with this once the user realizes what has happened, but I'd like to see graphical outlining so that the user can see it when it happens.

mem

Note that the IDE has an 'Auto Format' option in the tools menu that makes it easier to see the code structure. It's not as elaborate as Dave is suggesting but it will help.

Looking at the code I wonder if this is too complex an app to start with. My advice is to start with something simple so you can get to grips with how to use code block to write conditional statements and when you are comfortable with that move on to things like this that attach interrupts.

It may delay getting this particular project started but you will have a much easier job getting code to work if you spend a little time learning the fundamentals.

Have fun!

kazimier

thank you for all the replies - afraid the 'Auto format' did not help. I was not aware of that function but in this instance I could not see what changes it may have made to the structure (layout) of the code. will persevere. I am aware that this is out of my comfort zone so to speak, but I believe that by setting yourself hard challenges in fields you are not fully familiar with is a good way of learning.

mem

#5
Aug 12, 2009, 01:01 pm Last Edit: Aug 12, 2009, 01:01 pm by mem Reason: 1
This is a fragment from your post:
Code: [Select]
void checkButton(){    
 printing_byte = map(rpm, 0, 50, 0, 127);{
 if(printing_byte >= 120) noteSend(0x90, 65, 0); else noteSend(0x90, 65, 127);
 }
}

else
{


After using auto format:

Code: [Select]
void checkButton(){    
 printing_byte = map(rpm, 0, 50, 0, 127);
 {
   if(printing_byte >= 120) noteSend(0x90, 65, 0);
   else noteSend(0x90, 65, 127);
 }
}


else
{

Note how the curly brace before the if statment becomes more obvious.  This brace serves no purpose and can be a clue that your problem is it that you have braces in the wrong place. Auto Format will not fix coding errors but by using a standard coding style it is easier to see when you have misplaced a brace.

kazimier

thanks for the help - sometimes I just miss the little details and remain totally blind to them.
I actually ended up going about writing the code in a different way, just because the way that I was sending the midi data did not work (i.e. when I wanted to send both midi CC and NoteON / OFF ). The new code (as can be seen below) works great, but i have reached a new stumbling block  - as is usually the case.
I need the code to send a single NotON event when the rpm count goes over 120, this triggers a midi sequence of av events (Ableton and Modul8), however as the rpm count is constatly feeding out data the code continually sends the NoteON message for as long as the rpm count is above 120. Is there a way to make it so that it sends just one noteON event when the rpm count goes over 120 first time?

any help is greatly appreciated

Code: [Select]
/*
* Optical Tachometer
*
* Uses an IR LED and IR phototransistor to implement an optical tachometer.
* The IR LED is connected to pin 13 and ran continually. A status LED is connected
* to pin 12. Pin 2 (interrupt 0) is connected across the IR detector.
*
*
*/
//#define DEBUG      

int ledPin = 13;                // IR LED connected to digital pin 13
int statusPin = 12;
int lightPin = 11;// LED connected to digital pin 12
int brightness = 0;
int delay_time = 40; // delay for this amount each write cycle.
int noteDown = LOW;
byte MIDI_channel = 0;
byte cc_number = 0;
byte incomingByte;
byte button;
byte note;
byte printing_byte = 0;
int Value = 0;
int midi_pitch = 0;
int mappedrpm = 0;
int state=0;
#ifdef DEBUG
const int DEBUG_RATE = 9600;        // Serial debugging communicates at 9600 baud
const int SERIAL_PORT_RATE = DEBUG_RATE;
#else
const int MIDI_BAUD_RATE = 31250;   // MIDI communicates at 31250 baud
const int SERIAL_PORT_RATE = MIDI_BAUD_RATE;
#endif



volatile byte rpmcount;
volatile int status;

unsigned int rpm;

unsigned long timeold;

void rpm_fun()
{
 //Each rotation, this interrupt function is run twice, so take that into consideration for
 //calculating RPM
 //Update count
 rpmcount++;

 //Toggle status LED  
 if (status == LOW) {
   status = HIGH;
 }
 else {
   status = LOW;
 }
 digitalWrite(statusPin, status);
}

void setup()
{
 state = 0;

 Serial.begin(SERIAL_PORT_RATE);
 //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
 //Triggers on FALLING (change from HIGH to LOW)
 attachInterrupt(0, rpm_fun, FALLING);

 //Turn on IR LED
 pinMode(ledPin, OUTPUT);
 digitalWrite(ledPin, HIGH);

 //Use statusPin to flash along with interrupts
 pinMode(statusPin, OUTPUT);

 rpmcount = 0;
 rpm = 0;
 timeold = 0;
 status = LOW;


}

void loop()
{
 //Update RPM every second
 delay(800);
 //Don't process interrupts during calculations
 detachInterrupt(0);
 //Note that this would be 60*1000/(millis() - timeold)*rpmcount if the interrupt
 //happened once per revolution instead of twice. Other multiples could be used
 //for multi-bladed propellers or fans
 rpm = 3*1000/(millis() - timeold)*rpmcount;
 timeold = millis();
 rpmcount = 0;
 attachInterrupt(0, rpm_fun, FALLING);
 brightness = map(rpm, 0, 50, 0, 255);
 analogWrite(lightPin, brightness);
 printing_byte = map(rpm, 0, 50, 0, 127);{
 midiOUT(0xB0, 7, printing_byte);
 }

   if(printing_byte >= 120){
   midiOUT(0x90, 65, 127);
   }
 
}




 //Write it out to serial port
 //Restart the interrupt processing
 


void midiOUT(char command, char value1, char value2) {
 Serial.print(command, BYTE);
 Serial.print(value1, BYTE);
 Serial.print(value2, BYTE);

}


Dustin

im no expert to all this but isnt

Code: [Select]
if(rpm > 127) {
   printing_byte = 127;
 
  }
                   //if you want it to call a function shouldnt it be INSIDE   the }} etc etc



}
void checkButton(){    
 printing_byte = map(rpm, 0, 50, 0, 127);{
 if(printing_byte >= 120) noteSend(0x90, 65, 0); else noteSend(0x90, 65, 127);
 }
}


else
{

#ifdef DEBUG
 Serial.println(rpm, DEC);
#else
 noteSend(MIDI_channel, cc_number, printing_byte);
#endif
  //Write it out to serial port
  //Restart the interrupt processing
attachInterrupt(0, rpm_fun, FALLING);
}




wrong?   sorry if it is correct just didnt look correct

kazimier

Hi Dustin

you are correct - but the code you are referring to is from a previous version and it did not work. The code I have posted up subsequently (the one I put up today) does. The problem with it is that it continually sends a noteON message whilst the rpm count is above 120 as opposed to just sending a single noteON the first time it detects rpm>=120

Go Up