2

I'm trying to read an ADC (12 bit which is 0 - 4095) input from my AIN0 channel, and using that as an "int" so I could use it in a math function. Is this possible?

The directory I'm referring to is "sys/bus/iio/devices/iio:device0/in_voltage0_raw" on the Beaglebone Black Debian Wheezy.

Currently, I have a C file that reads the user's input (through terminal) and does the math function I need it to do, but I'm having a hard time wrapping my head around this active/constantly changing ADC value. I've looked into using "fopen" functions as well. Using the code below, I'm able to get the ADC value on the terminal, and it'll change based on how much volts go in. Is there a way to "grab" the input from the ADC and use it in a math function, even if the ADC value constantly changes?

#define SYSFS_ADC_DIR "/sys/bus/iio/devices/iio:device0/in_voltage0_raw"
#define MAX_BUFF 64
int main(){
  int fd;
  char buf[MAX_BUFF];
  char ch[5];   //Update
  ch[4] = 0;    //Update

  int i;
  for(i = 0; i < 30; i++)
      {
      snprintf(buf, sizeof(buf), SYSFS_ADC_DIR);
      fd = open(buf, O_RDONLY);
      read(fd,ch,4);
      printf("%s\n", ch);
      close(fd);

      usleep(1000);
    }
  }

Updated Code

I've made the changes to char ch[5], I've also gotten a little farther in the code putting the math functions I wanted.

int AIN0_low = 0;    //lowest input of adc
int AIN0_high = 4095;   //highest input of adc
int motor_low = 0;      //lowest speed value for motor
int motor_high = 3200;  //highest speed value for motor
double output = 0;

int  main(){
  double fd;
  char buf[MAX_BUF];
  char ch[4] = 0;

  int i;
  for(i = 0; i < 30; i++)
  {
    snprintf(buf, sizeof(buf), SYSFS_ADC_DIR);

    fd = open(buf, O_RDONLY);
    read(fd, ch, 4);

    double slope = 1.0 * (motor_high - motor_low) / (AIN0_high - AIN0_low);
    output = motor_low + slope * (ch - AIN0_low);

    printf("%f\n", output);

    close(fd);
    usleep(1000);
  }
}
Sam Protsenko
  • 14,045
  • 4
  • 59
  • 75
loco_tums
  • 23
  • 4
  • 1
    So it is changing. If it won't change, why would you need a program? Read the file in loop and calculate your function. It's results will change as well. – Eugene Sh. Apr 30 '15 at 16:01
  • For the conversion, see the man pages for atoi() and similar. I suspect that each time you open and read the file you will get a new distinct reading - it may be that you do not even need to re-open it, but the documentation/driver source would have to be consulted. Typically with an ADC, even with a "stable" input you will see some variation in the reading due to noise. – Chris Stratton Apr 30 '15 at 16:01
  • You have possible *undefined behavior* in your code, because unless the four bytes you read are actually three characters and the string terminator then `printf` will most likely go beyond the end of the array `ch`. – Some programmer dude Apr 30 '15 at 16:01
  • @JoachimPileborg - actually, as the value will often have four digits they are probably depending on ch[] starting out as all zeroes (realistically, being in memory yet unused since a sanitized page was given to the process by the kernel) – Chris Stratton Apr 30 '15 at 16:05
  • 2
    You declared `int ch[5]` yet you are using `printf()` with the `%s` string format specifier. Better to have `char ch[5]`, if the "file" is returning a 4-digit number. – Weather Vane Apr 30 '15 at 16:09
  • @WeatherVane: ... and at least set `ch[4]` to 0. – alk Apr 30 '15 at 16:14
  • Your update says `char ch[4]` and you still need to set `ch[4] = 0` to terminate a string. AND you are using the file handle `fd` in your calculation! – Weather Vane Apr 30 '15 at 16:48
  • @ChrisStratton I've made some changes, and updated the original post with what I'm trying to do. At least now on my terminal output I no longer get gibberish or symbols. Now I get an actual decimal, however now matter how much I rotate my pot, the output is always 2.344322 Am I at least heading in the right direction? – loco_tums Apr 30 '15 at 16:49
  • You have changed it again. Declare `char ch[5];`. Then set `ch[4] = 0;` to terminate the string. And using the file handle `fd` in the calculation makes no sense at all. I suggest you first print meaningful values of the 12-bit DAC before trying to compute with it. – Weather Vane Apr 30 '15 at 16:52
  • Please stop fumbling with the posted code. Read the 4 bytes into a char array. Print each byte of the char array as a hex value. Run the program while turning the pot from min to max, and see if you can establish the range of values required. – Weather Vane Apr 30 '15 at 16:57
  • Alright, I was confused with fd, I thought that was the variable that was calling the ADC. and @WeatherVane, then I run "cat sys/bus/iio/devices/iio:device0/in_voltage0_raw" on the terminal, I get a real digit from 0 - 4095. the original code I posted, when compiled and executed also gives me a real digit same from 0 - 4095. I'm new to this, so I'm still trying to learn the ropes. Thank you for your patience – loco_tums Apr 30 '15 at 16:58

1 Answers1

1

In your second function you are using the filehandle in your calculations. I think you meant the value you read (ch). Just convert the value to float before putting into the calculation.

Also add another byte to the buffer you read with to accommodate an ending \0

Something like this

int  main(){
  double fd = 0.0;
  char buf[MAX_BUF] = {0};
  char ch[5] = {0,0,0,0,0};

  // move slope here since it is constant
  double slope = 1.0 * (motor_high - motor_low) / (AIN0_high - AIN0_low);

  int i;
  for(i = 0; i < 30; i++)
  {
    snprintf(buf, sizeof(buf), SYSFS_ADC_DIR);

    fd = open(buf, O_RDONLY);
    read(fd, ch, 4);
    output = motor_low + slope * (atof(ch) - AIN0_low);

    printf("%f\n", output);

    close(fd);
    usleep(1000);
  }
  return 0; // add this
}

disclaimer: i don't know about the hardware you are using, just fixed your code if the device behaves like a file.

AndersK
  • 35,813
  • 6
  • 60
  • 86
  • 1
    THANK YOU! This worked flawlessly. Indeed I did mean to use ch instead of fd, I was just confused on which variable actually held the input value. Thank you for explaining the byte part and accommodating for the ending \0, now I know how to set up my other ADCs for future reference. Really appreciate your help, and everyone else's on this post. – loco_tums Apr 30 '15 at 17:09
  • @loco_tums when you originally printed the right values it was "luck" really. `read` doesn't care about the target data buffer type, only where to put the data and how much. It was put into an `int` array, which you then printed as if it was a `char` array, and it happened to have a terminating zero in the right place. – Weather Vane Apr 30 '15 at 17:14