0
\$\begingroup\$

Works fine with internal 8mhz, but when change to 32.7Khz, the multiplexing led display is not working properly (it's flashing very randomly). is this the limit of low clock speed or is there a problem to my code?

Timer0 is for multiplexing the 7-segment display; timer2 is for an external clock counting.

I also have played around the TCNT0, ie, to increase the multiplexing speed, in the interrupt, but with no luck;

///////////////////////////////////////////////////
// B1, B2, D3, D5, D6, B3, D2, D4 (+) active HIGH
// B0, D7, B5, B4 (-) active LOW
///////////////////////////////////////////////////
#include <avr/io.h> 
#include <avr/interrupt.h>

int8_t portA = 0b11011100;
int8_t pinA[8] = {1, 2, 3, 5, 6, 3, 2, 4};

uint8_t counter=0;

int8_t d1 = 0b00000110;
int8_t d2 = 0b01011011;
int8_t d3 = 0b01001111;
int8_t d4 = 0b01100110;

int8_t left=43;
int8_t right=21;

uint16_t one=9995;
uint8_t good;

uint8_t tsec;
uint8_t tmin;
uint8_t thr;

  int8_t dig[] = //digit mapping
    {
    //HGFEDCBA  
    0b00111111, // 0
    0b00000110, // 1
    0b01011011, // 2
    0b01001111, // 3
    0b01100110, // 4
    0b01101101, // 5
    0b01111101, // 6
    0b00000111, // 7
    0b01111111, // 8
    0b01101111, // 9
    0b00000000, // BLANK
    0b10000000  }; //dot

//----------------------------------------------------

int main(void) {

    //timer 0    
    TIMSK |= (1 << TOIE0);
    TCCR0 |= (1<<CS01); // timer0 No prescaler

    //timer 2

   TIMSK |= (1 << TOIE2);
   TCCR2 |= (1 << CS22) ;   // 64 prescaler
   //TCCR2 |= (1 << CS20) ;  // no prescaler   
   //ASSR |= (1<<AS2);   
     sei();  

    //adc
    ADCSRA |= (1<<ADPS2)|(1<<ADEN)|(1<<ADIE); 
    ADMUX |= (1<<REFS0) | (1<<MUX0)| (1<<MUX1);  
    ADCSRA |= 1<<ADSC; 

    // PORTs
    DDRD = 0xff;
    DDRB = 0xff;   

  while (1) {

    if( one>=9999)one=0;

    left=one/100;
    right=one%100;

    d1=dig[left/10];
    d2=dig[left%10];
    d3=dig[right/10];
    d4=dig[right%10];


 if(counter==0){
  PORTB |=0b00110000;
  PORTD |=0b10000000;  
     pinWrite(d1); 
  PORTB &= ~(1<<0);
  }

 if(counter==1){
  PORTB |=0b00110001;
  PORTD |=0b00000000;  
     pinWrite(d2); 
  PORTD &= ~(1<<7);
  }  

 if(counter==2){
  PORTB |=0b00010001;
  PORTD |=0b10000000;  
     pinWrite(d3); 
  PORTB &= ~(1<<5);
  }  

 if(counter==3){
  PORTB |=0b00100001;
  PORTD |=0b10000000;  
     pinWrite(d4); 
  PORTB &= ~(1<<4);
  }      

  if(counter==4) counter=0;        

  }
}

//----------------------------------------------------
ISR (TIMER0_OVF_vect)  // timer0 overflow interrupt
{
   TCNT0=100;
   counter++;

  //19Khz @ 8Mhz/256/2=15Khz
  }
//---------------------------------------------------- 

  //2hz   @ 32Khz/256/64=2hz  
ISR (TIMER2_OVF_vect)
{
  good=!good;
  if(good==1)one++;
}

//----------------------------------------------------
ISR(ADC_vect)    // adc interrupt
{
  //one = ADC;  
  ADCSRA |= 1<<ADSC; 
}

//----------------------------------------------------
// PortWrite

  int pinWrite ( int8_t data){

    for (int x = 0; x <8; x++) {

      if (data & (1 << x)) {
        if (portA & 1 << x) {
          PORTD |= 1 << pinA[x];
        }
        else {
          PORTB |= 1 << pinA[x];
        }
      }

      else {
        if (portA & 1 << x) {
          PORTD &= ~(1 << pinA[x]);
        }
        else {
          PORTB &= ~(1 << pinA[x]);
        }
      }
    }       
}
\$\endgroup\$
1
  • \$\begingroup\$ Your whole pinWrite function could be reduced by making a table for each port with the appropriate bits to output for a given input, and potential AND masks and ORs if you need to combine with something else. \$\endgroup\$ Commented Jun 4, 2016 at 17:29

1 Answer 1

1
\$\begingroup\$

For starters all those /10 and %10 calculations every loop are going to take a lot of clock cycles - probably several hundred if not a thousand. You are doing six of those each loop, so that is probably several thousand cycles every loop for each segment to be lit.

If you clock is only 32kHz, then each digit takes a sixteenth of a second to display. But because you have no synchronisation between your digit display and the interrupt that it toggling which digit to light, then if that interrupt is firing too fast the display counter will increase multiple times before a single digit can be displayed (thus skipping digits).


Each loop you appear to be calculating the value for every display segment, and then only using one of them - which is incredibly inefficient - you basically calculate the value for each digit four times for each one time it is shown.


Furthermore, you have issues of atomic access. Your interrupt is changing 16bit values which you are also trying to do calculations with in the loop - that means that an interrupt could occur and change the 16bit variable when you are half way through accessing it (thus corrupting the data).


I really don't know why you are using interrupts at all here, especially with such a low clock frequency. If you simply add the counter++ line to the end of the loop, and move the calculations for d1 to d4 inside their corresponding if statements, then it will probably start displaying properly - the time it takes to do the calculations will be enough for the digit to be displayed for a long enough period of time for you to see it.

\$\endgroup\$
1
  • \$\begingroup\$ Done what you have said. The randomness is gone, but the display is still flashing at the rate of 8hz. maybe 32k is not fast enough for mcu. \$\endgroup\$
    – user83582
    Commented Jun 4, 2016 at 16:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.