Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Interfacing Gas sensor, ATtiny13 and transmitter

Status
Not open for further replies.

zetinal34

Junior Member level 3
Junior Member level 3
Joined
Mar 21, 2012
Messages
25
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,561
Hi all,

I am a newbie here and I am trying to program ATtiny13.
All the system need to do is to delivered the output from the sensor and send it using transmitter.The transmitted duration will be 1 minute continuously, after that the system will pause/sleep for 10 minutes then start to send again.

From what I understand, I have to create a code which functions as below

1. Define one of the port as an input and one as an output.
2. Take the analog resistive output from gas sensor to micro controller input port
3. Send the data from the input port to output port which is connected to transmitter continuously for 1 minute. The system will go to sleep for 10 minutes then redo the sampling.

So my question is,
1. I have to use analog port correct? (in this case ADC0 - ADC3)
for example, I code, DDRB |= (0<<PB4)|(1<<PB3); making ADC2 as an input and ADC3 as an output?
2. How do I read the analog input from this port? what code is it? (I remember that in arduino is using analogRead()). Moreover, if I want to continuously send the data from input port to output port right way without storing data, what should I do?
3. Is it ok to send raw analog data that I receive from sensor right away to the transmitter? Is there any other thing I need to do like analog to digital conversion? (I actually just want the data with minimum noise when it sends out)
4. The sensor provides an analog resistive output, will this affect anything? Can I still read the data and send right away?

Here are the devices I have,

Gas sensor, **broken link removed**
Micro controller, http://www.atmel.com/devices/attiny13.aspx?tab=overview
Transmitter, http://www.sparkfun.com/products/10534

Please kindly advice,

Thank you everyone :))
 

That's right, you'll need to use one of those ADC pins. To read it, try something like the code shown below
(this was a quick attempt from the data-sheet, it may be incorrect. Still, it should get you started.).
You will need to change a few things, primarily the delay value in there, and the ADC clock prescaler,
based on your board, and what the datasheet suggests. I didn't have time to look into it deeply.
Note that the code is a quick 'test' and eventually you may want to use timers and the ADC itself to signal
via an interrupt when the conversion is complete. This simple code just waits a length of time.
The code will check to see if the analog value exceeds a threshold, and if it does, then it will turn on an
LED, so the code is quite simple.
Once your code works, adapt it to send a certain pulse rate to the transmitter, or send the binary value.
It's your choice.
Note that you should test the code first using (say) a 1k variable resistor connected to 0V and 5V.
If it works, then connect the analog sensor. However, you will most likely need a buffer stage or an amplifier
stage (I've no idea how this sensor works, but you could stick a multimeter/oscilloscope to it unconnected to the ADC as
an experiment, to see the voltage span when it detects, and also to see the effect of loading it with a resistance
that will simulate your ADC input impedance) because the sensor has a high impedance and will not directly
drive the ADC input I suspect.

Code:
#include <iotiny13.h>
#include <intrinsics.h>
#include <avr_macros.h>
#include <stdio.h>

// ATtiny13 pins:
// Port B bit0 (pin 5) - LED as a test
// Port B bit5 (pin 1) - ADC0 analog input


// Port B
#define LED 0x01

// outputs
#define LED_ON PORTB |= LED
#define LED_OFF PORTB &= ~LED

void
delay_10ms(unsigned int val)
{
  unsigned int i;
  for (i=0; i<val; i++)
  {
    __delay_cycles(20000);
  }
}

int main( void )
{
  unsigned char lsbyte, msbyte;
  unsigned int anaval;

  DDRB=0x01; // just let LED pin be an output
  ADMUX=0x00; // select channel 0
  DIDR0=0x20; // set channel 0 to be analog, not digital pin
  ADCSRB=0x00; // free-run mode for ADC
  ADCSRA=0xE7; // set prescaler to allow a slow clock for the ADC and auto-triggering

  LED_ON; // turn on the LED just to test the code is running
  
  while(1)
  {
    delay_10ms(100); // wait a second

    lsbyte=ADCL;  // read the low byte first
    msbyte=ADCH;

    anaval=((unsigned int)msbyte)<<8;
    anaval=anaval|((unsigned int)lsbyte);
    // anaval should now contain a value between 0 and 1023
  
    if (anaval>512)
    {
      LED_ON; // LED stays lit if the analog value is more than 2.5v
    }
    else
    {
      LED_OFF;
    }
  } // end of while(1) statement, i.e. loop forever


  return 0;
}
 
Thank you very much

I have question regarding to the conversion.
1) In free running mode, is it correct that I can freely set the duration of conversion to be anything (1minute in this case)?
2) If I use the single mode instead of free running mode, I can use the interrupt right? It says that the interrupt will occurs when the conversion is finished (I don't really get it on what finish conversion means and how it know when to finish converting).

3) Is it possible that I use the single mode to record data for 1 minute(Can I set the interrupt so that it triggers after 1 minute?) and once it is finished, I can read that data to anaval, and send to transmitter? Also, I think with single mode, I might lose a little time during interrupt ISR function so I won't get absolute continuous data right?

3) How to send all the data in that 1 minute period to transmitter (in binary)? Do I have to wait until the conversion complete then send or I am able to send it simultaneously during conversion? ie. I can set DDRB port 1 as output then PortB |= (anaval<<PB1)? is this mean that all the data will be sent to that port which is connected to transmitter?
Which way do you recommended? And How do I do that?
4) For longer conversion period, does this mean the data store in anaval will be larger?
5) How do I calculate/know how many sample it take per second?

Thank you very much :)
 
Last edited:

Actually the conversion takes an amount of time, which the data-sheet says is 13 ADC clock cycles. That clock cycle is determined by the prescaler value. You can use that to determine what rate (frequency)you can get your conversions
done at. The code above is really only a simple example, to get you started. You should really
rewrite it. The code above doesn't wait for 13 ADC cycles, it just waits a long delay time. If you wanted, you could wait
a minute before you read the value, but you wouldn't need to.
You'll know when the conversion is complete by the ADIF bit in the ADCSRA register going high, so you can either test for
that, or better still enable an interrupt to occur.
You could either wait for a single conversion to finish and then transmit the result, or take several conversions and transmit
multiple results, or average the results and transmit the final value, etc. The choice is really up to you.
To send the result as binary, you need to probably send some 'preamble' (a known bitstream), followed by your result
(maybe repeated several times) and then if you really wanted to be slick, some checksum. The preamble is necessary
to get the receiver's data slicer to kind-of sort itself out and become 'optimised' for the rest of the data.
Or, you could go a simpler approach and just send a PWM stream and let the remote end just time the period and that
will be proportional to the value transmitted.
 
Thank you for your reply.

So if I used 128 prescaler and my cpu speed is 8MHz then 8M/128 = 62.5KHz which is 1.6e-5 second per ADC cycle? which means 2.08e-4 second for 13 ADC life cycle for one conversion?
If I want it to be 1 minute then I have to repeat it 60s/2.08e-4s = 288,461.5385 = 288,462 times, is that correct?
So now I can use counter to count and once it reaches 288,462 times I then pause it for 10minutes using delay function?

Moreover, each time that the ADC conversion is completed, I can add function to send the data right? So the data will be sent every 2.08e-4 second?

**I still have difficulty on PWM and bitstream method, do you have any example or guide regarding to these?
***There is no way that I could just simply send anaval value to the port I want directly and it will just transmit via transmitter?

Thank you very much again :)
 

I think you're correct on the conversion time. If you just want to report every minute, then set a timer interrupt for every 60 sec, and when that occurs, kick of a conversion, delay for a few msec, collect the result then transmit it.
There are better ways to optimise it - the microcontroller could be put to sleep for most of the 60 seconds for instance. Anyway, you'd need to study the microcontroller documentation in more detail to investigate these ways. I've used that device
in the past, but I'm not overly familiar with it.
You could send the value directly to a serial interface if there is one on the microcontroller (but I don't think there is one on this tiny device), or you could do a so-called 'bit-banging' approach, i.e. transmit the MSB, wait a fraction of a second, then transmit bit 7, wait, and repeat.
You can use a 'left-shift' operator in C for that.
There should be lots of examples of that on the internet, I've pasted below some example code (you'd need to
set up a #define for the PIN_SET_LOW and PIN_SET_HIGH in a similar manner to the earlier code, and also implement a
delay function that in this example is called usec_delay().

Code:
void byte_write(unsigned char val)
{
  unsigned char i;
  for (i=0; i<8; i++)
  {
    if (val & 0x80)
    {
      PIN_SET_HIGH;
    }
    else
    {
      PIN_SET_LOW;
    }
    usec_delay();
    
    val <<= 1;
  }
}

For PWM method, you'd need to check the PWM section in the microcontroller datasheet.
 

Thank you for the sample code...

However, my ADC function as 10 bit resolution, is that mean I can't use this code? as this code is sending 8 bit data?
If I modify my ADC function to be 8 bit, what effect will I get and should I change it? The step will change from 1024 to 255 only right.. Will it affect my maximum reading voltage?

The below is my current code... (Still no transmission function yet)

Code:
#include <avr/io.h> 
#include <stdio.h>
#define F_CPU 8000000UL //frequency = 8MHz
#include <util/delay.h> 
#include <avr/interrupt.h>

void ReadADC(); 
unsigned char lsbyte, msbyte;
unsigned int anaval;
volatile int Scounter = 0;//Sampling Counter
volatile int Dcounter = 0;//Delay Counter
int main (void) 
{ 
   DDRB |= (1 << PB0); //LED at PB0 (Pin5) as OUTPUT
   DDRB &= (0 << PB5); //ADC0 as analog input
 	
   // Set up timer and interrupt, 
   TCCR0B |= (1<<CS02) | (1<<CS00);// prescaler timer to 1/1024 the clock rate
   TIMSK0 |=1<<TOIE0; // enable timer overflow interrupt
   sei();
   // Timer get increment at 8MHz/1024 = 7812.5
   // Clock cycle 256, 8bit timer will over flow 7812.5/256 = 30.5 times per second
   // One over flow period takes 32.8ms 
   // Using counter, increment it x3, 32.8ms*3 = 98ms;  x15, 32.8ms*15 = 0.49s   
   
     
   while (1) 
   {    
	    if(Scounter==2)//Set sampling interval (98ms~100ms)
		{
			ReadADC();//Read ADC values
	         
			 //LED test 
			 if (anaval > 512) 
			 { 
			 PORTB |= (1 << PB0); //LED on
			 } 
			 else 
			 { 
			 PORTB &= (0 << PB0);//LED off 
			 } 
	  	    
		  //Code for transmission here
		  
		  //Code for transmission here
		  
		  
		  Scounter = 0;
		}
		
		if(++Dcounter>31)// 1 minute interval, Dcounter = 30.5
		{
			//sleep function, 10minutes
			Dcounter = 0;
		}		  
   } 
   return 0;    
} 


void ReadADC() 
{ 
    ADMUX=0x00; // select channel 0 ADC0 PB5 
	DIDR0=0x20; // set channel 0 to be analog, not digital pin
    ADMUX |= (0 << REFS0); // VCC as Reference 
    ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set prescaler 128; 8MHz/128 = 62.5kHz
	  
	ADCSRA |= (1 << ADEN);  // Enable ADC 
    ADCSRA |= (1 << ADSC);  // Start A2D Conversions 
	
    while((ADCSRA & 0x40) !=0){}; // wait for conversion to be completed, ADSC bit goes to 0 

	lsbyte=ADCL;  // read the low byte first
    msbyte=ADCH;

    anaval=((unsigned int)msbyte)<<8;
    anaval=anaval|((unsigned int)lsbyte);
    // anaval now contains a value between 0 and 1023
}


ISR(TIM0_OVF_vect)
{
  	  Scounter++;
	  Dcounter++;
}

I enable interrupt timer over flow in order to create an interval between each sampling(using 100ms), also to check if it reaches 1 minute then put system to sleep mode for 10 minutes. (Do I understand correctly that that the timer will still counting even there is ADC going on? So the ADC time won't affect on timer?)

My goal is to send sample signal every 100ms for 1 minute then stop for 10minute
I don't know if it's the right way of doing it or not, please comment and suggest me

Thank you very much
 

I think the code outline looks fine (I only looked briefly at the code). Reading the ADC won't affect the timer, this is correct.
Personally I would reset Scounter and Dcounter in the ISR rather than in the main code, (i.e. put "if(Scounter>=2) Scounter=0;"
and a similar type of thing for Dcounter) just in case there is any odd condition where the while loop in the main function got delayed and the
ISR carried on incrementing the variables beyond the desired values, but I think your code is ok.
(If during your testing you plan on putting a loop to temporarily simulate the 10-mins sleep function, then the Scounter may have
incremented beyond 2, so resetting in the ISR would prevent that issue from occurring. Depending on the program I tend to do a lot
in ISRs, but many people don't.).

Regarding the number transmit, yes it is an 8-bit value, but you could transmit the high byte and then the low byte, to get the
entire 10-bit value.
 
Thank you, I just finished the sleep part, Please help me check if I am correct.
I used watchdog timer timeout to make system go to sleep for 4s, and repeat it for 150times (which is 10minutes)
I'm not so sure about the code as it is confusing for me.

For the reset part, I'm not sure is it correct as I use MCUSR = 0; to reset the system (Will it reset and the code start again from the beginning?)

here is my code
Code:
#include <avr/io.h> 
#include <stdio.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#define F_CPU 8000000UL //frequency = 8MHz
#include <util/delay.h> 
#include <avr/interrupt.h>


void ReadADC(); 
void wdsetup();
unsigned char lsbyte, msbyte;
unsigned int anaval;
volatile int timer_overflow_count = 0;
volatile int Scounter = 1;//Sampling Counter
volatile int Dcounter = 1;//Delay Counter
volatile int Wcounter = 1;//Watchdog counter
int main (void) 
{ 
   DDRB |= (1 << PB0); //LED at PB0 (Pin5) as OUTPUT
   DDRB &= (0 << PB5); //ADC0 as analog input
 	
   // Set up timer and interrupt, 
   TCCR0B |= (1<<CS02) | (1<<CS00);// prescaler timer to 1/1024 the clock rate
   TIMSK0 |=1<<TOIE0; // enable timer overflow interrupt
   sei();
   // Timer get increment at 8MHz/1024 = 7812.5
   // Clock cycle 256, 8bit timer will over flow 7812.5/256 = 30.5 times per second
   // One over flow period takes 32.8ms 
   // Using counter, increment it x3, 32.8ms*3 = 98ms;  x15, 32.8ms*15 = 0.49s   
   
     
   while (1) 
   {    
	    if(Scounter==4)//Set sampling interval (98ms~100ms)
		{
			ReadADC();//Read ADC values
	         //LED test 
			 if (anaval > 512) 
			 { 
			 PORTB |= (1 << PB0); //LED on
			 } 
			 else 
			 { 
			 PORTB &= (0 << PB0);//LED off 
			 } 
	  	    
		  //Code for transmission here
		  
		  //Code for transmission here
		 }
		
		if(Dcounter>30)// 1.017 minute interval, Dcounter = 30.5times
		{
			//sleep function, 10minutes
			wdsetup();
		}		  
   } 
   return 0;    
} 


void ReadADC() 
{ 
    ADMUX=0x00; // select channel 0 ADC0 PB5 
	DIDR0=0x20; // set channel 0 to be analog, not digital pin
    ADMUX |= (0 << REFS0); // VCC as Reference 
    ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set prescaler 128; 8MHz/128 = 62.5kHz
	  
	ADCSRA |= (1 << ADEN);  // Enable ADC 
    ADCSRA |= (1 << ADSC);  // Start A2D Conversions 
	
    while((ADCSRA & 0x40) !=0){}; // wait for conversion to be completed, ADSC bit goes to 0 

	lsbyte=ADCL;  // read the low byte first
    msbyte=ADCH;

    anaval=((unsigned int)msbyte)<<8;
    anaval=anaval|((unsigned int)lsbyte);
    // anaval now contains a value between 0 and 1023
}


ISR(TIM0_OVF_vect)
{
	  if(Scounter>=4)
	  {Scounter=1;}
	  Scounter++;
	  
	  if(Dcounter>=30)
	  {Dcounter=1;}
	  Dcounter++;
	 
}


void wdsetup()
{
  
   cli(); // Disable global interrupts	
   // Enable Watchdog timer, Prescaler 512, timeout = 4s 
   WDTCR |= (1<<WDP3); // (1<<WDP2) | (1<<WDP0);
 
   // Enable watchdog timer interrupts
   WDTCR |= (1<<WDTIE);
 
   sei(); // Enable global interrupts 
 
   // Use the Power Down sleep mode
   set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 
   for (;;) {
      sleep_mode();   // go to sleep and wait for interrupt...
   }
}   


ISR(WDT_vect) {
   // Toggle Port B pin 4 output state
    sleep_disable();
	WDTCR &= 0;// Disable Watchdog timer,
	Wcounter++;
	if(Wcounter>150)
	{
		MCUSR = 0; //Power on Reset  
	}		
	else
	{wdsetup();}
}

Just a little question for bit banging method. Because I have 10 bit data so I can just use the code below with i<10 instead of 8 and if(val & 0x200)? and val is anaval?
I am a bit confused on anaval, is it actually storing 10bit data? or I need to send lsbyte then msbyte ?

Code:
for (i=0; i<10; i++)
  {
    if (val & 0x200)
    {
      PIN_SET_HIGH;
    }
    else
    {
      PIN_SET_LOW;
    }
    usec_delay();
    
    val <<= 1;

Thank you very much for you help :)
 

I've not done this for ages, so I'm guessing a little bit, but looking at the user docs, I think you don't need to touch MCUSR. The sleep is invoked by an actual assembly language 'SLEEP' instruction, so you
need to execute that. Your compiler will have an internal function you can call, something like __sleep() that you can execute (on IAR compiler it is called __sleep() but it may be slightly different syntax on
other compilers). It will sleep until any interrupt occurs.

The variable 'anaval' stores a 16-bit value (it is defined as an unsigned integer), so the upper 6 bits are all zero. The code only transmits 8 bits, because that is a convention that usually you transmit in bytes. So, if you
wanted to transmit all 10 bits, you'd transmit two bytes, i.e. msbyte and lsbyte, instead of anaval.
Anyway, you need to transmit in the format that the receiver will recognise.
 

Ok.. so the code should look like this right?

Code:
//For msbyte
for (i=0; i<2; i++)
{
    if (msbyte & 0x02)
    {
      PIN_SET_HIGH;
    }
    else
    {
      PIN_SET_LOW;
    }
    usec_delay();
    
    msbyte <<= 1;
}

For lsbyte
for (i=0; i<8; i++)
{
    if (lsbyte & 0x80)
    {
      PIN_SET_HIGH;
    }
    else
    {
      PIN_SET_LOW;
    }
    usec_delay();
    
    lsbyte <<= 1;
}

BTW if I just sending this pulse, how does the receiver know that there is some signal coming in and start taking result? (If the first pulse is high then it's fine but if it's 0?)
Or I can implement start pulse and end pulse (Both high) and put in before and after the data?

Also on sleep thing, I think sleep mode() is the same function as __sleep() as they both put system to sleep and wait for interrupt. The reason I put MCUSR is that I don't know what happen after the watchdog timer interrupt, so I just try to reset the system. Maybe I don't need to if I can somehow go back to while loop state..

Thanks so much for the help :)
 

No need to repeat the code twice, you could just write the function once, then do
byte_write(msbyte); byte_write(lsbyte);
It is true, your receiver needs to be intelligent enough to time the received pulses, i.e. to read the pulses at the center period of each
bit, to determine the correct values. But something like this is true for most transmission/reception of data over radio.
It could be easier if the pulses are transmitted at a slow speed (maybe 300-1000 bits per sec).
Your receiver could begin timing after the preamble (some predetermined bits or bytes that you can send first).
Or, you could use some more complex coding scheme rather than this simplistic one. Personally I would have gone simpler and used
bursts of PWM. Anyway the coding scheme for the transmission is is all really up to however you wish to implement it, how complex you
wish to get, and how reliable you want the result, e.g. you may wish to repeat the transmission several times, and transmit
a checksum if there is a danger of an incorrect reading causing some harm.
I suggest you run some code (before your code is too complex) to get parts of it up-and-running, otherwise it is just complicated
to debug a large volume of code later. MCUSR shouldn't be used I think. You're not using a watchdog timer (which would reset the microcontroller in an error condition), you're using a sleep timer. Anyway, again personally I'd test parts of the code first (e.g. the
ADC conversion maybe using a variable resistor to generate a voltage in place of the sensor, confirm the transmit and receive function
etc, before implementing sleep and so on.
 
Thank you :)

I am building the testing board now with variable resistor, question is, I can just connect resistor to ground and to input port then test the circuit? Or I should replace the ground with voltage(3Volt maybe?) what is the right way to test this?

On the watchdog thing, I thought was using it?, I thought that when I put the system to power down sleep mode, the only timer that still run is watchdog timer. That is why I need it initiate it and use watchdog timeout to interrupt then wake up the system?

Anyway, now I'm going to test ADC function first like you suggest

THanks a lot :)
 

One end of the resistor goes to ground, the other goes to the microcontroller supply voltage, and the center wiper goes to the ADC input. Make sure it is approximately a 1k or 2k or 4.7k variable resistor and not much higher, because the ADC input consumes an amount of current.
I think you're right on the watchdog, I didn't realise that was the only timer that can wake up the microcontroller. Good luck with your ADC tests!
 
I just tested the ADC

When I'm not connecting anything, LED1 and LED2 light up (ADC_val>1022), is it correct? I think it is weird though as I didn't connect anything why the input is so high.

I am able to get right result by changing variable resistor value and get ((ADC_val > 800)&&(ADC_val<=1022)) where no LED light up at all, and else if((ADC_val >= 200)&&(ADC_val<=800)) where LED2, PB1 light up correctly.

However, I am not be able to get 0V.. I'm not sure how can I test 0V though... (I try connect it to ground then all LED suddenly turn off, and when I'm not connecting it to anything both LED light up)

Please kindly advice... my code is below

Code:
/ ATtiny13 
// ADC testing
#include <avr/io.h> 
#define F_CPU 8000000UL 
#include <util/delay.h> 


void ReadADC(); 
int val=0; 
int ADC_val=0;
int main (void) 
{ 
   DDRB |= (1 << PB0);// LED1
   DDRB |= (1 << PB1);// LED2
   DDRB &= ~(1 << PB4);// ADC0 pin

   ADMUX |= (0 << REFS0); // VCC as Reference 
   ADMUX = 0; // ADC0 PB5
   ADCSRA |= (1 << ADEN); // Enable ADC    
    
   while (1) 
   { 
        	ReadADC();  
			if (ADC_val > 1022) 
			 { 
			 PORTB |= (1 << PB0); 
			 PORTB |= (1 << PB1); 
			 
			 } 
			 else if ((ADC_val > 800)&&(ADC_val<=1022)) 
			 { 
		    PORTB &= (0 << PB0);
			PORTB &= (0 << PB1);

			 
			 } 
			 else if((ADC_val >= 200)&&(ADC_val<=800))
			 { 
			 PORTB &= (0 << PB0); 
			 PORTB |= (1 << PB1);
			
			 } 
			 else 
			 { 
			 PORTB |= (1 << PB0);
			 PORTB &= (0 << PB1);
			 } 
 }			 
   return 1;    
} 


void ReadADC() 
{       
      ADCSRA |= (1 << ADSC); // Start ADC Conversion 
		
      while((ADCSRA & 0x40) !=0){}; // wait for conversion to be completed, ADSC bit goes to 0 
	  ADC_val = ADCL;	 // read out ADCL register 
	  ADC_val += (ADCH << 8 );// read out ADCH register
}

Thank you very much
 

I think the ADC is working and your code is working to an extent, because the LEDs change when you change the ADC input.
However, I'm unsure about this code:
Code:
 ADC_val = ADCL;	 // read out ADCL register 
	  ADC_val += (ADCH << 8 );// read out ADCH register
I think you should cast the ADCH into an unsigned integer before left-shifting. Otherwise, you are just left-shifting 8 bits in an 8-bit variable.
You'll notice that this code used unsigned chars and unsigned ints, and did the casting, and it may solve some issues.
Code:
unsigned char lsbyte, msbyte;
  unsigned int anaval;


    lsbyte=ADCL;  // read the low byte first
    msbyte=ADCH;

    anaval=((unsigned int)msbyte)<<8;
    anaval=anaval|((unsigned int)lsbyte);
    // anaval should now contain a value between 0 and 1023
 

I tried both of the code and it still behaves the same. I think the ADC is working (I try change the value range and it works)
However, the lowest condition I can get is around 400.. Do you have anyway I could test the condition 0V ?

thank you :)
 

Ah... 400 is about (400/1024 * 5) approx 2V, which sounds like a digital threshold.. I think the analog input pin is still defined as a digital pin. In the original code,
I configured DIDR0 register, but I couldn't see it in your code. I've not tried the ADC in the AVR, so it's a bit of a guess, but worth trying that.
 

OK... after I tried that... still same result.. anyway, I think it is fine as long as it work for other range...

I just really want to know that when I'm not connecting the pin to anything it always show 2 lights (ADC_val = 1023)..

by the way, I'm using 3V Vcc... can that be the problem? (I use 2 AA battery..)


thank you so much...

PS. I tested the timer and it works fine, however, it seem that if I combine all the code, the hex file is 2Kb but I still can program it on ATtiny13.. is this weird as the ATtiny13 only handle up to 1Kb.
 

When you're not connecting anything to the pin, the result is invalid, because the device expects there to always be an input (between 0V and the supply voltage) with less than 10k of source resistance. So, for your tests, it should always be connected, and the variable resistor should be (say) 10k or less, e.g. 4.7k variable resistor.
It's still weird why you can't get a value less than 400. By the way, the code should be using unsigned values everywhere, not signed ints. In this case it seems that the high bits of the ADC conversion are low, but in general when doing this kind of manipulation of high and low bytes, it's best to always stick with unsigned ints and bytes unless you're sure you are expecting negative values.
The low supply should not be a problem, but it is worth checking with 5V.
The hex file may be larger than 2k, but that is because each byte is represented as 2 bytes or more in the hex file (e.g. a single byte '0xfe' is represented by two ASCII
bytes, 'F' and 'E').
 
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top