Search code examples
cmicrocontrolleravratmelstudio

Is this the right way to update global variable using ADC?


I am currently working on a small project. I'm trying to create a memory game. I have two LEDs that show some sequence and the player needs to repeat it. I want to use ADC to change the delay value, that is, the blinking speed.

I have a delay function with global variable like this...

uint16_t n = 500;

void delay(uint16_t n) {
    for(uint16_t i = 0; i < n ; i++) {
        for(uint16_t j = 0; j < 200 ; j++) {
            asm volatile ("NOP");
        }
    }
}

My ADC initialization looks like this

void ADC_Init() {
    ADMUX = (1<<MUX1 | 1<<REFS0);
    // ADEN --> ADC Enable | ADSC --> ADC Start Conversion | ADPS --> ADC Prescaler Select Bits (16)
    ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADPS2);    
}

Depending on the ADC reading, I want to change the value ​​of a global variable ( " n " ) that I use everywhere. In other words, I want to give a new value to the global variable from here

void NewDelayValue(n) {
    while (ADCSRA & (1<<ADIF)) {
    }
    if (n < 100) {
        n = 200;
    }
    else if (n > 200 && n < 300) {
        n = 300;
        return;
    }
    else if (n > 300 && n < 400) {
        n = 400;
        return;
    }
    else if (n > 500 && n < 600) {
        n = 500;
        return;
    }
    else if (n > 700 && n < 800) {
        n = 600;
        return;
    }
    else if (n > 900) {
        n = 700;
        return;
    }
    else {
        return;
    }
}

Is this the right way to do that ? How should i change my code to accomplish that ? I hope my words make sense, feel free to ask anythink.

My whole code

#define F_CPU 2000000UL
#include <avr/io.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

// Global
uint8_t Game[8];
int i;

uint16_t n = 500;
/*
void ADC_Init() {
    ADMUX = (1<<MUX1 | 1<<REFS0);
    // ADEN --> ADC Enable | ADSC --> ADC Start Conversion | ADPS --> ADC Prescaler Select Bits (16)
    ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADPS2);    
}
*/
/*
void NewDelayValue() {
    while (ADCSRA & (1<<ADIF)) {
    }
    if (n < 100) {
        n = 200;
    }
    else if (n > 200 && n < 300) {
        n = 300;
        return;
    }
    else if (n > 300 && n < 400) {
        n = 400;
        return;
    }
    else if (n > 500 && n < 600) {
        n = 500;
        return;
    }
    else if (n > 700 && n < 800) {
        n = 600;
        return;
    }
    else if (n > 900) {
        n = 700;
        return;
    }
    else {
        return;
    }
}
*/
void delay(uint16_t time_ms) {
    for(uint16_t i = 0; i < time_ms ; i++) {
        for(uint16_t j = 0; j < 200 ; j++) {
            asm volatile ("NOP");
        }
    }
}

void RandomNumber() {
    
    srand((unsigned int)time(NULL));
    for(unsigned int i = 0; i < sizeof(Game)/sizeof(Game[0]); i++) {
        int v = rand() % 2;
        Game[i] = v;
    }
}

void PlayDemo() {
    int i;
    for(i = 0; i < 8; i++) {
        if(Game[i] == 1) {
            PORTA = 0x80;
            delay(n);
            PORTA = 0x00;
            delay(n);
        }
        else if (Game[i] == 0) {
            PORTA = 0x01;
            delay(n);
            PORTA = 0x00;
            delay(n);
        }
        else {
            PORTA = 0x00;
        }
    }
}

uint8_t isButtonPressed(uint8_t PortValue) {
    if(PortValue & 0x08) {
        return 0;
    } else if(PortValue & 0x20) {
        return 1;
    }
    return 3;
}

int waitForPress() {

    uint8_t x = PINF;

    while(!(x & 0x20) && !(x & 0x08)) {
        x = PINF;
    }

    uint8_t ButtonPressed = isButtonPressed(x);
    delay(n);
    if(ButtonPressed == 1) {
        return 1;   
    } else if(ButtonPressed == 0) {
        return 0;
    }
    return 3;
}


int main(void) {
    MCUCR |= 0x80;
    MCUCR |= 0x80;
    DDRA = 0xFF;
    // 0x20 / 0x08 --> Joystick
    PORTF = 0x28;
    
    RandomNumber();
    PlayDemo();
    
    while(1)
    {
        /*
        if(isRightButtonPressed(PINF)) {
            PORTA = 0x01;
        } else {
            PORTA = 0x00;   
        }
        
        if(isLeftButtonPressed(PINF)) {
            PORTA = 0x80;
        } else {
            PORTA = 0x00;   
        }
        */
        
        for(uint8_t index = 0; index < 8; index++) {
            if(isButtonPressed(PINF) == 0) {
                PORTA = 0x01;
                int userInput = waitForPress();
                if(userInput != Game[index]) {
                    PORTA = 0xFF;
                    delay(n);
                    PORTA = 0x00;
                    delay(n);
                    break;
                } else if(userInput == Game[index]) {
                    PORTA = 0xFF;
                    delay(n);
                    PORTA = 0x00;
                    delay(n);
                }
            } else if(isButtonPressed(PINF) == 1) {
                PORTA = 0x80;
                int userInput = waitForPress();
                if(userInput != Game[index]) {
                    PORTA = 0xFF;
                    delay(n);
                    PORTA = 0x00;
                    delay(n);
                    break;
                } else if(userInput == Game[index]) {
                    PORTA = 0xFF;
                    delay(n);
                    PORTA = 0x00;
                    delay(n);
                } 
                }
        }
    }
}

Solution

  • Maybe this helps:

    unsigned int NewDelayValue() {
        // Use the single conversion bit to check if the ADC has finished if you
        // only use it one time. It helds 1 until the converstion has finished
        while (ADCSRA & (1<<ADSC));
    
        // It is not necessary that the ADC uses 10 Bit so you should configure
        // left adjustment (ADLAR = 1)
    
        // Read the ADC value:
        unsigned char data = ADCH;
    
        // Create a number 1 - 8
        // 0   - 31  = 0 + 1 = 1 * 100 = 100
        // 32  - 63  = 1 + 1 = 2 * 100 = 200
        // ...
        // 224 - 255 = 7 + 1 = 8 * 100 = 800
        //
        return 100UL * ((data>>5) + 1);
    
        // If there is a potentiometer connected to your ADC channel you can use
        // the whole length between 0 - End (0-255) to generate the numbers...
    }
    
    // Short form of your delay function
    void delay(unsigned int n) {
      // Can be included with -> #include <util/delay.h>
      _delay_ms(n);
    }
    
    
    // Call the function
    
    unsigned int d = NewDelayValue();
    delay(d);
    
    // Or short form
    delay(NewDelayValue());
    

    Configure the ADLAR register:

    void ADC_Init() {
        ADMUX = (1<<MUX1) | (1<<REFS0) | (1<<ADLAR);
        // ...
    }
    

    Global Variables that are changed by functions in c is a bad practice. Sometimes it is necessary (e.g. interrupts) but should be avoided.

    Let me know if this works...