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.

Digital Multimeter Design

Status
Not open for further replies.

imranahmed

Advanced Member level 3
Joined
Dec 4, 2011
Messages
817
Helped
3
Reputation
6
Reaction score
3
Trophy points
1,298
Location
Karachi,Pakistan
Activity points
6,492
Dear KlausST,

Welcome to new thread about Digital Multimeter.

The meter I need design ammeter with selectable ampere detector.
The code I wrote its interrupt is working well with 5ms time and cases are
select nicely but issue is I want scroll digits with buttons for setting required
ampere and store it,when ammeter detect pre-select ampere it operates a relay
(PORTD==PD7 for relay signal).
In my code it is run when I delete two IF conditions but when I wrote it,it was not work.
:thinker:

Code:
void InitTimer2(){ //CTC timer2
   
   OCR2   = 155; 
   TCCR2 |= 0x0E;
   TIMSK |= 0x80; 
   TCNT2  = 0;
}

ISR(TIMER2_COMP_vect){
    
	   TCNT2 = 0;
      
	   if((PINC & (1<<PC3)) == 0)
	   {
	   swcount2++;
	   if(swcount2==100){
	   q++;
           swcount2=0;
	   }}
	   
	 switch(q){ 
	 
	 case 0: 
	 av=read_adc(3); // yellow amps
	 dv1 = dv1 + (av - dv1) * fc ;
        mcount2++;
	 if(mcount2==100)
	 {
	 mcount2=0;
         dispv1=dv1;
	 }     
	 break;

	 case 1:
     
	 ampset = read_eeprom_word(&my_eeprom_word);
	 dispv1 = ampset;
	
	 if((PINC & (1<<PC4)) == 0){
	 mcount2++;
	 if(mcount2==50)
	 {
	 mcount2=0;
	 ampset++;
	 write_eeprom_word(&my_eeprom_word,ampset);//store value in eeprom	 
	 dispv1=ampset;
	 }
	 } 
	 
	 if((PINC & (1<<PC5)) == 0){
	 mcount2++;
	 if(mcount2==50)
	 {
	 mcount2=0;
	 ampset--;
	 write_eeprom_word(&my_eeprom_word,ampset);       // store value in eeprom	 
	 dispv1=ampset;
	 }
	 }  	 
	 break;

	 default:
         q=0;
	 break;
}

 while(1)
   {
   cli();
   tmp1=dispv1;
   tmp=dispv;
   sei();
   Print1(tmp1);  // Print1 for digit 1-3
   Print(tmp);    // Print  for digit 4-6
   if(tmp1>ampset)
   {  
   PORTD |= 1<<PD7;   
   }
   }
 

Hi Imran,

From the other thread i think you need RMS. If so, then google for RMS calculation.
Here you use average calculation.
RMS of a sine is 0.707 of sine peak. Average of a sine is zero.

Hope that helps
Klaus
 

Dear KlausST,

You do not understand what my ammeter needs.

Please try to understand what I want to say I do not need RMS calculations.
I have all calculations about CT. But issue exist in the programming.

for example : If there is a 30/5A,the current pass through its primary is 15A it will generate 2.5A on its secondary .
But for 60/5A if 15A current pass through its primary it will generate 1.25A.
If I design ammeter for 30/5A and 15A pass through its primary it will show 15A exact.But If i use
60/5A CT for same ammeter and 15A same pass through its primary it will show 7.5A.
Its mean that I design various ammeter for all ratings CTs but it is not possible for me.
If selectable ammeter would design so what would happen good.
 

Hi,

Maybe i really don't understand what you mean.....

You speak of an CT. Traditional or passive CTs only work with AC. They can not handle DC. But your code is for DC.

In my eyes you first need to change your code that it can handle AC.
This step is finidhed when you feed your ADC value with a fixed AC voltage and your display shos the desired value.

The next step is to change the ADC input circuit so that you are able to measure AC current. You want to use x/5A CT then your input must be able to handle 5A RMS. This means at least +/- 7.1 A full scale. This tep is finished when you feed 5A AC through your shunt and the display shows 5A.

The next step is to connect the CT to your 5A input. For example the 30/5A CT. This step is finished when you feed the primary with 30A and your display is showing 5A.

The next step is to tell the ucontroller what CT (rate, gain) you have connected. If you use a 30/5A CT then the gain is 30/5 = 6.
So simply multiply in your software the current valuy by 6 and display the result.

For a 60/5 CT the gain is 60/5=12, so multiply your value not with 6 but with 12 and get the correct disply reading.

Please go through this step by step and write which step is not working as you desired.

Hope this helps
Klaus
 

I agree with KlausST. Your code can't work for AC measurement.

The problem you are presently addressing is about Ampmeter user interface: Range selection, scaling, display.
My first impression of the code, it's a very bad idea to do all these things in a timer interrupt.
 

Hi Imran,

My first impression of the code, it's a very bad idea to do all these things in a timer interrupt.

This is what i meant with "the ISR should be short in time"
Especially reading EEPROM and even more writing EEPROM use busy wait. That takes too much time for an ISR.

Do this in main loop and store the information in variables. Mind the atomic read and write of multi byte variables in main loop.

About the timing of reading ADC and doing the filtering within an ISR i wrote above.

Klaus
 

Dear KlausST,

My internet was disabled because some problems occurred.

Please how my code is looking.

Code:
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 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();
   }
}
 

Hi Imran.

A lot of work to do....

The only place where flag is set should be in measurement isr.
Flag must be cleared when handled in main loop

Again: everything that is not timing critical should be done in main loop. Only timing critical things should be done in isr.
Disply for example: calculate as much as possible in main loop and store the data for the digits in variables.
In isr output the digits data to the port.

Some days ago we managed all the adc_read in measurement isr. Why, why do you do this in main loop now?
All the previously discussed filtering can not work in main loop...

So please go back to the state where all the measurement worked.
Then change one step and validate it, then change the next step....

Klaus
 

I agree with KlausST. Your code can't work for AC measurement.

The problem you are presently addressing is about Ampmeter user interface: Range selection, scaling, display.
My first impression of the code, it's a very bad idea to do all these things in a timer interrupt.

Dear FvM,

Why my code cannot work with AC measurement?

I also use ZXCT1041 IC is full-wave precision rectifier for signal conditioning for input of ADC.

According to KlausST, only timing critical things are done in ISR and I do it.

- - - Updated - - -

The only place where flag is set should be in measurement isr.
Flag must be cleared when handled in main loop

Ok I will do it.

Some days ago we managed all the adc_read in measurement isr. Why, why do you do this in main loop now?

Dear KlausST according to FvM he said "My first impression of the code, it's a very bad idea to do all these things in a timer interrupt. " thats why I moved all things to main loop and timing critical
variable are in ISR.

Please also tell me which things are in ISR and which are in main loop?
 

Why my code cannot work with AC measurement?

I also use ZXCT1041 IC is full-wave precision rectifier for signal conditioning for input of ADC.
Thats' good, you didn't mention a rectifier before. Let us assume that you are correctly converting the CT output current to DC voltage at ADC input.

I see that you have removed time consuming actions form the ISR.
 

Hi Imran,

I see you are confused.

Timing critial jobs are those who:
* need exact timing
* must run exactely n times per second
* must be finished before the next time the same job is executed (somehow difficult to explain..)

Timing critical is:
--> measurement ISR:
* select channel
* ADC conversion
* filter measured value
because measurement ISR has fixed timing you can use it to time the job for display value calculation
* set flag
do only as much as really needed: If you really need to calculate RBV in ISR, then do it only once per 100 runs (mcount), not 99 waste calculations.

--> displayMUXisr:
* output new segment data on display
* activate new segment

NOT timing critical, and therefore in main loop:
* checking key press and do all that is necessary with the keypress. prepare as much as possible for a short measurement ISR
* update portc0 ... portC2 .... here we can only guess what this means
* reading and writing EEPROM
* when flag is set: calvulate RBV, calculate the new value for the display, prepare all segement data for the displayMUXisr
* busywait


****
please try to inform us what you do:
... rectifier ... how can we know?
... is there an anaolg filter connected between rectifier and ADC input?
... isr setup: what frequency, what is the isr for?
... portc0 to portc2: what is it for?
... what display do you have?
... where is print and print1 defined? do they calculate digits(i)?
...


*********
Additionals:

With reading ADC there are a lot of things to check.
To your example:
You know - when converting a rectified sine with an ADC you will see values between zero and the peak level.
It will look like: 665, 201, 3, 529, 487...
It makes no sense to work with a single value, therfore you have to take more than one value into account.
This can be done by digital filtering.
There are a lot of different filters...
To get reliable results you have to calculate your filter. For calculating the filters you need a fixed sample rate.
In other words: you need to know how often per second you get a new adc value. And usually with every new adc value you run the filter job.
A fixed sample rate can easily be done with timers. This is timing critical. You should not loose a single adc value.

You call the read_ADC in state_display. But state_display is called as often as possible from main loop.
"as often as possible" is no exact timing...

Here a sketch of a timing diagram.
You can see a non_good isr and how it should be. Also you can see that it is no problem for tasks in the main loop when they are interrupted by ISRs.
DSC06612s.jpg

Hope this helps

Klaus
 

please try to inform us what you do:
... rectifier ... how can we know?
... is there an anaolg filter connected between rectifier and ADC input?
... isr setup: what frequency, what is the isr for?
... portc0 to portc2: what is it for?
... what display do you have?
... where is print and print1 defined? do they calculate digits(i)?

Dear KlausST,

Thank you explaining these things.

1) I am using ZXCT1041 full-wave precision rectifier for convert mains input AC
to rectified DC for ADC input.

2) PORTC0-2 use for which phase voltage is displaying. (I connect three LED`s).

3) print is a function for separating the digits and store in digits same as print1
but for amperes and print for voltages.

Please visit 7-segment decimal point management thread.
 

Dear KlausST,

By grace of God, I programmed the multimeter successfully,one thing I want to know that

how to program this thing,when I press button for setting ampere,one press the digits show 001 second press 002

and still press for 2 seconds the digits should change fastly.

I programmed,

Code:
ISR()   // 5 ms
{
if(button_press==PC3)
{
mcount++;
}

main()
{
if(mcount==50)
{
digits++;
}
}
But How to program when I still press for 2 seconds the digits increase fastly.I tried this below but no work.

Code:
ISR()   // 5 ms
{
if(button_press==PC3)
{
mcount++;
mcount1++;
}

main()
{
if(mcount==50)
{
mcount=0;
digits++;
if(mcount==200)
{
mcount2=0;
if(mcount==10)
{
mcount=0;
digits++;
}

}

}
}
 

Hi
I don't see where you want to react on 2 seconds....

If the isr runs every 5 ms, then how often does it run in two seconds?

If you want to detect 2 seconds you need a counter...
But ask yourself what to do with the counter
* when key is not pressed
* when counter shows more than 2 seconds...

To your code...
Why is mcount1 increased but never used?
Why is mcount2 used but never changed?
Why do you ask for mcount == 200, but set it zero on 50?

Klaus
 

Dear KlausST,

The real code is below

Code:
ISR(TIMER1_COMPA_vect)
      	   {     
           mcount++;
           mcount1++;
	  
	   if((PIND & (1<<PD6)) == 0)
	   {
	   swcount++;
	   if(swcount==100)
	   {
	   p++;
           swcount=0;
	   }
	   }
	  
	   if((PINC & (1<<PC3)) == 0)
	   {
	   swcount1++;
	   if(swcount1==100)
	   {
	   q++;
          swcount1=0;
	   }
	   }
	   
	   [COLOR="#0000FF"]if((PINC & (1<<PC4)) == 0)
	   {
	   mcount2++;
	   }[/COLOR]

	   if((PINC & (1<<PC5)) == 0)
	   {
	   mcount3++;
	   }

Please see blue above when press PC4 in CASE 1 execute below and it is running sucessfully;


Code:
         [COLOR="#0000FF"]case 1:[/COLOR]	 
	 
         dispv1=dv1c;
	 flag=1;
	
         if(mcount2==50)
	 {
	 mcount2=0;
	 if(dv1b<100)
	 dv1b=dv1b+0.1;
         else if(dv1b>=100)
	 dv1b=dv1b+1;	 
         write_eeprom_float(&my_eeprom_float,dv1b);
	 }	
		 	 
	 if(mcount3==50)
	 {
	 mcount3=0;
	 if(dv1b<100)
	 dv1b=dv1b-0.1;
         else if(dv1b>=100)
	 dv1b=dv1b-1;	 
         write_eeprom_float(&my_eeprom_float,dv1b);
	 }		
     
	 if(dv1b<100 && y==4)
	 {
	 PORTB &= ~(1<<PB7);
	 dv1c = dv1b * 10;
 	 }

	 if(dv1b>=100 && y==4)
	 {
	 PORTB |= (1<<PB7);
	 dv1c = dv1b;
	 }
	 	
	 if(dv1b<0)
	 {
	 dv1b=999;
	 dispv1=dv1b;
         write_eeprom_float(&my_eeprom_float,dv1b);
	 flag=1;
	 }

	 if(dv1b>999)
	 {
	 dv1b=0;
	 dispv1=dv1b;
         write_eeprom_float(&my_eeprom_float,dv1b);
	 flag=1;
	 }
	  
	[COLOR="#0000FF"] break;[/COLOR]         
 }

I need when I still press PC4 for 2 seconds the increase in dv1b should be every 50ms not 250ms.
 

You might consider auto-ranging, based on readings. Rather than switch duration.

Also consider analog errors from stray magnetic current on high impedance of ADC loop and ensure smallest loop at 90 deg angle relative to current flow.

Do you change CT and load ( burden R) and also change fixed shunt resistor too ? change scales? Just asking. Your layout and schematic would be helpful.
 

Hi Imran,

Undocumented code. And only a snippet, where i can not find out what it is for..
No information what is connected to ports, and what the function is...

For me it is impossible to help...maybe others can..

Klaus
 

Dear KlausST,

Please find attachment its useful code for ammeter.

I need that when I still press PC4 for 2 seconds the dv1b increase every 50ms not 250ms like as done.
 

Attachments

  • Ammeter_Code.rar
    2.1 KB · Views: 43

Dear KlausST,

I am proud that I am discussing with CEO of Electronic Developing Company.
Thanks for your co-operation.

Dear KlausST I am no need pre-build codes for any project but I want that I am able to write own codes but according to right approach by discussing
,reading,writing and learning.


Please find code below,

Code:
#include <avr/io.h>
#include <avr/interrupt.h>   
#include <avr/eeprom.h>
#define SEVEN_SEGMENT_PORT PORTB
#define SEVEN_SEGMENT_DDR  DDRB
#define read_eeprom_float(address) eeprom_read_float ((const float*)address)
#define write_eeprom_float(address,value) eeprom_write_float ((float*)address,(float)value)

//declare an eeprom variable
unsigned int EEMEM   my_eeprom_float;
volatile uint8_t digits[2];
volatile uint8_t digits1[2];
static uint8_t y=0;
unsigned char mcount=0,mcount1=0,mcount2=0,mcount3=0,mcount4=0,m=0,z=0,e=0,f=0,p=0,q=0,swcount=0,swcount1=0,flag=0;
unsigned int av=0,RBV=0,tmpset=0;
float fc=0.003,dispv=0,dispv1=0,dv=0,dv1=0,dv1a=0,dv1b=0,dv1c=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;


      switch (n)
      {
         case 0:
                          //.gfedcba
         SEVEN_SEGMENT_PORT=0b11000000;
         break;

         case 1:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b11111001;
         break;

         case 2:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b10100100;
         break;

         case 3:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b10110000;
         break;

         case 4:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b10011001;
         break;

         case 5:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b10010010;
         break;

         case 6:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b10000010;
         break;

         case 7:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b11111000;
         break;

         case 8:
                        //.gfedcba
         SEVEN_SEGMENT_PORT=0b10000000;
         break;

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


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)
      
	   {  
    
       mcount++;
       mcount1++;
	  
	   if((PIND & (1<<PD6)) == 0)
	   {
	   swcount++;
	   if(swcount==100)
	   {
	   p++;
       swcount=0;
	   }
	   }
	  
	   if((PINC & (1<<PC3)) == 0)
	   {
	   swcount1++;
	   if(swcount1==100)
	   {
	   q++;
       swcount1=0;
	   }
	   }
	   
	   if((PINC & (1<<PC4)) == 0)
	   {
	   mcount2++;
	   }

	   if((PINC & (1<<PC5)) == 0)
	   {
	   mcount3++;
	   }




       }
ISR(TIMER0_OVF_vect)
{
   TCNT0=0;

//   This interrupt service routine (ISR)
//   Updates the displays
   
   if(y==5)
   {
      //If on last display then come
      //back to first.
      y=0;
      
   }

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

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

}

void state_display_amps(){

     switch(q){

	 case 0:
     e=0;
	 f=0;
	 av=read_adc(3);// yellow amps
	 dv1 = dv1 + (av - dv1) * fc ;
    
	 if(dv1<100 && y==4)
	 {
	 PORTB &= ~(1<<PB7);
	 dv1a=dv1*10;
	 }

	 if(dv1>=100 && y==4)
	 {
	 PORTB |= (1<<PB7);
	 dv1a=dv1;
	 }

	 if(mcount1==100)
	 {
	 mcount1=0;
     dispv1=dv1a;
	 flag=1;
	 }
	 
	 

	 break;

	 case 1:
	 
	 e=1;
	 dispv1=dv1c;
	 flag=1;
     
     
	 if(mcount2==50)
	 {
	 mcount2=0;
	 if(dv1b<100)
	 dv1b=dv1b+0.1;
     else if(dv1b>=100)
	 dv1b=dv1b+1;	 
     write_eeprom_float(&my_eeprom_float,dv1b);
	 }	
	 	  
		 	 
	 if(mcount3==50)
	 {
	 mcount3=0;
	 if(dv1b<100)
	 dv1b=dv1b-0.1;
     else if(dv1b>=100)
	 dv1b=dv1b-1;	 
     write_eeprom_float(&my_eeprom_float,dv1b);
	 }		
     
	 if(dv1b<100 && y==4)
	 {
	 PORTB &= ~(1<<PB7);
	 dv1c = dv1b * 10;
 	 }

	 if(dv1b>=100 && y==4)
	 {
	 PORTB |= (1<<PB7);
	 dv1c = dv1b;
	 }
	 	 
	
	 if(dv1b<0)
	 {
	 dv1b=999;
	 dispv1=dv1b;
     write_eeprom_float(&my_eeprom_float,dv1b);
	 flag=1;
	 }

	 if(dv1b>999)
	 {
	 dv1b=0;
	 dispv1=dv1b;
     write_eeprom_float(&my_eeprom_float,dv1b);
	 flag=1;
	 }
	  
	 break;


	 default:
	 q=0;
	 break;
}
}


void atomic_display(){
   
   cli();
   tmp1=dispv1;
   sei();
   Print1(tmp1);  // Print1 for digit 1-3
  

}
void initialize(){


   dv1b = read_eeprom_float(&my_eeprom_float);     // restore from eeprom
   
   DDRD  |= 0b10111111;
   PORTD |= 0b01111111;
   
   DDRA   = 0b00000000;  
   
   DDRC  |= 0b00000111;   //76543210
   PORTC |= 0b00111000;  
   

   //Port B AS OUTPUT
   SEVEN_SEGMENT_DDR=0XFF;

   //Turn off all segments
   SEVEN_SEGMENT_PORT=0X00;
 
  // _delay_ms(1000); 
   InitTimer0();
   InitTimer1();
   InitADC();
   
     
   //Enable Global Interrupts
   sei();

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

This code is working without any problem with flying colors.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top