SparkFun Line Follower Array Library. based on https://github.com/sparkfun/SparkFun_Line_Follower_Array_Arduino_Library
Dependents: WRS_mechanamu_test
Diff: SensorBar.cpp
- Revision:
- 0:c1d649c7b904
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SensorBar.cpp Fri Aug 31 02:52:24 2018 +0000 @@ -0,0 +1,484 @@ +#include "SensorBar.h" +#include "stdint.h" +#include "sx1509_registers.h" + +/*example*************************************************** + +#include "mbed.h" +#include "SensorBar.h" + +const uint8_t SX1509_ADDRESS = 0x3E<<1; // SX1509 I2C address (00) + +int main() +{ + I2C i2c(p28, p27); + SensorBar mySensorBar(&i2c, SX1509_ADDRESS); + mySensorBar.setBarStrobe(); + mySensorBar.clearInvertBits(); + uint8_t returnStatus = mySensorBar.begin(); + printf("next, %d\r\n", returnStatus); + if(returnStatus) + { + printf("sx1509 IC communication OK"); + } + else + { + printf("i2c failed"); + wait_ms(10); + while(1); + } + + while(1) + { + uint8_t rawValue = mySensorBar.getRaw(); + + for( int i = 7; i >= 0; i-- ) + { + printf("%d", (rawValue >> i) & 0x01); + } + printf("b, "); + printf("%d\r\n", mySensorBar.getPosition()); + wait_ms(10); + } +} + +***********************************************************/ + + +SensorBar::SensorBar(I2C *i2c, uint8_t address, uint8_t resetPin, uint8_t interruptPin, uint8_t oscillatorPin) +{ + // Store the received parameters into member variables + _i2c = i2c; + deviceAddress = address; + pinInterrupt = interruptPin; + pinOscillator = oscillatorPin; + pinReset = resetPin; + invertBits = 0; + barStrobe = 0; //Default always on +} + +void SensorBar::debounceConfig(uint8_t configValue) +{ + // First make sure clock is configured + uint8_t tempuint8_t = readByte(REG_MISC); + if ((tempuint8_t & 0x70) == 0) + { + tempuint8_t |= (1 << 4); // Just default to no divider if not set + writeByte(REG_MISC, tempuint8_t); + } + tempuint8_t = readByte(REG_CLOCK); + if ((tempuint8_t & 0x60) == 0) + { + tempuint8_t |= (1 << 6); // default to internal osc. + writeByte(REG_CLOCK, tempuint8_t); + } + + configValue &= 0b111; // 3-bit value + writeByte(REG_DEBOUNCE_CONFIG, configValue); +} + +void SensorBar::debounceEnable(uint8_t pin) +{ + unsigned int debounceEnable = readWord(REG_DEBOUNCE_ENABLE_B); + debounceEnable |= (1 << pin); + writeWord(REG_DEBOUNCE_ENABLE_B, debounceEnable); +} + +//Run this once during initialization to configure the SX1509 as a sensor bar +//Returns 1 for success +uint8_t SensorBar::begin(void) +{ + uint8_t returnVar = 0; + + // Reset the SX1509 + reset(); + + // Communication test. We'll read from two registers with different + // default values to verify communication. + unsigned int testRegisters = 0; + testRegisters = readWord(REG_INTERRUPT_MASK_A); // This should return 0xFF00 + // Then read a uint8_t that should be 0x00 + if (testRegisters == 0xFF00) + { + //Success! Configure the device. + writeByte(REG_DIR_A, 0xFF); + writeByte(REG_DIR_B, 0xFC); + writeByte(REG_DATA_B, 0x01); + + returnVar = 1; + } + else + { + returnVar = 0; + } + + return returnVar; +} + +//Do a software reset +void SensorBar::reset( void ) +{ + // No hardware option, try software reset + writeByte(REG_RESET, 0x12); + writeByte(REG_RESET, 0x34); +} + +unsigned int SensorBar::interruptSource(void) +{ + unsigned int intSource = readWord(REG_INTERRUPT_SOURCE_B); + writeWord(REG_INTERRUPT_SOURCE_B, 0xFFFF); // Clear interrupts + return intSource; +} + +void SensorBar::configClock(uint8_t oscSource, uint8_t oscPinFunction, uint8_t oscFreqOut, uint8_t oscDivider) +{ + // RegClock constructed as follows: + // 6:5 - Oscillator frequency souce + // 00: off, 01: external input, 10: internal 2MHz, 1: reserved + // 4 - OSCIO pin function + // 0: input, 1 ouptut + // 3:0 - Frequency of oscout pin + // 0: LOW, 0xF: high, else fOSCOUT = FoSC/(2^(RegClock[3:0]-1)) + oscSource = (oscSource & 0b11) << 5; // 2-bit value, bits 6:5 + oscPinFunction = (oscPinFunction & 1) << 4; // 1-bit value bit 4 + oscFreqOut = (oscFreqOut & 0b1111); // 4-bit value, bits 3:0 + uint8_t regClock = oscSource | oscPinFunction | oscFreqOut; + writeByte(REG_CLOCK, regClock); + + // Config RegMisc[6:4] with oscDivider + // 0: off, else ClkX = fOSC / (2^(RegMisc[6:4] -1)) + oscDivider = (oscDivider & 0b111) << 4; // 3-bit value, bits 6:4 + uint8_t regMisc = readByte(REG_MISC); + regMisc &= ~(0b111 << 4); + regMisc |= oscDivider; + writeByte(REG_MISC, regMisc); +} + +//Call .setBarStrobing(); to only illuminate while reading line +void SensorBar::setBarStrobe( void ) +{ + barStrobe = 1; //Do strobe +} + +//Call .clearBarStrobing(); to illuminate all the time +void SensorBar::clearBarStrobe( void ) +{ + barStrobe = 0; //Always on +} + +// .setInvertBits(); to make the bar functions look for a white line on dark surface +void SensorBar::setInvertBits( void ) +{ + invertBits = 1; //Do strobe +} + +// .clearInvertBits(); to make the bar look for a dark line on a reflective surface +void SensorBar::clearInvertBits( void ) +{ + invertBits = 0; //Always on +} + +//****************************************************************************// +// +// Bar functions +// +//****************************************************************************// + +uint8_t SensorBar::getRaw( void ) +{ + //Get the information from the wire, stores in lastBarRawValue + scan(); + + return lastBarRawValue; +} + +int8_t SensorBar::getPosition( void ) +{ + //Assign values to each bit, -127 to 127, sum, and divide + int16_t accumulator = 0; + uint8_t bitsCounted = 0; + int16_t i; + + //Get the information from the wire, stores in lastBarRawValue + scan(); + + //count bits + for ( i = 0; i < 8; i++ ) + { + if ( ((lastBarRawValue >> i) & 0x01) == 1 ) + { + bitsCounted++; + } + } + + //Find the vector value of each positive bit and sum + for ( i = 7; i > 3; i-- ) //iterate negative side bits + { + if ( ((lastBarRawValue >> i) & 0x01) == 1 ) + { + accumulator += ((-32 * (i - 3)) + 1); + } + } + for ( i = 0; i < 4; i++ ) //iterate positive side bits + { + if ( ((lastBarRawValue >> i) & 0x01) == 1 ) + { + accumulator += ((32 * (4 - i)) - 1); + } + } + + if ( bitsCounted > 0 ) + { + lastBarPositionValue = accumulator / bitsCounted; + } + else + { + lastBarPositionValue = 0; + } + + return lastBarPositionValue; +} + +uint8_t SensorBar::getDensity( void ) +{ + uint8_t bitsCounted = 0; + uint8_t i; + + //get input from the I2C machine + scan(); + + //count bits + for ( i = 0; i < 8; i++ ) + { + if ( ((lastBarRawValue >> i) & 0x01) == 1 ) + { + bitsCounted++; + } + } + return bitsCounted; +} + + +//****************************************************************************// +// +// Utilities +// +//****************************************************************************// +void SensorBar::scan( void ) +{ + if( barStrobe == 1 ) + { + writeByte(REG_DATA_B, 0x02); //Turn on IR + wait_ms(2); //Additional delay required after IR is turned on to allow LEDs to achieve full brightness + writeByte(REG_DATA_B, 0x00); //Turn on feedback + } + else + { + writeByte(REG_DATA_B, 0x00); //make sure both IR and indicators are on + } + //Operate the I2C machine + lastBarRawValue = readByte( REG_DATA_A ); //Peel the data off port A + + if( invertBits == 1 ) //Invert the bits if needed + { + lastBarRawValue ^= 0xFF; + } + + if( barStrobe == 1 ) + { + writeByte(REG_DATA_B, 0x03); //Turn off IR and feedback when done + } + //delay(8); +} + +// readByte(uint8_t registerAddress) +// This function reads a single uint8_t located at the registerAddress register. +// - deviceAddress should already be set by the constructor. +// - Return value is the uint8_t read from registerAddress +// +// Currently returns 0 if communication has timed out +// +uint8_t SensorBar::readByte(uint8_t registerAddress) +{ + char readValue; + char data[2] = {registerAddress, 0}; + _i2c->write(deviceAddress, data, 1); + uint8_t val = _i2c->read(deviceAddress, &readValue, 1); + + return readValue; +} + +// readWord(uint8_t registerAddress) +// This function will read a two-uint8_t word beginning at registerAddress +// - A 16-bit unsigned int will be returned. +// - The msb of the return value will contain the value read from registerAddress +// - The lsb of the return value will contain the value read from registerAddress + 1 +unsigned int SensorBar::readWord(uint8_t registerAddress) +{ + unsigned int readValue; + unsigned int msb, lsb; + //unsigned int timeout = RECEIVE_TIMEOUT_VALUE * 2; + char data[2] = {registerAddress, 0}; + char r_data[2]; + uint8_t val = _i2c->write(deviceAddress, data, 1); + val = _i2c->read(deviceAddress, r_data, 2); + msb = ((unsigned int)r_data[0] & 0x00FF) << 8; + lsb = ((unsigned int)r_data[1] & 0x00FF); + readValue = msb | lsb; + + return readValue; +} + +// readBytes(uint8_t firstRegisterAddress, uint8_t * destination, uint8_t length) +// This function reads a series of uint8_ts incrementing from a given address +// - firstRegsiterAddress is the first address to be read +// - destination is an array of uint8_ts where the read values will be stored into +// - length is the number of uint8_ts to be read +// - No return value. +void SensorBar::readBytes(uint8_t firstRegisterAddress, char * destination, uint8_t length) +{ + char data[2] = {firstRegisterAddress, 0}; + _i2c->write(deviceAddress, data, 1); + uint8_t val = _i2c->read(deviceAddress, destination, length); +} + +// writeByte(uint8_t registerAddress, uint8_t writeValue) +// This function writes a single uint8_t to a single register on the SX509. +// - writeValue is written to registerAddress +// - deviceAddres should already be set from the constructor +// - No return value. +void SensorBar::writeByte(uint8_t registerAddress, uint8_t writeValue) +{ + char data[2] = {registerAddress, writeValue}; + _i2c->write(deviceAddress, data, 2); +} + +// writeWord(uint8_t registerAddress, ungisnged int writeValue) +// This function writes a two-uint8_t word to registerAddress and registerAddress + 1 +// - the upper uint8_t of writeValue is written to registerAddress +// - the lower uint8_t of writeValue is written to registerAddress + 1 +// - No return value. +void SensorBar::writeWord(uint8_t registerAddress, unsigned int writeValue) +{ + uint8_t msb, lsb; + msb = ((writeValue & 0xFF00) >> 8); + lsb = (writeValue & 0x00FF); + char data[3] = {registerAddress, msb, lsb}; + _i2c->write(deviceAddress, data, 3); +} + +// writeBytes(uint8_t firstRegisterAddress, uint8_t * writeArray, uint8_t length) +// This function writes an array of uint8_ts, beggining at a specific adddress +// - firstRegisterAddress is the initial register to be written. +// - All writes following will be at incremental register addresses. +// - writeArray should be an array of uint8_t values to be written. +// - length should be the number of uint8_ts to be written. +// - no return value. +void SensorBar::writeBytes(uint8_t firstRegisterAddress, uint8_t * writeArray, uint8_t length) +{ + char data[10] = {}; + data[0] = firstRegisterAddress; + for(int i = 0; i < length; i++) + { + data[1+i] = writeArray[i]; + } + _i2c->write(deviceAddress, data, length+1); +} + + +//****************************************************************************// +// +// Circular buffer +// +//****************************************************************************// + +//Construct a CircularBuffer type with arguments +// uint16_t inputSize: number of elements + +//mbed has CircularBuffer +namespace name +{ + +CircularBuffer::CircularBuffer(uint16_t inputSize) +{ + cBufferData = new int16_t[inputSize]; + cBufferLastPtr = 0; + cBufferElementsUsed = 0; + cBufferSize = inputSize; +} + +CircularBuffer::~CircularBuffer() +{ + delete[] cBufferData; +} + +//Get an element at some depth into the circular buffer +//zero is the push location. Max is cBufferSize - 1 +// +//Arguments: +// uint16_t elementNum: number of element in +// +int16_t CircularBuffer::getElement( uint16_t elementNum ) +{ + //Translate elementNum into terms of cBufferLastPtr. + int16_t virtualElementNum; + virtualElementNum = cBufferLastPtr - elementNum; + if( virtualElementNum < 0 ) + { + virtualElementNum += cBufferSize; + } + + //Output the value + return cBufferData[virtualElementNum]; +} + +//Put a new element into the buffer. +//This also expands the size up to the max size +//Arguments: +// +// int16_t elementVal: value of new element +// +void CircularBuffer::pushElement( int16_t elementVal ) +{ + //inc. the pointer + cBufferLastPtr++; + + //deal with roll + if( cBufferLastPtr >= cBufferSize ) + { + cBufferLastPtr = 0; + } + + //write data + cBufferData[cBufferLastPtr] = elementVal; + + //increase length up to cBufferSize + if( cBufferElementsUsed < cBufferSize ) + { + cBufferElementsUsed++; + } +} + +//Averages the last n numbers and provides that. Discards fractions +int16_t CircularBuffer::averageLast( uint16_t numElements ) +{ + //Add up all the elements + int32_t accumulator = 0; + int8_t i; + for( i = 0; i < numElements; i++ ) + { + accumulator += getElement( i ); + } + //Divide by number of elements + accumulator /= numElements; + return accumulator; +} + +//Returns the current size of the buffer +uint16_t CircularBuffer::recordLength( void ) +{ + return cBufferElementsUsed; +} + +} +