Trouble making 8x8 matrix with ''timelapse''

I’m not sure was that suitable word, timelapse I mean but couldn’t figure out better.
So what I’m trying to accomplish is that value is taken from ADC, converted to bar graph or dot graph, what is then stored and displayed as scrolling effect in matrix. And that most present value would be on either end of matrix. I can make scrolling text matrises, but would like to learn matrix that would show some actual data.
So far, I’ve managed actually to save that mapped value to array, as well as display it on matrix. But, there is still issues: the matrix updates too slowly, and causes flicker (refresh is under 60hz so flicker is seen).
If i increase refresh speed, array gets filled too quickly.
Ideas hints and corrections welcome! Runnin’ out of ideas here :confused:
Following sketch allows scrolling to be seen, but not nicely (did my best to comment code):
And before i forget, circuit is two chained 74595’s, latter takes care of columns w/ttl array, and first handles rows.

int dataPin = 2;        //  ic: 14, ser_in Define which pins will be used for the Shift Register control
int latchPin = 3;      //   ic:12         silkscreen numbers!
int clockPin = 4;      //   ic:11

const unsigned int numReadings = 8;          //matrix is 8-wide
unsigned int analogvals[numReadings];       //array where to store 8-readings from ADC
unsigned int i = 0;
unsigned int array[8];   //array where to store mapped values from ADC
byte mappedValue[9] = {0, 1, 3, 7, 15, 31, 63, 127}; //bar mode

void setup()
{
  DDRD = DDRD | B11111100;  //port registers used to set pin directions
}

void loop()
{

  int j = map( analogRead (A0), 0, 1023, 0, 8 );  //read and map
  j = mappedValue[j]; //convert mapped value to byte array
  //analogvals[i] = j;   //array where to store direct values from ADC
  array[i] = j;        //array where to store mapped values, taken from mappedValue array
  i++;                  //increment what array to read/write
  if (i >= numReadings)
  {
    i = 0; //reset to beginning of array, so you don't try to save readings outside of the bounds of the array
  }

  PORTD = B00001000; //close latch pin
  shiftOut(dataPin, clockPin, MSBFIRST, 1 << i);       //what column to power, only one active/time
  shiftOut(dataPin, clockPin, MSBFIRST, array[i]);     //data itself shown, taken from array where stored the mapped values
  PORTD = B00000000;  //open latch pin
  delay(5);

}

Any ideas? you guys need more information?

fezder: there is still issues: the matrix updates too slowly, and causes flicker (refresh is under 60hz so flicker is seen) if i increase refresh speed, array gets filled too quickly.

I've used '595 shift registers to control LED arrays. I haven't done this with the Arduino yet but I'll take a look at your code and see if I can offer some suggestions.

I recently uploaded a long boring video of one of my LED experiments. At time marker 7:45 (I told you it was long) is a graph type display. I think this is the sort of thing you want to do right?

From your description and a quick look at your code, I'm guessing you need an inner loop to keep the LEDs cycling while the pattern is stationary.

I will ask a favor in return for attempting to help. Please use proper capitalization in your posts (this is mentioned in the "How to use this forum" thread, so I'm pretty sure I'm not the only one bothered by a lowercase letter "i" where a capital "I" should be used (it's like fingernails on a chalkboard)).

Thanks Duane, I don't mind long videos, as long there is interesting content in there. Like some videos where there is 30 minutes of unnecessary talkshow at beginning and topic itself takes 5 minutes.... But yes, the effect I'm after is just like that what is displayed around 8.15 marker (leds lighting on and scrolled, so we're on the same page) Nice video, that reminds that I must talk more when I do my own videos (English Isn't my first language) As for that favor you asked, I'm not quite sure what do you mean? I do my best to avoid grammar errors, but of course, mistakes can and most likely will happen. Thanks for pointing out stuff people don't like around here!. I did read that ''how-to'' (read it first time I registered here, that's why they are) One part I did notice about capitals: i've and I've, is this what you were after?

Slight progress, I now have loop that fills the array even with right, readable values, as well as other loop made with ISR that refreshes screen.
So partially better, only issue is that screen can update the new value anywhere, not in other end of matrix as intended. And, the matrix end where scrolling starts is bit more brighter than rest, but that fiddled as OK with that small delay inside ISR.
Current code:

int dataPin = 2;        //IC 14       //Define which pins will be used for the Shift Register control
int latchPin = 3;       //IC 12
int clockPin = 4;       //IC 11
                        //OE-GND, can show mumbo-jumbo at beginning, but no issue
                        //MR-VCC
int delaytime = 1, timer, timerPrev = 0;
int shift = 0;
int len = 8;
static uint8_t  x [8];
int m;
const unsigned int numReadings = 8;          //matrix is 8-wide, 8 readings is enough
unsigned int analogvals[numReadings];       //array where to store 8-readings from ADC
unsigned int i = 0;
byte mappedValue[8] = {0, 1, 3, 7, 15, 31, 63, 127}; //bar mode



void setup()                  //setup, runs once
{
  DDRD = DDRD | B00011100;    //set pins as output (
  noInterrupts();
  TCCR1A = 0;
  TCCR1B = 0;                
  TCNT1 = 0;                  
  OCR1A = 34286;              //compare register
  TCCR1B |= (1 << WGM12);     // CTC mode, clear when compare matches
  TCCR1B |= (0 << CS10);      // 8 prescale
  TCCR1B |= (1 << CS11);      // 8 prescale
  TCCR1B |= (0 << CS12);      // 8 prescale
  TIMSK1 |= (1 << OCIE1A);    //enable timer compare interrupt
  interrupts();
}

void loop()                        //loop that takes care of loading the array as well as mapping
{
  int j = map( analogRead (A0), 0, 1023, 0, 8 );  //read and map
  j = mappedValue[j];                             //convert mapped value to byte array
  x[m] = j;                                       //array where to store mapped values, taken from mappedValue array
  m++;                                            //increment what array to read/write
  if (m >= numReadings)
  {
    m = 0;                                        //reset to beginning of array, so you don't try to save readings outside of the bounds of the array
  }
  delay(100);                                     //10 samples per second
}

ISR(TIMER1_COMPA_vect)              //ISR, refresh screen
{
  timer = millis ();
  if (timer - timerPrev > 200)
  {
    shift++;
    if (shift == len)shift = 0;
    timerPrev = timer;
  }
  for (int i = 0; i < 8; i++)                               //counter for columns
  {
    PORTD = B00000000;                                      //turn latch low
    shiftOut(dataPin, clockPin, MSBFIRST, 1 << i);          //(what columns to power)
    shiftOut(dataPin, clockPin, LSBFIRST, x[i]); //(what data to draw)
    PORTD = B00001000;                                      //turn latch on->show screen
    delayMicroseconds(1000);                                //is this unnecessary?  matrix behaves better, but inside ISR delays should be avoided yes?
  }
}

I don’t have LEDs wired up to test this so there’s very little change this will work.

const int DATA_PIN = 2;       //  ic: 14, ser_in Define which pins will be used for the Shift Register control
const int LATCH_PIN = 3;      //   ic:12         silkscreen numbers!
const int CLOCK_PIN = 4;      //   ic:11
const byte END_DATA_MARKER = 9;
const boolean TEST_MODE_FLAG = 1;
const boolean DEFAULT_REVERSE_FLAG = 0;
const byte NUMBER_OF_READINGS = 8;          //matrix is 8-wide
const byte MAX_COLUMN_INDEX = NUMBER_OF_READINGS - 1;
unsigned int analogvals[NUMBER_OF_READINGS];       //array where to store 8-readings from ADC
unsigned int pixelArray[8];   //array where to store mapped values from ADC
byte solidLedColumn[9] = {0, 1, 3, 7, 15, 31, 63, 127}; // was "mappedValue" //bar mode
byte testData[] = {0, 1, 3, 4, 3, 5, 4, 3, 6, 6, 7, 8, 8, 7, 5, 3, 4, 3, 2, 1, 0, END_DATA_MARKER};
byte testDataIndex = 0;
byte columnCount = 0;
byte activeColumn = 0;
const unsigned int SPEED_OPTIONS = 8;
const unsigned int MAX_SPEED = SPEED_OPTIONS - 1;
const int DEFAULT_SPEED = SPEED_OPTIONS / 2;
const unsigned int REFRESH_CYCLES_AT_LOWEST_SPEED = 100;
const unsigned int REFRESH_CYCLES_AT_HIGHEST_SPEED = 2;
unsigned int speedToCyclesTable[SPEED_OPTIONS];
unsigned int cyclesToUpdate;

void setup()
{
  fillTable();
  cyclesToUpdate = speedToCyclesTable[DEFAULT_SPEED];
  DDRD = DDRD | B11111100;  //port registers used to set pin directions  
}

void loop()
{
  byte activeLeds;
  
  if (TEST_MODE_FLAG)
  {
    if (testData[testDataIndex] == END_DATA_MARKER)
    {
      testDataIndex = 0;
    }
    activeLeds = testData[testDataIndex++];
  }
  else
  {
    activeLeds = map( analogRead (A0), 0, 1023, 0, 8 );  //read and map
  }

  if (activeColumn == MAX_COLUMN_INDEX)
  {
    shiftArray(DEFAULT_REVERSE_FLAG);
  }

  pixelArray[activeColumn] = solidLedColumn[activeLeds];

  cycleLeds(cyclesToUpdate);

  columnCount++;
  activeColumn = constrain(activeColumn + 1, 0, MAX_COLUMN_INDEX);
}

void cycleLeds(unsigned int cycles)
{
  for (int i = 0; i < cycles; i++)
  {
    for (int j = 0; j < NUMBER_OF_READINGS; j++)
    {
      PORTD = B00001000; //close latch pin
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, 1 << j);       //what column to power, only one active/time
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, pixelArray[j]);     //data itself shown, taken from array where stored the mapped values
      PORTD = B00000000;  //open latch pin
    }
  }
}

void shiftArray(boolean reverseFlag)
{
  if (reverseFlag)
  {
    for (int i = NUMBER_OF_READINGS - 1; i > 0 ; i--)
    {
      pixelArray[i] = pixelArray[i - 1];
    }
    pixelArray[0] = 0;
  }
  else
  {
    for (int i = 0; i < NUMBER_OF_READINGS - 1; i++)
    {
      pixelArray[i] = pixelArray[i + 1];
    }
    pixelArray[NUMBER_OF_READINGS - 1] = 0;
  }
}

void fillTable()
{
  unsigned int cyclesRange = 1 + REFRESH_CYCLES_AT_HIGHEST_SPEED - REFRESH_CYCLES_AT_HIGHEST_SPEED;

  for (int i = 0; i < SPEED_OPTIONS; i++)
  {
    speedToCyclesTable[i] = REFRESH_CYCLES_AT_HIGHEST_SPEED + (i * cyclesRange / MAX_SPEED);
  }
}

I haven’t looked through your latest code.

I think the biggest difference in the code I posted from your original code is the addition of the “cycleLeds()” function. You need something to cycle through the LEDs even when they’re not actively moving.

If I have time, I’ll wire up a couple shift registers to some of my monochrome LED arrays and see if I can test the code myself.

Just so there were something interesting to graph, I filled a “testData” array with some dummy values. If you want to graph the analog input change the constant “TEST_MODE_FLAG” from one to zero.

fezder:
One part i did notice about capitals: i’ve and I’ve, is this what you were after?

Yes. Exactly. I’ll need to do something so that sort of thing doesn’t bug me so much because it’s becoming very common (but it’s still completely WRONG! :slight_smile: ).

It means a lot if someone is willing to even look code, nevertheless write one to test out. Takes a while to translate code what is happening and when, i haven't done anything ''useful'' as of yet, but we all start with basics.

As for grammar issue, I too have things that annoy, like excess use of capitals, no sentences (all written in one looooong sentence). We all have something that buggers. But, I'll try to make mine grammar better now when it comes using capitals in right place. Some people say that mine english is better than some who have english as native, but that can be just talk...

But, back to topic, your code didn't thankfully whine about any errors, but with normal setting, matrix updates too fast. Did change values of these back and forth, I mean bigger and lower but no avail. Also did change that TEST_MODE_FLAG to show analogue data, and it does show change, but too fast So, in default it shows as fast-going wave. I'd take video but my camera is slowish

const unsigned int MAX_SPEED = SPEED_OPTIONS - 1;
const int DEFAULT_SPEED = SPEED_OPTIONS / 2;
const unsigned int REFRESH_CYCLES_AT_LOWEST_SPEED = 100;
const unsigned int REFRESH_CYCLES_AT_HIGHEST_SPEED = 2;

I added a short pause to let each row of LEDs to be on for a bit. I also increased the number of cycles by a factor of ten. It’s like the code below will be too slow.

const int DATA_PIN = 2;       //  ic: 14, ser_in Define which pins will be used for the Shift Register control
const int LATCH_PIN = 3;      //   ic:12         silkscreen numbers!
const int CLOCK_PIN = 4;      //   ic:11
const byte END_DATA_MARKER = 9;
const boolean TEST_MODE_FLAG = 1;
const boolean DEFAULT_REVERSE_FLAG = 0;
const byte NUMBER_OF_READINGS = 8;          //matrix is 8-wide
const byte MAX_COLUMN_INDEX = NUMBER_OF_READINGS - 1;
unsigned int analogvals[NUMBER_OF_READINGS];       //array where to store 8-readings from ADC
unsigned int pixelArray[8];   //array where to store mapped values from ADC
byte solidLedColumn[9] = {0, 1, 3, 7, 15, 31, 63, 127}; // was "mappedValue" //bar mode
byte testData[] = {0, 1, 3, 4, 3, 5, 4, 3, 6, 6, 7, 8, 8, 7, 5, 3, 4, 3, 2, 1, 0, END_DATA_MARKER};
byte testDataIndex = 0;
byte columnCount = 0;
byte activeColumn = 0;
const unsigned int SPEED_OPTIONS = 8;
const unsigned int MAX_SPEED = SPEED_OPTIONS - 1;
const int DEFAULT_SPEED = SPEED_OPTIONS / 2;
const unsigned int REFRESH_CYCLES_AT_LOWEST_SPEED = 1000;
const unsigned int REFRESH_CYCLES_AT_HIGHEST_SPEED = 20;
const unsigned long VERY_SHORT_PAUSE = 100;
unsigned int speedToCyclesTable[SPEED_OPTIONS];
unsigned int cyclesToUpdate;

void setup()
{
  fillTable();
  cyclesToUpdate = speedToCyclesTable[DEFAULT_SPEED];
  DDRD = DDRD | B11111100;  //port registers used to set pin directions  
}

void loop()
{
  byte activeLeds;
  
  if (TEST_MODE_FLAG)
  {
    if (testData[testDataIndex] == END_DATA_MARKER)
    {
      testDataIndex = 0;
    }
    activeLeds = testData[testDataIndex++];
  }
  else
  {
    activeLeds = map( analogRead (A0), 0, 1023, 0, 8 );  //read and map
  }

  if (activeColumn == MAX_COLUMN_INDEX)
  {
    shiftArray(DEFAULT_REVERSE_FLAG);
  }

  pixelArray[activeColumn] = solidLedColumn[activeLeds];

  cycleLeds(cyclesToUpdate);

  columnCount++;
  activeColumn = constrain(activeColumn + 1, 0, MAX_COLUMN_INDEX);
}

void cycleLeds(unsigned int cycles)
{
  for (int i = 0; i < cycles; i++)
  {
    for (int j = 0; j < NUMBER_OF_READINGS; j++)
    {
      PORTD = B00001000; //close latch pin
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, 1 << j);       //what column to power, only one active/time
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, pixelArray[j]);     //data itself shown, taken from array where stored the mapped values
      PORTD = B00000000;  //open latch pin
      delayMicroseconds(VERY_SHORT_PAUSE);
    }
  }
}

void shiftArray(boolean reverseFlag)
{
  if (reverseFlag)
  {
    for (int i = NUMBER_OF_READINGS - 1; i > 0 ; i--)
    {
      pixelArray[i] = pixelArray[i - 1];
    }
    pixelArray[0] = 0;
  }
  else
  {
    for (int i = 0; i < NUMBER_OF_READINGS - 1; i++)
    {
      pixelArray[i] = pixelArray[i + 1];
    }
    pixelArray[NUMBER_OF_READINGS - 1] = 0;
  }
}

void fillTable()
{
  unsigned int cyclesRange = 1 + REFRESH_CYCLES_AT_HIGHEST_SPEED - REFRESH_CYCLES_AT_HIGHEST_SPEED;

  for (int i = 0; i < SPEED_OPTIONS; i++)
  {
    speedToCyclesTable[i] = REFRESH_CYCLES_AT_HIGHEST_SPEED + (i * cyclesRange / MAX_SPEED);
  }
}

The constants to change are “REFRESH_CYCLES_AT_LOWEST_SPEED”, “REFRESH_CYCLES_AT_HIGHEST_SPEED” and “VERY_SHORT_PAUSE”.

The larger the above values are, the slower the display should move.

The array “speedToCyclesTable” should make it possible to vary the speed at some future time. For now the only speed setting is “DEFAULT_SPEED”.

Hmm, well that seemed to do trick. Now display scrolls at nice speed and shows data as intened. All I can say is thanks :) Just takes a while to implement this to future projects, and actually understand what is happening.... And it doesn't take much memory either.

fezder:
Hmm, well that seemed to do trick. Now display scrolls at nice speed and shows data as intened.
All i can say is thanks :slight_smile:
Just takes a while to implement this to future projects, and actually understand what is happening…
And it doesn’t take much memory either.

Good to hear.

I’m sure there are better ways to do this sort of thing. My guess is some sort of timer interrupt could be used to keep the LED refreshed but I’m still relatively new to the Arduino and I don’t know how to code for a timer interrupt (the microcontroller I use in most of my projects doesn’t have interrupts).

It should be easy to make the scroll speed adjustable. Either terminal commands, knob or buttons could be added to adjust the scroll speed. Let me know if you need help making these sorts of changes.

I'm glad to hear anything you're willing to share! From your code I'd never quessed you as new to Arduino. I haven't much used interrupts, only with POV-clock I made recently (well, It's not ''done'' yet, haven't decided whether it will be clock or something else. It was good advertising in local EE-meeting)https://www.youtube.com/watch?v=ub45muUcZGs Most recent variation is with potentiometer controlled, potentiometer controls how much is visible

Since the main problem is solved, I figured to keep (solved) tag, but please tell if you think it would be wise to delete that solved part…
But, here’s that code with potentiometer speed control, just insterted potentiometer to map variable speed.
IIRC, ADC in arduino is multiplexed so it can cause missed data? That said, perhaps interrupt with rotary encoder/buttons, or serial input with keyboard would eliminate that problem, thinking out loud.
Off topic, but I also yesterday tried playing with FFT, managed to set display as bar display, but output doesn’t make sense; about half of matrix is lit all the time and bars drop with music beat, as in my understanding some bars should rise and some drop

const int DATA_PIN = 2;       //  ic: 14, ser_in Define which pins will be used for the Shift Register control
const int LATCH_PIN = 3;      //   ic:12         silkscreen numbers!
const int CLOCK_PIN = 4;      //   ic:11
const byte END_DATA_MARKER = 9;
const boolean TEST_MODE_FLAG = 1;
const boolean DEFAULT_REVERSE_FLAG = 0;
const byte NUMBER_OF_READINGS = 8;          //matrix is 8-wide
const byte MAX_COLUMN_INDEX = NUMBER_OF_READINGS - 1;
unsigned int analogvals[NUMBER_OF_READINGS];       //array where to store 8-readings from ADC
unsigned int pixelArray[8];   //array where to store mapped values from ADC
byte solidLedColumn[9] = {0, 1, 3, 7, 15, 31, 63, 127}; // was "mappedValue" //bar mode
byte testData[] = {0, 1, 3, 4, 3, 5, 4, 3, 6, 6, 7, 8, 8, 7, 5, 3, 4, 3, 2, 1, 0, END_DATA_MARKER};
byte testDataIndex = 0;
byte columnCount = 0;
byte activeColumn = 0;
const unsigned int SPEED_OPTIONS = 8;
const unsigned int MAX_SPEED = SPEED_OPTIONS - 1;
const int DEFAULT_SPEED = SPEED_OPTIONS / 2;
const unsigned int REFRESH_CYCLES_AT_LOWEST_SPEED = 1000;
const unsigned int REFRESH_CYCLES_AT_HIGHEST_SPEED = 20;
 unsigned long VERY_SHORT_PAUSE;
unsigned int speedToCyclesTable[SPEED_OPTIONS];
unsigned int cyclesToUpdate;

void setup()
{
  fillTable();
  cyclesToUpdate = speedToCyclesTable[DEFAULT_SPEED];
  DDRD = DDRD | B11111100;  //port registers used to set pin directions
}

void loop()
{
  VERY_SHORT_PAUSE = map (analogRead(A1), 0,1023, 0,1000);/*this controls speed of scrolling, dunno what arduino likes if i read two at same time, but IIRC ADC is multiplexed so it takes what time it needs to read */
  byte activeLeds;
  if (TEST_MODE_FLAG)
  {
    if (testData[testDataIndex] == END_DATA_MARKER)
    {
      testDataIndex = 0;
    }
    activeLeds = testData[testDataIndex++];
  }
  else
  {
    activeLeds = map( analogRead (A0), 0, 1023, 0, 8 );  //read and map
  }

  if (activeColumn == MAX_COLUMN_INDEX)
  {
    shiftArray(DEFAULT_REVERSE_FLAG);
  }

  pixelArray[activeColumn] = solidLedColumn[activeLeds];

  cycleLeds(cyclesToUpdate);

  columnCount++;
  activeColumn = constrain(activeColumn + 1, 0, MAX_COLUMN_INDEX);
}

void cycleLeds(unsigned int cycles)
{
  for (int i = 0; i < cycles; i++)
  {
    for (int j = 0; j < NUMBER_OF_READINGS; j++)
    {
      PORTD = B00001000; //close latch pin
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, 1 << j);       //what column to power, only one active/time
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, pixelArray[j]);     //data itself shown, taken from array where stored the mapped values
      PORTD = B00000000;  //open latch pin
      delayMicroseconds(VERY_SHORT_PAUSE);
    }
  }
}

void shiftArray(boolean reverseFlag)
{
  if (reverseFlag)
  {
    for (int i = NUMBER_OF_READINGS - 1; i > 0 ; i--)
    {
      pixelArray[i] = pixelArray[i - 1];
    }
    pixelArray[0] = 0;
  }
  else
  {
    for (int i = 0; i < NUMBER_OF_READINGS - 1; i++)
    {
      pixelArray[i] = pixelArray[i + 1];
    }
    pixelArray[NUMBER_OF_READINGS - 1] = 0;
  }
}

void fillTable()
{
  unsigned int cyclesRange = 1 + REFRESH_CYCLES_AT_HIGHEST_SPEED - REFRESH_CYCLES_AT_HIGHEST_SPEED;

  for (int i = 0; i < SPEED_OPTIONS; i++)
  {
    speedToCyclesTable[i] = REFRESH_CYCLES_AT_HIGHEST_SPEED + (i * cyclesRange / MAX_SPEED);
  }
}

If you added the following the beginning of the loop function, I think it should adjust the scroll speed.

  byte scrollSpeed = map(analogRead(A1), 0, 1023, 0, MAX_SPEED);
  cyclesToUpdate = speedToCyclesTable[scrollSpeed];

I don't know the details of the Arduino's ADC.

I posted some code to average ADC readings not too long ago. It uses a ring buffer to average the ADC readings.

The constant "POWER_OF_TWO_TO_AVERAGE" sets the averaging buffer size. When buffers are a power of two in size, the math required to average the buffer is faster than when using other buffer sizes.

In stead of reading the pot every loop, it might be a good idea to have some sort of timer to indicate when to read the scroll speed pot.

Let me know how just adding the two lines above works.

Hmm, not sure why but adding those didn’t effect anything
Just placed them at the beginning of loop(), like you asked

const int DATA_PIN = 2;       //  ic: 14, ser_in Define which pins will be used for the Shift Register control
const int LATCH_PIN = 3;      //   ic:12         silkscreen numbers!
const int CLOCK_PIN = 4;      //   ic:11
const byte END_DATA_MARKER = 9;
const boolean TEST_MODE_FLAG = 1;
const boolean DEFAULT_REVERSE_FLAG = 0;
const byte NUMBER_OF_READINGS = 8;          //matrix is 8-wide
const byte MAX_COLUMN_INDEX = NUMBER_OF_READINGS - 1;
unsigned int analogvals[NUMBER_OF_READINGS];       //array where to store 8-readings from ADC
unsigned int pixelArray[8];   //array where to store mapped values from ADC
byte solidLedColumn[9] = {0, 1, 3, 7, 15, 31, 63, 127}; // was "mappedValue" //bar mode
byte testData[] = {0, 1, 3, 4, 3, 5, 4, 3, 6, 6, 7, 8, 8, 7, 5, 3, 4, 3, 2, 1, 0, END_DATA_MARKER};
byte testDataIndex = 0;
byte columnCount = 0;
byte activeColumn = 0;
const unsigned int SPEED_OPTIONS = 8;
const unsigned int MAX_SPEED = SPEED_OPTIONS - 1;
const int DEFAULT_SPEED = SPEED_OPTIONS / 2;
const unsigned int REFRESH_CYCLES_AT_LOWEST_SPEED = 1000;
const unsigned int REFRESH_CYCLES_AT_HIGHEST_SPEED = 20;
const unsigned long VERY_SHORT_PAUSE = 100;
unsigned int speedToCyclesTable[SPEED_OPTIONS];
unsigned int cyclesToUpdate;

void setup()
{
  fillTable();
  cyclesToUpdate = speedToCyclesTable[DEFAULT_SPEED];
  DDRD = DDRD | B11111100;  //port registers used to set pin directions
}

void loop()
{
  byte scrollSpeed = map(analogRead(A1), 0, 1023, 0, MAX_SPEED);
  cyclesToUpdate = speedToCyclesTable[scrollSpeed];
  byte activeLeds;
  if (TEST_MODE_FLAG)
  {
    if (testData[testDataIndex] == END_DATA_MARKER)
    {
      testDataIndex = 0;
    }
    activeLeds = testData[testDataIndex++];
  }
  else
  {
    activeLeds = map( analogRead (A0), 0, 1023, 0, 8 );  //read and map
  }

  if (activeColumn == MAX_COLUMN_INDEX)
  {
    shiftArray(DEFAULT_REVERSE_FLAG);
  }

  pixelArray[activeColumn] = solidLedColumn[activeLeds];

  cycleLeds(cyclesToUpdate);

  columnCount++;
  activeColumn = constrain(activeColumn + 1, 0, MAX_COLUMN_INDEX);
}

void cycleLeds(unsigned int cycles)
{
  for (int i = 0; i < cycles; i++)
  {
    for (int j = 0; j < NUMBER_OF_READINGS; j++)
    {
      PORTD = B00001000; //close latch pin
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, 1 << j);       //what column to power, only one active/time
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, pixelArray[j]);     //data itself shown, taken from array where stored the mapped values
      PORTD = B00000000;  //open latch pin
      delayMicroseconds(VERY_SHORT_PAUSE);
    }
  }
}

void shiftArray(boolean reverseFlag)
{
  if (reverseFlag)
  {
    for (int i = NUMBER_OF_READINGS - 1; i > 0 ; i--)
    {
      pixelArray[i] = pixelArray[i - 1];
    }
    pixelArray[0] = 0;
  }
  else
  {
    for (int i = 0; i < NUMBER_OF_READINGS - 1; i++)
    {
      pixelArray[i] = pixelArray[i + 1];
    }
    pixelArray[NUMBER_OF_READINGS - 1] = 0;
  }
}

void fillTable()
{
  unsigned int cyclesRange = 1 + REFRESH_CYCLES_AT_HIGHEST_SPEED - REFRESH_CYCLES_AT_HIGHEST_SPEED;

  for (int i = 0; i < SPEED_OPTIONS; i++)
  {
    speedToCyclesTable[i] = REFRESH_CYCLES_AT_HIGHEST_SPEED + (i * cyclesRange / MAX_SPEED);
  }
}

Just to make sure, you wired up another pot?

Is it the same kind of pot you were already using?

I use same pot, no other pot in circuit. Test signal coming out nice and smoothly, that random-bits you placed on code

Have you tried the earlier code with "TEST_MODE_FLAG" set to zero?

You had the scroll speed pot connected to A1?

Have you successfully run any of the analogRead demos?

It seems to cause misreadings when only one pot is connected, when I change speed pot value, output also changes. Suppose I could wire other pot to test. So, when i test with only one pot connected to A1, it behaves like in normal speed setting. Finger is enough to create reading, seems ADC doesn't like floating values, when not connected to anything

The code is likely reading from the ADC too frequently.

I'll see about adding a timer for checking the ADC and it might be a good idea to average multiple readings.

I might have time tomorrow to look at this.

The code below compiles but I’d be surprised if it works correctly.

const int DATA_PIN = 2;       //  ic: 14, ser_in Define which pins will be used for the Shift Register control
const int LATCH_PIN = 3;      //   ic:12         silkscreen numbers!
const int CLOCK_PIN = 4;      //   ic:11
const byte END_DATA_MARKER = 9;
const boolean TEST_MODE_FLAG = 1;
const boolean DEFAULT_REVERSE_FLAG = 0;
const byte NUMBER_OF_READINGS = 8;          //matrix is 8-wide
const byte MAX_COLUMN_INDEX = NUMBER_OF_READINGS - 1;
unsigned int analogvals[NUMBER_OF_READINGS];       //array where to store 8-readings from ADC
unsigned int pixelArray[8];   //array where to store mapped values from ADC
byte solidLedColumn[9] = {0, 1, 3, 7, 15, 31, 63, 127}; // was "mappedValue" //bar mode
byte testData[] = {0, 1, 3, 4, 3, 5, 4, 3, 6, 6, 7, 8, 8, 7, 5, 3, 4, 3, 2, 1, 0, END_DATA_MARKER};
byte testDataIndex = 0;
byte columnCount = 0;
byte activeColumn = 0;
const unsigned int SPEED_OPTIONS = 8;
const unsigned int MAX_SPEED = SPEED_OPTIONS - 1;
const int DEFAULT_SPEED = SPEED_OPTIONS / 2;
const unsigned int REFRESH_CYCLES_AT_LOWEST_SPEED = 1000;
const unsigned int REFRESH_CYCLES_AT_HIGHEST_SPEED = 20;
const unsigned long VERY_SHORT_PAUSE = 100;
unsigned int speedToCyclesTable[SPEED_OPTIONS];
unsigned int cyclesToUpdate;

const byte POT_PIN[] = {A0, A1};

 /****** Instructions ******/
 // The constant "POWER_OF_TWO_TO_AVERAGE" sets the size of
// the ring buffer used to average the pot values.
// Large buffers will provide smoother motion but large
// buffers also slow down response times.
// The minimum value of "POWER_OF_TWO_TO_AVERAGE"
// is one. If zero is used, the code will need to be
// modified.
const long POWER_OF_TWO_TO_AVERAGE = 4;          // User changeable.
// Changing "POWER_OF_TWO_TO_AVERAGE" changes several other constants.
// The constants "BUFFER_SIZE" and "BUFFER_LIMIT" are calculated based on "POWER_OF_TWO_TO_AVERAGE".

 /****** Instructions ******/
// It is important some time constants are larger than
// other time constants.
// "ANALOG_READ_PERIOD" must be smaller than "SERVO_PERIOD".
// "SERVO_PERIOD" must be smaller than "DEBUG_PERIOD".
// To reduce the stutter caused from multiple
// debug stateements at once, the debug data
// is staggered. Data from a single servo is
// displayted
const unsigned long ANALOG_READ_PERIOD = 5000;  // read pots at 200Hz "ANALOG_READ_PERIOD" must be <= "DEBUG_PERIOD"
const unsigned long DEBUG_PERIOD = 5000000;  // update serial at 4Hz "DEBUG_PERIOD" must be >= "SERVO_PERIOD"

const int BUFFER_SIZE = 1 << POWER_OF_TWO_TO_AVERAGE; // Do not change.
const int BUFFER_LIMIT = BUFFER_SIZE - 1;             // Do not change.

const int POTS_IN_USE = 2;
long averagingBuffer[POTS_IN_USE][BUFFER_SIZE];
int bufferIndex = 0;
long servoPosition[POTS_IN_USE];
long servoSpeed[POTS_IN_USE];

long bufferTotal[POTS_IN_USE];
unsigned long lastDebug;
unsigned long lastAnalogRead;

void setup()
{
  Serial.begin(115200);
   for (int i = 0; i < POTS_IN_USE; i++)
  {
       bufferTotal[i] = 0;
       for (int j = 0; j < BUFFER_SIZE; j++) // Fill buffer with start position.
    {
           averagingBuffer[i][j] = analogRead(POT_PIN[i]);
           bufferTotal[i] += averagingBuffer[i][j];
      delayMicroseconds(ANALOG_READ_PERIOD);
       
    } 
  }
   

  fillTable();
  cyclesToUpdate = speedToCyclesTable[DEFAULT_SPEED];
  DDRD = DDRD | B11111100;  //port registers used to set pin directions

  lastDebug = micros();
   lastAnalogRead = lastDebug;
}

void loop()
{
  byte activeLeds;
  checkAnalogReadTime();
  checkDebugTime();
  byte scrollSpeed = map(bufferTotal[1] >> POWER_OF_TWO_TO_AVERAGE, 0, 1023, 0, MAX_SPEED);
  cyclesToUpdate = speedToCyclesTable[scrollSpeed];

  if (TEST_MODE_FLAG)
  {
    if (testData[testDataIndex] == END_DATA_MARKER)
    {
      testDataIndex = 0;
    }
    activeLeds = testData[testDataIndex++];
  }
  else
  {
    activeLeds = map(bufferTotal[0] >> POWER_OF_TWO_TO_AVERAGE, 0, 1023, 0, 8 );  //read and map
  }

  if (activeColumn == MAX_COLUMN_INDEX)
  {
    shiftArray(DEFAULT_REVERSE_FLAG);
  }

  pixelArray[activeColumn] = solidLedColumn[activeLeds];

  cycleLeds(cyclesToUpdate);

  columnCount++;
  activeColumn = constrain(activeColumn + 1, 0, MAX_COLUMN_INDEX);
}

void cycleLeds(unsigned int cycles)
{
  for (int i = 0; i < cycles; i++)
  {
    for (int j = 0; j < NUMBER_OF_READINGS; j++)
    {
      PORTD = B00001000; //close latch pin
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, 1 << j);       //what column to power, only one active/time
      shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, pixelArray[j]);     //data itself shown, taken from array where stored the mapped values
      PORTD = B00000000;  //open latch pin
      delayMicroseconds(VERY_SHORT_PAUSE);
    }
    checkAnalogReadTime();
  }
}

void checkAnalogReadTime()
{
   if (micros() - lastAnalogRead > ANALOG_READ_PERIOD)
  {
    lastAnalogRead += ANALOG_READ_PERIOD;
    long potInput;

    bufferIndex++;
    bufferIndex &= BUFFER_LIMIT;

    for (int i = 0; i < POTS_IN_USE; i++)
    {
      potInput = analogRead(POT_PIN[i]);
           
      bufferTotal[i] -= averagingBuffer[i][bufferIndex]; // out with the old
      averagingBuffer[i][bufferIndex] = potInput;
      bufferTotal[i] += averagingBuffer[i][bufferIndex]; // in with the new
         
    }
     
  }
}

void shiftArray(boolean reverseFlag)
{
  if (reverseFlag)
  {
    for (int i = NUMBER_OF_READINGS - 1; i > 0 ; i--)
    {
      pixelArray[i] = pixelArray[i - 1];
    }
    pixelArray[0] = 0;
  }
  else
  {
    for (int i = 0; i < NUMBER_OF_READINGS - 1; i++)
    {
      pixelArray[i] = pixelArray[i + 1];
    }
    pixelArray[NUMBER_OF_READINGS - 1] = 0;
  }
}

void fillTable()
{
  unsigned int cyclesRange = 1 + REFRESH_CYCLES_AT_HIGHEST_SPEED - REFRESH_CYCLES_AT_HIGHEST_SPEED;

  for (int i = 0; i < SPEED_OPTIONS; i++)
  {
    speedToCyclesTable[i] = REFRESH_CYCLES_AT_HIGHEST_SPEED + (i * cyclesRange / MAX_SPEED);
  }
}

byte checkDebugTime()
// Called from "controlServo" function.
// This method checks to see if it's time to
// display data and returns the servo
// id number of the servo to debug.
{
   byte debugFlag = POTS_IN_USE;
   if (micros() - lastDebug > DEBUG_PERIOD)
  {
    lastDebug += DEBUG_PERIOD;
    debugPots();
  }
}

void debugPots()
// Called from "controlServo" function.
// Serial output slows down code execution.
// It would probably be a good idea to remove this section of code
// once the program is working as hoped and when serial
// output is now longer desired.
{
   Serial.print(F("pot # 0 = "));
   Serial.print(bufferTotal[0] >> POWER_OF_TWO_TO_AVERAGE, DEC);
   Serial.print(F(", pot # 1 = "));
   Serial.println(bufferTotal[1] >> POWER_OF_TWO_TO_AVERAGE, DEC);
}