?? analog.c
字號:
/* vim: set sw=8 ts=8 si : *//********************************************** Author: Guido Socher, Copyright: GPL ** Digital analog conversion of channel ADC0 and ADC1 in* free running mode. **********************************************/#include <inttypes.h> #include <avr/signal.h>#include <avr/interrupt.h>#include <avr/io.h>#include "avr_compat.h"#include "dac.h"#include "hardware_settings.h"volatile static unsigned char channel=0; volatile static unsigned char voltagecontrol=0; // 0=current limit, 1=voltage controlvolatile static uint16_t conversioncount=0; // changed at every conversionvolatile static unsigned char prev_voltagecontrol=0; // adc measurement results:volatile static int analog_result[2]; // datatype int is 16 bit// the value that is requested (control loop calibrates to this).volatile static unsigned int target_val[2]; // datatype int is 16 bitstatic unsigned char adlow,adhigh;static int dac_val=0;/* You must enable interrupt with sei() in the main program * before you call init_analog */void init_analog(void) { // initialize the adc result to very high values // to keep the control-loop down until proper measurements // are done: analog_result[0]=0; analog_result[1]=1025; target_val[0]=0; // initialize to zero target_val[1]=0; // initialize to zero /* enable analog to digital conversion in free run mode * without noise canceler function. See datasheet of atmega8 page 195 * We set ADPS2=1,ADPS1=0,ADPS0=1 to have a clock division factor of 32. * This is needed to stay in the recommended range of 50-200kHz * ADEN: Analog Digital Converter Enable * ADIE: ADC Interrupt Enable * ADIF: ADC Interrupt Flag * ADFR: ADC Free Running Mode * ADCSR: ADC Control and Status Register * ADPS2..ADPS0: ADC Prescaler Select Bits * REFS: Reference Selection Bits (page 203) */ // int-ref with external capacitor at AREF pin: // 2.56V int ref=REFS1=1,REFS0=1 // write only the lower 3 bit for channel selection // 2.56V ref, start with channel 0 ADMUX=(1<<REFS1)|(1<<REFS0)|(channel & 0x07); ADCSR=(1<<ADEN)|(1<<ADIE)|(1<<ADFR)|(1<<ADIF)|(1<<ADPS2)|(1<<ADPS0); /* start conversion */ sbi(ADCSR,ADSC); //wait until both channels are measured twice while(conversioncount < 4);}int is_dacval(void) { return(dac_val);}signed char is_current_limit(void) { // return 1 if current control loop active if (voltagecontrol==0){ return(1); } return(0);}/* set the target adc value for the control loop * values for item: 0 = u, 1 = i, units must be of the same as the values * from the dac. */void set_target_adc_val(unsigned char item,unsigned int val) { // here we can directly write to target_val target_val[item]=val;}/* get the result of an analog conversion. * The problem here is that we need to read more than 8 bit. Therefore * it will always result in two assembler instruction. In other words * it is not an atomic operation. To get it atomic we use the * conversion count variable. If it was unchanged then the reading was * like an atomic read. */int getanalogresult(unsigned char channel) { int rval; uint16_t conv_cnt_before; while(1){ conv_cnt_before=conversioncount; rval=analog_result[channel]; // make sure there was no AD conversion // while we were reading the result. If so then // read again. conversioncount is volatile. if (conversioncount == conv_cnt_before){ break; } } return(rval);}// the control loop changes the dac:static void control_loop(unsigned char channel){ int tmp; tmp=target_val[0] - analog_result[0]; if (tmp < 1){ voltagecontrol=0; // I control }else{ voltagecontrol=1; // U control tmp=target_val[1] - analog_result[1]; } if (conversioncount>2){ // go only once in a while close // to prevent permanent lsb toggle if (tmp > -2 && tmp < 2){ tmp=0; } } // slowly up: if (tmp >2){ tmp=1; } if (tmp <-2){ tmp=-1; } dac_val=dac_val + tmp; if (dac_val<0){ dac_val=0; } dac(dac_val);}/* the following function will be called when analog conversion is done. * It will be called every 13th cycle of the converson clock. At 4Mhz * and a ADPS factor of 32 this is: ((4000 kHz/ 32) / 13)= 9.6KHz intervalls */SIGNAL(SIG_ADC) { adlow=inp(ADCL); /* read low first !! */ adhigh=inp(ADCH); /* read low first !! */ // toggel the channel between 0 an 1. This will however // not effect the next conversion as that one is already // ongoing. channel++; if (channel>1){ channel=0; } // 2.56V ref ADMUX=(1<<REFS1)|(1<<REFS0)|(channel & 0x07); // channel=1 = U, channel=0 = I analog_result[channel]=((adhigh<<8)|(adlow & 0xFF)); // short circuit protection at about 4.5A (with 0.5 Ohm shunt): if (analog_result[0] > 900){ dac(30); dac_val=30; goto ENDSIG; } if (channel == 1){ // only when we have new current measurements goto ENDSIG; } control_loop(voltagecontrol); // end of interrupt handlerENDSIG: conversioncount++; }
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -