Hello,
Recently I was trying to recreate the Arduino ‘analogRead’ functionality using direct register manipulation, to get a better understanding of how MCU’s work and to be able to program MCU’s without being bound to Arduino library functions. I was using the ATmega328P (Nano) and implemented the below ADC code according to the datasheet.
One thing that struck me is that the output I received from ADC_Read() was different when the
Serial.println("Random String"); statement in the
while loop was commented and when left uncommented.
When serial.print was commented,
value was 0 (which is not what i was expecting).
When
serial.print was uncommented,
value was floating around with values of roughly 500 (which is what i was expecting, since nothing was attached to the analog input).
So, it seems that when
Serial.println("Random String"); was commented out, the
while loop didn’t execute properly. My suspicion is that possibly the while loop is optimised away, because the compiler thinks the while loop isn’t doing anything? Would anyone know what might be going on?
I recently came across another situation using a for loop, in which the code inside the loop only seemed to be executed properly when I included a serial.print statement as well, even though the variables that were used in the for loop were being used later on in the script as well (i.e. it would be unexpected for the loop to be optimised away).
#include <util/delay.h> #define DDRC (*((byte *)0x27)) // Data direction Register C #define ADMUX (*((byte *)0x7c)) // ADMUX register address #define ADCSRA (*((byte *)0x7a)) // ADCSRA register address #define ADSC 6 // ADSC bit position counting from the right #define ADIF 4 // ADIF bit position (within register) counting from the right #define ADCL (*((byte *)0x78)) // The value stored at register address 0x78 #define ADCH (*((byte *)0x79)) // The value stored at register address 0x79 void ADC_Init() { DDRC = 0b00000000; /* Make ADC port as input */ ADCSRA = 0b10000111; /* Set division as fr/128 AND set ADC enable bit ADEN. */ ADMUX = 0b01000001; /* Set analog channel 1 as input AND set ADC reference voltage as 01. */ } int ADC_Read(int channel){ int Ain, AinLow; // Upper and lower analog bytes ADMUX = ADMUX | (channel & 0x0f); // Set input channel to read. 0x0f = 0b1111 ADCSRA |= (1 << ADSC); // Start conversion. while((ADCSRA & (1<<ADIF)) == 0){ // While loop until conversion interrupt flag is set. Here the & refers to bitwise AND. // Serial.println("Random String"); // While loop only seems to function when there is something going on inside it. // _delay_us(100); } _delay_us(10); AinLow = (int)ADCL; //Read lower byte Ain = (int)ADCH * 256; //Read higher 2 bits and multiply by weight of 256 since this is the 9th bit, which is 2x128 of binary base. Ain = Ain + AinLow; return(Ain); } void setup() { Serial.begin(9600); ADC_Init(); } void loop() { int value; value = ADC_Read(1); // Read ADC channel 1 Serial.println(value); _delay_us(50); }