ATMEGA16 Programming

Discussion in 'Programmer's Corner' started by Mopinion, Apr 24, 2011.

  1. Mopinion

    Thread Starter New Member

    Apr 24, 2011
    6
    0
    Hello all,
    I am trying to set up a program that takes in an input from an ADC (potentiometer) and output it to an LED via PWM. I am doing this using the ATmega16 microcontroller. Also, I have set it up so that if switch 0 is pressed the output from the PWM is taken directly from the ADC. If switch 1 is pressed the output from the PWM is the full voltage if the ADC is greater than 128. I have gotten the ADC and PWM to work together with the LED, but when introducing the if statements for switch 0 and 1 it stops working.
    If anyone could help me that would be great.
    The code is below:
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #define F_CPU 3686400
    #include <util/delay.h>

    // Function Prototypes
    void PWM_init(void);
    void ADC_init(void);
    void start_convert(void);

    // Global variables
    volatile unsigned char dim;

    int main(void)
    {
    // initialize IO port, interrupt and PWM
    // Set Port B as output port for the LEDs
    DDRB = 0xFF;
    PORTB = 0xFF;
    // Set Port A as input ADC
    DDRA = 0x00;
    PORTA = 0xFF;
    // Set Port C as switch input
    DDRC = 0x00;
    PORTC = 0xFF;

    // enable global variable
    sei();
    // Initialize PWM
    PWM_init();
    // Initialize PWM
    ADC_init();

    while (1)
    {
    // keep looping the conversion process

    start_convert();
    // so the human eye can track bit changes
    _delay_ms(40);


    }
    return 0;
    }

    // PWM Interrupt Service Routine
    ISR(TIMER1_OVF_vect)
    {
    // If switch 0 is pressed then output through PWNM
    if(PINC=0xFE)
    {
    // Update the register by the binary value presented
    // at Port A
    OCR1A = dim;
    }

    if(PINC=0xFE)
    {
    if(~ADCH > 128)
    {
    OCR1A = 0xFF;
    }
    }
    }

    // ADC Interrupt Service Routine
    ISR(ADC_vect)
    {
    // Read from ADC data register (MSB)
    dim = ~ADCH;
    }

    // Inialization of PWM
    void PWM_init(void)
    {
    // Initialize OCIA as output port
    DDRD |= (1 << PD5);
    // Initialize Timer/Counter 1 overflow interrupt
    TIMSK |= (1 << TOIE1);
    // Program COM1A so that OCIA is set at TOP
    TCCR1A |= (1 << COM1A1);
    // Program WGM to Phase-correct, 8-bit mode
    TCCR1A |= (1 << WGM10);
    // Set Timer/Counter 1 prescalar to Clk/1
    TCCR1B |= (1 << CS10);
    }

    // Inialization of ADC
    void ADC_init(void)
    {
    // Enable ADC and ADC interrupt
    ADCSRA |= 0x88; // or ADCSRA |= (1<<ADEN)|(1<<ADIE)
    // Select ADC0 as single-ended analog input
    ADMUX |= 0xE0; // Set lower 5 bits to 0
    // Select the 2.56V internal voltage reference with external capacitor
    // at the AREF pin
    ADMUX |= (3<<REFS0);
    // Left adjusted register (ADLAR = 1)
    ADMUX |= (1<<ADLAR);
    }

    // Start conversion
    void start_convert(void)
    {
    // Start Conversion
    ADCSRA |= (1 << ADSC) | (1 << ADIE);
    }
     
  2. Kermit2

    AAC Fanatic!

    Feb 5, 2010
    3,783
    945
    It may not be the problem but in the code where the PWM INTERUPT SERVICE ROUTINE starts you have one more left bracket than you do right brackets. You may need to close it.
     
  3. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    I have added code formating tags (see the # sign ) in the menu icons above the editing window. It makes the code easier to follow... I also did a bit of indenting to help with readability.

     
  4. Mopinion

    Thread Starter New Member

    Apr 24, 2011
    6
    0
    hmm... by my count there are 4 open and 4 close brackets... Also, i'm pretty sure i would have gotten an error if i have uneven number of brackets when compiling. Can't figure out what's wrong. When testing it seems it automatically only runs the PWM case and not the other case.
     
  5. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    A couple of comments might be useful.

    1. You test the switch with the assignment operator '='. I think you need to use the "==" comparison operator.

    2. I think you would be better off if you used a mask with your switch state test.

    3. I think you would be better served if you placed your switch test in the main loop rather than put it into the interrupt service routine.

    hgmjr
     
  6. Mopinion

    Thread Starter New Member

    Apr 24, 2011
    6
    0
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #define F_CPU 3686400
    #include <util/delay.h>

    // Function Prototypes
    void PWM_init(void);
    void ADC_init(void);
    void start_convert(void);

    // Global variables
    volatile unsigned char dim;
    volatile unsigned char x;

    int main(void)
    {
    // initialize IO port, interrupt and PWM
    // Set Port B as output port for the LEDs
    DDRB = 0xFF;
    PORTB = 0xFF;
    // Set Port A as input ADC
    DDRA = 0x00;
    PORTA = 0xFF;
    // Set Port C as switch input
    DDRC = 0x00;
    PORTC = 0xFF;

    // enable global variable
    sei();
    // Initialize PWM
    PWM_init();
    // Initialize PWM
    ADC_init();

    while (1)
    {
    // keep looping the conversion process

    start_convert();
    // so the human eye can track bit changes
    _delay_ms(40);
    // If switch 0 is pressed then output through PWNM
    if((PINC&0x01)==0x00)
    {
    // Update the register by the binary value presented
    // at Port A
    x = dim;
    }

    if((PINC&0x02)==0x00)
    {
    if(~ADCH > 128)
    {
    x = 0xFF;
    }
    }
    }
    return 0;
    }

    // PWM Interrupt Service Routine
    ISR(TIMER1_OVF_vect)
    {
    OCR1A = x;
    }

    // ADC Interrupt Service Routine
    ISR(ADC_vect)
    {
    // Read from ADC data register (MSB)
    dim = ~ADCH;
    }

    // Inialization of PWM
    void PWM_init(void)
    {
    // Initialize OCIA as output port
    DDRD |= (1 << PD5);
    // Initialize Timer/Counter 1 overflow interrupt
    TIMSK |= (1 << TOIE1);
    // Program COM1A so that OCIA is set at TOP
    TCCR1A |= (1 << COM1A1);
    // Program WGM to Phase-correct, 8-bit mode
    TCCR1A |= (1 << WGM10);
    // Set Timer/Counter 1 prescalar to Clk/1
    TCCR1B |= (1 << CS10);
    }

    // Inialization of ADC
    void ADC_init(void)
    {
    // Enable ADC and ADC interrupt
    ADCSRA |= 0x88; // or ADCSRA |= (1<<ADEN)|(1<<ADIE)
    // Select ADC0 as single-ended analog input
    ADMUX |= 0xE0; // Set lower 5 bits to 0
    // Select the 2.56V internal voltage reference with external capacitor
    // at the AREF pin
    ADMUX |= (3<<REFS0);
    // Left adjusted register (ADLAR = 1)
    ADMUX |= (1<<ADLAR);
    }

    // Start conversion
    void start_convert(void)
    {
    // Start Conversion
    ADCSRA |= (1 << ADSC) | (1 << ADIE);
    }

    -------------------------------------------------------------------------------
    So i've slightly changed the code around. What happens now is that when I hold down switch 0 the PWM case kicks in, but when i hold down switch 1, the LED just switched off. So two problems:
    1) If statement for the second switch (switch 1) does not work.
    2) I have to hold down switch 0 or 1 in order for the case to work.
     
  7. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Used code tags to aid in reading the code...

     
  8. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    So are you wanting to be able to press the switch and then release it and have the circuit work as though you were continually holding down the switch?

    If so, then you need to introduce a variable (flag) that will toggle states when you press the appropriate switch. You can then test this flag to tell which state you are in.

    hgmjr
     
  9. Mopinion

    Thread Starter New Member

    Apr 24, 2011
    6
    0
    Yes, I apologize about the tags. Just noticed what you were talking about. I would like to do that, but i would first like to make sure that the switch 1 case works before editing it so that i don't need to hold down the switches... I have been trying for awhile now.
     
  10. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Have you checked the wiring of switch 1 to make sure that it is connected to the pin you are testing and that it is operating correctly?

    hgmjr
     
  11. Mopinion

    Thread Starter New Member

    Apr 24, 2011
    6
    0
    The microcontroller is on a development board. The only wiring involved is moving the jumper cables around, i have double checked them to make sure that they were correct. I am currently baffled.
     
  12. Mopinion

    Thread Starter New Member

    Apr 24, 2011
    6
    0
    The microcontroller is on a development board, along with the switches and the LED's. The jumper cables are the only connections I have control over, and I have checked them over and over again to make sure they are in the right places. I am baffled as to what is wrong with the program.
     
  13. hgmjr

    Moderator

    Jan 28, 2005
    9,030
    214
    Here is a quick check you can try.

    Temporarily assign the action for switch 1 into the 'if' statement for switch 0. If switch 0 performs the action properly then you have an issue with switch 1 and/or its wiring. If it does not perform the action then there is a code issue.

    hgmjr
     
Loading...