ATmega328p ADC to PWM

Go To Last Post
63 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use an ATmega328p Xplained mini board with a potentiometer at the ADC5 input. PWM off is PB1 (OC1A).

source snippet;

#define F_CPU    16000000UL

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

double dutyCycle;

int main(void)
{
    DDRB = (1 << PORTB1);
    
    TCCR1A |= (1 << COM1A1) | (1 << COM1A0) | (1 << WGM11); // fast PWM mode 14 en geinverteerd, set OC1A/OC1B on compare match
       TCCR1B |= (1<<WGM13) | (1 << WGM12) | (1 << CS11); // delen door 8
       ICR1 = 50; // Frequentie
    
    setupADC();
    
    sei();

        
    while(1)
    {
        
    }
}

void setupADC()
{
    ADMUX = (1 << REFS0) | (1 << MUX0) | (1 << MUX2);  
    ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS0) | (1 << ADPS1);// | (1 << ADPS2); // 128 prescaler
    DIDR0 = (1 << ADC5D);
    
    startConversion();
}

void startConversion()
{
    ADCSRA |= (1 << ADSC); // ADSC is start conversie
}

ISR(TIMER1_OVF_vect)
{
    OCR1A = dutyCycle;
}

ISR(ADC_vect)
{
    dutyCycle = ADC;
    startConversion();
}

 

With this source I'll get a constant signal as you can see in the picture, the position of the potentiometer does not matter.

Does anyone know how I can adjust the source so that I can use the potentiometer to control the duty cula of e.g. ~ 3% to 98%?

 

 

 

 

Attachment(s): 

Last Edited: Mon. Mar 5, 2018 - 12:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be_logic wrote:
double dutyCycle;

On quick glance, I see two problems, dutyCycle does not need to be double and it should be volatile...

 

I would change the definition to:

volatile uint16_t dutyCycle;

Edit: also you will need to scale dutyCycle to the period of the timer.

David (aka frog_jr)

Last Edited: Sun. Mar 4, 2018 - 01:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You've also set the ADC clock to 1 MHz, which is too fast for 10-bit results.  You'll get about 8-bit results (top 8 bits good, bottom 2 bits noise).  This is fine since you're only using about 5.7 bits with your top value of 50 (timer resolution of 51).

 

That resolution will give you a PWM frequency of about 314 kHz (assuming the m328p is in fact running at 16 MHz).  Is that what you're looking for?

 

dutyCycle ... should be volatile...

Yup.

 

you will need to scale dutyCycle to the period of the timer

Yup.

 

dutyCycle does not need to be double

Not a 'problem' per se, but definitely sub-optimal ;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can you show me what to adjust in the source because it is not entirely clear to me.

I would like to be able to arrange the duty cycle of ~ 3-98%.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nobody is going to do your homework for you ;-)

 

You've been given clear feedback on three points:

  1. dutyCycle must be declared volatile
  2. you must scale dutyCycle before writing it to the OCR1A
  3. dutyCycle need not be declared as double

 

Which of these is not entirely clear to you?

 

You've also been asked if a PWM frequency of 314 kHz is what you wanted.  Is it?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, I declared dutyCycle as volatile in the source and the clock frequency for the Xplained Mini board at 8 MHz, but could give me hints to scale dutyCycle before writing it to the OCR1A?

I do not need a certain frequency for my project, but I want to be able to arrange the duty cycle between ~ 3 and 98%.

Can you help me with that?

 

#define F_CPU    8000000UL

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

volatile uint16_t dutyCycle;

int main(void)
{
    DDRB = (1 << PORTB1);
    
    TCCR1A |= (1 << COM1A1) | (1 << COM1A0) | (1 << WGM11); // fast PWM mode 14 en geinverteerd, set OC1A/OC1B on compare match
       TCCR1B |= (1<<WGM13) | (1 << WGM12) | (1 << CS11); // delen door 8
    ICR1 = 50; // Frequentie
    
    setupADC();
    
    sei();

        
    while(1)
    {
        
    }
}

void setupADC()
{
    ADMUX = (1 << REFS0) | (1 << MUX0) | (1 << MUX2);  
    ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS0) | (1 << ADPS1);
    DIDR0 = (1 << ADC5D);
    
    startConversion();
}

void startConversion()
{
    ADCSRA |= (1 << ADSC); // ADSC is start conversie
}

ISR(TIMER1_OVF_vect)
{
    OCR1A = dutyCycle;
}

ISR(ADC_vect)
{
    dutyCycle = ADC;
    startConversion();
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This has already been mentioned but the ADC reading is going to be 0..1023 so you cannot just:

    OCR1A = dutyCycle;

because the range of active values for OCR1A is not just 0..1023 so you need to scale one to the other.

 

Let's say that OCR1A takes the entire 0..65535 range then you would need to scale up the ADC value 65536/1024 is 64 so in that case you would need:

    OCR1A = dutyCycle * 64;

but if the OCR1A range is different (if you used a mode where TOP was not 65536) then you would need to work out how to scale one to the other.

 

Of course you could change the counting of the timer so it only counts form 0..1023 for its complete range but if you do that then you change the PWM frequency.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Arduino has a really nice "MAP" function that is useful for scaling one range to another:

ex. map( 0, 1023, 3, 98);    // maps adc range 0-1023 to pwm range 3-98

 

Source code for this function is easy to find using google.

 

Jim

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Jim, shure thats a nice function but I'm using Atmel Studio 7.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I used OCR1A = dutyCycle * 64; in the source but I still have a constant duty cycle of ~98% so I can't adjust it with the potmeter.

Could I use OCR1AL en OCR1AH for using 16 bits?


 

this

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be_logic wrote:
Hi Jim, shure thats a nice function but I'm using Atmel Studio 7.

 

So, Arduino code is GCC, what's the problem?

 

long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

 

Jim

edit: added function c code

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

Last Edited: Mon. Mar 5, 2018 - 07:03 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Of course you could change the counting of the timer so it only counts form 0..1023 for its complete range but if you do that then you change the PWM frequency.

LOL -- while we can see that OP doesn't have a good grasp of the situation, from time-to-time over the years I've chosen fixed-TOP 8-/9-/10-bit PWM in production apps.  It eliminates picking a TOP register and in some cases makes for a trivial yet useful transfer function.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your pulse width is determined by the Input Compare 1 register, not the TimerCounter 1 register.   The pulse width is never modulated: it is always 50/256 percent because ICR1 is set to 50 and never changed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Simonetta wrote:
Your pulse width is determined by the Input Compare 1 register,
Err no...

He appears to be using mode 14. So ICR1 sets TOP - that is the PWM frequency, not the duty cycle. In mode14 OCR1A sets the duty cycle of the pulse on OC1A and OCR1B sets the duty cycle of the pulse on OC1B. So to vary the frequency (and also the couting range of the timer) he should vary ICR1 and to modulate the pulses he should change OCR1A / OCR1B.

 

You do however highlight the fact that he sets:

    ICR1 = 50; // Frequentie

So setting OCR1A values 0..1023 is not going to work as the majority of the range is beyond the end of the timer's counting range. So he actually needs to map 0..1023 from the ADC to 0..49 that the counter uses. That would seem to involve a division by 20.48. Wonder why he chose to set ICR1 to just 50 ?? Sure it's a very high PWM frequency but why? Anyway he needs:

   OCR1A = dutyCycle / 20.48;

as things stand at present. But life would be much simpler with:

    ICR1 = 1024; // Give timer same counting range as ADC readings for 1:1 mapping

in that case

   OCR1A = dutyCycle;

really could be used.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Err no...
clawson wrote:
mode 14. So ICR1 sets TOP

Err, yes...timer1's input capture register is used as TOP.  Isn't that what was said?

 

Simonetta wrote:
pulse width is determined by the Input Compare 1 register, not the TimerCounter 1 register.

Oh, I see now  -- "compare" versus "capture"?  I guess I kind of read over that, as I grasped Simonetta's intent.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Isn't that what was said?
I guess that depends on what we mean by "pulse width". Does that mean the width of the "active bit" (ie the "modulated" bit - the actual "pulse") or does it mean the overall width (ie the complete period of one cycle). I read it as the former.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks in advance for your help because I have modified the source according to Simonetta but I now get a constant PWM signal with only other values, see the attached jpg.

I still can not change the PWM signal with the potentiometer.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Showing your actual code (as revised) will help us help you...

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here is the revised code;

 

#define F_CPU    8000000UL

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

volatile uint16_t dutyCycle;

int main(void)
{
    DDRB = (1 << PORTB1);
    
    TCCR1A |= (1 << COM1A1) | (1 << COM1A0) | (1 << WGM11); // fast PWM mode 14 en geinverteerd, set OC1A/OC1B on compare match
       TCCR1B |= (1<<WGM13) | (1 << WGM12) | (1 << CS11); // delen door 8
    ICR1 = 1024; // Give timer same counting range as ADC readings for 1:1 mapping
    
    setupADC();
    
    sei();

        
    while(1)
    {
        
    }
}

void setupADC()
{
    ADMUX = (1 << REFS0) | (1 << MUX0) | (1 << MUX2);  
    ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS0) | (1 << ADPS1);
    DIDR0 = (1 << ADC5D);
    
    startConversion();
}

void startConversion()
{
    ADCSRA |= (1 << ADSC); // ADSC is start conversie
}

ISR(TIMER1_OVF_vect)
{
    OCR1A = dutyCycle;
}

ISR(ADC_vect)
{
    dutyCycle = ADC;
    startConversion();
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be_logic wrote:
Here is the revised code;

As these things go, the code looks OK at a first glance...

1)  Learn how to use the Code tages <> on the formatting toolbar to preserve formatting

2)  ...the below should be 1023 not 1024 but won't affect operation much

Be_logic wrote:
ICR1 = 1024; // Give timer same counting range as ADC readings for 1:1 mapping

3)  From your attached .JPG we see a PWM frequency of about 2kHz.  Does that make sense with your setup?  Which pin of the AVR are you actually probing with Channel 2 of your logic analyzer?

4)  Show the connections to your potentiometer.  Which AVR pin is the wiper connected to?  When you probe right at that pin, what Voltage do you see?  Does it change when you turn the pot?

5)  You are getting a runt PWM duty cycle, so I'm guessing ADC counts of zero.  So now we need to ask about AVcc and AGnd connections, and the level on those pins.

5a)  Now we need to ask about connections and the level on the AREF pin.

 

Discussion on the above:  Are you sure your AVR is running at 8MHz?  The PWM period suggests 16MHz to me, which is the Arduino frequency, right?

 

 

 

 

 

 

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

Last Edited: Mon. Mar 5, 2018 - 07:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

6)  In TIMSK1 you need to enable the overflow interrupt...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Still waiting:

You've also been asked if a PWM frequency of 314 kHz is what you wanted.  Is it?

 

You said:

I do not need a certain frequency for my project, but I want to be able to arrange the duty cycle between ~ 3 and 98%.

But that's not good enough.  Is a 1 Hz signal alright?  What about a 31.25 kHz signal?  Or an 80 kHz signal?  How about 0.0001 Hz?

 

"I want to get from New York City to Los Angeles.  It doesn't matter how long it takes."

 

Ok, if you walk 8 hours a day, 5 days a week, starting now, you'll get there in time for International Youth Day in August.   Is that OK?

 

You must decide what range of frequencies will be suitable for your needs.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Mon. Mar 5, 2018 - 07:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And you are still clocking the ADC too fast (as joeymorin pointed out in post #3). It needs to run between 50 and 200kHz for 10-bit resolution.

If F_CPU is actually 8MHz then you need set ADPSn to divide by 64 (8MHz/64 = 125kHz).

If F_CPU is 16MHz, then ADPSn should divide by 128.

 

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have added TIMSK1 = TOIE1.

 

I use a ATMEL ATmega328p Xplained Mini board wich is just like an UNO, also the connections.

 

@3) frequency is not important and my logic analyzer is connected to PB1 (OC1A)

@4) the wiper of the potentiometer is connected to PC5 (AD05) and has a variation 0.65 V to 2V

@5) Aref=5Vdc

@5a) according to an instructor on "Microchip Makes" (youtube) the ATmega328p on the Xplained board runs on 8MHz

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@3) frequency is not important and my logic analyzer is connected to PB1 (OC1A)

So a frequency of 0 Hz is OK?

 

C'mon.  Pick a range of suitable frequencies.  Or ask your professor to pick one for you.  Everything else depends on that range.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, lets say frequency between 30 and 150 kHz? Is that alright?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be_logic wrote:
I have added TIMSK1 = TOIE1.

So, did it work?

 

Show that code.  did you mean TIMSK1 = (1<<TOIE1);"

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, lets say frequency between 30 and 150 kHz? Is that alright?

30 Hz?  Or 30 kHz?

 

e.g. ~ 3% to 98%

With what degree of precision?  That is, how fine a step size do you need?  Is 5% per step sufficient?:

  • 3%
  • 8%
  • 13%
  • .
  • .
  • .
  • 88%
  • 93%
  • 98%

 

Or do you need 1%?  Better than 1%?

 

3% and 98% seem fairly arbitrary and specific.  Is this to control a specific device?  Where do these numbers come from?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Of course I placed TIMSK1 = (1<<TOIE1); in the source but I still have a fixed signal.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I mean the frequency range from 30kHz to 150kHz and I wil use it using a sensor (variable resistor) and after PWM, by means of a filter I will have a variable DC voltage.

I would like the smallest possible precision with the given values and possibilities with this WGM-mode.

Hopefully you understand my English.......

 

Bert

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With your code in #19 above, you've set ICR1 to 1024.  This sets a resolution of 1025, not 1024.  The register is 0 based, so for 1024 steps you want to set it to 1023.

 

In any event, with that many steps, and with a prescaler of 8 as you've done, the PWM frequency will be:

FPWM = FCPU / PRESCALER / STEPS

     = 8000000 / 8 / 1024

     = 976.5625 Hz

 

That falls outside your range of 30 kHz to 150 kHz.  You'll have to do something else.

 

 

I would like the smallest possible precision with the given values and possibilities with this WGM-mode.

Statements which include 'as ___ as possible' are not especially helpful to an engineer.  You must state the constraints of your problem in a way which can be quantified.

 

I would submit that you don't need nearly as small a step size as you think you do.  There's a limit to how accurately your finger can adjust a rotary pot, a linear pot, or even a 20-turn trim pot.  As a guess, I would discard your 'smallest possible' and simply try the full 8-bits provided by an 8-bit timer, i.e. 256 steps.  If that turns out not to be enough, then you'll have to re-specify the requirements.

 

Let's try an 8-bit timer doing Fast PWM with a full 256 steps, and a prescaler of 1.

FPWM = FCPU / PRESCALER / STEPS

     = 8000000 / 1 / 256

     = 31,250 Hz

 

That falls within your stated range of 30 kHz to 150 kHz.

 

With Fast PWM, you'll have the following duty cycles available:

  •   1/256
  •   2/256
  •   3/256
  •   4/256
  •   5/256
  •   6/256
  •   7/256
  •   8/256
  •   9/256

...

  • 248/256
  • 249/256
  • 250/256
  • 251/256
  • 252/256
  • 253/256
  • 254/256
  • 255/256
  • 256/256
  •  

As percentages:

 

  • OCRnx  PERCENT
  • --------------
  •   0:   0.39%
  •   1:   0.78%
  •   2:   1.17%
  •   3:   1.56%
  •   4:   1.95%
  •   5:   2.34%
  •   6:   2.73%
  •   7:   3.13%
  •   8:   3.52%

...

  • 247:  96.88%
  • 248:  97.27%
  • 249:  97.66%
  • 250:  98.05%
  • 251:  98.44%
  • 252:  98.83%
  • 253:  99.22%
  • 254:  99.61%
  • 255: 100.00%

 

Now you need to map your ADC results, which come in a range of 0 to 1023, onto the range that the timer's PWM channel will expect, which will be a range of 0 to 255.  @ki0bk has suggested a way to map it to the percentage range you've specified (3% to 98%), but you could simply divide by 4 to map it to 0% through 100%, and then limit the top and bottom.  If you want limit to 'about 3%', then you could simply clamp the OCRnx value to a minimum of 6 (2.73%) and a maximum of 250 (98.05%).

 

@5a) according to an instructor on "Microchip Makes" (youtube) the ATmega328p on the Xplained board runs on 8MHz

When running at 3.3V, yes.  At 5V it runs at 16 MHz.

 

What have you done to confirm that your board is running at 8 MHz and not 16 MHz?

 

With your stated requirement, it may not matter.  You can choose an ADC prescaler of /128.   This will give you an acceptable ADC clock for both 8 MHz (62.5 kHz) and 16 MHz (125 kHz).  It will also give you a PWM frequency within your stated range.  At 8 MHz, the PWM frequency would be 31.25 kHz, and at 16 MHz it would be 62.5 kHz.

 

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Tue. Mar 6, 2018 - 03:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Joey, thank you for this detailed explanation of what I did not find in the datasheet. Below I give some information and have some questions.

 

- I already had the value of ICR1 changed to 1023 and TIMSK1 = (1 << TOIE1) in the source.

- I don't need a very small step size and variable resistor is a simple one (60 Ohm til 280 Ohm)

- So, should I use the 8 bit Timer0 or 2 or can I use Timer1 anyway?

- In the final design I want to use the 8 MHz internal oscillator.

  in several films of Microchip Makes on youtube F_CPU 8000000UL is used  for the Xplained mini board.

- Should I use OCR1A=6 and OCRB=250 with Timer1? But OCR1A is already used in the (Timer1_OVF_vect) what about this?

 

with the current source I have a duty cycle between 59.5 and 86.9%

 

#define F_CPU    8000000UL

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

volatile uint16_t dutyCycle;

int main(void)
{
    DDRB = (1 << PORTB1);
    
    TCCR1A |= (1 << COM1A1) | (1 << COM1A0) | (1 << WGM11); // fast PWM mode 14 en geinverteerd, set OC1A/OC1B on compare match
       TCCR1B |= (1<<WGM13) | (1 << WGM12) | (1 << CS11); // delen door 8
    ICR1 = 1023; // Give timer same counting range as ADC readings for 1:1 mapping
    //OCR1A = 6;
    //OCR1B = 250;
    TIMSK1 = (1 << TOIE1);

    setupADC();
    
    sei();

        
    while(1)
    {
        
    }
}

void setupADC()
{
    ADMUX = (1 << REFS0) | (1 << REFS0) | (1 << MUX0) | (1 << MUX2);  
    ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);  //  /128
    DIDR0 = (1 << ADC5D);
    
    startConversion();
}

void startConversion()
{
    ADCSRA |= (1 << ADSC); // ADSC is start conversie
}

ISR(TIMER1_OVF_vect)
{
    OCR1A = dutyCycle;
}

ISR(ADC_vect)
{
    dutyCycle = ADC; // met delen door 4 duty cycle van 90-97% zonder /4  59.5-86.9%
    startConversion();
}

 

 

I hope you can help me further

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can you post a schematic of how you have the variable resistor connected with respect to GND, AVCC, and the ADC input?

A schematic provides information that a verbal description just doesn't convey effectively.

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have the drawing as an attachment

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm confused, for what value of the 60-280 variable resistor do you set the 1K variable resistor such that you have 2V at A?

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be_logic wrote:
I hope you can help me further

I'd like to see the generated code, such as the .LSS file.  And perhaps the build log and the ISP log -- is the right file getting to your target chip?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Indeed there is something happening that is "interesting".  As you are set up for inverted PWM and are seeing near 100% duty on the output, that would imply ADC conversion results always at 1023 counts.  That implies a very low reference.  Check the levels again, right on the AVR pins, for AGND and AVCC and AREF and PC5.

 

Then I'd make a sanity check program, and just make the PWM work.  [there is still a frequency mystery between the discussion and the posted traces]  E.g. in the main loop

 

while (1)

{

_delay_ms (123);

OCR1A++;

OCR1A &= 1023;

}

 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Although, you can be forgiven for not doing so, since a site upgrade earlier today broke the code editor.

 

#define F_CPU    8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint16_t dutyCycle;


int main(void) {

  DDRB = (1 << PORTB1);
  TCCR1A |= (1 << COM1A1) | (1 << COM1A0) | (1 << WGM11);
  TCCR1B |= (1<<WGM13) | (1 << WGM12) | (1 << CS11);
  ICR1 = 1023;
  //OCR1A = 6;
  //OCR1B = 250;
  TIMSK1 = (1 << TOIE1);
  setupADC();
  sei();
  while(1) {}
  
}


void setupADC() {
  ADMUX = (1 << REFS0) | (1 << REFS0) | (1 << MUX0) | (1 << MUX2);
  ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
  DIDR0 = (1 << ADC5D);
  startConversion();
}


void startConversion() {
  ADCSRA |= (1 << ADSC);
}


ISR(TIMER1_OVF_vect) {
  OCR1A = dutyCycle;
}


ISR(ADC_vect) {
  dutyCycle = ADC;
  startConversion();
}

Although it does no harm, you've specified (1 << REFS0) twice.  Once is enough ;-)

Should I use OCR1A=6 and OCRB=250 with Timer1? But OCR1A is already used in the (Timer1_OVF_vect) what about this?

I think you've misunderstood.  With mode 14 on TIMER1, ICR1 sets the >>resolution<< of the timer, while OCR1A and OCR1B are used to set the duty cycle of the two outputs OC1A and OC1B, respectively.  They do not set minimums and maximums.

 

You've made PB1/OC1A and output, so you should use OCR1A, which you are.

 

I think you can do away with the TIMER1 overflow interrupt altogether (and refrain from enabling it with TOIE1), and assign the new value for OCR1A directly in the ADC.

 

Your schematic doesn't make much sense.  Why two variable resistors?  Why not just a potentiometer?:

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

assign the new value for OCR1A directly in the ADC --> how should I make this in the source?

 

The sensor is a kind of potentiometer as is used in petrol tanks of cars, hence the strange resistance values (~ 65-280 Ohm, lineair type).

Of course, a potentiometer connected on one side to GND would be easier.

By the way do you have ideas how I could spoof the ADC for compensation of the 65 Ohm threshold?

The 1k 10 turn adjustment potentiometer serves as a pre-setting to set 2Vdc as bias, with another "potentiometer" this value should be 1Vdc

 

I tried posting the source with <> but it didn't work with copy-paste.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

assign the new value for OCR1A directly in the ADC --> how should I make this in the source?

Whoops that was supposed to say ADC_vect ISR.  What I mean is that you can assign the new value for OCR1A in the ADC ISR.  You don't need the timer ISR to do that.

 

The 1k 10 turn adjustment potentiometer serves as a pre-setting to set 2Vdc as bias, with another "potentiometer" this value should be 1Vdc

I'm not certain I understand.  Are you saying that the 1K pot needs to be adjusted such that when the sensor is 280 ohms (is that 'full'?), then the voltage of the resultant divider should be 2V, and when it is 65 ohms (is that empty), it should be 1V?  If not, then please say exactly what you mean.  Tell the range of voltages you want to see when the sensor swings from 65 ohms to 280 ohms.

 

This is what I mean by being specific when you state your requirements.  Here we are at post #40 and we are hardly any closer to answering your question than when this thread began.  Statement of the problem and the subsequent statement of the requirements for solving it are arguably the most important steps in any engineering endeavour.  I would argue that they are the most important steps in >>any<< human endeavour, technical or not.

 

Assuming I'm right and you want 1V-2V swing from the sensor, then there is a bit of arithmetic to do.  First we should try to determine the resistance needed on the 1K pot to achieve that range.

 

If:

  • the 1K pot we call R2
  • the 'full' voltage we call Vf
  • the 'empty' voltage we call Ve
  • the 'full' resistance of the sensor we call Rf
  • the 'empty' resistance of the sensor we call Re

 

... then we have two equations:

Vf = (Vcc * Rf) / (Rf + R2)

Ve = (Vcc * Re) / (Re + R2)

 

Filling in known values, we get:

2 = (5 * 280) / (280 + R2)

1 = (5 * 65) / (65 + R2)

 

Solving the first:

             2 = 1400 / (280 + R2)

2 * (280 + R2) = 1400

     560 + 2R2 = 1400

           2R2 = 840

            R2 = 420

 

Now we do the same for the second:

      1 = (5 * 65) / (65 + R2)

      1 = 325 / (65 + R2)

65 + R2 = 325

     R2 = 260

 

So we see that it is not possible to set the 1K to a single value which will result in the voltage swing you require.  Either I have misunderstood what you've said, or your circuit is not adequate to the task.  You need another resistor 'below' the sensor:

         VCC
          ^
          |
          |
          |
         +-+/
         | /   R3
         |/|   1K
         / |
        /+-+
          |
ADC5------+
          |
         +-+/
         | /  Sensor
         |/|  65-280
         / |
        /+-+
          |
          |
          |
         +-+/
         | /   R1
         |/|   1K
         / |
        /+-+
          |
          |
          |
         GND

 

Now we have two new equations:

Vf = (Vcc * (R1 + Rf)) / (R1 + Rf + R3)

Ve = (Vcc * (R1 + Re)) / (R1 + Re + R3)

 

Filling in known values:

2 = (5 * (R1 + 280)) / (R1 + 280 + R3)

1 = (5 * (R1 + 65)) / (R1 + 65 + R3)

 

Solving the first for R3 w.r.t. R1:

                  2 = (5 * (R1 + 280)) / (R1 + 280 + R3)

2 * (R1 + 280 + R3) = 5 * (R1 + 280)

    2R1 + 560 + 2R3 = 5R1 + 1400

          2R1 + 2R3 = 5R1 + 840

                2R3 = 3R1 + 840

                 R3 = (3R1 + 840) / 2

 

Solving the second for R3 w.r.t. R1:

           1 = (5 * (R1 + 65)) / (R1 + 65 + R3)

R1 + 65 + R3 = 5R1 + 325

          R3 = 4R1 + 260

 

Now we combine the two to solve for R1:

4R1 + 260 = (3R1 + 840) / 2

8R1 + 520 = 3R1 + 840

      5R1 = 320

       R1 = 64

 

Now we plug our solved value for R1 back into one of the equations (it doesn't matter which) to solve for R3:

          R3 = 4R1 + 260

             = (4 * 64) + 260

             = 256 + 260

             = 516

 

We can verify our results by plugging those values in to each initial equation:

Vf = (Vcc * (R1 + Rf)) / (R1 + Rf + R3)

   = (5 * (64 + 280)) / (64 + 280 + 516)

   = (5 * 344) / 860

   = 1720 / 860

   = 2

 

Ve = (Vcc * (R1 + Re)) / (R1 + Re + R3)

   = (5 * (64 + 65)) / (64 + 65 + 516)

   = (5 * 129) / 645

   = 654 / 645

   = 1

 

So that seems to work.  In order to get the 1V-2V swing on ADC5, you'll want a 516 ohm resistor above the sensor, and a 64 ohm resistor below the sensor.  A good value for the top trimpot is 1K as you already have.  A good value for the bottom trim pot would be 100 ohms.

 

If this makes sense to you, you can move on to the code.  If I've misunderstood your requirements for the voltage range presented to ADC5 by your sensor voltage divider, then please set me straight.  You might also want to explain the rationale behind those requirements.  For instance (if I'm right) why do you require a 1V-2V range?  Is this a requirement given to you by your teacher with no explanation?  Or was an explanation provided to you?

 

I think I've done enough of your homework for you for today ;-)

 

 

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sure that was a lot of work because I also started with Ohm's law equations to compensate the 65 ohm treshold.

This evening I have less time but tomorrowevening I will make the resistance circuit and then test with the code. thanks!

 

Bert

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You haven't answered my questions:

I'm not certain I understand.  Are you saying that the 1K pot needs to be adjusted such that when the sensor is 280 ohms (is that 'full'?), then the voltage of the resultant divider should be 2V, and when it is 65 ohms (is that empty), it should be 1V?  If not, then please say exactly what you mean.  Tell the range of voltages you want to see when the sensor swings from 65 ohms to 280 ohms.

If I've misunderstood your requirements for the voltage range presented to ADC5 by your sensor voltage divider, then please set me straight.  You might also want to explain the rationale behind those requirements.  For instance (if I'm right) why do you require a 1V-2V range?  Is this a requirement given to you by your teacher with no explanation?  Or was an explanation provided to you?

Once you nail down the range of voltages you want to see on ADC5, then we can determine what range of values you'll see from the ADC, and then create a transfer function which converts that range of values to the 3%-98% PWM values you want.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Wed. Mar 7, 2018 - 08:11 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One thing to consider is the current through the voltage divider.  If we go with the 516R and 64R settings for the two trimpots, then the current will be from:

I = Vcc / (R1 + Rf + R3)

  = 5 / (64 + 280 + 516)

  = 5 / 860

  = 5.8 mA

... up to:

I = Vcc / (R1 + R3 + R3)

  = 5 / (64 + 65 + 516)

  = 5 / 645

  = 7.8 mA

 

That should be fine for the trim pots. The 1K and 100R 10-turn pots I found on DigiKey are rated for 300 mW, and with the above arrangement they each will dissipate much less than that.

 

However, you will need to know what your sensor is rated for.  That includes voltage, current, and power.  Chances are you'll be OK, but engineering is about >>proving<< it.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have connected a normal potentiometer and with the current source I have a duty cycle of 1.075% to 99%. so it seems to me the source is ok.
Would I be able to adjust the ADC conversion value in ADCL etc. after conversion for the other adjustable sensor (resistance of 65-280 Ohm)?

Because for the sensor the voltage on the AD input should be between 0.1 and 2Vdc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have connected a normal potentiometer and with the current source I have a duty cycle of 1.075% to 99%. so it seems to me the source is ok.
Would I be able to adjust the ADC conversion value in ADCL etc. after conversion for the other adjustable sensor (resistance of 65-280 Ohm)?

Because for the sensor the voltage on the AD input should be between 0.1 and 2Vdc.

As mentioned several times now, you simply need to scale the resulting range of ADC values to the required range of PWM values.  But you have several questions to answer first.  See my previous posts.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

- How do I scale the resulting range of ADC values to the required range of PWM values?

- The voltage on the AD input should be between 0.1 and 2Vdc

- This range should give a 3-98% PWM range.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

- The voltage on the AD input should be between 0.1 and 2Vdc

So return to the work I did in #40 and redo the math for 0.1-2 instead of the 1-2 which I did.  To what value will the 1K trimmer need to be set?  Will you need another trimmer 'below' the sensor?

 

Once you know the voltages to expect on the ADC input, you will also know the range of values to expect from the ADC.  Simply multiply by the resolution of the ADC (1024), and divide by AVcc (5).

 

- How do I scale the resulting range of ADC values to the required range of PWM values?

[Sigh]... Does Google not work where you are?

https://www.google.ca/search?q=how+to+scale+a+number

 

Here's a hint:

https://www.avrfreaks.net/comment/2412566#comment-2412566

 

As Jim has hinted, you can find the source code for that pretty easily with Google:

https://www.google.ca/search?q=arduino+map+source+code

Second hit.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Sat. Mar 10, 2018 - 07:38 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ADC max value = 409.6 and ADC min value = 122.88    because ADC=(Vin*1024)/Vref

 

The minimum DutyCycle (DC) reached now is ~2% but the maximum DC is now ~67.5%

What could I do making the max DC 99.9%? remapping?

Could  you give me some help/hints how to remapping in Atmel Studio?

 

Bert

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be_logic wrote:
ADC max value = 409.6 and ADC min value = 122.88
Not sure how a register that only returns integers between 0 and 1023 can actually return n.6 or n.88 but anyway...

 

The fact is that your active range is 409.6 - 122.88 = 286.72. So if you end up with a value in the range 122.88 to 409.6 first subtract 122.88 from it. Now you have a value 0 .. 286.72. Assuming you want this to represent 0..100% then clearly you need to divide by 2.8672.

 

So say the value from your formula is 237.4 then 273.4 - 122.88 is 150.52 and 150.52 / 2.8672 is 52.497 so a reading of 273.4 is 52.497% and so n.

 

This is just simple algebra - don't try to "over think" this. It's simply an instanc of y=mx + c (a straight line).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ADC max value = 409.6 and ADC min value = 122.88    because ADC=(Vin*1024)/Vref

How did you get 122.88 from a required range of 0.1V to 2.0V?

 

The higher number is right (although Cliff has pointed out you can't represent fraction numbers in an integer), but the lower number represents 0.6V, not 0.1V.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, I will test it right away!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, the lower value for 0.1V is 20.48 and ofcource I understand that it can't be represented.

I have used the calculation in the source but does not provide any improvement for the maximum duty cycle.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, the value for 0.1V is 20.48 and ofcourse I understand that the figures behind the dot can't be represented.

I used the calculations in the source but it didn't provide a larger dutycycle towards 99%

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cliff has explained it perfectly well.  And both Jim and I have even pointed out where you can find the source code which will completely solve your problem.  Jim even actually posted it here!  Why are you still working on this?

 

IF you expect the ADC to return a value no lower than 20, and

IF you expect the ADC to return a value no higher than 410, and

IF you want a minimum OCR1A value of 6 (2.73%), and

IF you want a maximum OCR1A value of 250 (98.05%), and

WERE you to use the Arduino map() function, then it would look like this:

OCR1A = map(ADC, 20, 410, 6, 250);

Since you're not using the Arduino environment, you can simply implement the same function in your own code.  Have you even >>looked<< at the source?

 

You will need to handle cases where the ADC value is outside the range you expect so that your device doesn't explode.  What happens if the sensor fails?  What happens if there is a short somewhere?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I did make a recalculation and used it in the source but it gave no improvement for the maximum dutycycle e.g. 99.9%

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will not open a random .docx file.  Post the text of it here instead.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you even >>looked<< at the source?

 

I searched a lot for the Arduino map() source but could not find it.

Could you please tell me where finding it?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will post it in txt format.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I searched a lot for the Arduino map() source but could not find it.

Could you please tell me where finding it?

You have got to be kidding me.

 

It's in >>this<< thread!

 

Scroll to the top of the page and find post #11.

 

He first mentioned it in #8.

 

Also find it where I pointed you to a google search result it in post # 47, and mentioned it again in #54.

 

You are clearly not paying attention, or making much of an effort.

 

I'm out.  Good luck with your project.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Be_logic wrote:
but it gave no improvement for the maximum dutycycle e.g. 99.9%

???  Does everyone else know what that means?  Do you mean that you want a duty cycle greater than 99.9% ?  What duty cycle >>do<< you want?  For which input value?  What duty cycle are you getting now?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yesterday I made reply"s but can't see this here so I send it again.

 

The ADC value for 0.1V is 20.48, see the recalculations and ofcource I can use the figures after the dot.

At which part in the source I must place ORC1A = map(ADC, 20, 410, 6, 250);

Because I managed using the map function in Atmel Studio 7.

 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Dutycycle must be variable between 1 and 99.9%, now it's ~67.5 max

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

There must be some kind of a language barrier (or stubbornness, or laziness) at work here.  I don't care which.  I am tiring of it all, and just want it to end!  So here's a crack at it:

#include <avr/io.h>

#define ADC_MIN 21
#define ADC_MAX 409
#define PWM_MIN 6
#define PWM_MAX 250

static uint32_t map(const uint32_t x,
                    const uint32_t in_min, const uint32_t in_max,
                    const uint32_t out_min, const uint32_t out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

int main(void) {

  uint16_t adc;

  // Disable input buffer on ADC5.
  DIDR0 = (1 << ADC5D);
  // AVcc, ADC5.
  ADMUX = (1 << REFS0) | (5 << MUX0);
  // div128, free running, start.
  ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (7 << ADPS0);

  // OC1A output for PWM.
  DDRB = (1 << PORTB1);
  // Mode 5 (8-bit Fast PWM), /1, non-inverted output on OC1A.
  TCCR1A = (2 << COM1A0) | (1 << WGM10);
  TCCR1B = (1 << WGM12) | (1 << CS10);

  // Forever.
  while(1) {
    adc = ADC;
    // Constrain.
    if (adc < ADC_MIN) {
      adc = ADC_MIN;
    }
    else if (adc > ADC_MAX) {
      adc = ADC_MAX;
    }
    // Scale to PWM output.
    OCR1A = map(adc, ADC_MIN, ADC_MAX, PWM_MIN, PWM_MAX);
  }

}

Ask if you don't understand something.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Thu. Mar 15, 2018 - 03:26 AM