Initialize ADC conflict with Serial.print()

I want to adjust LED blinking frequency on the run, and I tested this code:

/*
 * The program for adjusting the LED blinking frequence by a potentiometer
 * chip: ATmega328p
 * potentiometer --> ADC0
 * OC1A(PB1/D9) --> 1.5kOhm --> LED
 * OC1B - PB2/D10(Arduino UNO)
 */
 
#define F_CPU 16000000UL
#define VREF 5
#define POT 10000 // potentiometer - ohm10K

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

double potVal = 0;
  
// initialize timer, interrupt and variable
void timer1_init()
{
    // set up timer with prescaler = 1024 and CTC mode
    // TOP = OCR1A
    // Update of OCR1A at Immediate
    TCCR1B |= (1 << WGM12)|(1 << CS12)|(1 << CS10);
    // Toggle OC1A/OC1B on compare match
    TCCR1A = (1 << COM1A0);
  
    // initialize counter
    TCNT1 = 0;
  
    // initialize compare value
    // OCR1A = 15625;
    //OCR1A = 625;
}
  
void setup(void)
{
    // connect led to pin PB1
    DDRB |= (1 << 1);
  
    // initialize timer
    //timer1_init();

    // inintialize ADC
    //initADC();
    //delay(10);

    // for debugging
    Serial.begin(9600);
    Serial.print("Hello, World!");
}
  
    // loop forever
    void loop(){
    //while(1)
    {
        potVal=readADC(0);
        potVal = (potVal/1023.0)*(15625-625)+625;
        OCR1A = (int)potVal;
        //Serial.begin(9600);
        while(!Serial);
        Serial.print("OCR1A = ");
        Serial.println(potVal);
        
        // check whether the flag bit is set
        // if set, it means that there has been a compare match
        // and the timer has been cleared
        // use this opportunity to toggle the led
//        if (TIFR1 & (1 << OCF1A)) // NOTE: '>=' used instead of '=='
//        {
//            PORTB ^= (1 << 1); // toggles the led
//        }
//  
//        // wait! we are not done yet!
//        // clear the flag bit manually since there is no ISR to execute
//        // clear it by writing '1' to it (as per the datasheet)
//        TIFR1 |= (1 << OCF1A);
  
        // yeah, now we are done!
    }
}

void initADC()
{
  //select ADC channel ADC0
  ADMUX &= 0x11110000;
  // Select Vref=AVcc
  ADMUX |= (1<<REFS0);
  //set prescaller to 128 and enable ADC 
  ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);
  // Bit 6 – ADSC: ADC Start Conversion
  // In single conversion mode, write this bit to one to start each conversion. 
  // In free running mode, write this bit to one to start the first conversion.
  ADCSRA |= (1<<ADSC);
  // Bit 3 – ADIE: ADC Interrupt Enable
  // When this bit is written to one and the I-bit in SREG is set, the ADC conversion complete interrupt is activated.
  ADCSRA |= (1<<ADIE);
  // Bit 5 – ADATE: ADC Auto Trigger Enable
  // When this bit is written to one, auto triggering of the ADC is enabled. 
  // The ADC will start a conversion on a positive edge of the selected trigger signal. 
  // The trigger source is selected by setting the ADC trigger select bits, ADTS in ADCSRB.
  ADCSRA |= (1<<ADATE); 
  //In free running mode, the ADC is constantly sampling and updating the ADC Data Registers.  
  //This mode is selected by the ADFR bit in the ADC Control and Status Register.
  ADCSRB = 0x00000000;// Free running mode - ADTS2=ADTS1=ADTS0=0;  
}

uint16_t readADC(uint8_t ADCchannel)
{
 //select ADC channel with safety mask
 ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);
 //single conversion mode
 ADCSRA |= (1<<ADSC);
 // wait until ADC conversion is complete
 while( ADCSRA & (1<<ADSC) );
 return ADC;
}

Anytime I comment "initADC();", it was printing in serial monitor, ant if not, it would print "He" in serial monitor, then stop there, anyone know why?

Try writing the question again. It doesn’t make sense currently. Your “hello world” probably fails due to timing

I want to adjust the LED blinking frequency on the run, my scheme:

  1. LED - 1.5kOhm - PB1(OC1A)
  2. potentiometer - A0(ADC0)
  3. Timer1 in CTC mode

Three functions defined:
Two for ADC - " void initADC() " and " void initADC() "
One for Timer1 - " void timer1_init() "

Since the code didn't ran as it was expected, so I tested Timer0 CTC and ADC separately, Timer0 was OK, but the ADC was not, so I added "Serial.println()" for testing:

/*
 * The program for adjusting the LED blinking frequence by a potentiometer
 * chip: ATmega328p
 * potentiometer --> ADC0
 * OC1A(PB1/D9) --> 1.5kOhm --> LED
 * OC1B - PB2/D10(Arduino UNO)
 */
 
#define F_CPU 16000000UL
#define VREF 5
#define POT 10000 // potentiometer - ohm10K

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

double potVal = 0;

void initADC()
{
  //select ADC channel ADC0
  ADMUX &= 0x11110000;
  // Select Vref=AVcc
  ADMUX |= (1<<REFS0);
  //set prescaller to 128 and enable ADC 
  ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);
  // Bit 6 – ADSC: ADC Start Conversion
  // In single conversion mode, write this bit to one to start each conversion. 
  // In free running mode, write this bit to one to start the first conversion.
  ADCSRA |= (1<<ADSC);
  // Bit 3 – ADIE: ADC Interrupt Enable
  // When this bit is written to one and the I-bit in SREG is set, the ADC conversion complete interrupt is activated.
  ADCSRA |= (1<<ADIE);
  // Bit 5 – ADATE: ADC Auto Trigger Enable
  // When this bit is written to one, auto triggering of the ADC is enabled. 
  // The ADC will start a conversion on a positive edge of the selected trigger signal. 
  // The trigger source is selected by setting the ADC trigger select bits, ADTS in ADCSRB.
  ADCSRA |= (1<<ADATE); 
  //In free running mode, the ADC is constantly sampling and updating the ADC Data Registers.  
  //This mode is selected by the ADFR bit in the ADC Control and Status Register.
  ADCSRB = 0x00000000;// Free running mode - ADTS2=ADTS1=ADTS0=0;  
}

uint16_t readADC(uint8_t ADCchannel)
{
 //select ADC channel with safety mask
 ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);
 //single conversion mode
 ADCSRA |= (1<<ADSC);
 // wait until ADC conversion is complete
 while( ADCSRA & (1<<ADSC) );
 return ADC;
}
  
void setup(void)
{
    // inintialize ADC
    initADC();
    
    // for debugging
    Serial.begin(9600);
    Serial.print("Hello, World!");
}

void loop()
{
    potVal=readADC(0);
    potVal = (potVal/1023.0)*(15625-625)+625;
    OCR1A = (int)potVal;
    //Serial.begin(9600);
    while(!Serial);
    Serial.print("OCR1A = ");
    Serial.println(potVal);
}

I found that, inside "setup()", if I commented
initADC();,
then "Serial.println" would run properly:

if not, it would stop at the start:

Does it “stop”? Or does it fail to complete the hello world and move on?

Those are both different things

I couldn't judge, since the LED didn't blinking anyway.

Just stick a serial print in loop to test. You need to post a schematic. Are you using a pin that conflicts with serial

I used only 5 pins:

5V
GND
A0 for potetiometer
D9 for LED
D7 for pushbutton(no use in this project)

In initADC() you are turning on an interrupt for which you didn't provide an interrupt handler. Your sketch crashes as soon as that interrupt occurs.

I comment it, and it was the same.

The ADC code is not needed, and since it is certainly part of the problem, I suggest to remove all the ADC code and just use analogRead().

I changed it into:

int main(void)
{
    // connect led to pin PB1
    DDRB |= (1 << 1);
  
    // initialize timer
    timer1_init();

    // inintialize ADC
    //initADC();
    delay(1);

    pinMode(A0, INPUT);

    // for debugging
    Serial.begin(115200);
    Serial.print("Hello, World!");
  
    // loop forever
    while(1)
    {
        //potVal=readADC(0);
        potVal=analogRead(A0);
        potVal = (potVal/1023.0)*(15625-625)+625;
        OCR1A = (int)potVal;
        Serial.print("OCR1A = ");
        Serial.println(OCR1A);
...

now, totally nothing in Serial Monitor.

Post the rest of the code.

This is a bad idea for a beginner:

int main(void)

Please start with the standard setup() and loop() way of Arduino programming, and get that working, before stumbling around trying to learn how the alternatives work.

the whole one:

/*
 * The program for adjusting the LED blinking frequence by a potentiometer
 * chip: ATmega328p
 * potentiometer --> ADC0
 * OC1A(PB1/D9) --> 1.5kOhm --> LED
 * OC1B - PB2/D10(Arduino UNO)
 */
 
#define F_CPU 16000000UL
#define VREF 5
#define POT 10000 // potentiometer - ohm10K

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

double potVal = 0;
  
// initialize timer, interrupt and variable
void timer1_init()
{
    // set up timer with prescaler = 1024 and CTC mode
    // TOP = OCR1A
    // Update of OCR1A at Immediate
    TCCR1B |= (1 << WGM12)|(1 << CS12)|(1 << CS10);
    // Toggle OC1A/OC1B on compare match
    TCCR1A = (1 << COM1A0);
  
    // initialize counter
    TCNT1 = 0;
  
    // initialize compare value
    // OCR1A = 15625;
    //OCR1A = 625;
}
  
int main(void)
{
    // connect led to pin PB1
    DDRB |= (1 << 1);
  
    // initialize timer
    timer1_init();

    // inintialize ADC
    //initADC();
    delay(1);

    pinMode(A0, INPUT);

    // for debugging
    Serial.begin(115200);
    Serial.print("Hello, World!");
  
    // loop forever
    while(1)
    {
        //potVal=readADC(0);
        potVal=analogRead(A0);
        potVal = (potVal/1023.0)*(15625-625)+625;
        OCR1A = (int)potVal;
        Serial.print("OCR1A = ");
        Serial.println(OCR1A);
        
        // check whether the flag bit is set
        // if set, it means that there has been a compare match
        // and the timer has been cleared
        // use this opportunity to toggle the led
        if (TIFR1 & (1 << OCF1A)) // NOTE: '>=' used instead of '=='
        {
            PORTB ^= (1 << 1); // toggles the led
        }
  
        // wait! we are not done yet!
        // clear the flag bit manually since there is no ISR to execute
        // clear it by writing '1' to it (as per the datasheet)
        TIFR1 |= (1 << OCF1A);
  
        // yeah, now we are done!
    }
}

void initADC()
{
  //select ADC channel ADC0
  ADMUX &= 0x11110000;
  // Select Vref=AVcc
  ADMUX |= (1<<REFS0);
  //set prescaller to 128 and enable ADC 
  ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);
  // Bit 6 – ADSC: ADC Start Conversion
  // In single conversion mode, write this bit to one to start each conversion. 
  // In free running mode, write this bit to one to start the first conversion.
  ADCSRA |= (1<<ADSC);
  // Bit 3 – ADIE: ADC Interrupt Enable
  // When this bit is written to one and the I-bit in SREG is set, the ADC conversion complete interrupt is activated.
  //ADCSRA |= (1<<ADIE);
  // Bit 5 – ADATE: ADC Auto Trigger Enable
  // When this bit is written to one, auto triggering of the ADC is enabled. 
  // The ADC will start a conversion on a positive edge of the selected trigger signal. 
  // The trigger source is selected by setting the ADC trigger select bits, ADTS in ADCSRB.
  ADCSRA |= (1<<ADATE); 
  //In free running mode, the ADC is constantly sampling and updating the ADC Data Registers.  
  //This mode is selected by the ADFR bit in the ADC Control and Status Register.
  ADCSRB = 0x00000000;// Free running mode - ADTS2=ADTS1=ADTS0=0;  
}

uint16_t readADC(uint8_t ADCchannel)
{
 //select ADC channel with safety mask
 ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);
 //single conversion mode
 ADCSRA |= (1<<ADSC);
 // wait until ADC conversion is complete
 while( ADCSRA & (1<<ADSC) );
 return ADC;
}

And, I tested just now, this works:

/*
 * The program for adjusting the LED blinking frequence by a potentiometer
 * chip: ATmega328p
 * potentiometer --> ADC0
 * OC1A(PB1/D9) --> 1.5kOhm --> LED
 * OC1B - PB2/D10(Arduino UNO)
 */
 
#define F_CPU 16000000UL
#define VREF 5
#define POT 10000 // potentiometer - ohm10K

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

double potVal = 0;

void initADC()
{
  //select ADC channel ADC0
  ADMUX &= 0x11110000;
  // Select Vref=AVcc
  ADMUX |= (1<<REFS0);
  //set prescaller to 128 and enable ADC 
  ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);
  // Bit 6 – ADSC: ADC Start Conversion
  // In single conversion mode, write this bit to one to start each conversion. 
  // In free running mode, write this bit to one to start the first conversion.
  ADCSRA |= (1<<ADSC);
  // Bit 3 – ADIE: ADC Interrupt Enable
  // When this bit is written to one and the I-bit in SREG is set, the ADC conversion complete interrupt is activated.
  ADCSRA |= (1<<ADIE);
  // Bit 5 – ADATE: ADC Auto Trigger Enable
  // When this bit is written to one, auto triggering of the ADC is enabled. 
  // The ADC will start a conversion on a positive edge of the selected trigger signal. 
  // The trigger source is selected by setting the ADC trigger select bits, ADTS in ADCSRB.
  ADCSRA |= (1<<ADATE); 
  //In free running mode, the ADC is constantly sampling and updating the ADC Data Registers.  
  //This mode is selected by the ADFR bit in the ADC Control and Status Register.
  ADCSRB = 0x00000000;// Free running mode - ADTS2=ADTS1=ADTS0=0;  
}

uint16_t readADC(uint8_t ADCchannel)
{
 //select ADC channel with safety mask
 ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);
 //single conversion mode
 ADCSRA |= (1<<ADSC);
 // wait until ADC conversion is complete
 while( ADCSRA & (1<<ADSC) );
 return ADC;
}
  
void setup(void)
{
    // inintialize ADC
    //initADC();
    pinMode(A0, INPUT);
    
    // for debugging
    Serial.begin(9600);
    Serial.print("Hello, World!");
}

void loop()
{
    //potVal=readADC(0);
    potVal=analogRead(A0);
    potVal = (potVal/1023.0)*(15625-625)+625;
    OCR1A = (int)potVal;
    //Serial.begin(9600);
    while(!Serial);
    Serial.print("OCR1A = ");
    Serial.println(potVal);
}

Great! Please mark the thread "solved".

I want to know why the register edition didn't work.

I think analogRead() is a part of the Arduino core that won't work if you don't initialize the core. Try calling 'init()' at the top of your main().

I tried these code, it works:

/*
 * The program for adjusting the LED blinking frequency by a potentiometer
 * chip: ATmega328p
 * potentiometer --> ADC0
 * (ATmega328p)PB0 --> 1.5kOhm --> LED
 */
 
#define F_CPU 16000000UL
#define VREF 5
#define POT 10000 // potentiometer - 10Kohm

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

volatile uint16_t potVal = 0;

void PB0_init();
void initADC();
uint16_t readADC(uint8_t);
  
int main(void)
{       
    // initialize ADC
    initADC();

    // LED connected to PB0/D8
    PB0_init();
 
    // loop forever
    while(1)
    {
      potVal = readADC(0);      
      PB0_toggle(potVal);
    }
}

void initADC()
{
  // Select V ref=AVcc
  // Bit 7:6 – REFS1:0: Reference Selection Bits
  // REFS1 REFS0 - 0 / 1 - AVCC with external capacitor at AREF pin
  ADMUX |= (1<<REFS0);

  // Bits 2:0 – ADPS2:0: ADC Prescaler Select Bits
  // These bits determine the division factor between the system clock frequency and the input clock to the ADC.
  //set prescaler to 128 
  ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
  // Bit 7 – ADEN: ADC Enable - Writing this bit to one enables the ADC.
  ADCSRA |= (1<<ADEN);

  // Bit 6 – ADSC: ADC Start Conversion
  // The first conversion after ADSC has been written after the ADC has been enabled, 
  // or if ADSC is written at the same time as the ADC is enabled, 
  // will take 25 ADC clock cycles instead of the normal 13. 
  // This first conversion performs initialization of the ADC.
  ADCSRA |= (1<<ADSC);
}

uint16_t readADC(uint8_t ADCchannel)
{
  //select ADC channel with safety mask
  ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);

  // A single conversion is started by disabling the power reduction ADC bit, PRADC, by writing a logical zero to it 
  // and writing a logical one to the ADC start conversion bit, ADSC.
  ADCSRA |= (1<<ADSC);
   
  // wait until ADC conversion is complete
  while( ADCSRA & (1<<ADSC) );
  
  return ADC;
}

void PB0_init(void){
   DDRB |= (1<<DDB0);
}

void PB0_toggle(int t){
   PORTB ^= (1<<PORTB0); // toggles the led
   for(int i = 0; i < t; i++){
     _delay_ms(1);
   }
}