Go Down

Topic: CDI tester project (Read 12939 times) previous topic - next topic

tombauer

Sep 23, 2016, 04:07 am Last Edit: Sep 23, 2016, 05:06 pm by tombauer
Hi all, I have a project I would like some help with. The code I have so far is attached and works great. It is on a pro mini 16Mhz clone. I repair CDI modules for mowers and other small engines and for a couple years I have had a 555 timer that I have used for testing. It is lacking in several ways. Now I have started this project that will have:

1) a LCD to display rpm from 500 to 3000
2) generate a pulse at intervals from 120Ms to 20Ms to trigger the CDI (one pulse / revolution)
3) generate pulses at 50Hz to 300Hz to simulate the charging coils. Here may be the tricky
part, as there are 6 pulses per revolution, but skip every 6th pulse and have that time interval
align with the above triggering pulse. (you don't want a triggering pulse at the same time the
charging coil has output because the part that the charging coil charges is shorted at that
moment)
4) input the trigger pulse and also input a signal from the coil and display the time interval as ° timing, as at low rpm there is a delay varying from 100us to 0us approx. The delay at low rpm is taken away at higher rpm to produce advance.

What I have so far is the LCD which works well and displays the rpm. Also for now I had it display the Ms between pulses just to be sure it was changing correctly. The pulse out I made 1Ms and used 2 transistors to switch 12 vdc to the input of the CDI, works well. I added the pin 7 output as the future high pulse rate simulating charging coils. I will feed this also with 2 transistors through a transformer to obtain approx 200 vac.
Thanks, hope it is not to ambitious!
(edited errors)

Code: [Select]


//Pulse Generator Arduino Code  
#include "U8glib.h"
U8GLIB_ST7920_128X64_1X u8g(13, 11, 10);  // SPI Com: SCK = en = 15, MOSI = rw = 16, CS = di = 17
int pot1 = A5;          // select the input pin for the pot
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

void draw() {
  // graphic commands to redraw the complete screen should be placed here  
  
  u8g.setPrintPos(0, 15);        // call procedure from base class, http://arduino.cc/en/Serial/Print
  u8g.print("RPM =");
  u8g.setPrintPos(50, 15);
  u8g.print(potValue);
  u8g.setPrintPos(8, 30);
  u8g.print("Ms =");
  u8g.setPrintPos(50, 30);
  u8g.print(pulseValue);
  u8g.setPrintPos(0, 45);
  u8g.print("Advance =");
  u8g.setPrintPos(80, 45);
  u8g.print("10");                               // for use in future code

}

void setup() {
  Serial.begin(115200);                       // serial com speed for display
  // flip screen, if required
  // u8g.setRot180();  
 pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
 pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
 u8g.firstPage();
 u8g.setFont(u8g_font_unifont);
 delay (2000);

 //Timer1 set up 2ms pulse every 50 ms
  TCCR1A = 0;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) |(1<<CS10); //prescaler 64  4us/tick
 
}
  
void loop() {
  // picture loop
  u8g.firstPage();
  do {
    draw();
} while( u8g.nextPage() );

  potValue = analogRead(pot1);                                          // read the value from the pot for rpm
  pulseValue = analogRead(pot1);                                        // read the value from the pot for pulse
  delayValue = analogRead(pot1);                                        // read the value from the pot for pulse delay
  potValue = map(potValue, 0, 1023, 500, 3000);                         // map pot for 500 - 3000 for rpm display
  pulseValue = map(pulseValue, 0, 1023, 120, 20);                       // map pot for pulse delay 20 to 120 Ms
  delayValue = map(delayValue, 0, 1023, 30000, 5000);                   // map pot for actual pulse delay
  delay (10);
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses
  digitalWrite(outputPin,HIGH); //turn on pin 8
  digitalWrite(chargePin,HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect) {
 digitalWrite(outputPin,LOW); //turn off pin 8
 digitalWrite(chargePin,LOW); //turn off pin 7
 
}


cattledog

Tom--

Let me see if I have this correct. I understand 1,2, and 3 as follows.

You have a 1 ms CDI trigger pulse at 0 degrees. The period between trigger pulses is 20 to 120 ms. In the CDI system is this the trigger for the discharge of the capacitor to the coil?

Then, within that period you then want to output a ? ms pulse at 60°, another at 120°, another at 180°, another at 240° and one at 300°. That's five pulses spaced 360/6 with a gap at 0.  This part seems straight forward. In the CDI system, are these pulses charging the capacitor?
 
I'm not certain about point 4

Quote
4) input the trigger pulse and also input a signal from the coil and display the time interval as ° timing, as at low rpm there is a delay varying from 100us to 0us approx. The delay at low rpm is taken away at higher rpm to produce advance.
The trigger fires. The capacitor discharges into the coil. Please explain more about the "signal from the coil". If you can get this into a 5v signal for input into the Arduino it should be possible to calculate the time from the trigger pulse. I'm not sure if this is better done with a pin change (or external interrupt) or a timer input capture.

For development, you can certainly simulate this pulse with one generated by the Arduino or from possibly a second one. Do you have a second pro mini to possibly use as a coil output signal generator?

I'm not sure if your project will require the millis() and micros() timer. You may need three timers --one to generate the trigger, one to generate the 5 pulses, and one to time the ignition delay. It's possible that this project could benefit from additional hardware timers. Are you bound to the pro mini, or is there the possibility of using a Mega with the additional timers.

I would recommend developing this system without the TFT display. Use a 4x20 lcd or serial to a laptop. Your program will be complicated enough without having to work around the blocking characteristics of the display draw while you are working through other issues.

6v6gt

#2
Sep 23, 2016, 08:24 am Last Edit: Sep 23, 2016, 08:25 am by 6v6gt Reason: add picture
I tried get the OP's description onto a time line to make it easier to visualise. I hope I've understood it correctly.


allanhurst

#3
Sep 23, 2016, 08:48 am Last Edit: Sep 23, 2016, 08:52 am by allanhurst
I take it you mean 18,000rpm, not 18,000 Hz - that would be a pretty quick engine!

regards

Allan.

ps I've looked at these gadgets - the ones I've seen are potted in epoxy or similar, and I've always thought them unrepairable. How do you get them apart?

tombauer

Tom--

Let me see if I have this correct. I understand 1,2, and 3 as follows.

You have a 1 ms CDI trigger pulse at 0 degrees. The period between trigger pulses is 20 to 120 ms. In the CDI system is this the trigger for the discharge of the capacitor to the coil?
   >>>>Yes this simulates the pusle coil and tells the CDI to fire.

Then, within that period you then want to output a ? ms pulse at 60°, another at 120°, another at 180°, another at 240° and one at 300°. That's five pulses spaced 360/6 with a gap at 0.  This part seems straight forward. In the CDI system, are these pulses charging the capacitor?
  >>>>Yes that is the a/c from the charging coil under flywheel that outputs around 200vac
 
I'm not certain about point 4

The trigger fires. The capacitor discharges into the coil. Please explain more about the "signal from the coil". If you can get this into a 5v signal for input into the Arduino it should be possible to calculate the time from the trigger pulse. I'm not sure if this is better done with a pin change (or external interrupt) or a timer input capture.
  >>>>I can use a induction coil or a voltage divider to pick up a signal from the coil.

For development, you can certainly simulate this pulse with one generated by the Arduino or from possibly a second one. Do you have a second pro mini to possibly use as a coil output signal generator?

I'm not sure if your project will require the millis() and micros() timer. You may need three timers --one to generate the trigger, one to generate the 5 pulses, and one to time the ignition delay. It's possible that this project could benefit from additional hardware timers. Are you bound to the pro mini, or is there the possibility of using a Mega with the additional timers.
  >>>>No I can use any other board as needed, the generation of the 5 pulses for charging is just a luxury,
         I  can use a high impedance transformer like I have now.

I would recommend developing this system without the TFT display. Use a 4x20 lcd or serial to a laptop. Your program will be complicated enough without having to work around the blocking characteristics of the display draw while you are working through other issues.

tombauer

#5
Sep 23, 2016, 04:49 pm Last Edit: Sep 23, 2016, 05:04 pm by tombauer
I take it you mean 18,000rpm, not 18,000 Hz - that would be a pretty quick engine!

regards

Allan.

ps I've looked at these gadgets - the ones I've seen are potted in epoxy or similar, and I've always thought them unrepairable. How do you get them apart?
Ok, 6 charging coils with magnet turning at 3000 rpm would be 300Hz signal so output needs
to be 50 - 300Hz.

I find the cheaper ones are epoxy but MANY others are in something softer.

6v6gt

6 charging coils with magnet turning at 3000 rpm would be 18000Hz signal would it not? . . .
Exactly, if your minute is only only one second in duration.

cattledog

#7
Sep 23, 2016, 05:08 pm Last Edit: Sep 23, 2016, 05:11 pm by cattledog
Quote
the generation of the 5 pulses for charging is just a luxury,
If you use the five pulses, what duration should they be?

If you use only one pulse, what duration should it be, and how should it be timed to the trigger?

Quote
Top line would only have 1 pulse at the time where the second line does   
not.
The top line represents a system clock and the overall timing. There are no output pulses, but the other pulses are timed in relationship to the clock.

tombauer

If you use the five pulses, what duration should they be?
  >>>These pulses would be fed to a small transformer so they can just be square wave.

If you use only one pulse, what duration should it be, and how should it be timed to the trigger?
  >>>.If I don't even have these pulses it is not that bad for a tester, I can just use a transformer off the line with isolation. Right now I have 2 12v to 120v transformers back to back so I also get my 12 vdc from them.

The top line represents a system clock and the overall timing. There are no output pulses, but the other pulses are timed in relationship to the clock.
  >>>>Ok, I did not understand, so it is correct.

cattledog

Here is a some test code with the advance (coil pulse delay) measurement in microseconds patched into a serial version of your code.

I have simulated a delay pulse with a signal on pin 4 generated by a software timer which sends a pulse 5 milliseconds after the main trigger. From my testing, most of the timing error is due to the analogRead() going on. Putting the advance measurement on a timer input capture interrupt, instead of an external interrupt might be more accurate.

How accurate does the advance measurement need to be? What is the range of advance measurements?

Code: [Select]
//Pulse Generator Serial Output Arduino Code

int pot1 = A5;          // select the input pin for the pot
int potValue = 0;       // variable to store the value coming from the sensor
int pulseValue = 0;    // 2 variables from one pot
int delayValue = 0;
int outputPin = 8;      // select the pin for the output for trigger pulse
int chargePin = 7;      // select the pin for the output for charge pulses

volatile boolean trigger = false;
volatile unsigned long delayPeriod;
unsigned long copy_delayPeriod;
volatile unsigned long delayPeriodStart;


void setup() {
  Serial.begin(115200);                       // serial com speed for display
  pinMode(outputPin, OUTPUT);            // declare the outputPin as an OUTPUT
  pinMode(chargePin, OUTPUT);            // declare the chargePin as an OUTPUT
  delay (2000);

  pinMode(4, OUTPUT); //signal out for delay test

  //Timer1 set up 1ms pulse every 50 ms
  TCCR1A = 0;
  TCCR1B = (1 << WGM12);//CTC mode to OCR1A
  OCR1A = 12500; //50 ms to top value
  TIMSK1 |= (1 << OCIE1A);//interrupt enable compareA
  TIMSK1 |= (1 << OCIE1B);//interrupt enable compareB
  OCR1B = 250; //1 ms pulse width
  TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64  4us/tick

  attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, RISING);
}

void loop() {

  potValue = analogRead(pot1);                                          // read the value from the pot for rpm
  pulseValue = analogRead(pot1);                                        // read the value from the pot for pulse
  delayValue = analogRead(pot1);                                        // read the value from the pot for pulse delay
  potValue = map(potValue, 0, 1023, 500, 3000);                         // map pot for 500 - 3000 for rpm display
  pulseValue = map(pulseValue, 0, 1023, 120, 20);                       // map pot for pulse delay 20 to 120 Ms
  delayValue = map(delayValue, 0, 1023, 30000, 5000);

  //my test for trigger pulse delay response)
  if (trigger == true)
  {
    if (micros() - delayPeriodStart >= 5000) //5 ms delay
    {
      trigger = false;
      digitalWrite(4, HIGH);//simulate pulse
      digitalWrite(4, LOW);
      noInterrupts();
      copy_delayPeriod = delayPeriod;
      interrupts();

      Serial.print("RPM =");
      Serial.println(potValue);
      Serial.print("Ms =");
      Serial.println(pulseValue);
      Serial.print("AdvanceMicroseconds =");
      Serial.println(copy_delayPeriod);                               // for use in future code

    }
  }
}

ISR(TIMER1_COMPA_vect) {
  OCR1A = (delayValue);                                                 // value to set delay between pulses
  digitalWrite(outputPin, HIGH); //turn on pin 8
  digitalWrite(chargePin, HIGH); //turn on pin 7
}

ISR(TIMER1_COMPB_vect)
{
  digitalWrite(outputPin, LOW); //turn off pin 8
  digitalWrite(chargePin, LOW); //turn off pin 7
  delayPeriodStart = micros();//start looking for response
  trigger = true;
}

void delayPeriodTiming()
{
 delayPeriod = micros() - delayPeriodStart;
}


tombauer

I am repairing just one such CDI right now and will get (hopefully) some measurements from it regarding pulse delay. I anticipate that 5 Ms delay will give 18° advance when it is taken away. I would think a range of 20° would be more than adequate. Also +/- .5° if obtainable would be fine, these are not race car engines!   

tombauer

So far unable to measure and delay! I have one OEM CDI and a cheap Chinese one that should have delay, I am looking at the pulse and the primary of the ign coil with dual trace scope (Tektronix 585A) at any speed pulses are at same time!

tombauer

I loaded the above code and it compiled and loaded but apparently locks up, the small led flashes once and goes out, no response after that??

cattledog

#13
Sep 24, 2016, 05:44 am Last Edit: Sep 24, 2016, 06:05 am by cattledog
Quote
I loaded the above code and it compiled and loaded but apparently locks up, the small led flashes once and goes out, no response after that??
I'm running it now on a Uno. Did you jumper pin 4 to pin 3? Did you set the Serial monitor to 115200 baud? I am also running a jumper from 3.3v to A5 for the analog read. Ms =56  RPM = 2110 delay = 5400 us.

Code: [Select]
RPM =2137
Ms =56
AdvanceMicroseconds =5052
RPM =2137
Ms =56
AdvanceMicroseconds =5052
RPM =2137
Ms =56
AdvanceMicroseconds =5060
RPM =2127
Ms =56
AdvanceMicroseconds =5232
RPM =2117
Ms =56
AdvanceMicroseconds =5224
RPM =2130
Ms =56
AdvanceMicroseconds =5504

tombauer

#14
Sep 24, 2016, 04:15 pm Last Edit: Sep 24, 2016, 04:31 pm by tombauer
I still have the 12864B display and it is a serial setup. I would like to understand "I would recommend developing this system without the TFT display. Use a 4x20 lcd or serial to a laptop. Your program will be complicated enough without having to work around the blocking characteristics of the display draw while you are working through other issues."
Yes 3 and 4 are jumped,
Thanks, Tom

Go Up