I had this working the other day, something changed between then and now, I cant figure out what…
Im trying to use the ADC in free running as a random number generator to drive TRIACs to generate a realistic flickering for lamps for Halloween this year…
I copied the ADC spinets from another project where it is working properly, yet I still have no luck. Im debuging with dW and what seems to be happening is ADCSRA|=(1<<ADSC); doesn’t change anything. It fails to set ADSC, and a conversion never starts. If i set it manually while debugging it runs a conversion fine. I assume the problem is the ADSC is never being set, why not?
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "ADC.h"
#include "timer.h"
#define nop() volatile asm("nop")
#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 << (x))
#define LIGHT0_ON PORTB&=(!(1<<PORTB0))
#define LIGHT0_OFF PORTB|=(1<<PORTB0)
#define LIGHT1_ON PORTB&=(!(1<<PORTB1))
#define LIGHT1_OFF PORTB|=(1<<PORTB1)
#define LIGHT2_ON PORTB&=(!(1<<PORTB2))
#define LIGHT2_OFF PORTB|=(1<<PORTB2)
#define LIGHT3_ON PORTC&=(!(1<<PORTC0))
#define LIGHT3_OFF PORTC|=(1<<PORTC0)
#define HEART_ON PORTD&=(!(1<<PORTD0))
#define HEART_OFF PORTD|=(1<<PORTD0)
#define PICKLE PIND3
unsigned char x, timer=0, adc;
ISR(TIMER2_OVF_vect){
timer++; //inc RTC
PORTD ^= (1<<PORTD0) | (1<<PORTD7); // toggle heart beat LED
}
ISR(ADC_vect){
adc=ADCH;
adc=ADCL; //
ADCSRA|=(1<<ADSC); //start conversions
}
ISR(INT0_vect){
x=150+(ADCL/3); //set base delay + random number
for (char i=0; i<x; i++){ //delay loop before fireing TRIAC
_delay_us(25);
}
LIGHT0_ON;
LIGHT1_ON;
LIGHT2_ON;
LIGHT3_ON;
_delay_us(2);
LIGHT0_OFF;
LIGHT1_OFF;
LIGHT2_OFF;
LIGHT3_OFF;
}
void ADC_setup(void){
ADCSRA|=(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0); // set the ADC clock prescaler to 64 (8m/64=125k) and enable ints
ADMUX|=(0<<ADLAR)|(0<<MUX3)|(1<<MUX2)|(1<<MUX1)|(0<<MUX0); //set the ADC result register right justified and select ADC chan 6
ADCSRA|=(1<<ADEN); //enable ADC
ADCSRA|=(1<<ADSC); //start conversions
}
void initialize (void) {
CLKPR=(1<<CLKPCE); // enable divisor change to turn of clk/8
CLKPR=0; // set divisor to 1 for a clock of 8mhz
timer_setup();
ADC_setup();
DDRB |= (1<<DDB0) | (1<<DDB1) | (1<<DDB2); //B0:2 output
DDRC |= (1<<DDC0);
DDRD |= (1<<DDD0) | (1<<DDD7) | (0<<DDD3);
// PORTD |= (1<<PORTD3); //enable the pullup on PD3, an input
EICRA |= (1<<ISC01) | (1<<ISC00); // Setup INT0 control reg
EIMSK |= (1<<INT0);
sei(); //enable global ints
LIGHT0_OFF;
LIGHT1_OFF;
LIGHT2_OFF;
LIGHT3_OFF;
}
int main (void){
initialize();
for(;;){
;
}
}
FWIW, a few years back I coded up a filtered-LFSR-based candle flicker routine from the ideas in [Philip Ching’s project here. Leaving off all the clever wind-sensor stuff, an old 90S1200 AVR easily produced four separate flicker outputs. The lack of hardware randomness input really isn’t perceptible. I could post my code if there’s interest, but Philip Ching’s article has some code, and I think there are other implementations floating around on the web as well.](http://instruct1.cit.cornell.edu/courses/eceprojectsland/STUDENTPROJ/2001to2002/pc59//index.htm)
I scraped all that code and started over fresh, and everything seems fine now. I have no idea what went wrong but I feel a lot better about it now.
The flicker seems fine. The incandescent lamps are probably more forgiving as far as blending all the randomness together to make it seem more smooth than it actually is. If i were using LEDs i would probably want to see your code wiml. Thanks for the help guys.
i changed my mind… i would like to see your code if you wouldn’t mind wiml. after testing it out today in the dark I realized it dosent look at all how I want it to.
Im having the same problem as before, which is a register is not being changed when it should. This is really frustrating.
Im trying to clean up my code… get those delay routines out of the ISR, instead just set a flag, and test for the flag in my main code and do the appropriate thing there. The ISR sets the Triac_refresh flag, which is tested in the main loop. The problem is the Triac_refresh=0 in the IF is not actually clearing the register, at least its not reporting this is happening when I debug. I know its posible the INT0 isr is being called so fast that its being set right after its cleared but thats not probable as that ISR is only being called 120 times a second, and the AVR is running at 8Mhz.
Im starting to think debugwire is lying to me or im missing something really basic. Any ideas?
/***********************************************************/
// Paul Mac
// Halloween show control board
// v1.0 Build Oct 24, 2008
//
/***********************************************************/
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
/***********************************************************/
//Defines
#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define bit_write(c,p,m) (c ? bit_set(p,m) : bit_clear(p,m))
#define BIT(x) (0x01 << (x))
#define LONGBIT(x) ((unsigned long)0x00000001 << (x))
#define NOP asm("nop")
#define LIGHT0_ON bit_clear(PORTB, BIT(0))
#define LIGHT0_OFF bit_set(PORTB, BIT(0))
#define LIGHT1_ON bit_clear(PORTB, BIT(1))
#define LIGHT1_OFF bit_set(PORTB, BIT(1))
#define LIGHT2_ON bit_clear(PORTB, BIT(2))
#define LIGHT2_OFF bit_set(PORTB, BIT(2))
#define LIGHT3_ON bit_clear(PORTC, BIT(0))
#define LIGHT3_OFF bit_set(PORTC, BIT(0))
#define HEART_ON bit_clear(PORTD, BIT(0))
#define HEART_OFF bit_set(PORTD, BIT(0))
#define BMID_ON bit_clear(PORTD, BIT(7))
#define BMID_OFF bit_set(PORTD, BIT(7))
#define BTOP_ON bit_clear(PORTC, BIT(3))
#define BTOP_OFF bit_set(PORTC, BIT(3))
/***********************************************************/
//Global Vars
char unsigned x, triac_fire=0, ch1_full;
char unsigned Triac_refresh;
static char unsigned timer=0;
/***********************************************************/
// ISRs
/*
ISR(INT0_vect){
triac_fire=1;
x=75+ADCH;
//x=0;
for (char i=0; i<x; i++){ //delay loop before fireing TRIAC
_delay_us(25);
}
LIGHT0_ON;
LIGHT1_ON;
LIGHT2_ON;
LIGHT3_ON;
_delay_us(2);
LIGHT0_OFF;
LIGHT1_OFF;
LIGHT2_OFF;
LIGHT3_OFF;
}*/
ISR(INT0_vect){
Triac_refresh=1;
}
ISR(TIMER2_OVF_vect){
timer++; //inc RTC
PORTD ^= (1<<PORTD0); // toggle heart beat LED
}
/***********************************************************/
// Functions
void adc_setup(void) {
ADCSRA|=(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(0<<ADPS0); // set the ADC clock prescaler to 64 (8m/64=125k) and enable ints
ADMUX|=(1<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0); //set the ADC result register right justified and select ADC chan 6
ADCSRA|=(1<<ADEN); //enable ADC
DIDR0|=(1<<ADC1D); //disable digital buffer on ADC1
}
void port_setup(void){
BTOP_OFF;
BMID_OFF;
DDRB |= (1<<DDB0) | (1<<DDB1) | (1<<DDB2); //B0:2 output
DDRC |= (1<<DDC0) | (1<<DDC3);
DDRD |= (1<<DDD0) | (0<<DDD3) | (1<<DDD6) | (1<<DDD7);
PORTD |= (1<<PORTD3); //enable the pullup on PD3, an input
EICRA |= (1<<ISC01) | (1<<ISC00); // Setup INT0 control reg
EIMSK |= (1<<INT0); //enable external int0
}
void timer_setup(void){
ASSR|=(1<<AS2);
TCCR2B|= (1<<CS22)|(0<<CS21)|(1<<CS20); //prescaler of 128
TIMSK2|=(1<<TOIE2); //enable the timer 2 overflow int.
}
void initialize (void) {
CLKPR=(1<<CLKPCE); // enable divisor change to turn of clk/8
CLKPR=0; // set divisor to 1 for a clock of 8mhz
port_setup();
adc_setup();
timer_setup();
sei(); //enable global ints
LIGHT0_OFF;
LIGHT1_OFF;
LIGHT2_OFF;
LIGHT3_OFF;
}
/***********************************************************/
// Main Function
int main (void){
initialize();
for(;;)
{
ADCSRA|=(1<<ADSC); //start conversions
if(!bit_get(PIND, BIT(3))){
ch1_full=1;
}
if(Triac_refresh==1)
{
Triac_refresh=0;
NOP;
}
}
}