I am trying to measure battery's voltage and current but with a very high accuracy. So i've selected a 12 bit ADC to be interfaced (via I2C) with my micro-controller. My micro-controller will receive these values form the ADC and send them to the PC via the USB.

Now my question is, can we interface a 12bit ADC with an 8bit MCU like this one ?

Being new to microcontrollers i did a research over the internet and got the concept of 8bit Micro-controllers. But i couldn't find any where if i am able to interface it with a 12 bit ADC.

Also IF i am able to interface it, would it be more easy to use for eg a 32 bit MCU like this one instead of using the 8bit micro-controller, and interfacing it with the 12 bit ADC ? P.S by 'more easy' i mean simplicity of coding.

Looking forward for your suggestions.


  • \$\begingroup\$ Why not use oversampling and decimation to get 12 bits of resolution from the 10-bit ADC in the MCU? \$\endgroup\$ – Ignacio Vazquez-Abrams Jul 4 '15 at 19:14

Typically you when interfacing devices through I2C or other IC level buses, you will transfer a word of information out of your device, like 8 bits at a time but the payload may vary between protocols (usually a defined protocol word or word range). So to see how your 8bit MCU will work with your 12 bit DAC, first look at the internal data structure of the ADC Output.

enter image description here

You can see that this is a padded 16 bit number and can neatly be stored in two bytes/words using your MCU. In c, this number would transparently be read as a u_int16 or equivalent definition for your platform. Moreover, if you program in C, multi-word data structures are handled transparently, processing and mathematical operations would be slower, but you would be able to safely store a 24bit ADC in a u_int32 and the compiler will handle the word level details for you.

Now when it comes to transfer protocol , I2C is a serial transfer protocol and you can chomp the data on MCU side however you wish (even with a 7 bit mcu if you had such a beast) , but the bus neatly divides the data for you by insisting on an ACK after every 8 bits.

Let's look at the I2C signaling for your ADC.

enter image description here

You can see that all communications are neatly split into 8 bit sections, writing command words, writing registers, reading data, etc. If you were bitbanging this protocol on your MCU in assembly, you would be able to easily work with your word level operations without too much headache. In C this would be done transparently by the compiler.

Your MCU is smart and will handle a lot of bus level details for for you. You can perform I2C transactions using a few control registers on your MCU without dealing with timing details like shown above. For the datasheet you linked (Atmega 48/88/168) the relevant chapter is Chapter 21 (Two-Wire Interface). A high level diagram of I2C communications using your MCU is shown in the following figure.

enter image description here

The benefit of using the integrated I2C is that you save a lot of program space and clock cycles that would be spent bit banging I2C in your code.

  • \$\begingroup\$ Since i am no expert in Micro-controller programming/interfacing, i assume from your answer that if its possible for the 8 bit MCU to be interfaced with a 12bit ADC over i2c, it would also be possible to do it over SPI (i.e if both my ADC and MCU are SPI compatible). Right ? \$\endgroup\$ – yiipmann Jul 8 '15 at 15:21
  • \$\begingroup\$ @yiipmann you can chop serial data into any number of bytes you like . The bittness of the adc only tells you how much data a single measurement gives you. With an 8 bit mcu this data will typically need two addresses to store and extra operations for arithmetic. With a 32 bit mcu this will fit in one addressable word and can be manipulated with fewer instructions \$\endgroup\$ – crasic Jul 8 '15 at 16:24
  • \$\begingroup\$ I would add that an adc or other device may have internal registers of any size (8-32 bits common). Dealing with this detail is more program logic and memory addresses for an 8 bit mcu but can still easily be done. \$\endgroup\$ – crasic Jul 8 '15 at 16:35

There is absolutely no problem in interfacing a 12-bit ADC with an 8-bit micro. The one you show has I2C interface, so it's a bit easier if you pick a micro with I2C bus support. Atmel calls theirs "Byte-oriented 2-wire Serial Interface" because of Philips' IP rights, and the Atmega processors have such an interface in hardware.

It is common to use more than one byte to represent data. If you were programming in C you might use an int, long int or even a float. You can write code in assembler to deal with 8, 16, 32 or 256 bit numbers if you really want (limited by memory).

Simplicity of coding is highly dependent on what exactly you are trying to accomplish, and what your tools and experience are. If you are using a compiler, the details of the hardware are mostly hidden from you so it doesn't much matter (speed could be a bigger factor).

  • 1
    \$\begingroup\$ Atmel's acronym for I2C is TWI (Two Wire Interface) to help find it in their datasheets, appnotes, etc. \$\endgroup\$ – Greg d'Eon Jul 5 '15 at 2:12

It is very common to have ADCs integrated with 8-bit microcontrollers that are either 10-bit or 12-bit.

The result of the ADC are typically returned in two 8-bit registers labeled high and low (ADRESH and ADRESL in the diagram below).

The result many be returned either left-justified, meaning the high bit of the result corresponds to the high bit (bit 7) of the high byte of two 8-bit registers.

The other option is for the result to be right-justified, meaning the low bit of the result corresponds to the low bit (bit 0) of the low byte of two 8-bit registers.

enter image description here

Left justified gives you effectively an 8 bit conversion by just reading ADRESH. The two least significant bits are in ADRESL and are thrown away. This is often useful when you want a quick result and don't want to deal with the extra code and time dealing with a 16-bit value.

Of course the left-justified format can still be used the to access the full 10 or 12 bit result, but the right-justified format described next is actually more useful.

Right justified gives a full 10 or 12-bit result (depending on the size of the ADC), in a convenient format. When read into a 16-bit variable, there is enough room to add readings together for averaging without an overflow. However you then have to deal with 16-bit arithmetic.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.