Code to read differential ADC values on Tiny84

I’ve searched high and low for examples on how to set the registers correctly then read the values for differential ADC. Unfortunately differential ADC seems to be rarely used, the only examples I’ve found are for the Mega. I’m not too good at deciphering the Atmel datasheets, but on page 133 of the datasheet it explains which registers to set and how to read them. If anyone could give an example of how to actually set the registers appropriately, that’d be great.


You first. Post your attempt.

How to set a register?

someregister = somevalue;

“someregister” is just the name of the register given in the datasheet, e.g. if the datasheet says PINB, then “someregister” would be PINB.

“somevalue” can be simply an integer such as 0xff, 128, 0b10101010, or it could be a variable. You can build integers in a more readable fashion by doing things such as:

PORTB = (1<<PORTB1) | (1<<PORTB0);

This would set bits PORTB1 and PORTB0 in the PORTB register, and clear all other bits in that register.

Page 146 (Table 16-5) of the datasheet for example shows you the MUX[5:0] values for selecting differential channels. These bits are set in the ADMUX register, so an example would be:

ADMUX = (0b00 << REFS0) | (0b101000 << MUX0); //select VCC as reference and PA0/PA1 as the differential channel

If you look at the register descriptions in the datasheet, all bits have been given a name. These bits have corresponding names in avr-libc.

Thankyou both for your replies, I had a feeling someone would say “You first” :stuck_out_tongue: I did have a good poke around, but due to not really understanding the MUX[5:0] bit, which I now do slightly more (thanks for pointing out that table Tom C, I missed it before), I didn’t know where to start. I tried printing the contents of the ADMUX register to see what was in it, but it was just zero. Probably because I hadn’t set it to do anything yet… :smiley:

Here’s my code now, which seems to output something useful! Attaching a 1.2v battery gives a reading of ~95. I’m not sure how that relates to the actual voltage though, as 5/1000 is 0.005mv per step, and I get 95 which is 95*0.005=0.475?

void setup() {                

void loop() {
  int tmp=0;
  ADMUX = (0b00 << REFS0) | (0b101000 << MUX0); //select VCC as reference and PA0/PA1 as the differential channel

  ADCSRA |= 1100000;

  tmp|=(ADCH << 8); 



I did attempt using the defines instead of ADCSRA |= 1100000; but it didn’t seem to work. I tried:



I then printed the values of ADSC and ADEN, and they were 110 and 111. Completely different to the binary I read from the datasheet.

Now print:


Does that look a bit more like you would expect?

The reason is that ADEN is defined as the bit number, i.e. 7. If you do 1 shifted up 7 places you get 0b10000000 which is I think what you were expecting.

At the bottom of page 143 there is a formula relating differential voltage with ADC values. Assuming you connected the negative of the battery to PA0 and the positive terminal to PA1, then from the formula you get:

ADC = ((1.2-0) * 512)/5 = 122

Working in reverse you get:

Vdiff = ADC*5/512 = 0.93V

Perhaps the battery is quite discharged? Or you power supply is not 5V, but something a bit less?

That makes much more sense. Thanks!

Perhaps the battery is quite discharged? Or you power supply is not 5V, but something a bit less?

Thanks for pointing out the formula, I skimmed over that but wasn't quite sure on the difference between unipolar and bipolar. I have since Googled it and now know! The battery is 1.16v and the Vcc is 5.01v, so maybe its just an inaccurate ADC?

I've just noticed I used the wrong formula, unless you have set the BIN bit in ADCSRB, it uses a unipolar mode.

So in the formulae I used I should have put 1024, not 512 which means the result returned equates to 0.464v.

Out of curiosity, what happens if you connect the 1.2V battery the other way around to the differential input?

Yeah I had a feeling something weird was going on, if I reverse the battery I get zero.

Doing ADCSRB |= (1<<BIN); doesn’t work as BIN has been redefined somewhere in the Arduino headers, but ADCSRB |= (1<<7); works and results in an read value of 670 floating, 600 when the battery is reversed and about 740 when it’s the right way around.

Edit: I discovered the problem, I had left a wire attached between the differential negative and ground… Oops. Since removing that both the bipolar and unipolar work perfectly. Thankyou very much for you help, I hope Google crawls this for the benefit of others!