Hello everyone.
I am developing a project that involves constant serial communication (0.1 to 0.5 sec interval pc-> arduino) between computer and arduino.
the initial idea is:
1- Computer obtains temperature and usage data (Delphi / Pascal).
2- data is processed and a code is generated
3- code sent to arduino (serial)
4- arduino changes engine speed is changed (PWM)
5- Arduino sends RPM to computer (serial)
6- repeat everything
If you send the code <xxx, xxx, xxx ....> 1 time, it works, but if you send it several times (5 per second), it behaves strangely.
the LEDs flash (even emitting 100% pwm signal).
If you remove the RPM code, it works perfectly.
//
// Read/Write serial port, 2x PWM 25khz control, Read RPM fan.
// tks: robin2
//
const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
char messageFromPC[numChars] = {0};
int slot2, slot3, slot4, slot5, slot6, slot7;
boolean newData = false;
// === PWM VAR ====//
word pwmA = 0; // (0-320 = 0-100% duty cycle)
word pwmB = 0; // (0-320 = 0-100% duty cycle)
//=== RPM VAR ===//
unsigned long time;
unsigned int rpm;
String stringRPM, stringRPM1, stringRPM2, stringRPM3, stringRPM4; //stringRPM5, stringRPM6, stringRPM7;
int FanCount = 0;
int i = 0;
// ============================================================
void setup() {
pinMode(3, OUTPUT);
// pinMode(5, OUTPUT);
// pinMode(6, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
// pinMode(11, OUTPUT); disable for pwm?
// ======================
// PWM Code for pin9 and 10 25khz
// ======================
TCCR1A = 0; //clear timer registers
TCCR1B = 0;
TCNT1 = 0;
TCCR1B |= _BV(CS10); //no prescaler
ICR1 = 320; //PWM mode counts up 320 then down 320 counts (25kHz)
OCR1A = pwmA; //0-320 = 0-100% duty cycle
TCCR1A |= _BV(COM1A1); //output A clear rising/set falling
OCR1B = pwmB; //0-320 = 0-100% duty cycle
TCCR1A |= _BV(COM1B1); //output B clear rising/set falling
TCCR1B |= _BV(WGM13); //PWM mode with ICR1 Mode 10
TCCR1A |= _BV(WGM11); //WGM13:WGM10 set 1010
// pin for read rpm//
digitalWrite(2, HIGH); // Starts reading (2)
digitalWrite(4, HIGH); // Starts reading (4)
digitalWrite(7, HIGH); // Starts reading (7)
digitalWrite(8, HIGH); // Starts reading (8)
//digitalWrite(12, HIGH); // Starts reading (12)
//digitalWrite(13, HIGH); // Starts reading (13)
Serial.begin(9600);
}
void loop() {
getRPMS(); // read rpm and print
recvWithStartEndMarkers();
if (newData == true) {
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
newData = false;
}
}
//============
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
//============
void parseData() { // split the data into its parts
char * strtokIndx; // this is used by strtok() as an index
// Slot 1 <Slot1, 111,111,111,111....>
strtokIndx = strtok(tempChars,","); // get the first part - the string
strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
// Slot 2 <char, slot2,111,111,111....>
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
slot2 = atoi(strtokIndx); // convert this part to an integer
// Slot 3 <char, 111, slot3 ,111,111....>
strtokIndx = strtok(NULL, ",");
slot3 = atof(strtokIndx); // convert this part to an integer
// Slot 4 <char, 111, 111, slot 4, 111....>
strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
slot4 = atoi(strtokIndx); // convert this part to an integer
// Slot 5 <char, 111, 111, 111, slot 5....>
//strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
//slot5 = atoi(strtokIndx); // convert this part to an integer
// Slot 6 <char, 111, 111, 111, 111, slot 6....>
//strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
//slot6 = atoi(strtokIndx); // convert this part to an integer
// Slot 7 <char, 111, 111, 111, 111, 111, slot 7....>
//strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
//slot7 = atoi(strtokIndx); // convert this part to an integer
}
//============
void showParsedData() {
OCR1B = (slot2*320/100); // Pwm25khz pin 10
OCR1A = (slot3*320/100); // Pwm25khz pin 9
analogWrite(3, (slot4*255/100) ); // Pwm Defaut Pin3
//analogWrite(5, (slot5*255/100) ); // Pwm Defaut Pin5
//analogWrite(6, (slot6*255/100) ); Pwm Defaut Pin6
//analogWrite(11, (slot7*255/100) ); // pwm defaut pin 11
}
void getRPMS() {
i = i + 1;
if (i == 1) {FanCount = 2;}
else if (i == 2){FanCount = 4;}
else if (i == 3){FanCount = 7;}
else if (i == 4){FanCount = 8;}
time = pulseIn(FanCount, HIGH);
rpm = (1000000 * 60) / (time * 4);
stringRPM = String(rpm);
if (stringRPM.length() < 5) {
if (i == 1) {stringRPM1 = stringRPM;}
else if (i == 2){stringRPM2 = stringRPM;}
else if (i == 3){stringRPM3 = stringRPM;}
else if (i == 4){stringRPM4 = stringRPM;}
}
if (i == 4){
i=0;
Serial.println("!Fan 1: " + stringRPM1 + " Fan 2: " + stringRPM2 + " Fan 3: " +
stringRPM3 + " Fan 4: " + stringRPM4 + "#");
}
}
I have a few theories:
1- Arduino / heavy code limitation
2- code incompatibility
3- problem in my logic.
Would anyone know how to help me?
I thought about using "attachInterrupt ().", but on the arduino uno, it only has 2 pins.