Go Down

Topic: LCD displaying weird Symbols after Interrupt (Read 3 times) previous topic - next topic

Newman180

Quote
Could be easier to debug than mindreading Wink


I'll spare you, at the moment, and give you the stripped down version of the code (no timing control). I made a few changes based upon your previous suggestions...

Quote

 //------------------------------------------------------------------------
 #include <LiquidCrystal.h>
 unsigned int revPeriod; // Rotation Time
 volatile unsigned long prevTDCtime; // Previous time Hall Sensor Picked up
 volatile unsigned long TDCtime; // Current TDC Time
 volatile unsigned long nextTDC; // Predicted next TDC Time
 volatile byte rpmcount;
 unsigned int rpm;
 unsigned int crankAngle; // Crankshaft Angle out of 360 degrees
 boolean TDCinterrupt1 = false; //
 const int V17Pin = 9; // Valves 1 and 7 assigned to Pin 3  Intake
 const int V35Pin = 11; // Valves 3 and 5 assigned to Pin 4  Intake
 const int V28Pin = 10; // Valves 2 and 8 assigned to Pin 5  Exhaust
 const int V46Pin = 12; // Valves 4 and 6 assigned to Pin 6  Exhaust
 LiquidCrystal lcd (8,7,6,5,4,3);
 
 
  void setup()
 {
    // Communicate to Serial Port
   Serial.begin (9600);
   lcd.begin(16,2);
   pinMode (V17Pin, OUTPUT); // Valve 1&7 as Output
   pinMode (V35Pin, OUTPUT); // Valve 3&5 as Output
   pinMode (V28Pin, OUTPUT); // Valve 2&8 as Output
   pinMode (V46Pin, OUTPUT); // Valve 4&6 as Output
   nextTDC = 1;
   lcd.setCursor(4,0);
   lcd.print("*READY*");
   attachInterrupt(0,TDCinterrupt, RISING); // Interrupt 0 is Pin 2 Hall Effect Sensor  
 }
 
 
 void TDCinterrupt()
{
  TDCinterrupt1 = true;
  prevTDCtime = TDCtime;  // save last TDC
  TDCtime = micros();  // save THIS TDC
  revPeriod = TDCtime - prevTDCtime;  // calculate revolution period
  if (prevTDCtime > TDCtime)  {
     revPeriod = TDCtime - prevTDCtime + 2147483648;  // correct for micros() overflow every 71 minutes
  }
   
  nextTDC = TDCtime + revPeriod;  
  rpm = 60000000L/revPeriod;
 
 }


void loop ()

  if ( TDCinterrupt1){
    
  cli();
  crankAngle = map(micros(), TDCtime, nextTDC, 0, 360);  // Change time into degrees
  sei(); 
  crankAngle = constrain(crankAngle,  0, 360); // Limit crankshaft vales from 0 to 360
  }
   
if ( crankAngle >= 1 && crankAngle <= 179) // If the crankshaft is inbetween 1 to 179 degrees of revolution then...
  { 
     digitalWrite(V17Pin, HIGH); // Fire Valve 1 and 7 (Intake)
     digitalWrite(V46Pin, HIGH); // Fire Valve 4 and 6 (Exhaust)
     Serial.println("Intake (1,7) Exhaust (4,6) Fired 100%"); // Print Status and Percent of Valve Open
     lcd.setCursor(12,1);
     lcd.print ("+");
     lcd.setCursor(13,1);
     lcd.print ("+");
   }
 else {
  digitalWrite(V17Pin, LOW); // Don't Fire Valve 1 and 7 (Intake)
  digitalWrite(V46Pin, LOW); // Don't Fire Valve 4 and 6 (Exhaust)
     lcd.setCursor(12,1);
     lcd.print ("-");
     lcd.setCursor(13,1);
     lcd.print ("-");
}
  if ( crankAngle >= 181 && crankAngle <= 359) // If the crankshaft is inbetween 181 to 359 degrees of revolution then...
  {
     digitalWrite(V35Pin, HIGH); // Fire Valve 3 and 5 (Intake)
     digitalWrite(V28Pin, HIGH); // Fire Valve 2 and 8 (Exhaust)
     lcd.setCursor(14,1);
     lcd.print ("+");
     lcd.setCursor(15,1);
     lcd.print ("+");
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 100%"); // Print Status and Percent of Valve Open
  }
else {
  digitalWrite(V35Pin, LOW); // Don't  Fire Valve 3 and 5 (Intake)
   digitalWrite(V28Pin, LOW); // Don't Fire Valve 2 and 8 (Exhaust)
    lcd.setCursor(14,1);
    lcd.print ("-");
    lcd.setCursor(15,1);
    lcd.print ("-");
}     
     
      lcd.setCursor(1,1);
      lcd.print(rpm,DEC);
}
      
     



robtillaart

First it is good practice to initialize your variables to a known value. The compiler will often make them zero / 0 but not al the times.

rpm = 60000000L/revPeriod;  
rpm is an int while this calculation is long so there is possible loss of precission.

crankAngle = map(micros(), TDCtime, nextTDC, 0, 360);
Not patched the map function to unsigned long as I proposed...

    lcd.setCursor(15,1);
    lcd.print ("+");

Your lcd is 16 x 2, by setting the cursor at 15, 1 it is at the end of the line and you are writing outside the LCD's screen, maybe into memory or registers or something.  Count of the positions goes from 0..15 not from 0..16.

This latter could be the cause of the weird chars.
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Newman180

Quote
rpm = 60000000L/revPeriod;  
rpm is an int while this calculation is long so there is possible loss of precission.


This is not the most important calculation in the code, but what could I do to prevent this loss of precision?

Quote
Not patched the map function to unsigned long as I proposed...

I forgot to add it. Would it look like this, since they are all unsigned longs ? Can you explain what the return is doing?
Code: [Select]

crankAngle = unsigned long map (micros(), TDCtime, nextTDC, 0, 360);
{
 return (micros - TDCtime) * (360 - 0) / (nextTDC - TDCtime) + 0;
}


Quote
 lcd.setCursor(15,1);
   lcd.print ("+");
Your lcd is 16 x 2, by setting the cursor at 15, 1 it is at the end of the line and you are writing outside the LCD's screen, maybe into memory or registers or something.  Count of the positions goes from 0..15 not from 0..16.

This latter could be the cause of the weird chars.


I already caught this and fixed it, after I posted the code.  ;D
But the weird characters were caused by the double pin assignment earlier, and is fixed now.

Thanks for the help thus far rob. When we go over these few crinkles, I'll give you the "complete" code to review, if you don't mind  ;)

robtillaart

#8
Jan 04, 2011, 12:34 pm Last Edit: Jan 04, 2011, 12:39 pm by robtillaart Reason: 1
Good to hear things work, if you have finalized your code please post it, also for people in the future who have similar issues.

Quote
This is not the most important calculation in the code, but what could I do to prevent this loss of precision?

make rpm a long too.



Add this function definition to your code (at the end is ok)
Code: [Select]
unsigned long ULmap(unsigned long x, unsigned long in_min, unsigned long in_max, unsigned long out_min, unsigned long out_max)
{
 return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}


And change the map call in your exisiting code
Code: [Select]
crankAngle = ULmap (micros(), TDCtime, nextTDC, 0, 360);

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Newman180

#9
Jan 04, 2011, 03:07 pm Last Edit: Jan 04, 2011, 03:15 pm by Newman180 Reason: 1
Quote
Good to hear things work, if you have finalized your code please post it, also for people in the future who have similar issues.

Great! It will probably take two posts. I have two questions regarding the final code. I have recently learned about calling to functions outside of the loop. I set up my timing and start control outside of the loop to try to minimize clutter, and allow the loop to run faster. Is this in fact the better way?

Also, with start mode, I use delays between each valve, but I don't think that will work right. The plan is that once the engine starts spinning, the interrupt kicks in and invalidates the start code. If the interrupt happens during a delay, I'm doomed. I was thinking of using a "blink without delay" but I'm not sure if I can call to micros/millis if the interrupt is as well.  Your opinion?

Thanks

FYI. The ULmap as displayed below does not compile correctly. It thinks the UL is part of the name, and states that ULmap has not been declared.
Quote

//--- NEWMAN180  1/4/11
 //------------------------------------------------------------------------
 #include <LiquidCrystal.h>
 volatile unsigned int revPeriod; // Rotation Time
 volatile unsigned long prevTDCtime; // Previous time Hall Sensor Picked up
 volatile unsigned long TDCtime; // Current TDC Time
 volatile unsigned long nextTDC; // Predicted next TDC Time
 volatile unsigned long rpm;
 volatile unsigned int crankAngle; // Crankshaft Angle out of 360 degrees
 unsigned int a; // first crank angle of 180
 unsigned int a1; // second crank angle of 180
 unsigned int b; // first crank angle of 360
 unsigned int b1; // second crank angle of 360
 boolean TDCinterrupt1 = false; //
 const int timingPin = 14;
 const int maintbuttonPin = 15;
 const int pushstartPin = 16;
 int pushstartState = 0;
 int maintbuttonState = 0;
 int buttonstate = 0;
 int buttonpushcounter = 0;
 int lastbuttonstate = 0;
 int start;
 int timing;
 int maint;
 const int V17Pin = 9; // Valves 1 and 7 assigned to Pin 3  Intake
 const int V35Pin = 11; // Valves 3 and 5 assigned to Pin 4  Intake
 const int V28Pin = 10; // Valves 2 and 8 assigned to Pin 5  Exhaust
 const int V46Pin = 12; // Valves 4 and 6 assigned to Pin 6  Exhaust
 LiquidCrystal lcd (8,7,6,5,4,3);
 
 
  void setup()
 {
    // Communicate to Serial Port
   Serial.begin (9600);
   lcd.begin(16,2);
   pinMode (V17Pin, OUTPUT); // Valve 1&7 as Output
   pinMode (V35Pin, OUTPUT); // Valve 3&5 as Output
   pinMode (V28Pin, OUTPUT); // Valve 2&8 as Output
   pinMode (V46Pin, OUTPUT); // Valve 4&6 as Output
   pinMode (pushstartPin, INPUT);
   pinMode (timingPin, INPUT);
   pinMode (maintbuttonPin, INPUT);
   rpm = 0;
   nextTDC = 1;
   lcd.setCursor(0,0);
   lcd.print("ON");
   attachInterrupt(0,TDCinterrupt, RISING); // Interrupt 0 is Pin 2 Hall Effect Sensor  
   digitalWrite(2,HIGH);
   delay(3500);
 }
 
 
 void TDCinterrupt()
{
  TDCinterrupt1 = true;
  prevTDCtime = TDCtime;  // save last TDC
  TDCtime = micros();  // save THIS TDC
  revPeriod = TDCtime - prevTDCtime;  // calculate revolution period
  if (prevTDCtime > TDCtime)  {
     revPeriod = TDCtime - prevTDCtime + 2147483648;  // correct for micros() overflow every 71 minutes
  }
  nextTDC = TDCtime + revPeriod;  
 
 rpm = 60000000L/revPeriod;
 }


void loop ()

  if ( TDCinterrupt1){
  cli();
  crankAngle = ULmap(micros(), TDCtime, nextTDC, 0, 360);  // Change time into degrees
  sei(); 
  crankAngle = constrain(crankAngle,  0, 360); // Limit crankshaft vales from 0 to 360
   }
//----------------------------------  Button Counter Control   
buttonstate = digitalRead(timingPin);
 
   if (buttonstate != lastbuttonstate)
   {
       if (buttonstate == HIGH) {
       buttonpushcounter++; // Update Button Counter
          }
    
   }
   
lastbuttonstate = buttonstate;
if( buttonpushcounter > 9){
  buttonpushcounter = 0;}
//--------------------------------------- Button Timing Control 
 timing = timingcontrol();
 timing; 

//--------------------------------  Timing Center

if ( crankAngle >= a && crankAngle <= a1) // If the crankshaft is inbetween 1 to 179 degrees of revolution then...
  { 
     digitalWrite(V17Pin, HIGH); // Fire Valve 1 and 7 (Intake)
     digitalWrite(V46Pin, HIGH); // Fire Valve 4 and 6 (Exhaust)
     Serial.println("Intake (1,7) Exhaust (4,6) Fired 100%"); // Print Status and Percent of Valve Open
     lcd.setCursor(12,1);
     lcd.print ("+");
     lcd.setCursor(13,1);
     lcd.print ("+");
   }
 
 else {
  digitalWrite(V17Pin, LOW); // Don't Fire Valve 1 and 7 (Intake)
  digitalWrite(V46Pin, LOW); // Don't Fire Valve 4 and 6 (Exhaust)
     lcd.setCursor(12,1);
     lcd.print (" ");
     lcd.setCursor(13,1);
     lcd.print (" ");
}
 
  if ( crankAngle >= b && crankAngle <= b1) // If the crankshaft is inbetween 181 to 359 degrees of revolution then...
  {
     digitalWrite(V35Pin, HIGH); // Fire Valve 3 and 5 (Intake)
     digitalWrite(V28Pin, HIGH); // Fire Valve 2 and 8 (Exhaust)
     lcd.setCursor(14,1);
     lcd.print ("+");
     lcd.setCursor(15,1);
     lcd.print ("+");
     Serial.println("Intake (3,5) Exhaust (2,8) Fired 100%"); // Print Status and Percent of Valve Open
  }

else {
  digitalWrite(V35Pin, LOW); // Don't  Fire Valve 3 and 5 (Intake)
   digitalWrite(V28Pin, LOW); // Don't Fire Valve 2 and 8 (Exhaust)
    lcd.setCursor(14,1);
    lcd.print (" ");
    lcd.setCursor(15,1);
    lcd.print (" ");
}     


Go Up