Hardware: Arduino MEGA as master, sends output to LCD(I2C) as slave, sends and receives data with Ardunio NANO (I2C) as slave.
This is for a motor controller for RC engine. I have When I run the component functions individually, they work fine. When I start I2C, starter works, fuel pump works until the next I2C transmission, then it stops.
I am assuming that there is a timer or interrupt issue, so I have swapped my PWM to all available. I removed all the delay functions (only there for testing) to see if that was the problem, and both PWM worked, but I2C stopped communicating when I used millis(). I can see that there is just a interrupt or provisioning problem here where the chip is looking at one and not the other.
For the given hardware, what would be the best PWM pins to use, considering the communication requirement of 1 transmission every 200ms to the arduino mega? Do I need to start digging into timer registers to get something like this to work? i was hoping that the 328p could handle this level of computation.
Arduino MEGA code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3F,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
volatile int RUNStatus = 0; // Global volatile system run status. 0 = OFF, 1 = START, 2 = RUN, 3 = SHUTDOWN
void setup(){
Wire.begin(); // join i2c bus (address optional for master)
lcd.init(); // initialize the lcd
lcd.backlight();
Serial.begin(9600);
}
void loop(){
if (Serial.available()>0){
Serial.print(RUNStatus);
RUNStatus = Serial.read();
}
if(RUNStatus == 49){
CMDstart();
}
int RPMcmd = 0;
WriteData(RPMcmd);
ReadDATA();
delay(200);
}
int WriteData(int x){
Wire.beginTransmission(8); // transmit to device #8
Wire.write(x); // sends one byte
Wire.endTransmission(); // stop transmitting
}
//Requests parameter data from the ECU. Min 20ms response time a normal I2C freq.
void ReadDATA(){
Wire.requestFrom(8, 5); // request 5 bytes from slave device #8
while (Wire.available()) { // slave may send less than requested
byte rpmH = Wire.read();
byte rpmM = Wire.read();
byte rpmL = Wire.read();
int egt = Wire.read();
int cmd = Wire.read();
int rpm = rpmH;
rpm = (rpm<<8)|rpmM;
rpm = (rpm<<8)|rpmL;
// In RPM will work for 500 - 99999 RPM (get negative values below 500 due to data rollover)
//(will switch to KRPM later, better resolution for calibration)
rpm = 21000000/rpm; // value compensation for microsec & duty cycle compressed data format 26086956
LCD(rpm,egt,cmd);
}
}
// Write data to LCD in fomat for 16 x 2 LCD
void LCD(int rpm, int egt, int cmd){
lcd.setCursor(0,0);
lcd.print("RPM:");
lcd.setCursor(4,0);
lcd.print(" ");
lcd.setCursor(4,0);
lcd.print(rpm);
lcd.setCursor(0,1);
lcd.print("EGT:");
lcd.setCursor(4,1);
lcd.print(" ");
lcd.setCursor(4,1);
lcd.print(egt);
lcd.setCursor(9,0);
lcd.print("CMD:");
lcd.setCursor(13,0);
lcd.print(" ");
lcd.setCursor(13,0);
lcd.print(cmd);
}
//Start command to ECM, automatically enters StartSEQ
int CMDstart(){
char x = 's';
char y = 'B';
Serial.print(x);
Wire.beginTransmission(8); // transmit to device #8
Wire.write(x); // sends one byte
Wire.write(y); // sends one byte
Wire.endTransmission(); // stop transmitting
RUNStatus = 1;
}
Arduino NANO code:
#include <Wire.h>
int EGTsense = A2; //Analog EGT reading needs calibration, sim with trimpot
int FPpin = 3; //Fuel Pump Run pin
int RPMsense = 5; //RPM sense input pin
int STRpin = 11; //Starter Run Pin
int FVpin = 8; //Fuel Valve enable / disable
int IGpin = 12;
volatile int RPMcmdin = 0; //Command input from ECU, used in Start/Run functions
unsigned long previousMillis = 0;
void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onRequest(requestEvent); // register event
Wire.onReceive(receiveEvent); // register event
pinMode(FPpin, OUTPUT);
pinMode(STRpin, OUTPUT);
pinMode(EGTsense,INPUT);
pinMode(RPMsense, INPUT_PULLUP);
pinMode(FVpin, OUTPUT);
pinMode(IGpin, OUTPUT);
Serial.begin(9600);
}
void loop() {
//Starter(int); FUELvalve(int); FuelPump(int); Ignition(int)
//StartSEQ(); ShutdownSEQ();
StartSEQ();
//delay(2000);
//ShutdownSEQ();
}
// Collects and sends RPM, EGT, CMD values from ECM to ECU
void requestEvent() {
int rpm = GetRPM();
byte RPMarray[3];
RPMarray[0] = (rpm >> 16) & 0xFF;
RPMarray[1] = (rpm >> 8) & 0xFF;
RPMarray[2] = rpm & 0xFF;
int egt = GetEGT();
int cmd = RPMcmdin;
Wire.write(RPMarray,3);
Wire.write(egt);
Wire.write(cmd);
}
// Receive RPM or Start command from ECU, Start or change program RPM setpoint
void receiveEvent(int howMany) {
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
if (c == 's'){
StartSEQ();
}
}
RPMcmdin = Wire.read(); // receive byte as an integer
analogWrite(FPpin, RPMcmdin);
}
// Rough start sequence, needs work with fuel pump and handoff to RUN function
void StartSEQ(){
//Starter(int); FUELvalve(int); FuelPump(int); Ignition(int)
//StartSEQ(); ShutdownSEQ();
unsigned long currentMillis = millis();
FUELvalve(1);
Ignition(1);
if (currentMillis - previousMillis > 100) {
FuelPump(20);
}
if (currentMillis - previousMillis > 1000) {
Starter(80);
}
//if (currentMillis - previousMillis < 5000) {
//StartSEQ();
//}
previousMillis = currentMillis;
return;
}
void ShutdownSEQ(){
FUELvalve(0); //Shut the fuel valve
FuelPump(0); //Turn off the fuel pump
int egt = GetEGT(); //Read EGT
if(egt>120){
Starter(85);
//delay(5000);
Starter(0);
//delay(5000);
ShutdownSEQ();
}else{
Starter(0);
return;
}
}
// Only measures HIGH pulse width and sends value back to ECU for computation.
// This requires 3 bytes, and is minimum load on processor.
int GetRPM(){
unsigned long PWH = pulseIn(RPMsense,HIGH);
return(PWH);
}
// Reads Thermocouple value. Will need calibration with real sensor at some point.
// If using k-type, use linear mapping requires component selections and testing
int GetEGT(){
int measure = analogRead(EGTsense);
int egt = map(measure, 0, 1023, 0, 255);
return (egt);
}
// Run values need to be calibrated at 8.4V, need min 11.4A supply.
int Starter(int STRin){
//2500RPM = 82PWM, 5000RPM = ???PWM Need to verify on Battery
analogWrite(STRpin, STRin);
return;
}
int FuelPump(int FP){
analogWrite(FPpin, FP);
return;
}
int FUELvalve(int pos){
//Pass in value of 1 opens valve, 0 closes valve.
if (pos == 1){
digitalWrite(FVpin, HIGH);
}else{
digitalWrite(FVpin, LOW);
}
}
int Ignition(int i){
if (i == 1){
digitalWrite(IGpin, HIGH);
}else{
digitalWrite(IGpin, LOW);
}
}