a few years ago, I started a simulator with a module Arduino Nano.
I've never finished this project.
Here is the code but not been finalized, only for a example :
Code:
//---------------------------------------//
// Générateur de signaux CKP, TDC et CYL //
//---------------------------------------//
// Didier PELEGRI //
//---------------------------------------//
// FxCKP = RPM * 12 / 60 = RPM / 5 //
// RPM = FxCKP * 60 / 12 = FxCKP * 5 //
//---------------------------------------//
// FxTDC = RPM * 2 / 60 = RPM / 30 //
// RPM = FxTDC * 60 / 2 = FxTDC * 30 //
//---------------------------------------//
// FxCYL = RPM * 0,5 / 60 = RPM / 120 //
// RPM = FxCYL * 60 / 0,5 = FxCYL * 120 //
//---------------------------------------//
// 300 tr/mn => FxCKP = 60 Hz //
// => FxTDC = 10 Hz //
// => FxCYL = 2,5 Hz //
//---------------------------------------//
// 9000 tr/mn => FxCKP = 1800 Hz //
// => FxTDC = 300 Hz //
// => FxCYL = 75 Hz //
//---------------------------------------//
// avr-libc library includes
#include <avr/io.h>
#include <avr/interrupt.h>
#include "avr/pgmspace.h"
// sequence pour simulation capteur CKP
PROGMEM prog_uchar CKP96[] = {
0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, // 1, 2, 3, 4, 5, 6
0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, // 7, 8, 9, 10, 11, 12
0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1, // 13, 14, 15, 16, 17, 18
0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,0,1,1 // 19, 20, 21, 22, 23, 24
};
// CKP __--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--__--
// TDC -_______________________-_______________________-_______________________-_______________________
// CYL __________________________________________________________________________________---___________
// sequence pour simulation capteur TDC
PROGMEM prog_uchar TDC96[] = {
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // 4
// 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // Err
// 0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // OK
// 0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // OK
// 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // OK <==
// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 // OK
// 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0 // Err
};
// sequence pour simulation capteur CYL
PROGMEM prog_uchar CYL96[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, //
0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 // 1
// 0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0 // Err 9
// 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0 // OK
// 0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0 // OK
// 0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 // OK <==
// 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0 // OK
// 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0 // OK
// 0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0 // Err 9
};
#define LedPin 13
#define OutCKP 8
#define OutTDC 9
#define OutCYL 10
#define OutECT 11
#define OutIAT 3
byte CptData;
byte ClignLed;
long ValTempo;
long RPM;
long New_RPM;
long Old_RPM;
int PotRpmValue;
int DataRx;
boolean CmdOn = false;
boolean CmdOk = false;
int PotEctValue;
int PotIatValue;
byte PWM_ECT;
byte PWM_IAT;
byte ValCalc;
int ValCalcIn;
int ValCalcOut;
void setup()
{
pinMode(LedPin, OUTPUT);
Serial.begin(115200);
Serial.println("Simulateur Allumeur");
Serial.println("-------------------");
pinMode(OutCKP, OUTPUT);
pinMode(OutTDC, OUTPUT);
pinMode(OutCYL, OUTPUT);
// pinMode(OutECT, OUTPUT);
Setup_Timer1(); // initialise Timer1
}
void loop()
{
if (CmdOn == false) // mode local
{
Old_RPM = RPM;
PotRpmValue = analogRead(0);
if (PotRpmValue>203)
{
New_RPM = map(PotRpmValue, 204, 1023, 2000, 10000);
}
else
{
if (PotRpmValue>126)
{
New_RPM = map(PotRpmValue, 127, 204, 1000, 2000);
}
else
{
New_RPM = map(PotRpmValue, 0, 126, 125, 1000);
}
}
New_RPM = (New_RPM +24)/25;
New_RPM = New_RPM * 25;
if (Serial.available() > 0) // test si reception ordre activation commande PC
{
DataRx = Serial.read();
if (DataRx == 79) // 4Fh=79="O"
{
CmdOn = true; // mode PC actif
Serial.println("Commande PC=On");
}
}
}
else // si mode PC actif
{
if (Serial.available() > 0) // test si commande reçu
{
CmdOk = false; // commande non valide
DataRx = Serial.read();
switch (DataRx)
{
case 70: // 46h=70="F" // commande retour mode local
CmdOn = false; // commande valide
Serial.println("Commande PC=Off");
break;
case 43: // 2Bh=43="+" // commande increment de 50tr/mn
if (RPM < 9949) New_RPM = RPM +50;
CmdOk = true; // commande valide
break;
case 45: // 2Dh=45="-" // commande decrement de 50tr/mn
if (RPM > 299) New_RPM = RPM -50;
CmdOk = true; // commande valide
break;
case 62: // 3Eh=62=">" // commande increment de 250tr/mn
if (RPM < 9749) New_RPM = RPM + 250;
CmdOk = true; // commande valide
break;
case 60: // 3Ch=60="<" // commande decrement de 250tr/mn
if (RPM > 449) New_RPM = RPM - 250;
CmdOk = true; // commande valide
break;
default: // Erreur Cmd
Serial.println("Erreur Commande");
}
}
}
if (CmdOn == false) // si mode local
{
if (New_RPM != RPM) // si nouvelle valeur de régime
{
RPM = New_RPM;
Serial.print(" / Régime=");
Serial.print(RPM);
Serial.println("tr/mn");
ValTempo = 1250000 / RPM;
}
}
else // si commande PC
{
if (CmdOk == true) // si commande valide
{
CmdOk = false; // commande invalde
RPM = New_RPM;
Serial.print(" / Régime=");
Serial.print(RPM);
Serial.println("tr/mn");
ValTempo = 1250000 / RPM;
}
}
// analogWrite(OutECT, PotValue/4);
analogWrite(OutIAT, 255-(PotRpmValue/4));
PotEctValue = analogRead(0);
// PotEctValue=770; pour test
ValCalcIn = PotEctValue;
ValCalc = PotEctValue / 85;
CalcTemp();
PWM_ECT = 255 - ValCalcOut;
PWM_ECT=132; // avec 50 ohms
// 0=-29,5°C
// 1=-16,7°C
// 2=-6,2°C
// 3=2,4°c
// 10=30,9°C
// 15=41,4°C
// 20=49,5°C
// 30=60,9°C
// 45=72,9°C à 73,8°C
// 60=82,6°C
// 75=89,6°C
// 90=94,8°C
// 105=9,1°C
// 120=103,7°C
// 135=106,9°C
// 150=108,6°C
// 165=110,4°C à 112,2°C
// 180=114°C
// 195=115,9°C
// 210=117,8°C
// 225=117,8°C
// 240=119,8°C
// 255=119,8 à 121,8°C
// 0=-26,1°C et 255=119,8°C
analogWrite(OutECT, PWM_ECT);
// PotIatValue = 1023 - analogRead(0);
PotIatValue=338;
ValCalcIn = PotEctValue;
ValCalc = PotIatValue / 85;
CalcTemp();
PWM_IAT = ValCalcOut;
analogWrite(OutIAT, PWM_IAT);
delay(100);
}
//******************************************************************
// timer1 setup
// set prscaler to 8, Compare mode, 16000000/8/64=31250 Hz clock
void Setup_Timer1() {
cli(); // désactive toutes les interruptions
TCCR1A = 0; // registre TCCR1A = 0000 0000
TCCR1B = 0; // registre TCCR1B = 0000 0000
OCR1A = 64; // initialisation registre de comparaison pour le comptage desiré
TCCR1B |= (1 << WGM12); // Active le mode CTC
// Initialise les bits CS10, CS11 et CS12 pour une division par 8 (16000000/8=2Mhz):
//TCCR1B |= (1 << CS10);
TCCR1B |= (1 << CS11);
//TCCR1B |= (1 << CS12);
TIMSK1 |= (1 << OCIE1A); // Autorise l'interruption compare du timer
sei(); // Active toutes les interruptions
}
void CalcTemp()
{
switch (ValCalc)
{
case 0:
ValCalcOut = map(ValCalcIn, 0, 85, 206, 185);
break;
case 1:
ValCalcOut = map(ValCalcIn, 85, 171, 185, 160);
break;
case 2:
ValCalcOut = map(ValCalcIn, 171, 256, 160, 134);
break;
case 3:
ValCalcOut = map(ValCalcIn, 256, 341, 134, 109);
break;
case 4:
ValCalcOut = map(ValCalcIn, 341, 426, 109, 87);
break;
case 5:
ValCalcOut = map(ValCalcIn, 426, 512, 87, 68);
break;
case 6:
ValCalcOut = map(ValCalcIn, 512, 597, 68, 52);
break;
case 7:
ValCalcOut = map(ValCalcIn, 597, 682, 52, 40);
break;
case 8:
ValCalcOut = map(ValCalcIn, 682, 767, 40, 31);
break;
case 9:
ValCalcOut = map(ValCalcIn, 767, 853, 31, 23);
break;
case 10:
ValCalcOut = map(ValCalcIn, 853, 937, 23, 17);
break;
case 11:
ValCalcOut = map(ValCalcIn, 937, 1023, 17, 11);
break;
case 12:
ValCalcOut = 11;
break;
}
}
ISR(TIMER1_COMPA_vect) { // 31250 Hz
OCR1A = ValTempo;
digitalWrite(OutCKP, pgm_read_byte_near(CKP96 + CptData));
digitalWrite(OutTDC, pgm_read_byte_near(TDC96 + CptData));
digitalWrite(OutCYL, pgm_read_byte_near(CYL96 + CptData));
CptData++;
if (CptData > 95) CptData=0 ;
ClignLed++;
if (ClignLed > 250)
{
//PORTB = PORTB ^ B00100000;
ClignLed = 0;
digitalWrite(LedPin, !digitalRead(LedPin));
Serial.println("CKP");
}
}