Hi all,
After some great help some time ago from cattledog, I have been improving my tester and think it would be easier to use if I could adjust for exact RPM to match the spreadsheet I use for programming PICs. I have read several articles on this but it leaves me just with a hurting brain! So anyone want to show me the way would be great!
The variable for RPM is what I want to change to encoder rather than pot.
Thanks, Tom
// update 7/14/2017 added correct math and setting for position of pickup
// revision 10 10/28/2016 adds charging pulse with Timer 2
// 3/2016 added wire to 2 for future pulse width (not needed as first pulse is all that is needed regardless of width)
// lowest RPM = 615 with charge pulse to keep OCR2A <= 255
// CDI Tester Pulse Generator Serial Output Arduino Code
int pot1 = A3; // select the input pin for the pot for rpm
int pot2 = A4; // select the input pin for the pot for pickup location
int potValue = 0; // variable to store the value coming from the sensor
int pickupValue = 0;
int timerTopValue = 12500; // changed from timerTopValue = 0
int outputPin = 4; // select the pin for the output for trigger pulse, changed from 8
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;
float delayDegrees; // changed from int to float for decimal place display
int RPM;
int pickup;
volatile boolean interruptFlag;
unsigned long analogReadInterval = 1000; //read pots and map
unsigned long lastAnalogRead;
const byte setFallingSwitch = 5;
char risefall = 'R'; //default rising mode
const byte setChargePulseSwitch = 6;
boolean chargePulse = false ; //default dc powered mode
volatile byte timeSliceCount = 0; //TDC 0 degrees
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// set the LCD address to 0x3f for a 20 chars 4 line display
// Set the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3f, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
void setup() {
//Serial.begin(115200);
//Serial.println("starting...");
lcd.begin(20, 4); // initialize the lcd for 20 chars 4 lines, turn on backlight
lcd.setCursor(1, 0); // lcd display setup of unchanging headings
lcd.print("RPM:"); // print fixed characters
lcd.setCursor(11, 0);
lcd.print("Mode:"); //to display code choice R or F
lcd.setCursor(1, 1);
lcd.print("Pickup Position:");
lcd.setCursor(1, 2);
lcd.print("Us Delay:");
lcd.setCursor(1, 3);
lcd.print("Deg Advance:");
pinMode(outputPin, OUTPUT); // declare the outputPin as an OUTPUT
pinMode(chargePin, OUTPUT); // declare the chargePin as an OUTPUT
pinMode (setFallingSwitch, INPUT_PULLUP);//check for a LOW input to indicate switch is closed to ground
pinMode(setChargePulseSwitch, INPUT_PULLUP);
if (digitalRead(setChargePulseSwitch) == LOW)
chargePulse = true; //AC CDI
//Timer1 default set up .5ms trigger pulse every 50 ms
TCCR1A = 0;
TCCR1B = (1 << WGM12); //CTC mode to OCR1A
OCR1A = timerTopValue;
TIMSK1 |= (1 << OCIE1A); //interrupt enable compareA
TIMSK1 |= (1 << OCIE1B); //interrupt enable compareB
OCR1B = 125; //sets trigger pulse width, 500 = 2Ms, 250 = 1Ms, 125 = .5Ms, set to 1250 for 5013
TCCR1B |= (1 << CS11) | (1 << CS10); //prescaler 64 4us/tick
//Timer2 default setup charge pulse 12 periods 30 degrees each; only 5 get turned on
//charge pulse timing interval = Timer1 trigger period/12 = timerTopValue/96
TCCR2A = 0;
TCCR2B = 0;
TCCR2A = 1 << WGM20; //lsb of mode 7 pwm to OCR2A
TCCR2B = 1 << WGM22; //msb of mode 7 pwm to OCR2A;
OCR2A = timerTopValue / 96; //96 = 12*4*2 (#periods, prescaler difference, up/down timer mode )
TIMSK2 = 0;
TIMSK2 = 1 << TOIE2; //enable overflow interrupt
// actually start timer in ISR(TIMER1_COMPA_vect
// to prevent out of sync charge pulse, no prescaler set here
attachInterrupt(digitalPinToInterrupt(3), delayPeriodTiming, FALLING);
}
void loop()
{
if (millis() - lastAnalogRead >= analogReadInterval)
{
lastAnalogRead += analogReadInterval;
potValue = analogRead(pot1);
pickupValue = analogRead(pot2);
//Timer2 OCR2A requires max value 255 => 615 lowest RPM
if (chargePulse)
{
RPM = map(potValue, 0, 1023, 615, 8000); // want this value for RPM to be set with encoder
pickup = 60; //map(pickupValue, 0, 1023, 0, 65); //to set position of pickup so advance will read based on delay
//RPM = 615;//for my serial test purposes 615-3800
}
else
{
RPM = map(potValue, 0, 1023, 500, 3800);
pickup = 25; //map(pickupValue, 0, 1023, 0, 50); //to set position of pickup so advance will read
// RPM = 500;//for my serial test purposes 500-3800
}
timerTopValue = 15000000UL / RPM;
if (digitalRead(setFallingSwitch) == LOW) //set Falling
{
risefall = 'F';
}
else
{
risefall = 'R';
}
lcd.setCursor(6, 0);
lcd.print(" "); // print blank spaces to clear old data
lcd.setCursor(6, 0);
lcd.print(RPM);
lcd.setCursor(17, 0);
lcd.print(" ");
lcd.setCursor(17, 0);
lcd.print(risefall); //print R or F at upper right side
lcd.setCursor(18, 1);
lcd.print(" ");
lcd.setCursor(18, 1);
lcd.print(pickup);
lcd.setCursor(11, 2);
lcd.print(" ");
lcd.setCursor(11, 2);
lcd.print(copy_delayPeriod);
lcd.setCursor(14, 3);
lcd.print(" ");
lcd.setCursor(14, 3);
lcd.print(delayDegrees, 1); //delayDegrees, 1);
}
if (trigger == true && interruptFlag == true )
{
trigger = false;
interruptFlag = false;
noInterrupts();
copy_delayPeriod = delayPeriod;
interrupts();
delayDegrees = pickup - (360.0 * (copy_delayPeriod) / (timerTopValue * 4.0)); //for decimal place in deg display.
}
}
ISR(TIMER1_COMPA_vect) {
OCR1A = (timerTopValue); // value to set delay between pulses to trigger cdi
digitalWrite(chargePin, LOW); //guarantee off charge pin at trigger
digitalWrite(outputPin, HIGH); //turn on pin trigger
if (risefall == 'R') //switch not set; default Rising trigger
{
delayPeriodStart = micros(); //start looking for response as pulse rises
trigger = true;
}
//start Timer 2 for charge pulses
if (chargePulse)
{
timeSliceCount = 0;
TCNT2 = 0;
OCR2A = timerTopValue/96; //set 12 periods
TCCR2B |= 1 << CS22 | 1 << CS21; //prescaleer 256 16us/tick
}
}
ISR(TIMER1_COMPB_vect) {
digitalWrite(outputPin, LOW);
if (risefall == 'F') //switch set for Falling trigger
{
delayPeriodStart = micros(); //start looking for response as pulse falls
trigger = true;
}
}
void delayPeriodTiming()
{
delayPeriod = micros() - delayPeriodStart;
interruptFlag = true;
}
ISR(TIMER2_OVF_vect)
//5 pulses of 30 degrees starting at 60 degrees
//ON at 60,120,180,240,300 = 2,4,6,8,10
//OFF at 90,150,210,270,330 = 3,5,7,9,11
{
if (timeSliceCount != 0 && timeSliceCount % 2 == 0)
{
digitalWrite (chargePin, HIGH);
}
else //if (timeSliceCount == 0 || timeSliceCount % 2 == 1)
{
digitalWrite(chargePin, LOW);
}
timeSliceCount++;
if (timeSliceCount == 12)
{
timeSliceCount = 0;
//stop Timer2 by clearing prescaler bits
TCCR2B &= ~1<< CS22;
TCCR2B &= ~1<< CS21;
}
}