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?
I want to adjust the LED blinking frequency on the run, my scheme:
LED - 1.5kOhm - PB1(OC1A)
potentiometer - A0(ADC0)
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:
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 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;
}
/*
* 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);
}
/*
* 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);
}
}