Zumo32U4 library
Zumo32U4ProximitySensors.cpp
1 // Copyright Pololu Corporation. For more information, see http://www.pololu.com/
2 
4 #include <Zumo32U4IRPulses.h>
5 #include <Arduino.h>
6 #include <FastGPIO.h>
7 #include <stdlib.h>
8 
9 // The Arduino's digitalRead, digitalWrite, and pinMode functions will have
10 // unexpected behavior if the pin number argument happens to be greater than
11 // NUM_DIGITAL_PINS. We protect users of our library from that.
12 static bool digitalReadSafe(uint8_t pin, bool defaultValue = 1)
13 {
14  if (pin < NUM_DIGITAL_PINS)
15  {
16  return digitalRead(pin);
17  }
18  else
19  {
20  return defaultValue;
21  }
22 }
23 
24 static void pinModeSafe(uint8_t pin, uint8_t mode)
25 {
26  if (pin < NUM_DIGITAL_PINS)
27  {
28  pinMode(pin, mode);
29  }
30 }
31 
32 void Zumo32U4ProximitySensors::clearAll()
33 {
34  dataArray = NULL;
35  numSensors = 0;
36 
37  lineSensorEmitterPin = SENSOR_NO_PIN;
38 
39  levelsArray = NULL;
40  numLevels = 0;
41 
42  pulseOnTimeUs = defaultPulseOnTimeUs;
43  pulseOffTimeUs = defaultPulseOffTimeUs;
44  period = defaultPeriod;
45 }
46 
47 void Zumo32U4ProximitySensors::init(uint8_t * pins, uint8_t numSensors,
48  uint8_t lineSensorEmitterPin)
49 {
50  this->lineSensorEmitterPin = lineSensorEmitterPin;
51 
52  // Allocate memory for the new dataArray. If there is an error, return
53  // before modifying the existing dataArray or numSensors so that we
54  // don't leave the object in an invalid state.
55  const size_t size = numSensors * sizeof(SensorData);
56  void * newArray = realloc(dataArray, size);
57  if (newArray == NULL) { return; }
58 
59  // Store the pointer to the new dataArray.
60  this->dataArray = (SensorData *)newArray;
61 
62  // Store the number of sensors.
63  this->numSensors = numSensors;
64 
65  for (uint8_t i = 0; i < numSensors; i++)
66  {
67  // Store the pin numbers specified by the user.
68  dataArray[i].pin = pins[i];
69  }
70 }
71 
72 
73 void Zumo32U4ProximitySensors::setBrightnessLevels(uint16_t * levels, uint8_t numLevels)
74 {
75  const size_t size = numLevels * sizeof(uint16_t);
76 
77  void * newArray = realloc(levelsArray, size);
78  if (newArray == NULL)
79  {
80  // There was an error allocating memory so just leave the
81  // state of the object the same as it was before.
82  return;
83  }
84 
85  memcpy(newArray, levels, size);
86  levelsArray = (uint16_t *)newArray;
87  this->numLevels = numLevels;
88 }
89 
90 void Zumo32U4ProximitySensors::prepareToRead()
91 {
92  pullupsOn();
93 
95 
96  if (levelsArray == NULL)
97  {
98  uint16_t defaultBrightnessLevels[] = { 4, 15, 32, 55, 85, 120 };
99  setBrightnessLevels(defaultBrightnessLevels, 6);
100  }
101 }
102 
104 {
105  // Set all the sensor pins to be pulled-up inputs so that they
106  // are high whenever the sensor outputs are not active.
107  for (uint8_t i = 0; i < numSensors; i++)
108  {
109  pinModeSafe(dataArray[i].pin, INPUT_PULLUP);
110  }
111 }
112 
113 // Turn off the down-facing IR LEDs because the proximity
114 // sensors tend to detect the IR coming from them.
116 {
117  if (lineSensorEmitterPin < NUM_DIGITAL_PINS)
118  {
119  digitalWrite(lineSensorEmitterPin, LOW);
120  pinMode(lineSensorEmitterPin, OUTPUT);
121  delayMicroseconds(pulseOffTimeUs);
122  }
123 }
124 
125 /* It is not feasible to turn off the pulses before checking the output of
126  * the sensor because an interrupt might fire and cause the sensor check to
127  * happen too late.
128  */
130 {
131  prepareToRead();
132 
133  for (uint8_t i = 0; i < numSensors; i++)
134  {
135  dataArray[i].withRightLeds = 0;
136  dataArray[i].withLeftLeds = 0;
137  }
138 
139  for (uint8_t i = 0; i < numLevels; i++)
140  {
141  uint16_t brightness = levelsArray[i];
142 
143  Zumo32U4IRPulses::start(Zumo32U4IRPulses::Left, brightness, period);
144  delayMicroseconds(pulseOnTimeUs);
145  for (uint8_t i = 0; i < numSensors; i++)
146  {
147  if (!digitalReadSafe(dataArray[i].pin, 1))
148  {
149  dataArray[i].withLeftLeds++;
150  }
151  }
153  delayMicroseconds(pulseOffTimeUs);
154 
156  delayMicroseconds(pulseOnTimeUs);
157  for (uint8_t i = 0; i < numSensors; i++)
158  {
159  if (!digitalReadSafe(dataArray[i].pin, 1))
160  {
161  dataArray[i].withRightLeds++;
162  }
163  }
165  delayMicroseconds(pulseOffTimeUs);
166  }
167 }
168 
169 bool Zumo32U4ProximitySensors::readBasic(uint8_t sensorNumber)
170 {
171  if (sensorNumber >= numSensors) { return 0; }
172  return !digitalReadSafe(dataArray[sensorNumber].pin, 1);
173 }
174 
175 uint8_t Zumo32U4ProximitySensors::countsWithLeftLeds(uint8_t sensorNumber) const
176 {
177  if (sensorNumber >= numSensors) { return 0; }
178  return dataArray[sensorNumber].withLeftLeds;
179 }
180 
181 uint8_t Zumo32U4ProximitySensors::countsWithRightLeds(uint8_t sensorNumber) const
182 {
183  if (sensorNumber >= numSensors) { return 0; }
184  return dataArray[sensorNumber].withRightLeds;
185 }
186 
187 uint8_t Zumo32U4ProximitySensors::findIndexForPin(uint8_t pin) const
188 {
189  for (uint8_t i = 0; i < numSensors; i++)
190  {
191  if (dataArray[i].pin == pin)
192  {
193  return i;
194  }
195  }
196 
197  // The specified pin is not being used as a sensor, so return 255. This can
198  // be safely passed to countsWithLeftLeds, countsWithRightLeds, or
199  // readBasic, and those functions will return 0.
200  return 255;
201 }
static const uint8_t SENSOR_NO_PIN
A constant that can be used in place of a pin number to indicate that no pin should be used.
static void stop()
Stops emitting IR pulses.
static void start(Direction direction, uint16_t brightness, uint16_t period=defaultPeriod)
Starts emitting IR pulses.
void read()
Emits IR pulses and gets readings from the sensors.
static const uint16_t defaultPeriod
The default period for the infrared pulses.
void init(uint8_t *pins, uint8_t numSensors, uint8_t lineSensorEmitterPin=defaultLineSensorEmitterPin)
Configures this object to use a custom set of pins.
uint8_t countsWithRightLeds(uint8_t sensorNumber) const
Returns the number of brightness levels for the right LEDs that activated the specified sensor.
void setBrightnessLevels(uint16_t *levels, uint8_t levelCount)
Sets the sequence of brightness levels used by read().
void lineSensorEmittersOff()
Turns the IR emitters for the line sensors off.
bool readBasic(uint8_t sensorNumber)
Does a quick digital reading of the specified sensor without emitting any IR pulses.
static const uint16_t defaultPulseOffTimeUs
The default time to leave the infrared LEDs off between readings, in microseconds.
static const uint16_t defaultPulseOnTimeUs
The default duration of the bursts of infrared pulses emitted, in microseconds.
uint8_t countsWithLeftLeds(uint8_t sensorNumber) const
Returns the number of brightness levels for the left LEDs that activated the specified sensor.
void pullupsOn()
Sets each sensor pin to an input with pull-up resistors enabled.