Библиотека датчиков света TCS3471 - PullRequest
0 голосов
/ 08 марта 2019

Я пытаюсь связаться по шине I2C от Arduino Mega с этим датчиком света. Я нашел эту библиотеку для I2C онлайн (написана на c ++), но я не знаю, как перевести ее на язык c. Я программирую в Atmel Studio 7.0. Микроконтроллер внутри моего Arduino - Atmega2560. Я уже создал загрузчик для загрузки программы из IDE Atmel.

Вот код:


TCS3471.C:


#include "TCS3471.h"

TCS3471::TCS3471(void (*i2cWriteFunc)(byte,byte,byte*),void (*i2cReadFunc)(byte,byte,byte*))
{
    _i2cWrite = i2cWriteFunc;
    _i2cRead = i2cReadFunc;
    _detected = false;
    _i2cAddress = 0;
}

bool TCS3471::detect()
{
    if (_detected)
        return true;
    else
    {
        _i2cAddress = TCS3471_ADDRESS_1;
        byte tmpaddr = read8(TCS3471_ID_REG);
        if (tmpaddr == 0x14 || tmpaddr == 0x1D)
            {
                _detected = true;
            }
        else
            {
                _i2cAddress = TCS3471_ADDRESS_2;
                tmpaddr = read8(TCS3471_ID_REG);
                if (tmpaddr == 0x14 || tmpaddr == 0x1D)
                    {
                        _detected = true;
                    }
                else
                    {
                        _i2cAddress = 0;
                    }
            }
    }
    return _detected;
}

bool TCS3471::enable()
{
    detect();
    if (_detected)
    {
        write8(TCS3471_ENABLE_REG, read8(TCS3471_ENABLE_REG) | TCS3471_PON_BIT);
        delay(3);
        write8(TCS3471_ENABLE_REG, read8(TCS3471_ENABLE_REG) | TCS3471_AEN_BIT);
        return true;
    }
    else
        return false;
}

void TCS3471::disable()
{
    if (_detected)
    {
        write8(TCS3471_ENABLE_REG, read8(TCS3471_ENABLE_REG) & ~(TCS3471_PON_BIT | TCS3471_AEN_BIT));
    }
}

void TCS3471::setIntegrationTime(float integrationTime)
{
    if (_detected)
    {
        word aTime = (word)(integrationTime * 10);
        aTime = aTime / 24;
        if (aTime > 256)
            aTime = 256;
        aTime = aTime - 256;
        write8(TCS3471_ATIME_REG, (byte)aTime);
    }
}

void TCS3471::setWaitTime(float waitTime)
{
    if (_detected)
    {
        int32_t wTime = (int32_t)(waitTime * 10);
        if (wTime < 24)
        {
            write8(TCS3471_ENABLE_REG, read8(TCS3471_ENABLE_REG) & ~TCS3471_WEN_BIT);
            return;
        }
        else if (wTime > 6144)
        {
            write8(TCS3471_CONFIG_REG, TCS3471_WLONG_BIT);
            if (wTime > 73728)
                wTime = 73728;
            wTime = wTime / 288;
        }
        else
        {
            write8(TCS3471_CONFIG_REG, 0x00);
            wTime = wTime / 24;
        }
        wTime = 256 - wTime;
        write8(TCS3471_WTIME_REG, (byte)wTime);
        write8(TCS3471_ENABLE_REG, read8(TCS3471_ENABLE_REG) | TCS3471_WEN_BIT);
    }
}

void TCS3471::setGain(tcs3471Gain_t gain)
{
    if (_detected)
    {
        write8(TCS3471_CONTROL_REG, gain);
    }
}

void TCS3471::enableInterrupt()
{
    if (_detected)
    {
        write8(TCS3471_ENABLE_REG, read8(TCS3471_ENABLE_REG) | TCS3471_AIEN_BIT);
    }
}

void TCS3471::disableInterrupt()
{
    if (_detected)
    {
        write8(TCS3471_ENABLE_REG, read8(TCS3471_ENABLE_REG) & ~TCS3471_AIEN_BIT);
    }
}

void TCS3471::clearInterrupt()
{
    if (_detected)
    {
        _i2cBuffer[0] = TCS3471_COMMAND_BIT | TCS3471_SPECIAL_BIT | TCS3471_INTCLEAR_BIT;
        _i2cWrite(_i2cAddress,1,_i2cBuffer);
    }
}

void TCS3471::interruptHighThreshold(word highThreshold)
{
    if (_detected)
    {
        write16(TCS3471_AIHTL_REG,highThreshold);
    }
}

void TCS3471::interruptLowThreshold(word lowThreshold)
{
    if (_detected)
    {
        write16(TCS3471_AILTL_REG,lowThreshold);
    }
}

void TCS3471::interruptPersistence(byte persistence)
{
    if (_detected)
    {
        byte valueToWrite = persistence;
        if (valueToWrite > 60)
            valueToWrite = 60;
        if (valueToWrite > 3)
            valueToWrite = valueToWrite / 5 + 3;
        write8(TCS3471_PERS_REG,valueToWrite & 0x0F);
    }
}

byte TCS3471::getChipID()
{
    detect();
    if (_detected)
    {
        return read8(TCS3471_ID_REG);
    }
    else
        return 0;
}

bool TCS3471::rgbcValid()
{
    if (_detected)
    {
        return (read8(TCS3471_STATUS_REG) & TCS3471_AVALID_BIT) == TCS3471_AVALID_BIT;
    }
    else
        return false;
}

word TCS3471::readCData()
{
    if (_detected)
    {
        return read16(TCS3471_CDATA_REG);
    }
    return 0;
}

word TCS3471::readRData()
{
    if (_detected)
    {
        return read16(TCS3471_RDATA_REG);
    }
    return 0;
}

word TCS3471::readGData()
{
    if (_detected)
    {
        return read16(TCS3471_GDATA_REG);
    }
    return 0;
}

word TCS3471::readBData()
{
    if (_detected)
    {
        return read16(TCS3471_BDATA_REG);
    }
    return 0;
}

void TCS3471::write8(byte reg, byte val)
{
    _i2cBuffer[0] = TCS3471_COMMAND_BIT | reg;
    _i2cBuffer[1] = val;
    _i2cWrite(_i2cAddress,2,_i2cBuffer);
}

void TCS3471::write16(byte reg, word val)
{
    _i2cBuffer[0] = TCS3471_COMMAND_BIT | TCS3471_AUTOINCR_BIT | reg;
    _i2cBuffer[1] = val & 0xFF;
    _i2cBuffer[2] = (val >> 8) & 0xFF;
    _i2cWrite(_i2cAddress,3,_i2cBuffer);
}

byte TCS3471::read8(byte reg)
{
    _i2cBuffer[0] = TCS3471_COMMAND_BIT | reg;
    _i2cWrite(_i2cAddress, 1, _i2cBuffer);
    _i2cRead(_i2cAddress, 1, _i2cBuffer);
    return _i2cBuffer[0];
}

word TCS3471::read16(byte reg)
{
    _i2cBuffer[0] = TCS3471_COMMAND_BIT | TCS3471_AUTOINCR_BIT | reg;
    _i2cWrite(_i2cAddress, 1, _i2cBuffer);
    _i2cRead(_i2cAddress, 2, _i2cBuffer);
    word ret = _i2cBuffer[1] << 8;
    ret |= _i2cBuffer[0];
    return ret;
}

TCS3471.H


#ifndef TCS3471_h
#define TCS3471_h

#if defined(ARDUINO) && ARDUINO >= 100
    #include "Arduino.h"
#else
    #include "WProgram.h"
#endif

// slave address
#define TCS3471_ADDRESS_1   0x29
#define TCS3471_ADDRESS_2   0x39

// registers
#define TCS3471_ENABLE_REG  0x00
#define TCS3471_ATIME_REG   0x01
#define TCS3471_WTIME_REG   0x03
#define TCS3471_AILTL_REG   0x04
#define TCS3471_AILTH_REG   0x05
#define TCS3471_AIHTL_REG   0x06
#define TCS3471_AIHTH_REG   0x07
#define TCS3471_PERS_REG    0x0C
#define TCS3471_CONFIG_REG  0x0D
#define TCS3471_CONTROL_REG 0x0F
#define TCS3471_ID_REG      0x12
#define TCS3471_STATUS_REG  0x13
#define TCS3471_CDATA_REG   0x14
#define TCS3471_CDATAH_REG  0x15
#define TCS3471_RDATA_REG   0x16
#define TCS3471_RDATAH_REG  0x17
#define TCS3471_GDATA_REG   0x18
#define TCS3471_GDATAH_REG  0x19
#define TCS3471_BDATA_REG   0x1A
#define TCS3471_BDATAH_REG  0x1B

// command register bits
#define TCS3471_COMMAND_BIT  0x80
#define TCS3471_AUTOINCR_BIT 0x20
#define TCS3471_SPECIAL_BIT  0x60
#define TCS3471_INTCLEAR_BIT 0x06

// enable register bits
#define TCS3471_AIEN_BIT     0x10
#define TCS3471_WEN_BIT      0x08
#define TCS3471_AEN_BIT      0x02
#define TCS3471_PON_BIT      0x01

// configuration register bits
#define TCS3471_WLONG_BIT    0x02

// control register bits
typedef enum
{
    TCS3471_GAIN_1X = 0x00,
    TCS3471_GAIN_4X = 0x01,
    TCS3471_GAIN_16X = 0x02,
    TCS3471_GAIN_60X = 0x03,
}
tcs3471Gain_t;

// ID register values
#define TCS3471_1_5_VALUE    0x14
#define TCS3471_3_7_VALUE    0x1D

// status register bits
#define TCS3471_AINT_BIT     0x10
#define TCS3471_AVALID_BIT   0x01

class TCS3471
{
public:
    TCS3471(void (*i2cWriteFunc)(byte,byte,byte*),void (*i2cReadFunc)(byte,byte,byte*));
    bool detect();
    bool enable();
    void disable();
    void setIntegrationTime(float integrationTime);
    void setWaitTime(float waitTime);
    void setGain(tcs3471Gain_t gain);
    void enableInterrupt();
    void disableInterrupt();
    void clearInterrupt();
    void interruptHighThreshold(word highThreshold);
    void interruptLowThreshold(word lowThreshold);
    void interruptPersistence(byte persistence);
    byte getChipID();
    bool rgbcValid();
    word readCData();
    word readRData();
    word readGData();
    word readBData();

    void write8(byte reg, byte val);
    void write16(byte reg, word val);
    byte read8(byte reg);
    word read16(byte reg);
private:
    byte _i2cBuffer[3];
    bool _detected;
    byte _i2cAddress;

    void (*_i2cWrite)(byte,byte,byte*);
    void (*_i2cRead)(byte,byte,byte*);
};

#endif

1 Ответ

0 голосов
/ 08 марта 2019

Что касается открытого кода, библиотека, похоже, не слишком полагается на функции ООП C ++. ИМХО, большая часть кода может быть транслитерирована на C без особых усилий. Итак, я хочу показать принципы, которые я бы применил для этого.

Образец класса C ++ CPlusPlusThing:

#include <iostream>

class CPlusPlusThing {
  private:
    int member1;
    int member2;
  public:
    CPlusPlusThing(int member1, int member2):
      member1(member1), member2(member2)
    { }

    void setMember1(int value) { member1 = value; }
    void setMember2(int value) { member2 = value; }

    void print();
};

void CPlusPlusThing::print()
{
  std::cout
    << "CPlusPlusThing {\n"
    << "  member1: " << member1 << '\n'
    << "  member2: " << member2 << '\n'
    << "}\n";
}

и краткий пример применения:

int main()
{
  { CPlusPlusThing thing(123, 0);
    thing.setMember2(321);
    thing.print();
  }
  { CPlusPlusThing *pThing = new CPlusPlusThing(234, 0);
    pThing->setMember2(432);
    pThing->print();
    delete pThing;
  }
  return 0;
}

Скомпилировано и протестировано:

CPlusPlusThing {
  member1: 123
  member2: 321
}
CPlusPlusThing {
  member1: 234
  member2: 432
}

Демонстрация в реальном времени на coliru

При транслитерации этого на C необходимо учитывать следующие моменты:

  1. Нет конструкторов / деструкторов в C. & rarr; Если конструктор просто инициализирует элементы, простая инициализация также подойдет. В противном случае должна быть предоставлена ​​функция инициализации.

  2. В C. нет функций-членов & & rarr; Оставляя virtual функции в стороне, функция-член - это не что иное, как функция с неявным аргументом this. Таким образом, аргумент this инициализируется выражением для левого операнда . или -> в вызове функции-члена. В С соотв. указатель становится только первым аргументом. Когда this неявно применяется внутри функции-члена всякий раз, когда это уместно, это не возможно в C. Это должно быть сделано вместо этого явно.

  3. В C ++ отдельные классы могут предоставлять функции-члены с одинаковыми именами. Вызов функции-члена выберет правильный в зависимости от типа левого операнда . или ->. Нет шансов в C. У разных функций должны быть разные имена. Обычный обходной путь - включить имя класса в имя функции для API C.

Так вот, как мог бы выглядеть приведенный выше пример в C:

#include <stdio.h>
#include <stdlib.h>

typedef struct {
  int member1;
  int member2;
} CThing;

CThing* newCThing(int member1, int member2)
{
  CThing *pThis = malloc(sizeof (CThing));
  if (pThis) {
    pThis->member1 = member1;
    pThis->member2 = member2;
  }
  return pThis;
}

void deleteCThing(CThing *pThis)
{
  free(pThis);
}

void setCThingMember1(CThing *pThis, int member1)
{
  pThis->member1 = member1;
}

void setCThingMember2(CThing *pThis, int member2)
{
  pThis->member2 = member2;
}

void printCThing(CThing *pThis)
{
  printf(
    "CThing {\n"
    "  member1: %d\n"
    "  member2: %d\n"
    "}\n",
    pThis->member1, pThis->member2);
}

и соответствующий пример приложения:

int main()
{
  { CThing thing = { 123, 0 };
    setCThingMember2(&thing, 321);
    printCThing(&thing);
  }
  { CThing *pThing = newCThing(234, 0);
    setCThingMember2(pThing, 432);
    printCThing(pThing);
    deleteCThing(pThing);
  }
  return 0;
}

Скомпилировано и протестировано:

CThing {
  member1: 123
  member2: 321
}
CThing {
  member1: 234
  member2: 432
}

Живой Демон на колиру

...