Hi I am new to this forum but I work with arduino for a few projets now. Right now I am building a miniature wind turbine in a small wind tunnel for education. I can set wind speed of the tunnel with a pwm signal to the motor. I measure the actual wind speed by taking the rpm of the fan (wich i have correlated to an thermal anemometer reading) . The fan has a built in tachometer. I am reading the rpm of the wind turbine as well by taking an opto sensor signal from a disk with 8 holes. Both RPM of the fan and the turbine is in the range of 0...1500 rpm. The turbine is also equipped with other sensors and functions. The turbine is connected via USB to a GUI written in python to plot data in real time and interact with the system. The computer programm triggers the serial connection aroud every 60 ms.
Difficulty is: The system has to show dynamic effects as precise as possible without time delay. So the classical tick counter does not help me with rpm measurement. I am using rotating buffer to low pass filter the measurement data and always get the most actual data.
Problem: With just one interrupt function I get very good data. As soon as both interrrupts are attached, after 420 seconds I get corrupted data for the fan rpm and the hx711 force sensor. After 840 seconds of running data is good again. But I can't see any overflow problem here.
Maybe you guys have tricks to improve the code. I know that lots is happening with all the sensor readings, serial connection and two interrupts. And I can see that this could cause problems. But I wonder why it works perfectly for the first 420 seconds.
Board is a Mega btw.
//LIBRARIES
#include <Wire.h>
#include <INA219_WE.h>
INA219_WE CurrentSensor = INA219_WE(0x40);
#define I2C_ADDRESS
#include <Servo_Hardware_PWM.h>
Servo PitchServo;
//PIN DEFINITION
const int pin_servo = 2; //orange cable
const int pin_turbine_tacho = 18;
const int pin_fan_tacho = 19; //yellow cable
const int pin_fan_pwm = 45; //green cable
const int pin_fan_on = 43; //red cable //GND blue cable
const int pin_force_clk = 8;
const int pin_force_data = 9;
const int pin_turbine_start = 48;
const int pin_torque_pwm = 46;
const int pin_LED = 13;
//VARIABLES
uint8_t fan_pwm = 100; //PWM value 0-255
uint8_t torque_pwm = 0;
uint16_t us_servo = 900;
unsigned long time_fan_tick = micros();
unsigned long time_turbine_tick = micros();
unsigned long dt_fan_mean = 0;
unsigned long dt_turbine_mean = 0;
bool rotating_fan = false;
bool rotating_turbine = false;
uint16_t speed_fan = 0;
uint16_t speed_turbine = 0;
float currentfloat = 0;
uint16_t current = 0;
uint32_t thrust_force = 0;
uint32_t thrust_force_offset = 0;
//ROTARY BUFFERS
unsigned long rot_turbine_tick[8]; //8 values stored for averaging (1/2 revolution)
int pos_turbine_tick = 0;
unsigned long rot_fan_tick[2]; //2 values stored for averaging (1 revolutions)
int pos_fan_tick = 0;
void setup() {
// put your setup code here, to run once:
//attach servo
PitchServo.attach(pin_servo);
PitchServo.writeMicroseconds(900);
Wire.begin();
//define pin functions
pinMode(pin_turbine_tacho,INPUT_PULLUP);
pinMode(pin_fan_tacho,INPUT_PULLUP);
pinMode(pin_fan_pwm,OUTPUT);
analogWrite(pin_fan_pwm,100);
pinMode(pin_fan_on,OUTPUT);
digitalWrite(pin_fan_on,HIGH);
pinMode(pin_force_clk,OUTPUT);
digitalWrite(pin_force_clk,LOW);
pinMode(pin_force_data,INPUT);
pinMode(pin_turbine_start,OUTPUT);
digitalWrite(pin_turbine_start,HIGH);
pinMode(pin_torque_pwm,OUTPUT);
analogWrite(pin_torque_pwm,0);
pinMode(pin_LED,OUTPUT);
digitalWrite(pin_LED,HIGH);
if (CurrentSensor.init()){
digitalWrite(pin_LED,HIGH);
}
else{
digitalWrite(pin_LED,LOW);
}
CurrentSensor.powerUp();
CurrentSensor.setADCMode(SAMPLE_MODE_64);//average 64 values
CurrentSensor.setMeasureMode(CONTINUOUS); // choose mode and uncomment for change of default
CurrentSensor.setPGain(PG_40);//max 0.4 A
CurrentSensor.setBusRange(BRNG_16); //max 16V
delay(10);
//set gain for force sensor
hx711_set_gain();
delay(500);
thrust_force_offset = hx711_read_force();
//change the timer 5 to increase the PWM frequency for the fan
TCCR5B = TCCR5B & 0b11111000 | 0x02; //Timer 5 is a 16-Bit timer. resulting frequency ~ 4kHz
//attach interrupt functions
attachInterrupt(digitalPinToInterrupt(pin_turbine_tacho),turbine_interrupt,CHANGE);
attachInterrupt(digitalPinToInterrupt(pin_fan_tacho),fan_interrupt,CHANGE);
//begin serial connection
Serial.begin(38400);
delay(100);
}
void loop() {
// put your main code here, to run repeatedly:
//wait for data request
while (Serial.available()==0){}
Serial.read();
//calculate data
if (rotating_fan==true){
if (micros()-time_fan_tick < 500000ul){
dt_fan_mean=rot_fan_tick[0];
dt_fan_mean+=rot_fan_tick[1];
dt_fan_mean/=2;
speed_fan=60000000/dt_fan_mean/2; //two ticks per rotation
}
else {
speed_fan=0;
rotating_fan=false;
}
}
if (rotating_turbine==true){
if (micros()-time_turbine_tick < 625000ul){
dt_turbine_mean=rot_turbine_tick[0];
dt_turbine_mean+=rot_turbine_tick[1];
dt_turbine_mean+=rot_turbine_tick[2];
dt_turbine_mean+=rot_turbine_tick[3];
dt_turbine_mean+=rot_turbine_tick[4];
dt_turbine_mean+=rot_turbine_tick[5];
dt_turbine_mean+=rot_turbine_tick[6];
dt_turbine_mean+=rot_turbine_tick[7];
dt_turbine_mean/=8;
speed_turbine=60000000/dt_turbine_mean/16; //16 ticks per rotation
}
else {
speed_turbine=0;
rotating_turbine=false;
}
}
currentfloat=CurrentSensor.getCurrent_mA();
current=(uint16_t)currentfloat;
if (digitalRead(pin_force_data) == LOW){
thrust_force=hx711_read_force();
}
//write data
Serial.write((byte*)(&speed_fan),2); // 2bytes
Serial.write((byte*)(&speed_turbine),2); // 2bytes
Serial.write((byte*)(¤t),2); // 2bytes
Serial.write((byte*)(&thrust_force),4); // 4bytes
//read data
while (Serial.available()==0){}
analogWrite(pin_fan_pwm,Serial.read());
while (Serial.available()==0){}
us_servo = Serial.read();
while (Serial.available()==0){}
us_servo |= (Serial.read()<<8); // 2 byte little endian
PitchServo.writeMicroseconds(us_servo);
while (Serial.available()==0){}
analogWrite(pin_torque_pwm,Serial.read());
while (Serial.available()==0){}
if (Serial.read() == 1){
digitalWrite(pin_turbine_start,LOW);
}
else {
digitalWrite(pin_turbine_start,HIGH);
}
}
void fan_interrupt(){
if (micros()-time_fan_tick > 30000ul){
rot_fan_tick[pos_fan_tick%2] = micros()-time_fan_tick;
time_fan_tick = micros();
pos_fan_tick++;
rotating_fan = true;
}
}
void turbine_interrupt(){
if (micros()-time_turbine_tick > 1000ul){
rot_turbine_tick[pos_turbine_tick%8] = micros()-time_turbine_tick;
time_turbine_tick = micros();
pos_turbine_tick++;
rotating_turbine = true;
}
}
uint32_t hx711_read_force(){
uint32_t value = 0;
uint32_t mask = 0x00800000; //1 at the 24th bit
while (mask > 0){
digitalWrite(pin_force_clk, HIGH);
delayMicroseconds(1); // T2 >= 0.2 us
if (digitalRead(pin_force_data) == HIGH)
{
value |= mask;
}
digitalWrite(pin_force_clk, LOW);
delayMicroseconds(1); // keep duty cycle ~50%
mask >>= 1;
}
hx711_set_gain();
return value-thrust_force_offset;
}
void hx711_set_gain(){
for (int i=0; i<3; i++){ //set gain
digitalWrite(pin_force_clk, HIGH);
delayMicroseconds(1); // T2 >= 0.2 us
digitalWrite(pin_force_clk, LOW);
delayMicroseconds(1); // keep duty cycle ~50%
}
}
If there is no good solution I may have to put the two rpm measurements to seperate micro controllers.
HX711 function is taken from Rob Tillaarts HX711 library. Just for credits