Codevision Codewizard read_adc function Where is it?

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

I am setting up a 120 volt sequencing program to switch between 3 2000 watt heaters on one 20 amp circuit. I am using an allegromicro hall effect device that will generate a 60 cycle AC voltage with a maximum of 2.5VAC Peak to Peak ( I tested a 1200 watt hot air gun that gave me 1.4 so I assume 2000 watts will be about 2.5 maximum.

I am attempting to use the ADC on a tiny45 to read the voltage levels. Not being very smart when it comes to sine waves I think the maximum positive voltage should then be 1.25V and the negative value would be -1.25V.

I have attached the code generated by codevision but I am at a loss as to starting the conversion, I understand the interrupt will store the value when it is finished.

The Help says

If the automatic inputs scanning is disabled, then a single analog-digital conversion can be executed using the function:
unsigned int read_adc(unsigned char adc_input)

Does this function just turn on ADEN in ADCSRA? Is there a library to link in? I am lost here.

Two other questions, The output of the allegro device I have used a 220 ohm resistor, do I need to clamp the negative voltage on the ADC pin with a diode to ground?

I have selected 500.00 kHZ in codevision for the ADC clock. is it correct than that a single conversion will take 13.5 clocks so it will be able to process 37,037 samples per second? Processor is using 8mhz internal with /8 fuse.

The plan is to turn on a heater, check for a full second if the heater goes on by reading the adc values and finding the on condition to have values above 128 in the adc return value. The heater will be allowed to be on for up to 10 seconds and then the next heater will be enabled after shutting the current one down.

Here is a link to the initial questions I had on current transformers and a pic of what I am working on.
https://www.avrfreaks.net/index.p...

All comments welcome.

Edit, I just realized because of the peak to peak that 1.25 will be my maximum so I should change the ADC REF to the 1.1V ref.

I also see I only need to turn on ADSC to start and the ADIE to enable the interrupt.
[/code]

Attachment(s): 

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

To be honest, I am not prepared to download a file that you could have copy-pasted within CODE tags.

Examine the CodeWizard code with your data sheet open.
Replace all the magic values with the named BIT values.

In the Project options tick the box for "Use bit names".

Add any comments for you own edification. Re-compile.

If you still have a question, copy-paste the lines involving ADCSRA and ADMUX that you did not understand.

David.

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

Quote:

I am lost here.

What are you lost about? If you ask the Wizard to enable the ADC, isn't the function in the generated source?

Note that interrupt-driven and read_adc() are mutually exclusive.

#include 

#include 

#define ADC_VREF_TYPE 0x00

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=(adc_input & 0x07) | (ADC_VREF_TYPE & 0xff);
if (adc_input & 0x08) ADCSRB |= 0x08;
else ADCSRB &= 0xf7;
// 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 ADCW;
}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
...
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// ADC initialization
// ADC Clock frequency: 115.200 kHz
// ADC Voltage Reference: AREF pin
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
// ADC4: On, ADC5: On, ADC6: On, ADC7: On
DIDR0=0x00;
// Digital input buffers on ADC8: On, ADC9: On, ADC10: On, ADC11: On
// ADC12: On, ADC13: On, ADC14: On, ADC15: On
DIDR2=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x86;

while (1)
      {
      // Place your code here

      };
}

Right out of the Wizard.

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

Sorry I thought uploading the c file was preferred over a cut and paste. Here is the code, I have added code to do preliminary test. My only question remains, I don't see where the code is to start the ADC is generated by the code wizard. I added the line ADCSRA = 0b11001000 & 0xff; to start the conversion. Clock cycles are 52 for the conversion so I should get 0.015 V resolution. I will write a more robust test to test the tops and bottoms of the sine wave so a single bad high reading in the peek voltage code wont give a false ON signal, the code in main() is just for initial testing.

/*****************************************************
This program was produced by the
CodeWizardAVR V2.04.8a Standard
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : Sequencer
Version : 
Date    : 1/25/2011
Author  : Mark
Company : 
Comments: 


Chip type               : ATtiny45
AVR Core Clock frequency: 1.000000 MHz
Memory model            : Tiny
External RAM size       : 0
Data Stack size         : 64
*****************************************************/

#include 

#include 

unsigned int Myadcvalue = 0;
unsigned int temp=0;
unsigned char adc_data;
unsigned int secondtimer=0;
unsigned int maxvalue=0;


// Timer1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
// Place your code here
 secondtimer++;
}

#define ADC_VREF_TYPE 0xA0  // I Changed from $B0 to $A0 for 1.1 Ref

// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{

// Read the 8 most significant bits
// of the AD conversion result
adc_data=ADCH;
Myadcvalue=1;

// Place your code here

}

// Declare your global variables here



void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Func5=In Func4=In Func3=Out Func2=Out Func1=Out Func0=Out 
// State5=T State4=T State3=0 State2=0 State1=0 State0=0 
PORTB=0x00;
DDRB=0x0F;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=FFh
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 0.244 kHz
// Mode: Normal top=FFh
// OC1A output: Disconnected
// OC1B output: Disconnected
// Timer1 Overflow Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
PLLCSR=0x00;

TCCR1=0x0D;
GTCCR=0x00;
TCNT1=0x00;
OCR1A=0xF4;
OCR1B=0x00;
OCR1C=0x00;

// External Interrupt(s) initialization
// INT0: Off
// Interrupt on any change on pins PCINT0-5: Off
GIMSK=0x00;
MCUCR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x40;

// Universal Serial Interface initialization
// Mode: Disabled
// Clock source: Register & Counter=no clk.
// USI Counter Overflow Interrupt: Off
USICR=0x00;

// Analog Comparator initialization
// Analog Comparator: Off
ACSR=0x80;
ADCSRB=0x00;

// ADC initialization
// ADC Clock frequency: 500.000 kHz
// ADC Voltage Reference: 2.56V, AREF discon.
// ADC Bipolar Input Mode: Off
// ADC Reverse Input Polarity: Off
// ADC Auto Trigger Source: ADC Stopped
// Only the 8 most significant bits of
// the AD conversion result are used
// Digital input buffers on ADC0: On, ADC1: On, ADC2: Off, ADC3: On
DIDR0&=0x03;
DIDR0|=0x10;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x89;
ADCSRB&=0x5F;

// Global enable interrupts
#asm("sei")

// Wait for timer to tick to next 1 second mark
      secondtimer=0;
      while(secondtimer==0){
      }
while (1)
      {
      // Place your code here  
 
// wait for 1 second and read ADC to find maximum voltage value      
      secondtimer=0;
      maxvalue=0;
      
      while (secondtimer==0)
      {
       Myadcvalue=0;
       ADCSRA = 0b11001000 & 0xff;   
       while(Myadcvalue==0) {
       temp++;
       } 
     if( maxvalue < adc_data )
      {
      maxvalue = adc_data;
      }
      
      }
      
 // test maxvalue here if > 128 then device is on
      
       
      }
}

[/code]

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

These Allegro current sensors have a positive only (unipolar) output cenered around the internally generated VCC/2 voltage, so you don't need any clamping etc.

Warning: Grumpy Old Chuff. Reading this post may severely damage your mental health.

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

MBedder wrote:
These Allegro current sensors have a positive only (unipolar) output cenered around the internally generated VCC/2 voltage, so you don't need any clamping etc.

I will have to re scope it, I am not sure where my zero line is on the scope (it's a DSO-2100 from linkinstruments and the software does not run on my 64bit windows7 machine so it was a pain to get it set up and running last night.) Perhaps it is centered on 2.5V. Thanks I will re check it.

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

As a hint: It won't be exactly half. And there may be some ripple. and you probably want to make it ratiometric with its supply voltage and the AVR's reference. (Short answer: use AVcc for supply and reference.)

So I take a number of readings at "no current" and use the average as my baseline.

Then I continually sample at a rate not in sync with the AC frequency, and use the peak value over a time period for my calculations.

[edit] Excerpt from my ACS712 code

// Amp readings revisd ABL40q:
//
//	Do continuous conversions over a 500ms period, finding the high and low A/D counts.
//	Take the average of that, and use the absolute value from the nominal of 512
//	counts for "no current" from the Allegro sensor.
//	From there, use 76 A/D counts/amp.

eeprom	struct signal_convert	ee_convert[MAX_FACTOR] =
{
		{1000,	758,	0},			// A/D counts to Amps*100 (centiamps), Allegro ACS712, auger
		{1000,	758,	0},			// A/D counts to Amps*100 (centiamps), Allegro ACS712, fan, pump
...

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

Thanks for the hint theusch, baseline no current, I like that. I will have to use the VCC with AREF pin disconnected mode as that pin is used to trigger one of the relays.

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

Just finished testing and it works perfectly. Took me some time though to figure out why is was not working, I misread the codewizard screen for setting up the ADC, I thought the boxes to disable digital input actually selected the ADC to use. After I got the ADMUX bits set for ADC2 I was happy. I am going to slow it down though, 1 second is pretty short to be snapping relays around. I am using 100ms for relays to settle.

Here is the code turning off the ssr then turning on the relay, then the ssr with 100 ms between each step.

void heater1start()
{
 PORTB.3=0;
 delay_ms(100);
 PORTB = 0b00000001;
 delay_ms(100); 
 PORTB.3 = 1;
 delay_ms(100);
}

Here is how I did the testing. Now I just have to remove the cheap 8 pin socket because it's messed up and the chip does not stay connected. Those relays make a bit of vibration so I better solder the chip to the board. The LED's on the fets should work as failsafe to pull down the gates if the chip does get loose, I will have an additional buss fuse on the device as well.

void heateron() // poll for 1 second the ADC to find values over 100 (1 volt peaks = 6.6 amp draw )
{ 
   
      
      secloop = 10;                         // initialize loop counter
      while (secloop > 0 )
      {  
       secondtimer=0;                       // initialize variables
       ison=0; 
       
       while (secondtimer==0)               // loop for about 1 second (timer interrupt sets secondtimer flag)
       {
        Myadcvalue=0;                       // reset flag
        ADCSRA = ADCSRA | 0b11001000;       // Start conversion
        
        while(Myadcvalue==0)                // Wait for conversion value
        {
        } 


      if( adc_data > 100 )                 // If reading is over 100 it's greater than 1V about 6.6 AMPS
       {     
       if (ison < 255)                     // Must get at least 255 readings over 1 second, about 18,000 ADC reads
        ison++;        

       }

       }

                                           // if ison is 255 then the unit is on
        secloop--;                         // decrement loop counter let it stay on for up to 10 seconds.
       if (ison != 255)                    // If we did not reach threshold
       {
        secloop = 0;                       // Exit loop and go to next heater.

       }
      }
}

Attachment(s): 

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

I decided to use the reset pin as an output to create this plot that shows the points on the AC signal where the software finds the voltage meets the required levels. Each time the ADC returns a value, the value is tested and if it is over 100 the blue line on the trace is triggered and then shut off. There is about 50 points on every cycle so it actually gets a true value 3000 times in one second. If I needed more processor time for something else this could be cut way back but alas there is not much to do in a sequencing program.

I am going to add some adaptive reasoning so the sequencing will adapt to the actual heaters timing by setting up three more timers and using those to delay a variable amount of time for each heaters test routine so that the relays should adjust to the 10 seconds on and 30 seconds off.

Just for those interested and new to using the ADC this may help some understand better what is going on with this type of logic.

Attachment(s):