Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

7-segment decimal point management

Status
Not open for further replies.

imranahmed

Advanced Member level 3
Advanced Member level 3
Joined
Dec 4, 2011
Messages
822
Helped
3
Reputation
6
Reaction score
3
Trophy points
1,298
Location
Karachi,Pakistan
Visit site
Activity points
6,533
Please let me know that how to display 3-digit display with decimal point movement according to input

ADC_value or input voltages.
 

Since you are using 3 digits, you can use fixed decimal point at the source code are't you?

Code:
Digit=number;                        // Convert float to Integer
   Decimal=(number - Digit) * 10;      // Get The Decimal Digit

Code from http://www.ermicro.com/blog/?p=844
 

    V

    Points: 2
    Helpful Answer Positive Rating
Thank you dear PA3040,

Dear I need to display amperes i.e 0.5 , 1.75 , 1.5 , 7.5 , 11.8 , 23.5 or etc like this.

But he makes fixed decimal point , how to move decimal point according to input value of current?
 

Hi Imran:

i don´t know what range to display.

For a range from 1mA to 9999A --> displayed as 0.001 to 9999:
always display integer values from 0001 to 9999 (and the decimalpoint).
****************

if adc_value < 10 then display ADC-Value * 1000 and set dp to the most left position: showing 0.000 up to 9.999

else if adc_value < 100 then display ADC-Value * 100 and set dp to the second left position: showing 00.00 up to 99.99

else if adc_value < 1000 then display ADC-Value * 10 and set dp to the right position: showing 000.0 up to 999.9

else display ADC-Value and set no dp: showing 0000 up to 9999

Klaus
 

Dear KlausST,

The range 0.5A to 999A.

But I want to display 0.5 or 0.75 or 1.5 or 11.8 or 23.6 or 100 or 120 or etc.

But you defined is very good I try it.
 

Thank you dear PA3040,

Dear I need to display amperes i.e 0.5 , 1.75 , 1.5 , 7.5 , 11.8 , 23.5 or etc like this.

But he makes fixed decimal point , how to move decimal point according to input value of current?

Post your codes with Proteus ISIS
 

Dear PA3040,

Please see my code.



Code:
#include <avr/io.h>
#include <avr/interrupt.h>


#define SEVEN_SEGMENT_PORT PORTB
#define SEVEN_SEGMENT_DDR  DDRB

volatile uint8_t digits[2];
volatile uint8_t digits1[2];

unsigned char mcount=0,p=0,swcount=0,flag=0;
unsigned int av=0,RBV=0;
float fc=0.005,dispv=0,dispv1=0,dv=0,dv1=0,dv2=0,tmp1=0,tmp=0;

void SevenSegment(uint8_t n)
{


/*
n must be less than 9

//0x3f,~0x06,~0x5b,~0x4f,~0x66,
//0x6d,~0x7d,~0x07,~0x7f,~0x67;


*/

   if(n<10)
   {
      switch (n)
      {
         case 0:
                          //.gfedcba
         SEVEN_SEGMENT_PORT=~0b00111111;
         break;

         case 1:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=~0b00000110;
         break;

         case 2:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=~0b01011011;
         break;

         case 3:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=~0b01001111;
         break;

         case 4:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=~0b01100110;
         break;

         case 5:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=~0b01101101;
         break;

         case 6:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=~0b01111101;
         break;

         case 7:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=~0b00000111;
         break;

         case 8:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=~0b01111111;
         break;

         case 9:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=~0b01101111;
         break;
      
	  
	  }
  }
}

void Print(uint16_t num)
{
   /* 

   
   This function breaks apart a given integer into separate digits
   and writes them to the display array i.e. digits[]
   
   */
   uint8_t i=0;
   uint8_t j;

   if(num>999) 
   
   return ;


   while(num)
   {
      digits[i]=num%10;
      i++;

      num=num/10;
   }
    for(j=i;j<3;j++)
    digits[j]=0;
}

void Print1(uint16_t num1)
{
    

 /*  
   This function breaks apart a given integer into separate digits
   and writes them to the display array i.e. digits[]
   */
   
   uint8_t i=5;
   uint8_t j;

   if(num1>999) 
   
   return ;


   while(num1)
   {
      digits1[i]=num1%10;
      i++;

      num1=num1/10;
   }
    for(j=i;j<8;j++)
    digits1[j]=0;
}



void InitTimer0(){ //Overflow timer0
       
   TCCR0|=(1<<CS01)|(1<<CS00); // PRESCALAR = 64
   TIMSK|=(1<<TOIE0);
   TCNT0 = 0;
   OCR0  = 20;
}
void InitTimer1(){
  
  TCCR1B |= 0x09;
  OCR1AH  = 0x9C; 
  OCR1AL  = 0x3F; 
  TIMSK  |= 0x10; 
}
void InitADC()
{
   ADMUX |=(1<<REFS0);          // For Aref=AVcc;
   ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS0);// Prescalar = 32
   ADCSRA|=(1<<ADSC);
}

uint16_t read_adc(uint8_t ch)
{
   //Select ADC Channel ch must be 0-7
     ADMUX =  (ADMUX & 0xF8) | ch;
     ADCSRA|=(1<<ADSC);
	 while(!(ADCSRA & (1<<ADIF)));
     ADCSRA|=(1<<ADIF);
	 return(ADCW);
}

ISR(TIMER1_COMPA_vect)
      

	{  
      if((PIND & (1<<PD6)) == 0)
	   {
	   swcount++;
	   if(swcount==100)
	   {
	   p++;
       swcount=0;
	   }
	   }
	   mcount++;  
	}

	 
	 


ISR(TIMER0_OVF_vect)
{
   TCNT0=0;

//   This interrupt service routine (ISR)
//   Updates the displays

   
   static uint8_t i=0;

   if(i==5)
   {
      //If on last display then come
      //back to first.
      i=0;
      
   }

   else
   {
      //Goto Next display
      i++;
      
   }

   //Activate a display according to i
   
   PORTD&=(0b11000000);
   PORTD|=(1<<i);     
   SevenSegment(digits[i]);

}

void state_display(){

     
	 switch(p){
	 
	 case 0:
	 PORTC &= ~(1<<PC0);
	 PORTC &= ~(1<<PC2);
	 PORTC |= 1<<PC1; 
	 
	 av=read_adc(1); // yellow volts
	 dv = dv + ( av - dv) * fc ;
	 
	 av=read_adc(3); // yellow amps
	 dv1 = dv1 + (av - dv1) * fc ;
	 
	 if(mcount==100)
	 {
	 mcount=0;
     dispv=dv;
     dispv1=dv1;
	 flag=1;
	 }
     break;

	 case 1:
	 PORTC &= ~(1<<PC1);
	 PORTC |= 1<<PC2;
	 av=read_adc(2);  // blue volts
	 dv = dv + ( av - dv) * fc ;
	 	 
	 av=read_adc(3);  // yellow amps
	 dv1 = dv1 + (av - dv1) * fc ;
    

	 if(mcount==100)
	 {
	 mcount=0;
     dispv=dv;
     dispv1=dv1;
	 flag=1;
	 }
     break;

	 case 2:
	 PORTC &= ~(1<<PC2);
	 PORTC |= 1<<PC0;
	 av=read_adc(0);  // red volts
	 dv = dv + ( av - dv) * fc ;
	 	 
	 av=read_adc(3);  // yellow amps
	 dv1 = dv1 + (av - dv1) * fc ;
     

	 if(mcount==100)
	 {
	 mcount=0;
     dispv=dv;
     dispv1=dv1;
	 flag=1;
	 }
     break;

	 case 3:
	  
	 PORTC |= 1<<PC0;
	 PORTC |= 1<<PC2;
	
	 av=read_adc(0);  // red_blue volts
	 dv = dv + ( av - dv) * fc ;
	 av=read_adc(2);  // blue_red volts
	 dv2 = dv2 + ( av - dv2) * fc ;
	 RBV=((dv+dv2)*0.866);	 
	
	 av=read_adc(3);  // yellow amps
	 dv1 = dv1 + (av - dv1) * fc ;
	      

	 if(mcount==100)
	 {
	 mcount=0;
     dispv=RBV;
     dispv1=dv1;
	 flag=1;
	 }	 
	 break;

	 case 4:
	 PORTC &= ~(1<<PC0);
	 PORTC |= 1<<PC1;
	 PORTC |= 1<<PC2;
	 
	 av=read_adc(2);  // blue_yellow volts
	 dv = dv + ( av - dv) * fc ;
	 av=read_adc(1);  // yellow_blue volts
	 dv2 = dv2 + ( av - dv2) * fc ;
	 RBV=((dv+dv2)*0.866);	 
	
	 av=read_adc(3);  // yellow amps
	 dv1 = dv1 + (av - dv1) * fc ;
     

	 if(mcount==100)
	 {
	 mcount=0;
     dispv=RBV;
     dispv1=dv1;
	 flag=1;
	 }
     break;

	 case 5:
	 PORTC &= ~(1<<PC2);
	 PORTC |= 1<<PC0;
	 PORTC |= 1<<PC1;
	
	 av=read_adc(0);  // red_yellow volts
	 dv = dv + ( av - dv) * fc ;
	 av=read_adc(1);  // yellow_red volts
	 dv2 = dv2 + ( av - dv2) * fc ;
	 RBV=((dv+dv2)*0.866);	 
	 
	 av=read_adc(3);  // yellow amps
	 dv1 = dv1 + (av - dv1) * fc ;
	     

	 if(mcount==100)
	 {
	 mcount=0;
     dispv=RBV;
     dispv1=dv1;
	 flag=1;
	 }
     break;

	 default:	  
	 p=0;
	 break; 
 
	 }}

void atomic_display(){
   
   cli();
   tmp1=dispv1;
   tmp=dispv;
   sei();
   Print1(tmp1);  // Print1 for digit 1-3
   Print(tmp);    // Print  for digit 4-6

}
void initialize(){

   DDRD|= 0b00111111;
   PORTD|= 0b01111111;
   
   
   //Port B AS OUTPUT
   SEVEN_SEGMENT_DDR=0XFF;

   //Turn off all segments
   SEVEN_SEGMENT_PORT=0X00;
  // _delay_ms(1000); 
   InitTimer0();
   InitTimer1();
   InitADC();
   
   DDRA = 0b00000000;  
   DDRC |= 0x07;   
   PORTC = 0x00;  
    

  
   //Enable Global Interrupts
   sei();

   //Infinite loop
}
int main()
{
   
   initialize();
   
   
   while(1)
   {   
   state_display(); 
   if(flag==1){  
   atomic_display();
   flag=0;
   }}
}

- - - Updated - - -

Dear KlausST,

You also please find attached proteus file and code.
 

Attachments

  • CT_Ammeter.rar
    21.7 KB · Views: 92

Hello!

1. I have looked at your code (at least at the beginning). You may consider making
some efforts designing simpler code. For example your SevenSegment function:
Let's suppose that you have no choice but writing this function as complicated as you
did: your if(n < 10) statement is absolutely useless. The case statement itself is
sufficient.

Now you can rewrite this function a lot better and simpler: How about this:

Code C - [expand]
1
2
//  Define the segment combinations corresponding to each number
const char Segments[10] = {0b00111111, 0b00000110, ...};



Then your function becomes:


Code C - [expand]
1
2
3
void SevenSegment(uint8 n) {
    SEVEN_SEFGMNET_PORT = Segments[n];
}



2. I don't understand what you want to do with your digits and digits1 buffers.
You have only 2 characters per buffer, so in each case the latest character is
buffer[1] or buffers1[1].
Now what will happen with these lines:


Code C - [expand]
1
2
for(j=i;j<3;j++) digits[j]=0;
for(j=i;j<8;j++) digits1[j]=0;



You clearly write outside of the buffers in each case. At least, you write 0 to digits[2]
which doesn't exist in the first case and same for j=5, 6, 7 in the second case.

Wouldn't it be simpler to:
1. Use sprintf to write your number into a 4-byte buffer;
2. Find the position of the point in this string
3. Write all the numbers (using buf - '0')
4. Write the point at the right position

Your 300+ lines program would fit within 50 ~ 100, I guess.
And even if you're not allowed to use sprintf, it would be a lot simpler to write a
function like NumberToString and then deal with it.

Dora.
 
Thank you dear Dora for explaining and co-operation.

First of all you yes "if(n<10)" is useless.

You defined SevenSegment function as simple as possible.Its great.I will do it.

I have 6 digits for displaying voltages and amperes.3 for volts and 3 for amps.

In print function this "for(j=i;j<3;j++) digits[j]=0;" use separating digits coming from ADC channel.
If ADC value is 345 then i=0; and display 3 then i=1 display 4 then i=2 display 5.
Same as with print1 function. Print and Print1 are separate function for volts and amps.

Dear Dora main problem is moving DOT according to ADC values.

How can I handle DOT in my code?

Please let me know that sprintf work with 7-segment display.
I think sprintf perfectly work with LCD.
 
Last edited:

Dear Dora and KlausST,

Please let me know that I want to use sprintf command for displaying three digits value of volts and amps.

Dear KlausST according to Post#4, I am using three digits 7-segment display, please define according three digits display.
 

Hi Imran,

With 3 digits it is not difficult to imagine. You can show integer values from 000 to 999.

With decimal point on the right side 00.0 to 99.9
With decimal point at the leftt side 0.00 to 9.99

The programming is on you.

Klaus
 

Dear KlausST,

99.9 and 9.99 as integer is same as 999.

for example:

1.23 and 12.3 is as integer 123. When starting all digits show 000 after increasing input volts or amps.
It will 00.1....00.9....01.0........02.5.......09.9........10.0.....12.0......12.3 but actually 12.3 is not 12.3 it is
123 its mean ADC value reach 123 but how keep its original value show. Now is showing if it display 102.4
its means actual volt at ADC_Channel is 0.5 [from ((Vin*1024)/5)] 204.8
means 1 volt at ADC_Channel. I want to keep it as if 0.5 volts at ADC_channel it shows 102.4
0.1 if volts at ADC is 20.4or5 and if ADC volts is 0.2 it shows 40.9 or 41.
 
Last edited:

Hello!

In print function this "for(j=i;j<3;j++) digits[j]=0;" use separating digits coming from ADC channel.

Again, you are writing to areas that are undefined:


Code C - [expand]
1
2
volatile uint8_t digits[2];
volatile uint8_t digits1[2];



To be crystal clear: our digits and digits1 arrays exist for j=0 and j=1 but not for j=2
and you are trying to write something to digits[2].

Now your last mail is very confusing. You cannot display 102.4 because you have only
3 digits. Suppose you have a 10-bit converter, 1024 is 5V, 0 is 0. You have many
options depending on what you want to do. How do you want to display 0?
0.0?
0?
0.00?
The third case is the simplest one because the point is fixed. Just calculate the
integer number that fits your voltage. To 1024 should correspond 500. Why not
simply dividing your digital value by 2, set the dot at the second position and
then you can directly have a voltage. And if you are not happy with the 0.12V
inaccuracy, then do the math to fit 1024 into 500 and that will be about it, with
an accuracy of 0.01V.

Beside this, you are calculating Vin*1024/5 and it gives you the digital value.
But what you want is the opposite: you have the digital value and you want to
calculate vin. So it's not val = vin * 1024 / 5 but vin = val * 5 / 1024.

And beside this, just for your info: avoid divisions on a MCU except if you cannot
do anything else. In this case, you can.

Dora
 

Now your last mail is very confusing. You cannot display 102.4 because you have only
3 digits.

Sorry for this.

To 1024 should correspond 500.
Do you mean 1024 correspond 5.00?


And beside this, just for your info: avoid divisions on a MCU except if you cannot
do anything else. In this case, you can.
Please more clarify above quote.

- - - Updated - - -

Please reply.
 

Hello!

Do you mean 1024 correspond 5.00?

I don't know. You should know better than me.

If your converter is 10 bits
AND
If your power supply is 5V
AND
If you measure directly the voltage (without divider)
AND
If you configure the ADC with VCC as its reference
AND
If you choose the last method I was saying (always write 3-digit integer and write the point at a fixed place)

then, yes, 1024 (or more precisely 1023) will correspond to 500, and the fixed point at the 2nd position will
allow you to display 5.00.

Dora.
 

Hi Dora,

you write:
...yes, 1024 (or more precisely 1023) will ...

for most applications this is not important, but most ADCs and DACs work with
1024 to be fullscale (for a 10 bit converter)

So 1024 would represent VRef,

and 1023 represent 1023/1024 x VRef.

The more precise is "1024 correspond to 500"

Because 1023 is the max. output one "ignores" the single LSB (here 0.1%)...
.... and all is fine.... ;-)

Klaus
 
Hello,

The ADC-Values are successfully displayed with decimal values on 3-digit 7-segment display 00.0...09.9....10.1...99.1...99.9...100....104...800..900....999.
I am multiplied ADC-values by 10 in the condition if(ADC-value<100) and DP is on and the if(ADC-values>=100) then DP is off.


Another issue is that I want to make it adjustable.
Starts from 00.0 then 00.1...00.2.....00.9.....01.0....01.5...01.9...02.0....ss....09.9.....10.0.....10.5...10.9...ss...99.9....100....101..200..800..900..999.
By using button for setting it.The button I has been done successfully and increasing value with 1 means 1,2,3,4,,,,999.
But values should increase 00.0 to 999.
 

Hello!

for most applications this is not important, but most ADCs and DACs work with
1024 to be fullscale (for a 10 bit converter)

I agree, but if you do this, you will never have a 5V reading even if you measure the reference.
With 10 bits, I agree that 1024 corresponds to 5V, but the problem is that with 10 bit, there
is no 1024. So dividing by 1023 instead of 1024 has its advantages.

Dora.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top