Using VL6180 proximity sensor to control digital potentiometer

Hello, I am extremely new to writing code and I've been attempting to control a MCP4151 digital POT with a VL6180 I2C proximity sensor.

Starting off I'm using a Micro and my goal is to control the resistance of the POT based upon the distance an object is from the sensor. I've been able to get to the point where I can read the I2C input from the sensor in the serial monitor and I'm able to send the "SPI.transfer(val)" to the pot to set a specific value.

My question is this:

Is there any way to control the POT continuously or "live" (for lack of a better term) rather than send it a specific value once with the SPI transfer line? Please forgive my complete lack of understanding... I'm only on day two of all this and before then I'd never written a single line of code in my life.

Essentially I'd like to run the data I see in the serial monitor through a "map" that puts it into the 0-255 range for the POT and have it continually update based on that value. I may be trying something thats not possible and I've scoured the forums and worn google out trying to find an answer.

I'll attach the code I'm using (I'm sure its a laughable mess to anyone who is actually proficient in this stuff)

Obviously that last line "SPI.transfer(map);" is silly and doesn't work, I just put it there temporarily to show what I am attempting to make happen.

Any advice or information would be greatly appreciated.

Thank you!

#include <VL6180X.h>
#include <Wire.h>
#include <SPI.h>
byte address = 0x11;
int tof_address = 0x29;
int CS = 4;


 
VL6180X vl;
SevSeg sevseg;

void setup() {
  pinMode(CS,OUTPUT);
  SPI.begin();
  Serial.begin(115200);
  if (!vl.init()) Serial.println("VL6180X init failed");
  Serial.println("INIT OK");
  pinMode(VL_INT_PIN, INPUT);
  digitalWrite(VL_INT_PIN,HIGH);
  pinMode(VL_SW_PIN, INPUT);
  digitalWrite(VL_SW_PIN,HIGH);

  
 
}


void loop() 
{

  
  Wire.beginTransmission(tof_address);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(tof_address, 8);
  while(Wire.available() == 0);
  int distance = Wire.read();

         Serial.print("  OUTPUT =   ");
         vl.read();
          Serial.println(vl.range);
          delay(15);
          int val = vl.range;
          val = map(val, 20, 1000, 1, 255);
          SPI.transfer(map);
          
          
}

Project_1.ino (920 Bytes)

Is there any way to control the POT continuously or "live" (for lack of a better term) rather than send it a specific value once with the SPI transfer line?

Forget the Arduino, for a moment. How would YOU perform the task? You need to adjust the potentiometer based on the sensor reading. To do that, you need to read from the sensor, and write to the potentiometer.

Isn't that what the code does now?

Why do you request 8 bytes, and then read only one?

Do you really need to send a 0 to the device on every pass through loop()?

The code is not at all clear. You should have a function to get data from the proximity sensor. You should have a function to write data to the potentiometer. Do not write to the pot in the reading function. Do not read from the sensor in the writing function.

Why does it appear that the address of the proximity sensor is stored in tof_sensor? Or is that the potentiometer address? Use names that make sense.

Posting code that actually compiles is a bonus.

I appreciate the reply, but is it really necessary to be so harsh? I came here with a legitimate question and was quite clear that I am completely new to this.

First off my proximity sensor is a TOF sensor... so I named its address tof_sensor... yeah, that makes NO sense. also the code DOES compile. you just need to remove my dummy value from the last line, which I mentioned.

I'm trying hard to find something constructive in your comment that actually does anything useful. I guess I'll address the point you made about the read function and write function. Obviously I need to read from the sensor and write to the potentiometer... that's the whole reason I even posted this in the first place. I am simply unclear on HOW I go about doing that. I believe I understand what you are getting at and at least I have something to research and learn about. Maybe it will provide some answers.

Thanks I guess.

I appreciate the reply, but is it really necessary to be so harsh?

OK. I've added you to the "thin-skinned" list.

First off my proximity sensor is a TOF sensor... so I named its address tof_sensor.

It senses time of flight? That's pretty unusual. Usually a proximity sensor senses a reflected wave. Measuring the time of flight is up to the microcontroller.

I am simply unclear on HOW I go about doing that.

If you can't read from the sensor, how do you know it is working?
If you can't write to the potentiometer, how do you know it is working?

If you can do either of those things, doing so in a function is trivial. If you can't, then asking how to do something different with the data is pointless.

I'm struggling to understand what you are trying to change, and to follow your uncommented code. Adding comments would help with understanding the code. Once that is working, then we can work on what you want to do differently.

I can read the sensor data in the serial monitor fine. It seems to be working. I've also been able to run a stock example code to fade an LED with the POT so thats also working. Sorry for not mentioning that already.

I've added a few comments to the sections that are relevant.

#include <VL6180X.h>
#include <Wire.h>
#include <SPI.h>
byte address = 0x11;
int tof_address = 0x29;
int CS = 4;


 
VL6180X vl;
SevSeg sevseg;

void setup() {
  pinMode(CS,OUTPUT);
  SPI.begin();
  Serial.begin(115200);
  if (!vl.init()) Serial.println("VL6180X init failed");
  Serial.println("INIT OK");
  pinMode(VL_INT_PIN, INPUT);
  digitalWrite(VL_INT_PIN,HIGH);
  pinMode(VL_SW_PIN, INPUT);
  digitalWrite(VL_SW_PIN,HIGH);

  
 
}


void loop() 
{

  /* This section is one I lifted from a demo example code provide
   *  by the sensor manufacturer. It initializes the sensor in my 
   *  understanding. 
   */
  Wire.beginTransmission(tof_address);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(tof_address, 8);
  while(Wire.available() == 0);
  int distance = Wire.read();


         //Here I am printing the sensor output to the serial monitor
         Serial.print("  OUTPUT =   ");
         vl.read();
          Serial.println(vl.range);
          delay(15);
          
          
          
          
}
byte address = 0x11;
int tof_address = 0x29;

Why are the two address different sizes? Why does one define what it is for, but the other one doesn't?

  Wire.beginTransmission(tof_address);
  Wire.write(0);
  Wire.endTransmission();

Why is it necessary to send data to the device, on every pass through loop? What does the 0 tell it to do?

  Wire.requestFrom(tof_address, 8);
  while(Wire.available() == 0);
  int distance = Wire.read();

Ask for 8 bytes. Wait for 1. Read 1.

         vl.read();

You are now asking the library to read some data, for the same sensor, right? I'm confused as to why.

Can you post a link to the proximity sensor? Maybe that would help with understanding the code.

I've also been able to run a stock example code to fade an LED with the POT so thats also working.

That code is not integrated in this code. So, it is unclear what the problem is.

Okay, so most of that code is left over from the example stuff. I went through and stripped out anything that I could find that seemed irrelevant (god it was a mess, sorry)

Here's a link to the sensor

and if it means anything here is the POT

http://www.microchip.com/wwwproducts/Devices.aspx?product=MCP4151

Im trying to make the POT fade an LED based on the distance from the sensor. My ability to write code means something simple like that seems extremely difficult to me. I'm trying to learn as much as I can but I'm a complete idiot right now with this stuff. I apologize for overreacting so much earlier. :o

Here is the stripped down code.

I'm not sure how to answer the read 8 bit/write 1 bit question. would it be better to write 8 as well or read 1 and write 1? Not sure what the POT will accept.

#include <VL6180X.h>
#include <Wire.h>
#include <SPI.h>
int tof_address = 0x29;
int CS = 4;


 
VL6180X vl;
SevSeg sevseg;

void setup() {
  pinMode(CS,OUTPUT);
  SPI.begin();
  Serial.begin(115200);
  if (!vl.init()) Serial.println("VL6180X init failed");
  Serial.println("INIT OK");
  pinMode(VL_INT_PIN, INPUT);
  digitalWrite(VL_INT_PIN,HIGH);
  pinMode(VL_SW_PIN, INPUT);
  digitalWrite(VL_SW_PIN,HIGH);

  
 
}


void loop() 
{

  
         
         Wire.requestFrom(tof_address,8);
         //Here I am printing the sensor output to the serial monitor
         Serial.print("  OUTPUT =   ");
         vl.read();
          Serial.println(vl.range);
          delay(15);
          
          
          
          
}

Sparkfun's site has a link to an Arduino library with examples, for reading from the sensor. The only method that you should need to call is getDistance(). Have you tried that library?

If not, where did you get the library you are using?

but I'm a complete idiot

Are you sure that there are no parts missing? 8)

I do have the library you mentioned. I'm just not well versed enough to know how to implement it correctly I suppose. Maybe I'm a lost cause :confused:

I'm not sure how to use the get distance line. I appreciate the help btw. Where would I put that in the code? obviously in loop, but beyond that I don't know how to make use of the library.

I'm just not well versed enough to know how to implement it correctly I suppose.

If you have the library, there is an examples folder that contains an example that can be uploaded to the Arduino. Give that a try.

Hey! So I went to my local Maker Space and found someone to take a look at the code. We still weren't able to make it work but this is what came of it. Any thoughts? It's been a while since he had worked on C so it may not be perfect.

#include <VL6180X.h>
#include <Wire.h>
#include <SPI.h>

/* 
 * potentiometer settings
 */

const int LED_SPI_CS = 4;
const byte POT_INCREMENT = 0x04;
const byte POT_DECREMENT = 0x08;
const int POT_UPDATE_DELAY = 1;
const int DEBUG = 0;

/* 
 * Proximity Sensor
 */
VL6180X proximity_sensor;
const int proximity_sensor_address = 0x29;

void setup() {
  /*
   * Init Serial port
   */
  Serial.begin(115200);

  /*
   * Initialize proximity sensor
   */
  if (!proximity_sensor.init())
    Serial.println("VL6180X (proximity sensor) init failed");
  
  pinMode(VL_INT_PIN, INPUT);
  digitalWrite(VL_INT_PIN, HIGH);

  pinMode(VL_SW_PIN, INPUT);
  digitalWrite(VL_SW_PIN, HIGH);

  /*
   * Initialize the digital potentiometer which controls the LED
   */
  pinMode (LED_SPI_CS, OUTPUT);
  SPI.begin();

  /*
   * set the pot to 0
   */
  int current_pot_value;
  
  for (current_pot_value = 255; current_pot_value > 0; current_pot_value--) {
    digitalWrite(LED_SPI_CS, LOW);
    SPI.transfer(POT_DECREMENT);
    digitalWrite(LED_SPI_CS, HIGH);
  }
}

void loop() 
{
  /* This section is one I lifted from a demo example code provide
   *  by the sensor manufacturer. It initializes the sensor in my 
   *  understanding. 
   */
  Wire.beginTransmission(proximity_sensor_address);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(proximity_sensor_address, 8);

  while (Wire.available() == 0);

  /*
   * print the sensor output to the serial monitor.
   * And, for now, change the brightness a tad brighter or dimmer
  if (proximity_sensor.range > 100) {
    Serial.print("++ ");
    digitalPotIncrement();
  } else {
    Serial.print("-- ");
    digitalPotDecrement();
  }
   */

  if (DEBUG)
    Serial.print("  OUTPUT =   ");
  proximity_sensor.read();
  if (DEBUG)
    Serial.println(proximity_sensor.range);

  /*
   * map the distance to brightness
   */
//  int new_level;
//  new_level = map(proximity_sensor.range, 0, 255, 0, 255);
  DigitalPotSetLevel(proximity_sensor.range);

  /*
   * chill for a bit
   */
  delay(20);
}

void DigitalPotSetLevel(int need_level)
{
  static int current_pot_level = 0;


  /*
   * is the current pot level too low
   */
  while (current_pot_level > need_level) {
    digitalWrite(LED_SPI_CS, LOW);
    SPI.transfer(POT_DECREMENT);
    digitalWrite(LED_SPI_CS, HIGH);
    
    current_pot_level --;
    if (DEBUG)
      Serial.print("-");
    delay(POT_UPDATE_DELAY);
  }
  /*
   * is the current pot level too low
   */
  while (current_pot_level < need_level) {
    digitalWrite(LED_SPI_CS, LOW);
    SPI.transfer(POT_INCREMENT);
    digitalWrite(LED_SPI_CS, HIGH);

    current_pot_level ++;
    if (DEBUG)
      Serial.print("+");
    delay(POT_UPDATE_DELAY);
  }

  if (DEBUG)
    Serial.print(current_pot_level);
}

void digitalPotIncrement()
{
  digitalWrite(LED_SPI_CS, LOW);
  SPI.transfer(POT_INCREMENT);
  digitalWrite(LED_SPI_CS, HIGH);
}

void digitalPotDecrement()
{
  digitalWrite(LED_SPI_CS, LOW);
  SPI.transfer(POT_DECREMENT);
  digitalWrite(LED_SPI_CS, HIGH);
}

We were able to essentially divide the proximity range into two sections so if the object was less than lets say 100mm away, it would turn the LED hooked up to the POT on, and if was further than 100mm it would turn it off. That little test worked fine, but all attempts to send the proper data from the sensor to the POT simply wouldn't work.

We were able to essentially divide the proximity range into two sections so if the object was less than lets say 100mm away, it would turn the LED hooked up to the POT on, and if was further than 100mm it would turn it off.

That suggests to me that you are able to get good data from the proximity sensor and that you were able to control the potentiometer. That sounds like great news.

all attempts to send the proper data from the sensor to the POT simply wouldn't work.

Haven't we been down this path? Handwaving is useless on this forum. Post the code that works. Post the code that does not do-what-you-want (notice that I avoided the phrase does not work). Describe what the second code actually does. Describe how that differs from what you want.

Here is the code

#include <VL6180X.h>
#include <Wire.h>
#include <SPI.h>

/* 
 * potentiometer settings
 */

const int LED_SPI_CS = 4;
const byte POT_INCREMENT = 0x04;
const byte POT_DECREMENT = 0x08;
const int POT_UPDATE_DELAY = 1;
const int DEBUG = 0;

/* 
 * Proximity Sensor
 */
VL6180X proximity_sensor;
const int proximity_sensor_address = 0x29;

void setup() {
  /*
   * Init Serial port
   */
  Serial.begin(115200);

  /*
   * Initialize proximity sensor
   */
  if (!proximity_sensor.init())
    Serial.println("VL6180X (proximity sensor) init failed");
  
  pinMode(VL_INT_PIN, INPUT);
  digitalWrite(VL_INT_PIN, HIGH);

  pinMode(VL_SW_PIN, INPUT);
  digitalWrite(VL_SW_PIN, HIGH);

  /*
   * Initialize the digital potentiometer which controls the LED
   */
  pinMode (LED_SPI_CS, OUTPUT);
  SPI.begin();

  /*
   * set the pot to 0
   */
  int current_pot_value;
  
  for (current_pot_value = 255; current_pot_value > 0; current_pot_value--) {
    digitalWrite(LED_SPI_CS, LOW);
    SPI.transfer(POT_DECREMENT);
    digitalWrite(LED_SPI_CS, HIGH);
  }
}

void loop() 
{
  /* This section is one I lifted from a demo example code provide
   *  by the sensor manufacturer. It initializes the sensor in my 
   *  understanding. 
   */
  Wire.beginTransmission(proximity_sensor_address);
  Wire.write(0);
  Wire.endTransmission();
  Wire.requestFrom(proximity_sensor_address, 8);

  while (Wire.available() == 0);

  /*
   * print the sensor output to the serial monitor.
   * And, for now, change the brightness a tad brighter or dimmer
  if (proximity_sensor.range > 100) {
    Serial.print("++ ");
    digitalPotIncrement();
  } else {
    Serial.print("-- ");
    digitalPotDecrement();
  }
   */

  if (DEBUG)
    Serial.print("  OUTPUT =   ");
  proximity_sensor.read();
  if (DEBUG)
    Serial.println(proximity_sensor.range);

  /*
   * map the distance to brightness
   */
//  int new_level;
//  new_level = map(proximity_sensor.range, 0, 255, 0, 255);
  DigitalPotSetLevel(proximity_sensor.range);

  /*
   * chill for a bit
   */
  delay(20);
}

void DigitalPotSetLevel(int need_level)
{
  static int current_pot_level = 0;


  /*
   * is the current pot level too low
   */
  while (current_pot_level > need_level) {
    digitalWrite(LED_SPI_CS, LOW);
    SPI.transfer(POT_DECREMENT);
    digitalWrite(LED_SPI_CS, HIGH);
    
    current_pot_level --;
    if (DEBUG)
      Serial.print("-");
    delay(POT_UPDATE_DELAY);
  }
  /*
   * is the current pot level too low
   */
  while (current_pot_level < need_level) {
    digitalWrite(LED_SPI_CS, LOW);
    SPI.transfer(POT_INCREMENT);
    digitalWrite(LED_SPI_CS, HIGH);

    current_pot_level ++;
    if (DEBUG)
      Serial.print("+");
    delay(POT_UPDATE_DELAY);
  }

  if (DEBUG)
    Serial.print(current_pot_level);
}

void digitalPotIncrement()
{
  digitalWrite(LED_SPI_CS, LOW);
  SPI.transfer(POT_INCREMENT);
  digitalWrite(LED_SPI_CS, HIGH);
}

void digitalPotDecrement()
{
  digitalWrite(LED_SPI_CS, LOW);
  SPI.transfer(POT_DECREMENT);
  digitalWrite(LED_SPI_CS, HIGH);
}
  int current_pot_value;
  
  for (current_pot_value = 255; current_pot_value > 0; current_pot_value--) {
    digitalWrite(LED_SPI_CS, LOW);
    SPI.transfer(POT_DECREMENT);
    digitalWrite(LED_SPI_CS, HIGH);
  }

There is no need to declare current_pot_value separately. Add int after the ( in the for statement, and get rid of the separate declaration.

The name, current_pot_value, is a misnomer. It never represents the current value of the potentiometer. You don't even KNOW the current value. You simply tell the potentiometer to decrement it's value 255 times. If it was at 0, it will STILL be at 0 when this loop ends.

What's the purpose of creating a function called digitalPotIncrement() if you are going to replicate the code in DigitalPotSetLevel()? Why does one function start with an upper case letter, while the other starts with a lower case letter?

Does digitalPotIncrement() actually do what it's name says?