Sei sulla pagina 1di 10

/*

Multimeter Kit v1.5


2/10/2010
SparkFun Electronics
Jim Lindblom

Basic Multimeter code to test voltage, current, resistance (continuity).


and display the result on a 4-digit, 7-segment display
*/

#define F_CPU 8000000

#include <avr/io.h>
#include <math.h>

// Needed for trunc function

#include <util/delay.h>
#include <avr/interrupt.h>

/* Function Definitions */
void ioinit(void);
void display(int number, int digit);

// SBI and CBI to set/clear bits


#define sbi(port_name, pin_number) (port_name |= 1<<pin_number)
#define cbi(port_name, pin_number) ((port_name) &= (uint8_t)~(1 <<
pin_number))

uint8_t DPStatus = 0x00;


volatile uint8_t mode = 1;
volatile int dig0 = 0;
volatile int dig1 = 0;
volatile int dig2 = 0;

volatile int dig3 = 0;


volatile uint8_t resDP = 0;

// Interrupt Timer 1 updates the display


ISR(TIMER1_COMPA_vect)
{
if (mode == 1) DPStatus = 0b00000010;
if (mode == 2) DPStatus = 0b00000001;
if (mode == 3) DPStatus = resDP;

display(dig0, 0);
_delay_ms(1);
display(dig1, 1);
_delay_ms(1);
display(dig2, 2);
_delay_ms(1);
display(dig3, 3);
_delay_ms(1);
PORTB = PORTB & 0b11100000;
}

// Interrupt Timer 0 checks for button press


ISR(TIMER0_COMPA_vect)
{
// Check mode button
if((PINB & (1<<5)) == 0)
{
TIMSK1 = 0; // Turn off timer 1 interrupt temporarily

mode++;

if (mode == 4) mode = 1;

// Update Display
for (int i = 0; i<125; i++)
{
DPStatus = 0xFF;
display(mode, 0);
_delay_ms(1);
display(mode, 1);
_delay_ms(1);
display(mode, 2);
_delay_ms(1);
display(mode, 3);
_delay_ms(1);
display(mode, 4);
_delay_ms(1);
PORTB = 0b00111111;
_delay_ms(1);
}
DPStatus = 0x00;

PORTB = PORTB | 0b00100000;


TIMSK1 = _BV(OCIE1A);
}
}

int main()
{
float adResult = 0;
float voltage = 0;

// Enable OCR1A interrupt

float resistance = 0;
double current = 0;
int buzzPeriod = 200;

ioinit();

while(1)
{

// Every loop starts with ADC measurement


// measurement is processed and display updated
ADMUX = mode - 1;
ADCSRA = ADCSRA | (1<<ADSC);

// Start ADC conversion

while(!(ADCSRA & (1<<ADIF))) // Wait for AD interrupt flag


;
adResult = ((ADCL) | ((ADCH)<<8));

/*

// Shift high and low to 10-bit

This code will display ADC results


dig0 = trunc(adResult/1000);
dig1 = trunc(adResult/100) - 10*dig0;
dig2 = trunc(adResult/10) - 100*dig0 - 10*dig1;
dig3 = trunc(adResult) - 1000*dig0 - 100*dig1 - 10*dig2;

*/
if (mode == 1)

// Voltage mode

{
voltage = adResult/1024;
dig0 = trunc(voltage*3.281);
dig1 = trunc(voltage*32.81) -10*dig0;
dig2 = trunc(voltage*328.1) - 100*dig0 - 10*dig1;
dig3 = trunc(voltage*3281) - 1000*dig0 - 100*dig1 - 10*dig2;

if (mode == 2)

// Current mode

{
current = adResult/1024;
dig0 = trunc(current*0.484);
dig1 = trunc(current*4.84) - 10*dig0;
dig2 = trunc(current*48.4) - 100*dig0 - 10*dig1;
dig3 = trunc(current*484) - 1000*dig0 - 100*dig1 - 10*dig2;
}
if (mode == 3)

// Resistance mode

{
resistance = (1024000/(adResult+1)) - 1000;
if (resistance < 10000) resDP = 0;
if ((resistance >= 1000000)&&(resistance < 200000))
{
resDP = 0b00000111;
resistance /= 1000;
}
else if ((resistance >= 100000)&&(resistance < 200000))
{
resDP = 0b0000100;
resistance /= 100;
}
else if ((resistance >= 10000)&&(resistance < 200000))
{
resDP = 0b00000010;
resistance /= 10;
}
else
resDP = 0b00001000;
if ((resistance < 10000)&&(resistance < 200000))

{
dig0 = trunc(resistance/1000);
dig1 = trunc(resistance/100) - 10*dig0;
dig2 = trunc(resistance/10) - 100*dig0 - 10*dig1;
dig3 = trunc(resistance) - 1000*dig0 - 100*dig1 - 10*dig2;
}
else
{
resDP = 0x00;
dig0 = 10;

// -

dig1 = 0;

// 0

dig2 = 11;

// L

dig3 = 10;

// -

// Buzzer if Resistance = 0
if (resistance == 0)
{
cli();

// disable interrupts, else get yucky buzzer

for(int i = 0 ; i < 100 ; i++)


{
cbi(PORTC, 4);
sbi(PORTC, 5);
_delay_us(buzzPeriod);
sbi(PORTC, 4);
cbi(PORTC, 5);
_delay_us(buzzPeriod);
}
sei(); // enable interrupts
}

if ((mode == 1)||(mode == 2)||((mode==3)&&(adResult<1023)))


_delay_ms(50);

//This delay is to make display more readable

in V anc I modes
PORTC = 0b0001000;
}

return 0;
}

void ioinit(void)
{
sei();

DDRD = 0xFF;

// Set data direction for port D (A,B,...,G)

PORTD = PORTD | 0b00000000; // Initialize all segments off

DDRB = 0b00011111;

// Set data direction for digits and button (PB5)

PORTB = PORTB | 0b00111111; // All digits off, button high

DDRC = 0x78;

// PC0-2 are input, rest output

/* Set up ADC */
ADCSRA = (1<<ADEN);

// Enable ADC

// Set 16-bit Timer 1 to update display


TCCR1A = 0x00;
TCCR1B = (_BV(WGM12) | _BV(CS12) | _BV(CS10)); // Divide clock by 1024,
CTC mode
OCR1A = 50;

// Set top of counter

TIMSK1 = _BV(OCIE1A);

// Enable OCR1A interrupt

// Set Timer 0 to check button press


TCCR0A = _BV(WGM01);
TCCR0B = _BV(CS00) | _BV(CS02);
OCR0A = 255;
debounce time

// OCCR0A can be adjusted to change the button

TIMSK0 = _BV(OCIE0A);
}

// Output number to digit 0,1,2, or 3, 4 to display dots


void display(int number, int digit)
{
// Clear display initially
PORTB &= 0b11100000;
PORTD = 0x00;

// Turn on Digit
sbi(PORTB, digit);

switch(number)

// Set PORTD, display pins, to correct output

{
case 0:
PORTD = 0b11000000;
break;
case 1:
PORTD = 0b11111001;
break;
case 2:

PORTD = 0b10100100;
break;
case 3:
PORTD = 0b10110000;
break;
case 4:
PORTD = 0b10011001;
break;
case 5:
PORTD = 0b10010010;
break;
case 6:
PORTD = 0b10000010;
break;
case 7:
PORTD = 0b11111000;
break;
case 8:
PORTD = 0b10000000;
break;
case 9:
PORTD = 0b10011000;
break;
case 10:
PORTD = 0b10111111;
break;
case 11:
PORTD = 0b11000111;
break;
}

if (DPStatus != 0)
{
// Turn on decimal points depending on DPStatus
if ((DPStatus & (1<<0))&&(digit==0))
{
cbi(PORTD, 7);
}
if ((DPStatus & (1<<1))&&(digit==1))
{
cbi(PORTD, 7);
}
if ((DPStatus & (1<<2))&&(digit==2))
{
cbi(PORTD, 7);
}
if ((DPStatus & (1<<3))&&(digit==3))
{
cbi(PORTD, 7);
}

}
}

Potrebbero piacerti anche