Wednesday, June 27, 2012

AVR Tutorial - 6. Analogue to Digital Converter ( ADC )


1.                  ADC

·         The world around us is analogue in nature and the microcontroller usually understands only digitial information .ie. Whether input is there or not.
·         There is a built in Analogue to digital converter inside the microcontroller which could be used to read the input voltage given to the ADC pins of the µC.
·         AVcc and AGND are the pins to power on the ADC peripheral and we use the voltage given in AREF as the analogue reference voltage.
·         There is a 10 bit counter inside the µC for counting the ADC input as the fraction of AREF voltage. So the ADC has got a resolution of 10-bit and it has got an operational speed of 15kSPS (Kilo Samples per Second)
·         We need to set two registers for using ADC:
i.                    ADCSRA – ADC Control and Status Register




ADEN: This bit is set to enable the ADC.
ADSC: This bit is set to start an ADC Conversion
ADIF: ADC Interrupt flag set by the hardware when a conversion is over.
ADIF: ADC Interrupt mask bit.
ADSPx : ADC prescaler bit. ADC Sampling works well at a frequence range of 50kHz to 200kHz. So we need to prescale the system clock value down to a value within that frequency.

ii.                  ADMUX – ADC Multiplexer
This register is being mainly used to set the ADC source, ADC reference source and also the ADC bit alignment selector







·         ADC could be used in 8-bit and 10-bit modes.
·         We will be having ADCH and ADCL as the ADC counter. If we are using the 8-bit mode then we could get the maximum reading as 255 and in 10bit mode we could get it as 1023.
·         In 8 bit mode the input voltage will be (ADC_count * VREF) / 255
·         In 10 bit mode the input voltage will be (ADC_count * VREF) / 1023


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




void main()
{
     DDRB = 0b00000111; //Green in PB0, Yellow in PB1, Red in PB2
     PORTB = 0x00;

     ADCSRA = (1<<ADEN) | (1<<ADSC) | (1<<ADIE);
ADCSRA|=(1<<ADPS2)|(1<<ADPS1)|(0 << ADPS0); //Setting the prescaler
     ADMUX = (1<<ADLAR)|(1<<MUX0)|(1<<MUX1)|(1<<MUX2); //ADC7 for I/P
    
     sei();
          
     while(1)
     {
    
     }
}

ISR(ADC_vect)
{
     uint8_t x = ADCH; //Using the 8-bit ADC mode
     if( (((float)x*5)/255) > 3.5)
     {
                PORTB = 0x02;
     }
     else if( (((float)x*5)/255) < 1.5)
     {
                PORTB = 0x01;
     }
     else
           PORTB = 0x04;
    
     ADCSRA |= (1<<ADSC);


}

AVR Tutorial - 5. Timers and Counters





1.                  Timers and Counters
·         Timers and Counters are the one of the most commonly used complex peripheral in a microcontroller.
·         They are used for getting time periods, generating pulse signals and also for measuring time period of pulses.
·         There are two main TIMER/COUNTER in ATMEGA32 : TIMER0(8-Bit) and TIMER1(16-Bit)
·         Timer0 will roll over after 255 and Timer1 will rollover after 65,535. So be careful about this roll over when using Timers in a µC.
·         TCNT0 is the counter for TIMER0 ie. It is like a variable which counts with the oscillation of system clock and rolls over back to 0.
·         Similarly TCNT1 is the counter for TIMER1.

Timer0:
Using timer 1 includes setting the appropriate values in the Timer Counter Control Register mainly for setting the speed / frequency at which TCNT0 is counting.


Program:



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


void main()
{
                DDRB = 0b00000011;
                PORTB = 0b00000000;
               
                TCCR0 = (1<<CS02) | (0<<CS01) | (1<<CS00); //   8MHz / 1024 as prescaler
                TCNT0 = 0;           
                int ctr1 = 0;
                int sec_ctr = 0;

                                               
                while(1)
                {
                                if(TCNT0 == 200)
                                {
                                                PORTB = 0b00000000;
                                                TCNT0 = 0;
                                                ctr1++;
                                                if(ctr1 == 39)
                                                {
                                                                ctr1 = 0 ;
                                                                PORTB = 0b00000001;
                                                                sec_ctr++;
                                                                if(sec_ctr >= 60) //checking for elapsing of one minute
                                                                {
                                                                                PORTB |= 0b00000010;
                                                                                sec_ctr = 0;
                                                                                _delay_ms(10);
                                                                }
                                                }
                                }
                }}
·         An interrupt is also being generated when the overflow of Timer occurs.
·         We need to unmask the TIMER0 overflow interrupt in the TIMSK registers and should use suitable ISRs.


·         The previous example could be done with the help of interrupts as given below:

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

int ctr1 = 0;
int sec_ctr = 0;

void main()
{
     DDRB = 0b00000011;
     PORTB = 0b00000001;
     TCCR0 = (1<<CS02) | (0<<CS01) | (1<<CS00);
     TIMSK = 0x01; //Enabling TIM0 ovf interrupt
     TCNT0 = 55;
     sei();
     int ctr1 = 0;
     int sec_ctr = 0;
     OCR0 = 0;
     while1)
     {
           //Do nothing…
     }
}




ISR(TIMER0_OVF_vect)
{
     TCNT0 = 55;
     PORTB = 0b00000000;
     ctr1++;
     if(ctr1 == 39)
     {
           ctr1 = 0 ;
           PORTB = 0b00000001;
           sec_ctr++;
           if(sec_ctr >= 60) //checking for elapsing of one minute
           {
                PORTB |= 0b00000010;
                sec_ctr = 0;
                _delay_ms(10);
           }
     }


}

TIMER1:
·         Timer1 is a 16 bit counter and rolls over occur after 65535.
·         Here the Timer Counter Control Registers are TCCR1A and TCCR1B
·         We will be using here just TCCR1B for setting the prescaler bits.





Program:
Source: www.newbiehack.com
#include <avr/io.h>
int main(void)
{
DDRB = 0b01111111;
PORTB = 0b00000000;
DDRD = 0b01111111;
PORTD = 0b00000000;
TCCR1B |= 1<<CS10 | 1<<CS11;
int LEDNumber[2];
while(1)
{
if (TCNT1 > 2232)
{
TCNT1 = 0;
PORTB = 1<<LEDNumber[0];
LEDNumber[0] ++;
if (LEDNumber[0] > 6)
{
LEDNumber[0] = 0;
PORTD = 1<<LEDNumber[1];
LEDNumber[1] ++;
if (LEDNumber[1] > 6)
LEDNumber[1] = 0;
}
}
}
}
·         We could also do this thing using interrupts:
Source: www.newbiehack.com
#include <avr/io.h>
#include <avr/interrupt.h>

int main(void)
{
sei();

DDRB |= 1<<PINB0;

TCCR1B |= 1<<CS10 | 1<<CS11 | 1<<WGM12;
TIMSK |= 1<<OCIE1A;
OCR1A = 15624;

while(1)
{
}
}

ISR(TIMER1_COMPA_vect)
{
PORTB ^= 1<<PINB0;
}

AVR Tutorial - 4. Interrupts




In a microcontroller or in any microprocessor, we could check the status of a device or input from a pin in two different ways:
i.                    Polling
ii.                  Interrupt Method
In polling the µC periodically check for the input or status flags from the external peripheral to get the status of its working. In the case of interrupt method when the external (or even internal) peripheral needs the attention of the processor, it will trigger an interrupt and the processor will stop execution of the current statements and store the present program address in system stack, execute a set of codes called ISR (Interrupt Service Routine) associated with the particular interrupt and restores the lastly executed program from stack and continue its work.

            In this chapter we will be demonstrating how we can make an external interrupt to trigger our ATMEGA32 µC. We will be connecting an external switch to the external interrupt 0 (INT0) of our µC and toggling the led connected to the circuit.

            In order to trigger enable the external interrupt we must do three things mainly:
i.                    Unmask the needed external interrupt in the GICR (General Interrupt Control Register).


Unmask the INT0 bit for enabling INT0
Unmask the INT1 bit for enabling INT1
Unmask the INT2 bit for enabling INT2


ii.                  Set the interrupt sense bits in the MCUCR (MCU Control Register), ie. to enable interrupt when there is a change in voltage level / when there is a rising edge / falling edge etc.

iii.                Set the global interrupt enable bit in the SREG which is being done by calling the function sei( );
Example 1: Toggling LED on External Interrupt INT0



Program:
#include <avr/io.h>
#include <util/delay.h>
#include<avr/interrupt.h>


void main()
{
            DDRB = 0b00000001;
            PORTB = 0b00000001;
           
            GICR = 0b01000000; //Enabling external interrupt 0
            MCUCR = 0b00000011; //INT0 triggered on rising edge
            sei( );              
            while(1)
            {
            }
}

ISR(INT0_vect) //Interrupt Service Routine for external Interrupt
{

            PORTB ^= 0b00000001;

}




·         Here we have included the interrupt.h header file which do contains the vector number and other interrupt related definitions for using external interrupts.
·         In the circuit we have connected a switch to the INT0th pin with a 10K pull up resistor so that is we press switch it will become logical low and else it will be logical high.
·         In GICR we have enabled just the external interrupt 0 ie. INT0.
·         We have set the MCUCR to trigger the INT0 on external interrupt 0 on rising edge.
·         We have called the sei( ) interrupt enabler function.
·         We have used ISR(INT0_vect) to write the statements associated with the INT0 interrupt. INT0_vect is the alias for interrupt vector number whose definition comes in the interrupt.h header file.

The following tables give the list of all available interrupts and its use:
Vector name
Old vector name
Description
ADC_vect
SIG_ADC
ADC Conversion Complete
ANALOG_COMP_0_vect
SIG_COMPARATOR0
Analog Comparator 0
ANALOG_COMP_1_vect
SIG_COMPARATOR1
Analog Comparator 1
ANALOG_COMP_2_vect
SIG_COMPARATOR2
Analog Comparator 2
ANALOG_COMP_vect
SIG_COMPARATOR
Analog Comparator
ANA_COMP_vect
SIG_COMPARATOR
Analog Comparator
CANIT_vect
SIG_CAN_INTERRUPT1
CAN Transfer Complete or Error
EEPROM_READY_vect
SIG_EEPROM_READY, SIG_EE_READY
EE_RDY_vect
SIG_EEPROM_READY
EEPROM Ready
EE_READY_vect
SIG_EEPROM_READY
EEPROM Ready
EXT_INT0_vect
SIG_INTERRUPT0
External Interrupt Request 0
INT0_vect
SIG_INTERRUPT0
External Interrupt 0
INT1_vect
SIG_INTERRUPT1
External Interrupt Request 1
INT2_vect
SIG_INTERRUPT2
External Interrupt Request 2
INT3_vect
SIG_INTERRUPT3
External Interrupt Request 3
INT4_vect
SIG_INTERRUPT4
External Interrupt Request 4
INT5_vect
SIG_INTERRUPT5
External Interrupt Request 5
INT6_vect
SIG_INTERRUPT6
External Interrupt Request 6
INT7_vect
SIG_INTERRUPT7
External Interrupt Request 7
IO_PINS_vect
SIG_PIN, SIG_PIN_CHANGE
External Interrupt Request 0
LCD_vect
SIG_LCD
LCD Start of Frame
LOWLEVEL_IO_PINS_vect
SIG_PIN
Low-level Input on Port B
OVRIT_vect
SIG_CAN_OVERFLOW1
CAN Timer Overrun
PCINT0_vect
SIG_PIN_CHANGE0
Pin Change Interrupt Request 0
PCINT1_vect
SIG_PIN_CHANGE1
Pin Change Interrupt Request 1
PCINT2_vect
SIG_PIN_CHANGE2
Pin Change Interrupt Request 2
PCINT3_vect
SIG_PIN_CHANGE3
Pin Change Interrupt Request 3
PCINT_vect
SIG_PIN_CHANGE, SIG_PCINT
PSC0_CAPT_vect
SIG_PSC0_CAPTURE
PSC0 Capture Event
PSC0_EC_vect
SIG_PSC0_END_CYCLE
PSC0 End Cycle
PSC1_CAPT_vect
SIG_PSC1_CAPTURE
PSC1 Capture Event
PSC1_EC_vect
SIG_PSC1_END_CYCLE
PSC1 End Cycle
PSC2_CAPT_vect
SIG_PSC2_CAPTURE
PSC2 Capture Event
PSC2_EC_vect
SIG_PSC2_END_CYCLE
PSC2 End Cycle
SPI_STC_vect
SIG_SPI
Serial Transfer Complete
SPM_RDY_vect
SIG_SPM_READY
Store Program Memory Ready
SPM_READY_vect
SIG_SPM_READY
Store Program Memory Read
TIM0_COMPA_vect
SIG_OUTPUT_COMPARE0A
Timer/Counter Compare Match A
TIM0_COMPB_vect
SIG_OUTPUT_COMPARE0B
Timer/Counter Compare Match B
TIM0_OVF_vect
SIG_OVERFLOW0
Timer/Counter0 Overflow
TIM1_CAPT_vect
SIG_INPUT_CAPTURE1
Timer/Counter1 Capture Event
TIM1_COMPA_vect
SIG_OUTPUT_COMPARE1A
Timer/Counter1 Compare Match A
TIM1_COMPB_vect
SIG_OUTPUT_COMPARE1B
Timer/Counter1 Compare Match B
TIM1_OVF_vect
SIG_OVERFLOW1
Timer/Counter1 Overflow
TIMER0_CAPT_vect
SIG_INPUT_CAPTURE0
ADC Conversion Complete
TIMER0_COMPA_vect
SIG_OUTPUT_COMPARE0A
TimerCounter0 Compare Match A
TIMER0_COMPB_vect
SIG_OUTPUT_COMPARE0B, SIG_OUTPUT_COMPARE0_B
Timer Counter 0 Compare Match B
TIMER0_COMP_A_vect
SIG_OUTPUT_COMPARE0A, SIG_OUTPUT_COMPARE0_A
Timer/Counter0 Compare Match A
TIMER0_COMP_vect
SIG_OUTPUT_COMPARE0
Timer/Counter0 Compare Match
TIMER0_OVF0_vect
SIG_OVERFLOW0
Timer/Counter0 Overflow
TIMER0_OVF_vect
SIG_OVERFLOW0
Timer/Counter0 Overflow
TIMER1_CAPT1_vect
SIG_INPUT_CAPTURE1
Timer/Counter1 Capture Event
TIMER1_CAPT_vect
SIG_INPUT_CAPTURE1
Timer/Counter Capture Event
TIMER1_CMPA_vect
SIG_OUTPUT_COMPARE1A
Timer/Counter1 Compare Match 1A
TIMER1_CMPB_vect
SIG_OUTPUT_COMPARE1B
Timer/Counter1 Compare Match 1B
TIMER1_COMP1_vect
SIG_OUTPUT_COMPARE1A
Timer/Counter1 Compare Match
TIMER1_COMPA_vect
SIG_OUTPUT_COMPARE1A
Timer/Counter1 Compare Match A
TIMER1_COMPB_vect
SIG_OUTPUT_COMPARE1B
Timer/Counter1 Compare MatchB
TIMER1_COMPC_vect
SIG_OUTPUT_COMPARE1C
Timer/Counter1 Compare Match C
TIMER1_COMPD_vect
SIG_OUTPUT_COMPARE0D
Timer/Counter1 Compare Match D
TIMER1_COMP_vect
SIG_OUTPUT_COMPARE1A
Timer/Counter1 Compare Match
TIMER1_OVF1_vect
SIG_OVERFLOW1
Timer/Counter1 Overflow
TIMER1_OVF_vect
SIG_OVERFLOW1
Timer/Counter1 Overflow
TIMER2_COMPA_vect
SIG_OUTPUT_COMPARE2A
Timer/Counter2 Compare Match A
TIMER2_COMPB_vect
SIG_OUTPUT_COMPARE2B
Timer/Counter2 Compare Match A
TIMER2_COMP_vect
SIG_OUTPUT_COMPARE2
Timer/Counter2 Compare Match
TIMER2_OVF_vect
SIG_OVERFLOW2
Timer/Counter2 Overflow
TIMER3_CAPT_vect
SIG_INPUT_CAPTURE3
Timer/Counter3 Capture Event
TIMER3_COMPA_vect
SIG_OUTPUT_COMPARE3A
Timer/Counter3 Compare Match A
TIMER3_COMPB_vect
SIG_OUTPUT_COMPARE3B
Timer/Counter3 Compare Match B
TIMER3_COMPC_vect
SIG_OUTPUT_COMPARE3C
Timer/Counter3 Compare Match C
TIMER3_OVF_vect
SIG_OVERFLOW3
Timer/Counter3 Overflow
TIMER4_CAPT_vect
SIG_INPUT_CAPTURE4
Timer/Counter4 Capture Event
TIMER4_COMPA_vect
SIG_OUTPUT_COMPARE4A
Timer/Counter4 Compare Match A
TIMER4_COMPB_vect
SIG_OUTPUT_COMPARE4B
Timer/Counter4 Compare Match B
TIMER4_COMPC_vect
SIG_OUTPUT_COMPARE4C
Timer/Counter4 Compare Match C
TIMER4_OVF_vect
SIG_OVERFLOW4
Timer/Counter4 Overflow
TIMER5_CAPT_vect
SIG_INPUT_CAPTURE5
Timer/Counter5 Capture Event
TIMER5_COMPA_vect
SIG_OUTPUT_COMPARE5A
Timer/Counter5 Compare Match A
TIMER5_COMPB_vect
SIG_OUTPUT_COMPARE5B
Timer/Counter5 Compare Match B
TIMER5_COMPC_vect
SIG_OUTPUT_COMPARE5C
Timer/Counter5 Compare Match C
TIMER5_OVF_vect
SIG_OVERFLOW5
Timer/Counter5 Overflow
TWI_vect
SIG_2WIRE_SERIAL
2-wire Serial Interface
TXDONE_vect
SIG_TXDONE
Transmission Done, Bit Timer Flag 2 Interrupt
TXEMPTY_vect
SIG_TXBE
Transmit Buffer Empty, Bit Itmer Flag 0 Interrupt
UART0_RX_vect
SIG_UART0_RECV
UART0, Rx Complete
UART0_TX_vect
SIG_UART0_TRANS
UART0, Tx Complete
UART0_UDRE_vect
SIG_UART0_DATA
UART0 Data Register Empty
UART1_RX_vect
SIG_UART1_RECV
UART1, Rx Complete
UART1_TX_vect
SIG_UART1_TRANS
UART1, Tx Complete
UART1_UDRE_vect
SIG_UART1_DATA
UART1 Data Register Empty
UART_RX_vect
SIG_UART_RECV
UART, Rx Complete
UART_TX_vect
SIG_UART_TRANS
UART, Tx Complete
UART_UDRE_vect
SIG_UART_DATA
UART Data Register Empty
USART0_RXC_vect
SIG_USART0_RECV
USART0, Rx Complete
USART0_RX_vect
SIG_UART0_RECV
USART0, Rx Complete
USART0_TXC_vect
SIG_USART0_TRANS
USART0, Tx Complete
USART0_TX_vect
SIG_UART0_TRANS
USART0, Tx Complete
USART0_UDRE_vect
SIG_UART0_DATA
USART0 Data Register Empty
USART1_RXC_vect
SIG_USART1_RECV
USART1, Rx Complete
USART1_RX_vect
SIG_UART1_RECV
USART1, Rx Complete
USART1_TXC_vect
SIG_USART1_TRANS
USART1, Tx Complete
USART1_TX_vect
SIG_UART1_TRANS
USART1, Tx Complete
USART1_UDRE_vect
SIG_UART1_DATA
USART1, Data Register Empty
USART2_RX_vect
SIG_USART2_RECV
USART2, Rx Complete
USART2_TX_vect
SIG_USART2_TRANS
USART2, Tx Complete
USART2_UDRE_vect
SIG_USART2_DATA
USART2 Data register Empty
USART3_RX_vect
SIG_USART3_RECV
USART3, Rx Complete
USART3_TX_vect
SIG_USART3_TRANS
USART3, Tx Complete
USART3_UDRE_vect
SIG_USART3_DATA
USART3 Data register Empty
USART_RXC_vect
SIG_USART_RECV, SIG_UART_RECV
USART, Rx Complete
USART_RX_vect
SIG_USART_RECV, SIG_UART_RECV
USART, Rx Complete
USART_TXC_vect
SIG_USART_TRANS, SIG_UART_TRANS
USART, Tx Complete
USART_TX_vect
SIG_USART_TRANS, SIG_UART_TRANS
USART, Tx Complete
USART_UDRE_vect
SIG_USART_DATA, SIG_UART_DATA
USART Data Register Empty
USI_OVERFLOW_vect
SIG_USI_OVERFLOW
USI Overflow
USI_OVF_vect
SIG_USI_OVERFLOW
USI Overflow
USI_START_vect
SIG_USI_START
USI Start Condition
USI_STRT_vect
SIG_USI_START
USI Start
USI_STR_vect
SIG_USI_START
USI START
WATCHDOG_vect
SIG_WATCHDOG_TIMEOUT
Watchdog Time-out
WDT_OVERFLOW_vect
SIG_WATCHDOG_TIMEOUT, SIG_WDT_OVERFLOW
Watchdog Timer Overflow
WDT_vect
SIG_WDT, SIG_WATCHDOG_TIMEOUT
Watchdog Timeout Interrupt