Full Version : Using 1-Bit ADC on ATTINY26
avr >>BEGINNERS & BUTTERFLIES >>Using 1-Bit ADC on ATTINY26


flank- 04-27-2006
Hello,
I am new to this forum and to Atmel microcontrollers. I have been working with an ATTINY26, and I would like to use just one (or two) pins of the ADC port to read a temperature sensor output. Would someone send me an example of how to set up the ADC so that it reads one pin of the ADC (PORTA.0) each time the TIMER0 interrupt occurs? Any explanations with with code would be appreciated.

thanks,
flank

Gregg- 04-27-2006
Hey Mate, you forgot to mention what language you are using and the type of tempurature sensor you are using.

The Butterflies have a built-in temperature sensor, have you looked at the code to see how they do it?


Admin5- 04-27-2006
I've never used the Temperature Sensor but if you are a C programmer I am going to upload the Original Butterfly program so you can look at the source cose and see how the Butterfly does it.

The Butterfly does almost axactly what you want. It has a small temperature sensitive resistor connected to one pin of an ADC.


Also,there are tons of programs in the projects forum that sence temperature, mybe you can get lucky there.


Admin5- 04-27-2006
I dug through the Butterfly Source Code and am posting the part that sets-up and uses the ADCs that are used for measuring the light level & another for the temperature:


CODE

//***************************************************************************
//
//  File........: ADC.c
//
//  Author(s)...: ATMEL Norway
//
//  Target(s)...: ATmega169
//
//  Compiler....: IAR EWAAVR 2.28a
//
//  Description.: AVR Butterfly ADC routines
//
//  Revisions...: 1.0
//
//  YYYYMMDD - VER. - COMMENT                                       - SIGN.
//
//  20030116 - 1.0  - Created                                       - LHM
//
//***************************************************************************

#include <inavr.h>
#include "iom169.h"
#include "main.h"
#include "ADC.h"
#include "BCD.h"
#include "LCD_functions.h"
#include "Timer0.h"

__flash int TEMP_Celcius_pos[] =    // Positive Celcius temperatures (ADC-value)
       {                           // from 0 to 60 degrees
           806,796,786,775,765,754,743,732,720,709,697,685,673,661,649,
           636,624,611,599,586,574,562,549,537,524,512,500,488,476,464,
           452,440,429,418,406,396,385,374,364,354,344,334,324,315,306,
           297,288,279,271,263,255,247,240,233,225,219,212,205,199,193,
           187,
       };

__flash int TEMP_Celcius_neg[] =    // Negative Celcius temperatures (ADC-value)
       {                           // from -1 to -15 degrees
           815,825,834,843,851,860,868,876,883,891,898,904,911,917,923,
       };
   
__flash int TEMP_Farenheit_pos[] =  // Positive Farenheit temperatures (ADC-value)
       {                           // from 0 to 140 degrees
     938, 935, 932, 929, 926, 923, 920, 916, 913, 909, 906, 902, 898,
     894, 891, 887, 882, 878, 874, 870, 865, 861, 856, 851, 847, 842,
     837, 832, 827, 822, 816, 811, 806, 800, 795, 789, 783, 778, 772,
     766, 760, 754, 748, 742, 735, 729, 723, 716, 710, 703, 697, 690,
     684, 677, 670, 663, 657, 650, 643, 636, 629, 622, 616, 609, 602,
     595, 588, 581, 574, 567, 560, 553, 546, 539, 533, 526, 519, 512,
     505, 498, 492, 485, 478, 472, 465, 459, 452, 446, 439, 433, 426,
     420, 414, 408, 402, 396, 390, 384, 378, 372, 366, 360, 355, 349,
     344, 338, 333, 327, 322, 317, 312, 307, 302, 297, 292, 287, 282,
     277, 273, 268, 264, 259, 255, 251, 246, 242, 238, 234, 230, 226,
     222, 219, 215, 211, 207, 204, 200, 197, 194, 190, 187,
       };

       
__flash int LIGHT_ADC[] = // Table used to find the Vref, when using the voltage-reading function
       {
           0x35,0x60,0x80,0x0B0,0x11D,0x13D,0x15A,0x17A,0x197,0x1B9,0x1DA,
           0x1F9,0x216,0x240,0x26D,0x282,0x2A2,0x2EF,0x332,0x3B0,0x3F2
       };
       
__flash float LIGHT_VOLTAGE[] = // Vref table correspondent to the LIGHT_ADC[] table
       {
           2.818,2.820,2.824,2.827,2.832,2.835,2.839,2.841,2.843,2.847,2.850,
           2.853,2.857,2.863,2.867,2.870,2.874,2.882,2.893,2.917,2.939
       };


float Vref = 2.900; // initial value
char degree = CELCIUS;


/*****************************************************************************
*
*   Function name : ADC_init
*
*   Returns :       None
*
*   Parameters :    char input
*
*   Purpose :       Initialize the ADC with the selected ADC-channel
*
*****************************************************************************/
void ADC_init(char input)
{
 
   ADMUX = input;    // external AREF and ADCx
   
   ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);    // set ADC prescaler to , 1MHz / 8 = 125kHz    

   input = ADC_read();        // dummy
}


/*****************************************************************************
*
*   Function name : ADC_read
*
*   Returns :       int ADC
*
*   Parameters :    None
*
*   Purpose :       Do a Analog to Digital Conversion
*
*****************************************************************************/
int ADC_read(void)
{
   char i;
   int ADC_temp;
   int ADC = 0;
   
   // To save power, the voltage over the LDR and the NTC is turned off when not used
   // This is done by controlling the voltage from a I/O-pin (PORTF3)
   
   sbi(PORTF, PORTF3);     // Enable the VCP (VC-peripheral)
   sbi(DDRF, PORTF3);        

   sbi(ADCSRA, ADEN);     // Enable the ADC

   //do a dummy readout first
   ADCSRA |= (1<<ADSC);        // do single conversion
   while(!(ADCSRA & 0x10));    // wait for conversion done, ADIF flag active
       
   for(i=0;i<8;i++)            // do the ADC conversion 8 times for better accuracy
   {
       ADCSRA |= (1<<ADSC);        // do single conversion
       while(!(ADCSRA & 0x10));    // wait for conversion done, ADIF flag active
       
       ADC_temp = ADCL;            // read out ADCL register
       ADC_temp += (ADCH << 8);    // read out ADCH register        

       ADC += ADC_temp;      // accumulate result (8 samples) for later averaging
   }

   ADC = ADC >> 3;     // average the 8 samples
       
   cbi(PORTF, PORTF3);     // disable the VCP
   cbi(DDRF, PORTF3);  
   
   cbi(ADCSRA, ADEN);      // disable the ADC

   return ADC;
}


/*****************************************************************************
*
*   Function name : ADC_periphery
*
*   Returns :       None
*
*   Parameters :    None
*
*   Purpose :       Calculates the Temperature/Voltage/Ligth from the ADC_read
*                   and puts it out on the LCD.
*
*****************************************************************************/
void ADC_periphery(void)
{
   int ADCresult = 0;
   int ADCresult_temp = 0;
   int Temp_int;
   char Temp;
   unsigned char i = 0;
   char TL;
   char TH;    
   char VL;

   float V_ADC;
   char VoltageHB;
   char VoltageLB;
   
   ADCresult = ADC_read();         // Find the ADC value
   
   if( ADMUX == TEMPERATURE_SENSOR )
   {
       if(degree == CELCIUS)
       {
           if(ADCresult > 810)         // If it's a negtive temperature
           {    
               for (i=0; i<=25; i++)   // Find the temperature
               {
                   if (ADCresult <= TEMP_Celcius_neg[i])
                   {
                       break;
                   }
               }
               
               LCD_putc(1, '-');       // Put a minus sign in front of the temperature
           }
           else if (ADCresult < 800)   // If it's a positive temperature
           {
               for (i=0; i<100; i++)  
               {
                   if (ADCresult >= TEMP_Celcius_pos[i])
                   {
                       break;
                   }
               }        
           
               LCD_putc(1, '+');       // Put a plus sign in front of the temperature
           }
           else                        //If the temperature is zero degrees
           {
               i = 0;
               LCD_putc(1, ' ');
           }
           
           Temp = CHAR2BCD2(i);        // Convert from char to bin
   
           TL = (Temp & 0x0F) + '0';   // Find the low-byte
           TH = (Temp >> 4) + '0';     // Find the high-byte
           
           LCD_putc(0, ' ');
           //LCD character 1 is allready written to
           LCD_putc(2, TH);
           LCD_putc(3, TL);
           LCD_putc(4, '*');
           LCD_putc(5, 'C');
           LCD_putc(6, '\0');
       }
       else if (degree == FARENHEIT)
       {
           for (i=0; i<=141; i++)   // Find the temperature
           {
               if (ADCresult > TEMP_Farenheit_pos[i])
               {
                   break;
               }
           }        
       
           Temp_int = CHAR2BCD3(i);
       
           if (i > 99) // if there are three digits
           {
               LCD_putc(0, '+');
               TH = (Temp_int >> 8) + '0';   // Find the high-byte
               LCD_putc(1, TH);
           }
           else    // if only two digits
           {
               LCD_putc(0, ' ');
               LCD_putc(1, '+');
           }
           
           TL = (Temp_int & 0x0F) + '0';   // Find the low-byte
           TH = ( (Temp_int >> 4) & 0x0F ) + '0';     // Find the high-byte                

           LCD_putc(2, TH);
           LCD_putc(3, TL);
           LCD_putc(4, '*');
           LCD_putc(5, 'F');
           LCD_putc(6, '\0');
       
       }

//        Can't set LCD_UpdateRequired = TRUE here cause we are inside the Timer0 interrupt
//        LCD_UpdateRequired(TRUE, 0);        
         
   }
   else if( ADMUX == VOLTAGE_SENSOR )
   {
     
//  Do a Light-measurement first to determine the Vref,
//  because the LDR affects the Vref

       ADCresult_temp = ADCresult;     // Store the ADCresult from the voltage reading
         
       ADC_init(LIGHT_SENSOR);         // Init the ADC to measure light
           
       ADCresult = ADC_read();         // Read the light value

       // Find Vref
       for (i=0; i<=22; i++)
       {
           if (ADCresult <= LIGHT_ADC[i])
           {
               break;
           }
       }
       if(!i)              // if it's very bright
           Vref = 2.815;
       else if(i > 21)
           Vref = 2.942;   // if it's totally dark
       else
           Vref = LIGHT_VOLTAGE[i];  
         
       ADMUX = VOLTAGE_SENSOR;    
       ADCresult = ADCresult_temp; // Get the ADCresult from the voltage reading

// Light-measurement finished
           
                   
       V_ADC = ( ADCresult * Vref ) / 1024; // Calculate the voltage
         
       V_ADC = ( V_ADC * 6 );      // Multiply by 6 cause of the voltage division
           
       VoltageHB = V_ADC;              // Store the high-byte
       V_ADC = ( V_ADC - VoltageHB );
       VoltageLB = ( V_ADC * 100 );    // Store the low-byte
   
       Temp = CHAR2BCD2(VoltageHB);    // Convert from char to bin
   
       TL = (Temp & 0x0F) + '0';
       TH = (Temp >> 4) + '0';
           
       Temp = CHAR2BCD2(VoltageLB);    // Convert from char to bin
 
       VL = (Temp >> 4) + '0';

       LCD_putc(0, ' ');
       LCD_putc(1, ' ');
       LCD_putc(2, ' ');
       LCD_putc(3, TL);
       LCD_putc(4, 'V');
       LCD_putc(5, VL);
       LCD_putc(6, '\0');
       
//        Can't set LCD_UpdateRequired = TRUE here cause we are inside the Timer0 interrupt
//        LCD_UpdateRequired(TRUE, 0);        
                           
   }
   else if( ADMUX == LIGHT_SENSOR )
   {
       // The relation between ADC-value and lux is yet to be found,
       // for now the ADC-value is presented on the LCD
       
       VoltageHB = CHAR2BCD2(ADCH);    // Convert from char to bin

       Temp = ADCL;                
   
       TL = (Temp & 0x0F) + '0';      
       if(TL > '9')        // if the hex-value is over 9, add 7 in order to go
           TL += 7;        // jump to the character in the ASCII-table
               
       TH = (Temp >> 4) + '0';
       if(TH > '9')        // if the hex-value is over 9, add 7 in order to go
           TH += 7;        // jump to the character in the ASCII-table
           
       LCD_putc(0, 'A');
       LCD_putc(1, 'D');
       LCD_putc(2, 'C');
       LCD_putc(3, (ADCH + 0x30));
       LCD_putc(4, TH);
       LCD_putc(5, TL);
       LCD_putc(6, '\0');

//        Can't set LCD_UpdateRequired = TRUE here cause we are inside the Timer0 interrupt
//        LCD_UpdateRequired(TRUE, 0);        

   }
}


/*****************************************************************************
*
*   Function name : TemperatureFunc
*
*   Returns :       char ST_state (to the state-machine)
*
*   Parameters :    char input (from joystick)
*
*   Purpose :       Enable or disable temperature measurements
*
*****************************************************************************/
char TemperatureFunc(char input)
{
   static char enter = 1;
   
   if (enter)
   {
       enter = 0;
       
       ADC_init(TEMPERATURE_SENSOR);       // Init the ADC

       // Enable auto-run of the ADC_perphery every 10ms
       // (it will actually be more than 10ms cause of the SLEEP)
       Timer0_RegisterCallbackFunction(ADC_periphery);
   }
   else
       LCD_UpdateRequired(TRUE, 0);        // New data to be presented
   
   if (input == KEY_PREV)
   {
       // Disable the auto-run of the ADC_periphery
       Timer0_RemoveCallbackFunction(ADC_periphery);
       
       enter = 1;  // Set enter to 1 before leaving the TemperatureFunc
       
       return ST_TEMPERATURE;
   }
   else if (input == KEY_PLUS)
   {  
       if (degree == FARENHEIT)
           degree = CELCIUS;
       else
           degree = FARENHEIT;
   }
   else if (input == KEY_MINUS)
   {
       if (degree == FARENHEIT)
           degree = CELCIUS;
       else
           degree = FARENHEIT;
   }
   
   return ST_TEMPERATURE_FUNC;        
}


/*****************************************************************************
*
*   Function name : VoltageFunc
*
*   Returns :       char ST_state (to the state-machine)
*
*   Parameters :    char input (from joystick)
*
*   Purpose :       Enable or disable voltage measurements
*
*****************************************************************************/
char VoltageFunc(char input)
{
   static char enter = 1;
   
   if (enter)
   {
       enter = 0;

       ADC_init(VOLTAGE_SENSOR);       // Init the ADC
       
       // Enable auto-run of the ADC_perphery every 10ms
       // (it will actually be more than 10ms cause of the SLEEP)        
       Timer0_RegisterCallbackFunction(ADC_periphery);        
   }
   else
       LCD_UpdateRequired(TRUE, 0);

   if (input == KEY_PREV)
   {
       // Disable the auto-run of the ADC_periphery        
       Timer0_RemoveCallbackFunction(ADC_periphery);
       
       enter = 1;  // Set enter to 1 before leaving the TemperatureFunc
       
       return ST_VOLTAGE;
   }
   else
       return ST_VOLTAGE_FUNC;    
}    


/*****************************************************************************
*
*   Function name : LightFunc
*
*   Returns :       char ST_state (to the state-machine)
*
*   Parameters :    char input (from joystick)
*
*   Purpose :       Enable or disable light measurements
*
*****************************************************************************/
char LightFunc(char input)
{
   static char enter = 1;
   
   if (enter)
   {
   
       enter = 0;
       
       ADC_init(LIGHT_SENSOR);     // Init the ADC
       
       // Enable auto-run of the ADC_perphery every 10ms
       // (it will actually be more than 10ms cause of the SLEEP)  
       Timer0_RegisterCallbackFunction(ADC_periphery);        
   }
   else
       LCD_UpdateRequired(TRUE, 0);

   if (input == KEY_PREV)
   {
       // Disable the auto-run of the ADC_periphery      
       Timer0_RemoveCallbackFunction(ADC_periphery);
       
       enter = 1;  // Set enter to 1 before leaving the TemperatureFunc
   
       return ST_LIGHT;
   }
   else
       return ST_LIGHT_FUNC;    
}    



flank- 04-28-2006
Wow, thanks for all the suggestions. I think I have more then enough to figure it out now.

flank

Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.