loop too slow

What are you developing?
Post Reply
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

loop too slow

Post by stan »

Hi
It seems that the loop is doing only one cycle after pressing the button, then stop.

This is a stereo VU meter, the goal is to switch displays from bar graph to value it in numbers, switching is ok, however respond to input is working incorrectly.
If i change input signal and press the button the changes are recordet only once, no reding in real time. What is wrong ?

Code: Select all


#include <LiquidCrystal.h>
///////////////////
const int button = PB11;            // GPIO 8 for the button
const int led = PC13;               // GPIO 7 for the LED
int ledflag = 0;                 // LED status flag
byte z, z0, z1;
int ur, ul, urr, ull;
/////////////////////
/* Modify the pin number below to meet your board
*/
#define IN_LEFT   PB0  // analog input for left channel
#define IN_RIGHT  PA6  // analog input for right channel
LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);
#define T_REFRESH    50           // msec bar refresh rate
//#define T_PEAKHOLD   3*T_REFRESH    // msec peak hold time before return
#define T_PEAKHOLD   1*T_REFRESH
/* local variable
*/
byte  fill[6] = { 0x20, 0x00, 0x01, 0x02, 0x03, 0xFF }; // character used to fill (0=empty  5=full)
byte  peak[7] = { 0x20, 0x00, 0x04, 0x05, 0x06, 0x07, 0x20 }; // character used to peak indicator
int   lmax[2];                                        // level max memory
int   dly[2];
// delay & speed for peak return
//int PC13;
void  bar  ( int row, int lev )
{
  lcd.setCursor( 0, row );
  lcd.write( row ? 'R' : 'L' );
  for ( int i = 1 ; i < 16 ; i++ )
  {
    int f = constrain( lev      - i * 5, 0, 5 );
    int p = constrain( lmax[row] - i * 5, 0, 6 );
    if ( f )
      lcd.write( fill[ f ] );
    else
      lcd.write( peak[ p ] );
  }
  if ( lev > lmax[row] )
  {
    lmax[row] = lev;
    dly[row]  = -(T_PEAKHOLD) / T_REFRESH;              // Starting delay value. Negative=peak don't move
  }
  else
  {
    if ( dly[row] > 0 )
      lmax[row] -= dly[row];

    if ( lmax[row] < 0 )
      lmax[row] = 0;
    else
      dly[row]++;
  }
}

byte block[8][8] =
{
  { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, // define character for fill the bar
  { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 },
  { 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C },
  { 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E },

  { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, // define character for peak level
  { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 },
  { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
};

void  setup  ( void )
{
  lcd.begin( 16, 2 );
  for ( int i = 0 ; i < 8 ; i++ )
    lcd.createChar( i, block[i] );
  ///////////////
  pinMode(button, INPUT_PULLDOWN);         // define button as an input
  pinMode(led, OUTPUT);          // define LED as an output
  digitalWrite(led, LOW);
  //////////////
}

long  lastT = 0;

void  loop  ( void )
{
  if ( millis() < lastT )
    return;
  lastT += T_REFRESH;
  int anL = map( sqrt( analogRead( IN_LEFT  ) * 16 ), 0, 128, 0, 80 ); // sqrt to have non linear scale (better was log)
  //int anR = map( sqrt( analogRead( IN_RIGHT )*16 ),0,128,0,80 );// calibration *******************************************
  int anR = map( sqrt( analogRead( IN_RIGHT ) * 4 ), 0, 128, 0, 80 );

  ///////////
  if (digitalRead(button) == HIGH) { // if button is pressed
    if (ledflag == 0) {           // and the status flag is LOW
      ledflag = 1;                // make status flag HIGH
      digitalWrite(led, HIGH);
     
       // lcd.clear();
      bar( 0, anL );
      bar( 1, anR );
      ////////////////////
    }                           //
    else {                        // otherwise...
      ledflag = 0;                // make status flag LOW
      digitalWrite(led, LOW);
      //lcd.print(" .    ");
      lcd.clear();
      lcd.setCursor(0, 1);
      lcd.print(anR);// and turn off the LED
      lcd.setCursor(0, 0);
      lcd.print(anL);
      // lcd.clear();
    }
    delay(10);                    // wait a sec for the
  }



}
Last edited by stan on Wed Nov 18, 2020 6:52 am, edited 1 time in total.
Edogaldo
Posts: 10
Joined: Fri Jul 10, 2020 10:11 pm

Re: the loop is stuck

Post by Edogaldo »

Hi, what's the purpose of this code?

Code: Select all

  if ( millis() < lastT )
    return;
  lastT += T_REFRESH;
 
It would prevent the subsequent code to run if lastT becomes big enough.

Cheers, E.
mlundin
Posts: 94
Joined: Wed Nov 04, 2020 1:20 pm
Answers: 6
Location: Sweden

Re: the loop is stuck

Post by mlundin »

The test for T_REFRESH will misbehave when millis() overflows, using the difference and converting to signed will return correct values even after millis overflows.

Code: Select all

  if ( (int)(millis()-lastT) < T_REFRESH )
    return;
  lastT += T_REFRESH;
The display code is called only when/while the button is pressed, HIGH. You should separate the button and disply mode handling from the actual updates of the display

Code: Select all

  if (digitalRead(button) == HIGH) { // if button is pressed
    if (ledflag == 0) {           // and the status flag is LOW
      ledflag = 1;                // make status flag HIGH
      digitalWrite(led, HIGH);
    }                           //
    else {                        // otherwise...
      ledflag = 0;                // make status flag LOW
      digitalWrite(led, LOW);
    }
  }

  if (ledflag == 1) {           // status flag decides display mode
     // lcd.clear();
    bar( 0, anL );
    bar( 1, anR );
  }                           //
  else {                        // otherwise...
    //lcd.print(" .    ");
    lcd.clear();
    lcd.setCursor(0, 1);
    lcd.print(anR);// and turn off the LED
    lcd.setCursor(0, 0);
    lcd.print(anL);
    // lcd.clear();
  }
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

Re: the loop is stuck

Post by stan »

Thanks it is working.
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

Re: loop too slow

Post by stan »

Now I added AC meter instead anR and anR and program is very slow, changing from 0V to 3.3V on PB7 (AC input ) on LCD the changes take 4 second. Separately AC meter is quick no delays on LCD.

Code: Select all

/*
  /*
  Measuring AC Current Using ACS712
  www.circuits4you.com

*/
#include <LiquidCrystal.h> //library for LCD
//LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);
//LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);
const int sensorIn = PA7;
int mVperAmp = 185; // use 100 for 20A Module and 66 for 30A Module

double Voltage = 0;
double VRMS = 0;
double AmpsRMS = 0;
double maxValue = 0;

const int numReadings = 25;
//const int ResetPin = PB11;
const int Vobutton = PB11;
//const int ResetPin = PB5;
int readings[numReadings];
int readIndex = 0;
int total = 0;
int average = 0;
int currentaverage = average;
int previousaverage = 0;

float Vo;
////////////////
//const int button = PB11;            // GPIO 8 for the button
const int button = PB5; 
const int led = PC13;               // GPIO 7 for the LED
int ledflag = 0;                 // LED status flag
byte z, z0, z1;
int ur, ul, urr, ull;
/////////////////////
/* Modify the pin number below to meet your board
*/
#define IN_LEFT   PB0  // analog input for left channel
#define IN_RIGHT  PA6  // analog input for right channel
//LiquidCrystal lcd(PA0, PA1, PA2, PA3, PA4, PA5);
#define T_REFRESH    50           // msec bar refresh rate
//#define T_PEAKHOLD   3*T_REFRESH    // msec peak hold time before return
#define T_PEAKHOLD   1*T_REFRESH
/* local variable
*/
byte  fill[6] = { 0x20, 0x00, 0x01, 0x02, 0x03, 0xFF }; // character used to fill (0=empty  5=full)
byte  peak[7] = { 0x20, 0x00, 0x04, 0x05, 0x06, 0x07, 0x20 }; // character used to peak indicator
int   lmax[2];                                        // level max memory
int   dly[2];
// delay & speed for peak return
//int PC13;
void  bar  ( int row, int lev )
{
  lcd.setCursor( 0, row );
  lcd.write( row ? 'R' : 'L' );
  for ( int i = 1 ; i < 16 ; i++ )
  {
    int f = constrain( lev      - i * 5, 0, 5 );
    int p = constrain( lmax[row] - i * 5, 0, 6 );
    if ( f )
      lcd.write( fill[ f ] );
    else
      lcd.write( peak[ p ] );
  }
  if ( lev > lmax[row] )
  {
    lmax[row] = lev;
    dly[row]  = -(T_PEAKHOLD) / T_REFRESH;              // Starting delay value. Negative=peak don't move
  }
  else
  {
    if ( dly[row] > 0 )
      lmax[row] -= dly[row];

    if ( lmax[row] < 0 )
      lmax[row] = 0;
    else
      dly[row]++;
  }
}

byte block[8][8] =
{
  { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, // define character for fill the bar
  { 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18 },
  { 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C },
  { 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E },

  { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, // define character for peak level
  { 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 },
  { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02 },
  { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
};
////////////////
//************************
void setup() {
 ////////////////////////

  for ( int i = 0 ; i < 8 ; i++ )
    lcd.createChar( i, block[i] );
  ///////////////
  pinMode(button, INPUT_PULLDOWN);         // define button as an input
  pinMode(led, OUTPUT);          // define LED as an output
  digitalWrite(led, LOW);
 /////////////////////
  Serial.begin(115200);
  lcd.begin(16, 2);
  pinMode(LED_BUILTIN, OUTPUT);
 pinMode(Vobutton, INPUT_PULLDOWN);
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}
long  lastT = 0;
//********************
void loop() {
////////////////////
 digitalWrite(PC13, HIGH);
  if ( (int)(millis() - lastT) < T_REFRESH )
    return;
  lastT += T_REFRESH;

  lastT += T_REFRESH;
  int anL = map( sqrt( analogRead( IN_LEFT  ) * 16 ), 0, 128, 0, 80 ); // sqrt to have non linear scale (better was log)
  //int anR = map( sqrt( analogRead( IN_RIGHT )*16 ),0,128,0,80 );// calibration *******************************************
  int anR = map( sqrt( analogRead( IN_RIGHT ) * 4 ), 0, 128, 0, 80 );
  /////////////////
  int ACin = map( sqrt( analogRead( IN_RIGHT ) * 4 ), 0, 128, 0, 80 );
  int ACf = map( sqrt( analogRead( IN_RIGHT ) * 4 ), 0, 128, 0, 80 );
  ///////////
  if (digitalRead(button) == HIGH) { // if button is pressed
    if (ledflag == 0) {           // and the status flag is LOW
      ledflag = 1;                // make status flag HIGH
      digitalWrite(led, HIGH);
    }                           //
    else {                        // otherwise...
      ledflag = 0;                // make status flag LOW
      digitalWrite(led, LOW);
    }
  }

  if (ledflag == 1) {           // status flag decides display mode
    // lcd.clear();
    bar( 0, anL );
    bar( 1, anR );
  }                           //
  else {
  ///////////////////////
lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print( currentaverage);// red line
  lcd.setCursor(5, 0);
  lcd.print((Vo - currentaverage), 0);
  //////////////////////
   // bar( 0, ACin );
    //bar( 1, ACf );
     bar( 1, currentaverage/40 );
  
  }
  //delay(10);                    // wait a sec for the
////////////////////
  if (digitalRead(Vobutton) == HIGH)
  {
    Vo = currentaverage;
  }

  previousaverage = currentaverage;
  currentaverage = average;
  //*******************************************************************************
  if (abs(currentaverage -  previousaverage) <  previousaverage / 70 ) // 100 = 1%
    //********************************************************************************
  {
    currentaverage = previousaverage;
  }
digitalWrite(PC13, LOW);
  total = total - readings[readIndex];
  readings[readIndex] = AmpsRMS;
  total = total + readings[readIndex];
  readIndex = readIndex + 1;
  if (readIndex >= numReadings) {
    readIndex = 0;
  }
  average = total / numReadings;

  Voltage = getVPP();
  VRMS = (Voltage / 2.0) * 0.707; //root 2 is 0.707
  // AmpsRMS = (VRMS * 1000)/mVperAmp;
  AmpsRMS = (VRMS * 1000);
  /////
  Serial.print(AmpsRMS);// blue
  // Serial.println(" ");
  Serial.print("\t");
  Serial.print( currentaverage + 8);//red
  Serial.print("\t");
  Serial.println(average + 10);// green
  //******************************************************
  if (abs(Vo -  currentaverage) > 3) // generator 1% changes = 12
    //********************************************************
  {
    //  digitalWrite(PB14, HIGH);
    // LED = 1;
    digitalWrite(LED_BUILTIN, HIGH);
  }
  else
  {
    // digitalWrite(PB14, LOW);
    //LED = 0;
    digitalWrite(LED_BUILTIN, LOW);
  }
/*
lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print( currentaverage);// red line
  lcd.setCursor(5, 0);
  lcd.print((Vo - currentaverage), 0);
*/
}

float getVPP()
{
  float result;
  int readValue;             //value read from the sensor
  int maxValue = 0;          // store max value here
  int minValue = 1024;          // store min value here

  uint32_t start_time = millis();
  // while((millis()-start_time) < 1000) //sample for 1 Sec
  //***************************************************************
  while ((millis() - start_time) < 20) // speed
    //****************************************************************
  {
    readValue = analogRead(sensorIn);
    // see if you have a new maxValue
    if (readValue > maxValue)
    {
      maxValue = readValue;
    }
    if (readValue < minValue)
    {
      minValue = readValue;
    }
  }
  result = ((maxValue - minValue) * 5.0) / 1024.0;
  return result;
}
}
Using digitalWrite(PC13, HIGH);and digitalWrite(PC13, LOW); in loop, I have a pulses on PC13 100 mS.
AC meter only 23 mS
Last edited by stan on Wed Nov 18, 2020 6:51 am, edited 1 time in total.
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

loop too slow

Post by stan »

Only AC meter is slow, bar mode is not affected

Code: Select all

  if (ledflag == 1) {           // status flag decides display mode
    // lcd.clear();                      // not affected
    bar( 0, anL );
    bar( 1, anR );
mlundin
Posts: 94
Joined: Wed Nov 04, 2020 1:20 pm
Answers: 6
Location: Sweden

Re: loop too slow

Post by mlundin »

You have duplicated lastT += T_REFRESH so the refresh interval is 2*T_REFRESH = 100ms. The getVPP() function takes 20ms. As for the refresh of the AC values, it is a mean value of 25 VPP samples and they are taken very 100ms so there is a 2.5s time constant before the new value is stable.
stan
Posts: 70
Joined: Wed Nov 11, 2020 7:40 pm

Re: loop too slow

Post by stan »

I removed one lastT += T_REFRESH reading still slow, your calculation 2.5 s = I agree with that, so I have to use different AC meter program.
Thanks.
I reduced T_REFRESH by 50 times and 2,5 s is change to 1 s, so there is something else slowing down AC meter

Code: Select all

//#define T_REFRESH    50           // msec bar refresh rate
#define T_REFRESH    1 
Bambo
Posts: 75
Joined: Wed Jan 15, 2020 8:36 pm

Re: loop too slow

Post by Bambo »

Hi, you might want to look into Hardware Timers if you are finding the main loop too slow: https://github.com/stm32duino/wiki/wiki ... er-library
Post Reply

Return to “Projects”