Analog Input

From Nutwiki
Revision as of 17:02, 27 October 2016 by Harald (Talk | contribs) (1 revision imported)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Overview

This example demonstrates how to read analog data with the Nut/OS ADC routines. To allow for changing values, the ADC0 port and the external reference were linked up with a potentiometer to allow for easy changing of the read values. Output between 0 and 5V was within the measurable range.

To fully enjoy this example, you will have to enable floating point support for Nut/OS, otherwise %f will be interpreted as f, not as number.

Note for Nut/OS 4.8.3 and below

As of now, the ADC driver is broken. It will not output any error messages but may produce strange and undefined behaviour. The driver is being reworked but you should apply at least one manual patch to make it work correctly:

Open the file "adc.c" in \nut\arch\avr\dev and find the line

<source lang="c"> ADC_buffer = NutHeapAlloc(sizeof(uint16_t) * ADC_BUF_SIZE + 2); </source>

change it to

<source lang="c"> ADC_buffer = NutHeapAlloc(sizeof(uint16_t) * (ADC_BUF_SIZE + 2)); </source>

Now rebuild your Nut/OS by issuing the Build -> Build Nut/OS command from the configurator.

Principle description for Ethernut 2.1

On this boards, we use PF0 of PORT F which is reffered to as pin 5 in the hardware manuals as our analog input pin connected to the slider of the potentiometer and pin 4 as Analog ground.

Connect the ther side of the potentiometer to AREF which is reffered to as pin 2.

   AREF ----------+                
                  |               
                 ---  
                 | /------- PF0               
                 |/|                    
                 / |                    
                \---                     
                  |                            
                  |                           
                  | 
                  |                             
    AGND ---------+

Source Code

<source lang="c">

  1. include <cfg/os.h>
  2. include <cfg/crt.h>
  3. include <dev/board.h>
  4. include <dev/adc.h>
  1. include <stdio.h>
  2. include <string.h>
  3. include <io.h>
  1. include <sys/timer.h>

int main(void) {

   u_long baud = 115200;
   uint16_t adc_value = 0;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   puts("\nADC example");
   ADCInit();
   for (;;) {
       ADCStartConversion();
       while (ADCRead(&adc_value)) {
           NutThreadYield();
       }
       printf("Checked power 5V: %f\n", (double) (adc_value * 5.0 / 1023.0));
       NutSleep(1000);
   }
   return 0;

} </source>

Details

<source lang="c">

   u_long baud = 115200;
   uint16_t adc_value = 0;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   puts("\nADC example");

</source>

As usual we set up the debug device to make output to the terminal possible. The variable adc_value is also declared. Since we will use default settings for the Analog Digital Converter, we will read a 10 bit value which we will store in it.

<source lang="c"> ADCInit(); </source>

Before reading anything, we initialize the ADC. This will also set some sensible default values. For more info on read adc.c, which is the driver for the ADC.

<source lang="c">

   for (;;) {
       ADCStartConversion();
       while (ADCRead(&adc_value)) {
           NutThreadYield();
       }
       printf("Checked power 5V: %f\n", (double) (adc_value * 5.0 / 1023.0));
       NutSleep(1000);
   }

</source>

In this endless loop we do the actual reading. The ADC supports multiple modes, we will use the one for single conversions. Thus we have to start the conversion for every time we want to read a value using ADCStartConversion().

Now we read a value with ADCRead(). ADCRead takes a single parameter, the address of the variable we want our value to be stored in. Since the function may fail returning a 1 when no data is present, we wait for it to return 0 before we continue and finally print our value to the screen.

The value calculation is pretty easy actually: We get a 10 digit number from the ADC, 0 meaning no signal at all and 1023 meaning highest possible signal. To get our 5V, we have to multiplay it with and divide it by 1023.

Output

<source lang="text"> ADC example

Checked power 5V: 5.000000 Checked power 5V: 4.765396 Checked power 5V: 4.525904 Checked power 5V: 4.379277 Checked power 5V: 3.768328 Checked power 5V: 3.201369 Checked power 5V: 2.502444 Checked power 5V: 2.028348 Checked power 5V: 1.681329 Checked power 5V: 1.094819 Checked power 5V: 0.620723 Checked power 5V: 0.307918 Checked power 5V: 0.014663 Checked power 5V: 0.000000 </source>

See also





Template:Languages