AVR sense/PWMing Help!

Hi again! I'm intent on finishing up a few loose end projects of mine, but before I do so, need the following information. How can I sense some resistance or voltage with my uC? I know I can do an a/d conversion, but that only triggers when Vin > some 1 preset value. I'm looking to make an adjustable knob to turn the intensity of an LED up and down. Also, how can I PWM some LEDs with my AVR uC - I can use the tiny2313 or mega8 or tiny 13, but I have no preference. I just need 3 different PWM channels. Any ideas? I already googled, but apparently I'm terrible at finding good tutorials. (oh, and I'm coding in C) The LEDs will be inserted into this nice, custom built (by myself) welded devil duckie. Horns and tail will turn to control RGB. Thanks a whole lot, -Muffin

Picture of AVR sense/PWMing Help!
sort by: active | newest | oldest
gmoon9 years ago
hehe. devil duckie.

AFAIK, the Atiny2313 doesn't have any ADCs, just a comparator (if you were planning on sampling voltage as well as using the PWM.)

Yep, as has been said, the ADC's can read an input voltage (like a POT as a voltage divider) at a fairly rapid frequency.

If you need code for a mega8, you could check out the transmitter for my Radio controlled 3D & joystick controller project (this uses the same accelerometer board as oskay.) It uses 5 ADC inputs, although not more than 3 at any one time--3 for the accelerometer, and two for the joystick.

(this got Hack-a-day-ed just about exactly a year ago..)
oskay9 years ago
Hey Muffin,
I wrote up a tutorial on using PWM on the AVR to create analog output levels. (The PWM outputs are smoothed with a low-pass filter to make true analog levels that look nice on the scope, but you don't need to do that with LEDs.)

I used the same code as the basis for this AVR tutorial on using an accelerometer, which takes analog inputs (from the accelerometer) and displays the data using the brightness of six LEDs driven from six PWM outputs, red or blue for each axis for positive or negative acceleration, with brightness depending upon the magnitude of acceleration. You could use the same to take your own analog inputs from *whatever* and display the result on the LEDs.

Both tutorials include source code for the ATmega188, ATmega168 and family. The ATmega8 is pretty close, but not exactly the same-- there are some minor changes between them, including the definitions of the ADC and timer registers-- this document lists some of the differences.
westfw9 years ago
Here's some C code that does software PWM for 5 pins on a PIC. It should translate pretty easily to AVR. This particular program has an outer loop that picks random values for each LED brightness, to simulate "flames", but that should be easy to replace with another method of picking the brightnesses.

/* * flames.c * October, 2003 by Bill Westfield * * Turn a PIC12f675 (8pin flash) PIC into "simulated fire" by output * pseudo-random PWM to the 5 available output pins, so you can drive * LEDs or lamp drivers or whatever. * * Target language: freeware version of PIC cc5x */#include "12f675.h"// #define PICKIT1 1            /* test on pickit */#pragma config |= 0x1184  // Internal oscillator, etc.#pragma config WDTE=0     //   (not derived - read from the pickit demo :-)#define LOOPTIME 255#define DELTIME 50char bright1, bright2, bright3, bright4, bright5;#if PICKIT1/* * The LEDs on the PIC-Kit 1 are set up "funny" so that the 8-pin PIC * can make up to 12 LEDs flash.  Individually.  Since we some on at * the same time, we're limitted to just a couple, but keep code for * the others around just for timing purposes.  This way you can debug * the algorithms without having to move the chip to the target circuit. */#define led1_off GPIO5 = 0#define led1_on  GPIO5 = 1#define led2_off GPIO1 = 0#define led2_on  GPIO1 = 1/* * Note that GPIO3 is an input only, so these are all no-ops */#define led3_off GPIO3 = 0#define led3_on  GPIO3 = 1#define led4_on led3_on#define led5_on led3_on#define led4_off led3_off#define led5_off led3_offvoid led_all_on (void){   GPIO5 = 1;   GPIO1 = 1;}#else/* * In the 'real application', we sink current for LEDs connected to V+ * through current limitting resistors, so setting the pin to 0 turns on * an LED and a 1 turns it off (not that it matters which state is on and * which state is off, since they're all random anyway. */#define led_all_on(a) GPIO = 0#define led1_on GPIO0 = 0#define led1_off  GPIO0 = 1#define led2_on GPIO1 = 0#define led2_off  GPIO1 = 1#define led3_on GPIO2 = 0#define led3_off  GPIO2 = 1#define led4_on GPIO4 = 0#define led4_off  GPIO4 = 1#define led5_on GPIO5 = 0#define led5_off  GPIO5 = 1#endif // PICKIT11void init(void){    /*     * set all pins to real, program controlled outputs     */    ANSEL = 0x0;    VRCON = 0;             //Turn Off Voltage Reference Peripheral    CMCON = 0x07;          //Turn Off Comparator Peripheral    TMR0 = 0;              //Clear Timer0    INTCON = 0;    OPTION = 0x80;     TRISIO = 0b001000;    GPIO = 0;}/* * getbright() * * Get a new set of pseudo-random brightnesses for each output * * generating the random numbers isn't time-critical, but use a macro * so that we can easilly change the algorithm for all outputs without * changing too much code.  We could use pointers to each brightness * or arrays, but that seems a bit gratuitously HLL-like. * * 127 state pseudo-random numer * Shift register with feedback at bits 0,6 */#define nextrandom(last)  \    newbit = last & 0b01000000;  /* bit 6 */  \    if (last & 1)                /* bit 0 */ \      newbit ^=  0b01000000; \    last = (last>>1) + newbit;void getbright( void){   char newbit;   nextrandom(bright1);   nextrandom(bright2);   nextrandom(bright3);   nextrandom(bright4);   nextrandom(bright5);}void main(void){   char pwm1, pwm2, pwm3, pwm4, pwm5, level_delay, pwm_delay;   init();   bright1 = 50;  // "random" initialization    bright2 = 20;     bright3 = 10;   bright4 = 1;   bright5 = 100;   while (1) {  // forever      getbright();      for (level_delay = 50; level_delay != 0; level_delay--) {         pwm1 = bright1;         pwm2 = bright2;         pwm3 = bright3;         pwm4 = bright4;         pwm5 = bright5;         led_all_on();         for (pwm_delay = 128; pwm_delay !=0; pwm_delay--) {             /*              * We have a random number in each PWM between 1 and 128              * and we're going to have 128 cycles of delay.  So each              * decremented output can only cross zero once, at which              * time we toggle the output state.              */             if (--pwm1 == 0) {                 led1_off;             }             if (--pwm2 == 0) {                 led2_off;             }             if (--pwm3 == 0) {                 led3_off;             }             if (--pwm4 == 0) {                 led4_off;             }             if (--pwm5 == 0) {                 led5_off;             }         } /* time for new PWM cycle */      } /* time for new brightness */   } /* while forever */}
LinuxH4x0r9 years ago
Ah! looks awesome! Can't wait to see the final project
T3h_Muffinator (author)  LinuxH4x0r9 years ago
Sigh - I hope there will be one!
I do too.