A friend of mine tells me that my range of adc can be a multiple of the reference voltage...so that if im using Vcc as my reference voltage, which is going to be 2V, i should be able to measure more than 4V.
i checked the documentation on my attiny13, but i didnt see anything about that, although im probably not looking for the right thing.
I'd put more faith in the datasheets than a "friend". Generally the 0..255/0..1023 range of readings will be split between Gnd and the reference voltage.
thats what i thought, the reference voltage is the MAX voltage you can measure.
the problem is that i wanted to use an attiny to measure battery voltages, while running off of the batterys. but if its running off the batters, the attiny has to be able to run when the batterys are at there discharge point, which is 2.7V so its possible, but then if Vcc is my reference i wouldnt be able to measure more than that...
edit:
i could probably just use a couple of resistors so that the attiny gest 1.8V while the batterys are at 2.7V, then have it calculate for full etc...
The method to measure battery voltage using the ADC has been widely documented here a number of times. A search should find a suitable thread (I'm guessing the words "ADC" and "battery" are going to be involved! ;-))
Placing a resistor divider from Vbat to ground to measure battery voltage is ok, but you will waste current in the divider. If the device is supposed to run for a long time, this is a problem
You can solve that by adding a mosfet on the bottom of the divider, using an I/O pin to turn the mosfet on before you make your measurement. This way, the divider is disconnected when not in use. The mosfet draws no current in the on or off state, and its on resistance is so low that it won't be noticable.
How long you need to delay between turning on the mosfet and making the reading depends on the resistor values and whatever filter capacitance you're using.
If the battery voltage is much higher than VCC, then you'll want to switch it on the high side, using a Pfet and an open collector or open drain inverter.
since im using an attiny13, my adc' reference voltage is the attiny13's source voltage, which means i have to be able to power the attiny13 at the same time the batterys are virtually dead.
right now the resistor divider is the only way i can think it would work right now, although a bit wasteful.
You use the internal bandgap 1.1V not Vref when measuring the battery. I DID suggest you search for this above. When I tried it "internal bandgap adc battery" hit a load of very useful looking threads. Just a few of those:
You use the internal bandgap 1.1V not Vref when measuring the battery. I DID suggest you search for this above. When I tried it "internal bandgap adc battery" hit a load of very useful looking threads. Just a few of those
i did do several searches, and didnt find any results anywhere close to that good :oops:
I am new to Microcontrollers and i am wrting a program for ADC for atmega128.my aim is to display two analog inputs ADCO and ADC7 and display it on LCD.it shpuld be updated evry 5second.I tried running the program but there are few errors.Please look into it.Thanks
#include
int ADC0=0;
int ADC7=0;
int main (void)
{
DDRE |= (1 << 2); // Set LED1 as output
DDRG |= (1 << 0); // Set LED2 as output
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz
//set pin1 as ADCO
ADMUX &= ~( ( 1 << MUX0 ) | ( 1 << MUX1 ) | ( 1 << MUX2 ) | ( 1 << MUX3
ADMUX |= (1 << REFS0); // Set ADC reference to AVCC
ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading
I am sorry.I have recently joined this site and I wasnt aware of it.it will not happen again.regarding the code i posted above,i badly need help.could anyone guide me?
I used the tutorial in a Mega16A, off course i had to do a little modification, and i have the ADC working, but... I don´t understand why!
here is the code:
#define F_CPU 1000000UL //1MHz
#include
//Ports
#define LED1 PA0
#define LED2 PA1
#define POT ADC2
int main(void){
DDRA|=_BV(LED1)|_BV(LED2); //LEds input,
//ADC CONF
//1MHz/8=125kHz limit Prescaler [50 200] kHz
ADCSRA|=_BV(ADPS1)|_BV(ADPS0); //Define prescaler 8=(0b011)
ADMUX|=_BV(MUX1); //input ADC2
ADMUX|=_BV(REFS0); //Ref AVCC
//Free-running mode 000
ADCSRA|=_BV(ADATE); //set Auto Triguer
ADMUX|=_BV(ADLAR); //use only ADCH
ADCSRA|=_BV(ADEN); //ADC on
ADCSRA|=_BV(ADSC); //start ADC
//end ACD CONF
while(1){
if(ADCH<128){ // Led1 on
PORTA|=_BV(LED2);
PORTA&=~_BV(LED1);
}
else{ //led2 on
PORTA|=_BV(LED1);
PORTA&=~_BV(LED2);
}
ADCSRA|=_BV(ADIF); // if i remove this line it stops working
}
return (0);
}
in the datasheet they say that the Interrupt flag is set when the conversion ends, so why do i have to set it manually?
the code is correct?
Thanks for your help
This is because there is no ADFR bit in ADCSRA of MEGA16 to set it into free-running mode .
Try to Start ADC in A loop so that it it starts another conversion after finishing one
Like the one i did...
#include
#include
#include
int main(void)
{
DDRB=0XFF; //To set all pins of port b as outputs
ADCSRA|=(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//prescaling
ADMUX|=(1<<ADLAR);
ADMUX|=(1<<MUX1);
ADCSRA=(1<<ADEN);
ADCSRA|=(1<<ADIE);
sei();
for(;;)
{
ADCSRA|=(1<<ADSC);
_delay_ms(400); //must required as adc needs 13 or 25 cpu cycles to convert
}
}
ISR(ADC_vect)
{
if(ADCH<123)
{
PORTB=0XF0;
}
else if(ADCH>130)
{
PORTB=0X0F;
}
}
I used the tutorial in a Mega16A, off course i had to do a little modification, and i have the ADC working, but... I don´t understand why!
here is the code:
#define F_CPU 1000000UL //1MHz
#include
//Ports
#define LED1 PA0
#define LED2 PA1
#define POT ADC2
int main(void){
DDRA|=_BV(LED1)|_BV(LED2); //LEds input,
//ADC CONF
//1MHz/8=125kHz limit Prescaler [50 200] kHz
ADCSRA|=_BV(ADPS1)|_BV(ADPS0); //Define prescaler 8=(0b011)
ADMUX|=_BV(MUX1); //input ADC2
ADMUX|=_BV(REFS0); //Ref AVCC
//Free-running mode 000
ADCSRA|=_BV(ADATE); //set Auto Triguer
ADMUX|=_BV(ADLAR); //use only ADCH
ADCSRA|=_BV(ADEN); //ADC on
ADCSRA|=_BV(ADSC); //start ADC
//end ACD CONF
while(1){
if(ADCH<128){ // Led1 on
PORTA|=_BV(LED2);
PORTA&=~_BV(LED1);
}
else{ //led2 on
PORTA|=_BV(LED1);
PORTA&=~_BV(LED2);
}
ADCSRA|=_BV(ADIF); // if i remove this line it stops working
}
return (0);
}
in the datasheet they say that the Interrupt flag is set when the conversion ends, so why do i have to set it manually?
the code is correct?
Thanks for your help
This is because there is no ADFR bit in ADCSRA of MEGA16 to set it into free-running mode .
Try to Start ADC in A loop so that it it starts another conversion after finishing one
Like the one i did...
#include
#include
#include
int main(void)
{
DDRB=0XFF; //To set all pins of port b as outputs
ADCSRA|=(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//prescaling
ADMUX|=(1<<ADLAR);
ADMUX|=(1<<MUX1);
ADCSRA=(1<<ADEN);
ADCSRA|=(1<<ADIE);
sei();
for(;;)
{
ADCSRA|=(1<<ADSC);
_delay_ms(400); //must required as adc needs 13 or 25 cpu cycles to convert
}
}
ISR(ADC_vect)
{
if(ADCH<123)
{
PORTB=0XF0;
}
else if(ADCH>130)
{
PORTB=0X0F;
}
}
Although not identical, different timers on "modern" AVRs are fairly similar, patterns will re-occur through the different timer implementations. Even when narrowing down to the ATmega16 that specific AVR model has several timers that differ (eg in resolution, there are both 8-bit and 16-bit timers).
Start by reading Deans tutorial. If you have problems understanding that, then it is not unlikely that you need to read up on his "general" timer tutorial. Then proceed with a simple PWM mode on one of the ATmega16 timers. Use it to eg vary the brightness of a LED. Then move in small learning steps toward what you ultimately need (you say nothing about your ultimate goal). When you get into obstacles or troubles, search for previous threads here at AVRfreaks, and if not successful with that, ask a question. Be prepared to be pointed to the data sheet for specific details.
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
Thank u Tilak, the code finally worked by your method. I just started with AVRs and I was having problem trying to make the code in this tutorial work in my ATMega32. This free running mode is mentioned in the datasheet but i didn't understand what to do. Isn't there any other way avoid using any code in that for(;;) loop. I mean from hardware itself like in Mega128 in this tutorial?
This is a pdf conversion of this for anyone to download. If his violates any rule, sorry, and please delete my post if necessary. Also, great tutorial :)
Posted by JohanEkdahl: Thu. Nov 19, 2009 - 02:43 PM
1
2
3
4
5
Total votes: 0
Quote:
This is a pdf conversion of this for anyone to download. If his violates any rule [...]
Rules, or no rules - when the original tutorial gets updated this PDF will be out-dated. Who will promise now to take care of that then?
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
Hi everyone.
I red a discussion you had posted here about the sampling frequency, I also red the ADC section in the data sheet, but it isn't very clear to me how to calculate the sampling frequency.
I'm working with some audio signal (1kHz-15kHz), I would like to use the ADC in the Mega32, so according to the data sheet, the ADC clock source requires a frequency between 50kHz and 200 kHz to get maximum resolution, and it takes 13.5 conversion cycles for auto triggered conversion.
So if i have the internal clock at 8Mhz, program the prescaler CK/8:
8Mhz/8 = 1Mhz ; 1Mhz/13.5 = 74.074 KHz
And 74 kHz complies with the requirement for maximum resolution, but it also complies with the Nyquist Theorem for my signal Fs >> 2*Fmax = 30 kHz.
I have tested this with a sinusoidal signal, but when the signal is reconstructed with a DAC, seems like the sampling frequency is incorrect because at 10kHz the signal is barely reconstructed, and with 15kHz the signal is not reconstructed.
Does anyone knows why?? :roll:
Is it noise, or the Sampling Frequency, or my conversion is incorrect???
So if i have the internal clock at 8Mhz, program the prescaler CK/8:
8Mhz/8 = 1Mhz ; 1Mhz/13.5 = 74.074 KHz
And 74 kHz complies with the requirement for maximum resolution
No, the 50kHz to 200kHz refers to the ADC clock frequency, not the sample rate. At 8MHz you need at least a /64 prescaler to get within the range needed. Also, the sample takes 13 clocks, not 13.5.
If you don't need 10 bit resolution, then you could get away with a 32 or even 16 prescaler. The 16 prescaler would give you ~38.5kHz sample rate.
Just to note that you might actually want to DROP your F_CPU to get a higher sample rate. At 8MHz to get a 50kHz..200kHz ADC clock you have to use /64 which actually gets you 125kHz ADC clock but if you drop to 6.4MHz then you could use /32 to get the fastest ADC clock of 200kHz
Posted by angrysurgeon: Fri. Dec 4, 2009 - 12:22 PM
1
2
3
4
5
Total votes: 0
An absolutely brilliant tutorial! Thanks alot for making life easier for all of us!
Here is the code for Atmega8: connect long pin (+) of LED1 to Pin 14 (=PB0) and the short pin (-) to a 300 ohm resistance, which goes to ground. Do the same for LED2 but here, the long pin goes to pin 28. Then you can cut and paste the following code.
#include
int main (void)
{
DDRC |= (1 << 4); // Set LED1 as output
DDRB |= (1 << 1); // Set LED2 as output
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz
ADMUX |= (1 << REFS0); // Set ADC reference to AVCC
ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading
// No MUX values needed to be changed to use ADC0
ADCSRA |= (1 << ADFR); // Set ADC to Free-Running Mode
ADCSRA |= (1 << ADEN); // Enable ADC
ADCSRA |= (1 << ADSC); // Start A2D Conversions
for(;;) // Loop Forever
{
if(ADCH < 128)
{
PORTC |= (1 << 4); // Turn on LED1
PORTB &= ~(1 << 1); // Turn off LED2
}
else
{
PORTC &= ~(1 << 4); // Turn off LED1
PORTB |= (1 << 1); // Turn on LED2
}
}
}
Many thanks for the excellent tutorial. I modified the bit settings for ADMUX using REFS0 and REFS1 == 0 to set the Vref to AVCC as I'm using an attiny85
Probably a newbie question, but...
Is it guaranteed that all status register bits are set to zero unless otherwise set with (1<<BitName)?
On power up reset, the values of the registers are guaranteed to be what the datasheet says they will be (in the case of some registers this is not zero).
I've been miscalculating the ADC frequency. but I think I got it all wrong still.
I'm still using the internal 8MHz frequency, and 500KHz to the ADC in free running mode:
500kHz/13 ~ 38kHz
So my sampling rate should be around this value, but when I use the "read_adc" command in Codevision looks like my frequency drops down, I dont know why it takes to long for the ADC to convert, because I use one pin of the chip as output and XOR'it every time the ADC finish the conversion. The frequency on this pin is around 18kHz,
#include
#include
#define ADC_VREF_TYPE 0x60
unsigned char read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCH;
}
void main(void)
{
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
DDRB=0x00;
DDRC=0x02;
DDRD=0xFF;
DIDR0=0x01;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0xA4;
ADCSRB&=0xF8;
while (1)
{
PORTC^=0x02;
PORTD=read_adc(PORTC.0);
};
}
If I dont call read_adc, the frequency on the pin is 600kHz.
Why is this frequency so low, even if I don use the ADC???, I already disable the CLKDIV8 fuse, It must but up to Mhz at least.
I compiled both programs using the Simulator in AVR studio (picking the atmega128 chip). The 1st example works fine, but the second example there is a problem as the interrupt only happens once.
As an experiment I put the line
ADCSRA |= (1 << ADSC);
in the interrupt section and the interrupt triggers continuously, but I assume I shouldn't be doing this in free running mode.
Any ideas as to why the interrupt only triggers once in the ADC interrupt example with the simulator?
1) No, the only requirement is that F_CPU is divided by the ADC prescaler into the 50kHz to 200kHz range. If F_CPU is already in that range then the ADC prescale can be set to /1
2) Most usual solution would be a timer interrupt. Just set up a timer to interrupt every 100ms and when the interrupt occurs take the previous ADC reading and set ADSC again to start another. If the ADC is clocked at 125kHz and it takes 13 ADC clocks to make a conversion then the next reading will be ready after just 13/125000 seconds ~= 0.1ms so it'll be ready LONG before the next interrupt occurs. I guess one thing you could do is use the 100ms to make quite a few readings and then take the average at the 100ms point.
Posted by JohanEkdahl: Tue. Apr 13, 2010 - 10:40 AM
1
2
3
4
5
Total votes: 0
Quote:
If I prescale my clock from 8M to 125kHz, do I need to prescale the ADC aswell?
That depends on what frequency you want to clock the ADC at. But I suppose you already understood that and you're actually asking "what frequency should I clock the ADC with?".
One clue lies in
with a delay between, lets say 100ms
Going from memory, the ADC needs 13 clocks for a conversion. 100ms is 10 Hz, so it would be nice if the ADC was clocked with at least 130 Hz. And that is well below 125 KHz so that's no problem.
Other comments:
I'd take a look in the data sheet for the limitations and requirements on the ADC clock frequency. Have you?
What does your input signal look like? It to might influence the selection of ADC frequency. If it's at a steady level at time spans like a full conversion, then no problem there. But if it is a signal that varies with a certain frequency w.r.t. the ADC sampling frequency you might get "interesting" results. The people here that live in the time domain, and worship Nyquist every morning, can tell you more.
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
But the datasheet says it should be 50kHz minimum? (I presume the charge on the sample/hold capacitor will not remain long enough for slower ADC conversions?)
Posted by Blipp-Blopp-Bob: Tue. Apr 13, 2010 - 11:23 AM
1
2
3
4
5
Total votes: 0
clawson wrote:
2)I guess one thing you could do is use the 100ms to make quite a few readings and then take the average at the 100ms point.
Thats the plan. :)
Thank you for the help.
JohanEkdahl wrote:
What does your input signal look like? It to might influence the selection of ADC frequency. If it's at a steady level at time spans like a full conversion, then no problem there.
Im hoping steady but the sensor is new and uniqe so we are not so sure of the result. :/
2)I guess one thing you could do is use the 100ms to make quite a few readings and then take the average at the 100ms point.
But if the ADC Clock rate is 62.5kHz (the only choice available with a 125kHz system clock), that would mean close to 500 readings every 100ms. Not very practical.
Quote:
Most usual solution would be a timer interrupt. Just set up a timer to interrupt every 100ms and when the interrupt occurs take the previous ADC reading and set ADSC again to start another.
A much better idea, especially since the ADC can be auto-triggered by timer 0 or timer 1.
Posted by JohanEkdahl: Tue. Apr 13, 2010 - 06:35 PM
1
2
3
4
5
Total votes: 0
Quote:
But the datasheet says it should be 50kHz minimum?
Which in my world is "at least 130 Hz" :wink:, and
I wrote:
I'd take a look in the data sheet for the limitations and requirements on the ADC clock frequency. Have you?
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
Thanks for the tutorial. I'm having a little problem: I made thermometer based on Atmega8 with TC1047(Precision Temperature-to-Voltage Converter) so this tutorial was very helpful, but when Atmega8 ran out of memory(full program takes over 13k) I decide move to Atmega16. And there is problem: I don't know how to set free-runing mode ADC, there is no ADFR bit in ADCSRA to set free-running mode.
Structure of code:
int main(void)
{
ADCSRA|=(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);//prescaling of 64. Internal 8MHz
//No MUX values needed to be changed to use ADC0
ADMUX|=(0<<ADLAR); //for all 10bit
ADCSRA|=(1<<ADATE); //set Auto Triguer
ADMUX|=(1<<REFS1)|(1<<REFS0); //Internal 2,56V
ADCSRA=(1<<ADEN); //Enable ADC
ADCSRA|=(1<<ADSC); //Start ADC
#include
#include
#define F_CPU 8000000UL
#include
int main(void)
{
void pwm() {
CLKPR = 0x80; //enabling CPU CLOCK scaling : clk_io
CLKPR = 0x00; //setting CPU clock's prescaler to 1
//Phase Correct PWMMODE 5 utilizing 0CR0A as TOP storage register.
//This therefore inhibits the usage of OC0A pin;
//We will use OC0B as the output compare action pin.
//This requires PB1(OC0B) to be setup as an output pin:
PORTB = 0x00;
DDRB = 0x02; //setting PB1 to O/P mode and rest I/P?
//SETUP OF TCCR0A:
TCCR0A = (1<<WGM00)|(0<<WGM01)|(0<<COM0B0)|(1<<COM0B1)
|(0<<COM0A0)|(0<<COM0A1); //{PC_PWM Mode 5 ; OC0B = noninvert OC0A = off}
TCCR0B = (1<<CS00)|(0<<CS01)|(1<<CS02)
|(1<<WGM02)|(0<<FOC0B)|(0<<FOC0A); //{No prescaling; PC_PWM = mode5; Force comp = off}
//STARTING TIMER:
TCNT0 = 0;
//DEFINING TOP & D VALUEs:
OCR0A = 255; // TOP = FF
OCR0B = 128; // D = .5
}
// Set Port B pins for 3 and 4 as outputs
DDRB = ( 1 << DDB3 );
//set the reference voltage for the ATTINY45 ADC to be VCC
ADMUX |= ((0 << REFS0) | (0 << REFS1));
//set pin #1 as ADC0
ADMUX |= ( ( 0 << MUX0 ) | ( 0 << MUX1 ) | ( 0 << MUX2 ) | ( 0 << MUX3 ) );
//left allign the adc value
ADMUX |= (1 << ADLAR);
//set the division factor to 128 (see the datasheet)
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
//auto triger enable
ADCSRA |= (1 << ADATE);
//enable the ADC
ADCSRA |= (1 << ADEN);
//start the adc measurments
ADCSRA |= (1 << ADSC);
for ( ; 1==1 ; ) {
if(ADCH < 128) {
PORTB = 0x08;
} else {
pwm();
}
//optional
//PORTB = 0x00;
}
return 1;
}
I am trying to use vcc as vref, adc input upto 5 volts, if voltage less than 2.1 nothing happens, when higher than that it should turn on led at portb3 when volt higher than 2.5 then it should turn on the pwm output. I am inputting the pwm into n-channel mosfet to control another led.
The problem is when i power on at 2.1volt led turns on nicely but i keep going say up until 5 volts the mosfet led doesn't turn on ,then i switch back to 2.5 volts or something like that then the mosfet led nicely turns on and off like it supposed to(blinks as 50% duty cycle),but then when i drop to 2.1 volts the other led does not turn on, but the mosfet led turns off, then when i pull the volt again to 2.2 led turns on at high volt the mosfet doesn't work, have to go down then only it works!!
Why are you changing the clock pre-scaler inside of pwm()?
Why are you changing DDRB in pwm() (and to something different than what you set it to in main())?
If you want TOP to be 255, then why not use mode 1?
But then, why not use CTC mode for a 50% duty cycle?
When do you ever turn PWM off after it has been turned on?
#include
Do not include this file. The AVR is specified in the makefile or project options.
Quote:
then the mosfet led nicely turns on and off like it supposed to(blinks as 50% duty cycle)
You can see the LED blink at 30Hz?
I changed the DDRB in pwm cause i want pwm out of PB1.
I am changing the prescaler inside pwm to control the pwm.
I am defining my duty cycle cause later i will vary the duty cycle depending on the ADC input.
thnx for the reply, i am trying to fix all that you said, but i think i am getting a 15Hz pwm frequency and the mosfet is switching the led and its blinking.
I changed the DDRB in pwm cause i want pwm out of PB1.
But you also want output to PB3. You don't want to keep switching between input and output for these pins. If you want PB1 off when the PWM is enabled, then turn it off using PORTB, don't change it to an input. The same goes for PWM, don't change it to input, disable PWM. (By the way, 0x02 is PB2, not PB1).
Quote:
I am changing the prescaler inside pwm to control the pwm.
But why change it there? Either the rest of the app doesn't care, or worse, it does care and you are changing the pre-scaler without warning. Either way, the best place to do this is at the beginning of main. And since you have:
#define F_CPU 8000000UL
You are telling the compiler that you are running at a specific speed. Any code relying on this will have no clue that you change the speed at a random time during runtime.
A friend of mine tells me that my range of adc can be a multiple of the reference voltage...so that if im using Vcc as my reference voltage, which is going to be 2V, i should be able to measure more than 4V.
i checked the documentation on my attiny13, but i didnt see anything about that, although im probably not looking for the right thing.
I'd put more faith in the datasheets than a "friend". Generally the 0..255/0..1023 range of readings will be split between Gnd and the reference voltage.
thats what i thought, the reference voltage is the MAX voltage you can measure.
the problem is that i wanted to use an attiny to measure battery voltages, while running off of the batterys. but if its running off the batters, the attiny has to be able to run when the batterys are at there discharge point, which is 2.7V so its possible, but then if Vcc is my reference i wouldnt be able to measure more than that...
edit:
i could probably just use a couple of resistors so that the attiny gest 1.8V while the batterys are at 2.7V, then have it calculate for full etc...
The method to measure battery voltage using the ADC has been widely documented here a number of times. A search should find a suitable thread (I'm guessing the words "ADC" and "battery" are going to be involved! ;-))
Placing a resistor divider from Vbat to ground to measure battery voltage is ok, but you will waste current in the divider. If the device is supposed to run for a long time, this is a problem
You can solve that by adding a mosfet on the bottom of the divider, using an I/O pin to turn the mosfet on before you make your measurement. This way, the divider is disconnected when not in use. The mosfet draws no current in the on or off state, and its on resistance is so low that it won't be noticable.
How long you need to delay between turning on the mosfet and making the reading depends on the resistor values and whatever filter capacitance you're using.
If the battery voltage is much higher than VCC, then you'll want to switch it on the high side, using a Pfet and an open collector or open drain inverter.
since im using an attiny13, my adc' reference voltage is the attiny13's source voltage, which means i have to be able to power the attiny13 at the same time the batterys are virtually dead.
right now the resistor divider is the only way i can think it would work right now, although a bit wasteful.
You use the internal bandgap 1.1V not Vref when measuring the battery. I DID suggest you search for this above. When I tried it "internal bandgap adc battery" hit a load of very useful looking threads. Just a few of those:
https://www.avrfreaks.net/index.p...
https://www.avrfreaks.net/index.p...
https://www.avrfreaks.net/index.p...
https://www.avrfreaks.net/index.p...
i did do several searches, and didnt find any results anywhere close to that good :oops:
has anyone tried my code in a avr mega16?
Very nice tutorial, I never fully understood ADC but this tutorial made the difference.
How about considering an PWM and timers tutorial? :roll:
But that line does not set the flag, it clears it. Read the datasheet for why this is so and why you need it.
Regards,
Steve A.
The Board helps those that help themselves.
hi guys,
I am new to Microcontrollers and i am wrting a program for ADC for atmega128.my aim is to display two analog inputs ADCO and ADC7 and display it on LCD.it shpuld be updated evry 5second.I tried running the program but there are few errors.Please look into it.Thanks
#include
int ADC0=0;
int ADC7=0;
int main (void)
{
DDRE |= (1 << 2); // Set LED1 as output
DDRG |= (1 << 0); // Set LED2 as output
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128 - 125KHz sample rate @ 16MHz
//set pin1 as ADCO
ADMUX &= ~( ( 1 << MUX0 ) | ( 1 << MUX1 ) | ( 1 << MUX2 ) | ( 1 << MUX3
ADMUX |= (1 << REFS0); // Set ADC reference to AVCC
ADMUX |= (1 << ADLAR); // Left adjust ADC result to allow easy 8 bit reading
//set pin1 as ADC7
ADMUX &= ~( ( 1 << MUX0 ) | ( 1 << MUX1 ) | ( 1 << MUX2 ) | ( 1 << MUX3
ADCSRA |= (1 << ADEN); // Enable ADC
ADCSRA |= (1 << ADSC); // Start A2D Conversions
for(;;) // Loop Forever
{
lcd_gotoxy(0,0); // Display ADC0
lcd_puts("ADC0: ");
num = adc0;
itoa(num , buffer, 10);
lcd_puts(buffer);
lcd_puts(" ");
lcd_gotoxy(0,1); // Display ADC7
lcd_puts("ADC7: ");
num = adc7;
itoa(num , buffer, 10);
lcd_puts(buffer);
lcd_puts(" ");
}
}
ISR(ADC_vect)
{
if (adcport==0)
{
if (ADCH==0)
adc0 = ADCL;
else adc0 = ADCH * 256;
adcport = 1;
ADMUX |= (1<<MUX0); // Switch to ADC0
}
if (adcport==1)
{
if (ADCH==0)
adc1 = ADCL;
else adc1 = ADCH * 256;
adcport = 0;
ADMUX &= ~(1<<MUX0); // Switch to ADC7
}
}
}
Dear agop by double posting your request all you are doing is to annoy people!! And less likely to recieve help.
John Samperi
Ampertronics Pty. Ltd.
https://www.ampertronics.com.au
* Electronic Design * Custom Products * Contract Assembly
I am sorry.I have recently joined this site and I wasnt aware of it.it will not happen again.regarding the code i posted above,i badly need help.could anyone guide me?
Thanks for your Outstanding Tutorial
I expect a Tutorial on PWM with ATMEGA16
This is because there is no ADFR bit in ADCSRA of MEGA16 to set it into free-running mode .
Try to Start ADC in A loop so that it it starts another conversion after finishing one
Like the one i did...
https://www.avrfreaks.net/index.p...
Although not identical, different timers on "modern" AVRs are fairly similar, patterns will re-occur through the different timer implementations. Even when narrowing down to the ATmega16 that specific AVR model has several timers that differ (eg in resolution, there are both 8-bit and 16-bit timers).
Start by reading Deans tutorial. If you have problems understanding that, then it is not unlikely that you need to read up on his "general" timer tutorial. Then proceed with a simple PWM mode on one of the ATmega16 timers. Use it to eg vary the brightness of a LED. Then move in small learning steps toward what you ultimately need (you say nothing about your ultimate goal). When you get into obstacles or troubles, search for previous threads here at AVRfreaks, and if not successful with that, ask a question. Be prepared to be pointed to the data sheet for specific details.
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
Thank u Tilak, the code finally worked by your method. I just started with AVRs and I was having problem trying to make the code in this tutorial work in my ATMega32. This free running mode is mentioned in the datasheet but i didn't understand what to do. Isn't there any other way avoid using any code in that for(;;) loop. I mean from hardware itself like in Mega128 in this tutorial?
This is a pdf conversion of this for anyone to download. If his violates any rule, sorry, and please delete my post if necessary. Also, great tutorial :)
Attachment(s):
Hi, it's my first post in the forum, and in a word, it's a perfect newbie tut.
tnxs .
Rules, or no rules - when the original tutorial gets updated this PDF will be out-dated. Who will promise now to take care of that then?
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
Hi everyone.
I red a discussion you had posted here about the sampling frequency, I also red the ADC section in the data sheet, but it isn't very clear to me how to calculate the sampling frequency.
I'm working with some audio signal (1kHz-15kHz), I would like to use the ADC in the Mega32, so according to the data sheet, the ADC clock source requires a frequency between 50kHz and 200 kHz to get maximum resolution, and it takes 13.5 conversion cycles for auto triggered conversion.
So if i have the internal clock at 8Mhz, program the prescaler CK/8:
8Mhz/8 = 1Mhz ; 1Mhz/13.5 = 74.074 KHz
And 74 kHz complies with the requirement for maximum resolution, but it also complies with the Nyquist Theorem for my signal Fs >> 2*Fmax = 30 kHz.
I have tested this with a sinusoidal signal, but when the signal is reconstructed with a DAC, seems like the sampling frequency is incorrect because at 10kHz the signal is barely reconstructed, and with 15kHz the signal is not reconstructed.
Does anyone knows why?? :roll:
Is it noise, or the Sampling Frequency, or my conversion is incorrect???
Attachment(s):
No, the 50kHz to 200kHz refers to the ADC clock frequency, not the sample rate. At 8MHz you need at least a /64 prescaler to get within the range needed. Also, the sample takes 13 clocks, not 13.5.
If you don't need 10 bit resolution, then you could get away with a 32 or even 16 prescaler. The 16 prescaler would give you ~38.5kHz sample rate.
Regards,
Steve A.
The Board helps those that help themselves.
Just to note that you might actually want to DROP your F_CPU to get a higher sample rate. At 8MHz to get a 50kHz..200kHz ADC clock you have to use /64 which actually gets you 125kHz ADC clock but if you drop to 6.4MHz then you could use /32 to get the fastest ADC clock of 200kHz
https://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=644489#644489
I was having only 0xFF output from ADCH, hope someone finds this helpful.
An absolutely brilliant tutorial! Thanks alot for making life easier for all of us!
Here is the code for Atmega8: connect long pin (+) of LED1 to Pin 14 (=PB0) and the short pin (-) to a 300 ohm resistance, which goes to ground. Do the same for LED2 but here, the long pin goes to pin 28. Then you can cut and paste the following code.
Many thanks for the excellent tutorial. I modified the bit settings for ADMUX using REFS0 and REFS1 == 0 to set the Vref to AVCC as I'm using an attiny85
Probably a newbie question, but...
Is it guaranteed that all status register bits are set to zero unless otherwise set with (1<<BitName)?
On power up reset, the values of the registers are guaranteed to be what the datasheet says they will be (in the case of some registers this is not zero).
Regards,
Steve A.
The Board helps those that help themselves.
Thanks Koshchi and Clawson.
I've been miscalculating the ADC frequency. but I think I got it all wrong still.
I'm still using the internal 8MHz frequency, and 500KHz to the ADC in free running mode:
500kHz/13 ~ 38kHz
So my sampling rate should be around this value, but when I use the "read_adc" command in Codevision looks like my frequency drops down, I dont know why it takes to long for the ADC to convert, because I use one pin of the chip as output and XOR'it every time the ADC finish the conversion. The frequency on this pin is around 18kHz,
If I dont call read_adc, the frequency on the pin is 600kHz.
Why is this frequency so low, even if I don use the ADC???, I already disable the CLKDIV8 fuse, It must but up to Mhz at least.
Hi,
Thanks for the excellent tutorial.
I compiled both programs using the Simulator in AVR studio (picking the atmega128 chip). The 1st example works fine, but the second example there is a problem as the interrupt only happens once.
As an experiment I put the line
in the interrupt section and the interrupt triggers continuously, but I assume I shouldn't be doing this in free running mode.
Any ideas as to why the interrupt only triggers once in the ADC interrupt example with the simulator?
Thanks :)
Thank you for the tutorial!
CAN SOME ONE ALSO HELP IN PROVIDING THE ASM CODE TOO...
C compiler says:
Got 2 questions. :)
(note: im using attiny861)
1) If I prescale my clock from 8M to 125kHz, do I need to prescale the ADC aswell?
2) I need to take 10 samples with a delay between, lets say 100ms, every sample. How should I do this?
1) No, the only requirement is that F_CPU is divided by the ADC prescaler into the 50kHz to 200kHz range. If F_CPU is already in that range then the ADC prescale can be set to /1
2) Most usual solution would be a timer interrupt. Just set up a timer to interrupt every 100ms and when the interrupt occurs take the previous ADC reading and set ADSC again to start another. If the ADC is clocked at 125kHz and it takes 13 ADC clocks to make a conversion then the next reading will be ready after just 13/125000 seconds ~= 0.1ms so it'll be ready LONG before the next interrupt occurs. I guess one thing you could do is use the 100ms to make quite a few readings and then take the average at the 100ms point.
That depends on what frequency you want to clock the ADC at. But I suppose you already understood that and you're actually asking "what frequency should I clock the ADC with?".
One clue lies in
with a delay between, lets say 100ms
Going from memory, the ADC needs 13 clocks for a conversion. 100ms is 10 Hz, so it would be nice if the ADC was clocked with at least 130 Hz. And that is well below 125 KHz so that's no problem.
Other comments:
I'd take a look in the data sheet for the limitations and requirements on the ADC clock frequency. Have you?
What does your input signal look like? It to might influence the selection of ADC frequency. If it's at a steady level at time spans like a full conversion, then no problem there. But if it is a signal that varies with a certain frequency w.r.t. the ADC sampling frequency you might get "interesting" results. The people here that live in the time domain, and worship Nyquist every morning, can tell you more.
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
But the datasheet says it should be 50kHz minimum? (I presume the charge on the sample/hold capacitor will not remain long enough for slower ADC conversions?)
Thats the plan. :)
Thank you for the help.
Im hoping steady but the sensor is new and uniqe so we are not so sure of the result. :/
But if the ADC Clock rate is 62.5kHz (the only choice available with a 125kHz system clock), that would mean close to 500 readings every 100ms. Not very practical.
A much better idea, especially since the ADC can be auto-triggered by timer 0 or timer 1.
Regards,
Steve A.
The Board helps those that help themselves.
Which in my world is "at least 130 Hz" :wink:, and
As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here.
No guarantees, but if we don't report problems they won't get much of a chance to be fixed! Details/discussions at link given just above.
"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]
Thanks for the tutorial. I'm having a little problem: I made thermometer based on Atmega8 with TC1047(Precision Temperature-to-Voltage Converter) so this tutorial was very helpful, but when Atmega8 ran out of memory(full program takes over 13k) I decide move to Atmega16. And there is problem: I don't know how to set free-runing mode ADC, there is no ADFR bit in ADCSRA to set free-running mode.
Structure of code:
int main(void)
{
ADCSRA|=(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0);//prescaling of 64. Internal 8MHz
//No MUX values needed to be changed to use ADC0
ADMUX|=(0<<ADLAR); //for all 10bit
ADCSRA|=(1<<ADATE); //set Auto Triguer
ADMUX|=(1<<REFS1)|(1<<REFS0); //Internal 2,56V
ADCSRA=(1<<ADEN); //Enable ADC
ADCSRA|=(1<<ADSC); //Start ADC
while(1)
{
ADC_L = ADCL;
ADC_H = ADCH;
kodas = ( ADC_H<<8 ) | ADC_L;
....
....
}
ADCSRA|=_BV(ADIF);
}
Thanks for advises
Set the ADTSx bits in SFIOR to the mode that you want, then set the ADATE bit in ADCSRA.
Regards,
Steve A.
The Board helps those that help themselves.
I found the problem :) Code is working in free-runing mode. Mistake was wrong pin :D :D :D
Hi this is my code
I am trying to use vcc as vref, adc input upto 5 volts, if voltage less than 2.1 nothing happens, when higher than that it should turn on led at portb3 when volt higher than 2.5 then it should turn on the pwm output. I am inputting the pwm into n-channel mosfet to control another led.
The problem is when i power on at 2.1volt led turns on nicely but i keep going say up until 5 volts the mosfet led doesn't turn on ,then i switch back to 2.5 volts or something like that then the mosfet led nicely turns on and off like it supposed to(blinks as 50% duty cycle),but then when i drop to 2.1 volts the other led does not turn on, but the mosfet led turns off, then when i pull the volt again to 2.2 led turns on at high volt the mosfet doesn't work, have to go down then only it works!!
Why?
Why are you defining pwm() inside of main()?
Why are you changing the clock pre-scaler inside of pwm()?
Why are you changing DDRB in pwm() (and to something different than what you set it to in main())?
If you want TOP to be 255, then why not use mode 1?
But then, why not use CTC mode for a 50% duty cycle?
When do you ever turn PWM off after it has been turned on?
Do not include this file. The AVR is specified in the makefile or project options.
Regards,
Steve A.
The Board helps those that help themselves.
I changed the DDRB in pwm cause i want pwm out of PB1.
I am changing the prescaler inside pwm to control the pwm.
I am defining my duty cycle cause later i will vary the duty cycle depending on the ADC input.
thnx for the reply, i am trying to fix all that you said, but i think i am getting a 15Hz pwm frequency and the mosfet is switching the led and its blinking.
You are telling the compiler that you are running at a specific speed. Any code relying on this will have no clue that you change the speed at a random time during runtime.
Regards,
Steve A.
The Board helps those that help themselves.
Pages