Помогите с программированием

gentlemanOP
Offline
Зарегистрирован: 29.07.2018

Пытаюсь запустить данный сенцор без библиотеки ( https://learn.sparkfun.com/tutorials/apds-9301-sensor-hookup-guide)  но при выдаче получаю всегда одно и тоже число ( Luminous flux: 1223223), с библиотекой все работает.

Помогите найти ошибку в коде. 
(APDS-9301 Sensor)
 

gentlemanOP
Offline
Зарегистрирован: 29.07.2018
#include <Wire.h>
#include "Arduino.h"
#if defined(ARDUINO) && ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif
#define INT_PIN 2
bool lightIntHappened = false;

#define CONTROL_REG        0x80
#define TIMING_REG         0x81
#define THRESHLOWLOW_REG   0x82
#define THRESHLOWHI_REG    0x83
#define THRESHHILOW_REG    0x84
#define THRESHHIHI_REG     0x85
#define INTERRUPT_REG      0x86
#define ID_REG             0x8A
#define DATA0LOW_REG       0x8C
#define DATA0HI_REG        0x8D
#define DATA1LOW_REG       0x8E
#define DATA1HI_REG        0x8F

  typedef enum {LOW_GAIN, HIGH_GAIN} gain;
  typedef enum {INT_TIME_13_7_MS, INT_TIME_101_MS, INT_TIME_402_MS} intTime;
  typedef enum {SUCCESS, I2C_FAILURE} status;
  typedef enum {INT_OFF, INT_ON} interruptEnable;
  typedef enum {POW_OFF, POW_ON} powEnable;

  status begin(uint8_t address);
  
  status powerEnable(powEnable powEn);
  status setGain(gain gainLevel);
  status setIntegrationTime(intTime integrationTime);
  status enableInterrupt(interruptEnable intMode);
  status clearIntFlag();
  status setCyclesForInterrupt(uint8_t cycles);
  status setLowThreshold(unsigned int threshold);
  status setHighThreshold(unsigned int threshold);
  uint8_t getIDReg();
  gain getGain();
  intTime getIntegrationTime();
  uint8_t getCyclesForInterrupt();
  unsigned int getLowThreshold();
  unsigned int getHighThreshold();
  unsigned int readCH0Level();
  unsigned int readCH1Level();
  float readLuxLevel();

  uint8_t address;
  uint8_t A;
  uint8_t getRegister(uint8_t regAddress);
  status setRegister(uint8_t regAddress, uint8_t newVal);
  uint16_t getTwoRegisters(uint8_t regAddress);
  status setTwoRegisters(uint8_t regAddress, uint16_t newVal);




void setup() {
  

     delay(2500);   
      Serial.begin(115200);
      Wire.begin();
    
      // APDS9301 sensor setup.
      begin(0x39);  
      setGain(LOW_GAIN); 
      setIntegrationTime(INT_TIME_13_7_MS); 
      setLowThreshold(0); 
      setHighThreshold(50);
      setCyclesForInterrupt(34);
      enableInterrupt(INT_ON); 
      clearIntFlag();

      
      pinMode(INT_PIN, INPUT_PULLUP); 
      attachInterrupt(digitalPinToInterrupt(2), lightInt, FALLING);
      Serial.println(getLowThreshold());
     Serial.println(getHighThreshold());
}

void loop()  
{

   

        //Serial.read();

     

  
      static unsigned long outLoopTimer = 0;
      clearIntFlag();                          

    
      if (millis() - outLoopTimer >= 2000)
      {
        outLoopTimer = millis();
    
        Serial.print("Luminous flux: ");
        Serial.println(readCH0Level(),6);

        if (lightIntHappened)
        {
          Serial.println("Interrupt");
          lightIntHappened = false;
        }
      }
    }
    
    void lightInt()
    {
      lightIntHappened = true;
    }

status begin(uint8_t A)
{
A = address;
  powerEnable(POW_ON);
  //APDS9301::status result = setGain(HIGH_GAIN);
  //if (setIntegrationTime(INT_TIME_402_MS) != SUCCESS) result = I2C_FAILURE;
  //return result;
  return SUCCESS;
}
status powerEnable(powEnable powEn)
{
  if (powEn == POW_OFF) return setRegister(CONTROL_REG, 0);
  else                  return setRegister(CONTROL_REG, 3);
}

status setGain(gain gainLevel)
{
  uint8_t regVal = getRegister(TIMING_REG);
  if (gainLevel == LOW_GAIN) regVal &= ~0x10;
  else                       regVal |= 0x10;
  return setRegister(TIMING_REG, regVal);
}

status setIntegrationTime(intTime integrationTime)
{
  uint8_t regVal = getRegister(TIMING_REG);
  regVal &= ~0x03;
  if (integrationTime == INT_TIME_13_7_MS)      regVal |= 0x00;
  else if (integrationTime == INT_TIME_101_MS)  regVal |= 0x01;
  else if (integrationTime == INT_TIME_402_MS)  regVal |= 0x02;
  return setRegister(TIMING_REG, regVal);
}

status enableInterrupt(interruptEnable intMode)
{
  uint8_t regVal = getRegister(INTERRUPT_REG);
  // This is not a typo- OFF requires bits 4&5 to be cleared, but
  //  ON only requires bit 4 to be set. I dunno why.
  if (intMode == INT_OFF) regVal &= ~0x30;
  else                    regVal |= 0x10;
  return setRegister(INTERRUPT_REG, regVal);
}

status clearIntFlag()
{
  Wire.beginTransmission(A);
  Wire.write(0xC0);
 status retVal;
  if (Wire.endTransmission() == 0) return SUCCESS;
  else return I2C_FAILURE;
}

status setCyclesForInterrupt(uint8_t cycles)
{
  uint8_t regVal = getRegister(INTERRUPT_REG);
  regVal &= ~0x0F; // clear lower four bits of register
  cycles &= ~0xF0; // ensure top four bits of data are clear
  regVal |= cycles; // Sets any necessary bits in regVal.
  return setRegister(INTERRUPT_REG, regVal);
}

status setLowThreshold(unsigned int threshold)
{
  int retVal = setTwoRegisters(THRESHLOWLOW_REG, threshold);
  if (retVal == 0) return SUCCESS;
  else             return I2C_FAILURE;
}

status setHighThreshold(unsigned int threshold)
{
  int retVal = setTwoRegisters(THRESHHILOW_REG, threshold);
  if (retVal == 0) return SUCCESS;
  else             return I2C_FAILURE;
}

uint8_t getIDReg()
{
  return getRegister(ID_REG);
}


gain getGain()
{
  uint8_t regVal = getRegister(TIMING_REG);
  regVal &= 0x10;
  if (regVal != 0) return HIGH_GAIN;
  else             return LOW_GAIN;
}

intTime getIntegrationTime()
{
  uint8_t regVal = getRegister(TIMING_REG);
  regVal &= 0x03;
  if (regVal == 0x00)       return INT_TIME_13_7_MS;
  else if (regVal == 0x01)  return INT_TIME_101_MS;
  else                      return INT_TIME_402_MS;
}

uint8_t getCyclesForInterrupt()
{
  uint8_t regVal = getRegister(INTERRUPT_REG);
  regVal &= ~0x0F;
  return regVal;
}

unsigned int getLowThreshold()
{
  unsigned int retVal = getRegister(THRESHLOWHI_REG)<<8;
  retVal |= getRegister(THRESHLOWLOW_REG);
  return retVal;
}

unsigned int getHighThreshold()
{
  unsigned int retVal = getRegister(THRESHHIHI_REG)<<8;
  retVal |= getRegister(THRESHHILOW_REG);
  return retVal;
}

unsigned int readCH0Level()
{
  return getTwoRegisters(DATA0LOW_REG);
}

unsigned int readCH1Level()
{
  return getTwoRegisters(DATA1LOW_REG);
}

float readLuxLevel()
{
  unsigned int ch1Int = readCH1Level();
  unsigned int ch0Int = readCH0Level();
  float ch0 = (float)readCH0Level();
  float ch1 = (float)readCH1Level();
  switch (getIntegrationTime())
  {
    case INT_TIME_13_7_MS:
    
    if ((ch1Int >= 5047) || (ch0Int >= 5047)) 
    {
      return 1.0/0.0;
    }
    break;
    case INT_TIME_101_MS:
    if ((ch1Int >= 37177) || (ch0Int >= 37177)) 
    {
      return 1.0/0.0;
    }
    break;
    case INT_TIME_402_MS:
    if ((ch1Int >= 65535) || (ch0Int >= 65535))
    { 
      return 1.0/0.0;
    }
    break;
  }
  float ratio = ch1/ch0;
  switch (getIntegrationTime())
  {
    case INT_TIME_13_7_MS:
    ch0 *= 1/0.034;
    ch1 *= 1/0.034;
    break;
    case INT_TIME_101_MS:
    ch0 *= 1/0.252;
    ch1 *= 1/0.252;
    break;
    case INT_TIME_402_MS:
    ch0 *= 1;
    ch1 *= 1;
    break;
  }

  if (getGain() == LOW_GAIN) 
  {
    ch0 *= 16;
    ch1 *= 16;
  }
  
  float luxVal = 0.0;
  if (ratio <= 0.5)
  {
    luxVal = (0.0304 * ch0) - ((0.062 * ch0) * (pow((ch1/ch0), 1.4)));
  }  
  else if (ratio <= 0.61)
  {
    luxVal = (0.0224 * ch0) - (0.031 * ch1);
  }
  else if (ratio <= 0.8)
  {
    luxVal = (0.0128 * ch0) - (0.0153 * ch1);
  }
  else if (ratio <= 1.3)
  {
    luxVal = (0.00146 * ch0) - (0.00112*ch1);
  }

  return luxVal;
  return 0;
}

uint8_t getRegister(uint8_t regAddress)
{
  Wire.beginTransmission(A);
  Wire.write(regAddress);
  Wire.endTransmission(false);
  Wire.requestFrom(A, (uint8_t)1);
  return Wire.read();
}

uint16_t getTwoRegisters(uint8_t regAddress)
{
  Wire.beginTransmission(A);
  Wire.write(0x20 | regAddress);
  Wire.endTransmission(false);
  Wire.requestFrom(A, (uint8_t)2);
  uint16_t regVal = Wire.read();
  return regVal | (Wire.read()<<8);
}

status setRegister(uint8_t regAddress, uint8_t newVal)
{
  Wire.beginTransmission(A);
  Wire.write(regAddress);
  Wire.write(newVal);
  if (Wire.endTransmission() == 0) return SUCCESS;
  else return I2C_FAILURE;

}

status setTwoRegisters(uint8_t regAddress, uint16_t newVal)
{
  Wire.beginTransmission(A);
  Wire.write(0x20 | regAddress);
  Wire.write((uint8_t)newVal);
  Wire.write((uint8_t)(newVal>>8));
  if (Wire.endTransmission() == 0) return SUCCESS;
  else return I2C_FAILURE;
}

 

 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А чем Вас не устраивает бибилиотека, если с нею всё работает? Она делает как-то не так? А если так, то что мешает посмотреть как делает она и сделать также?

gentlemanOP
Offline
Зарегистрирован: 29.07.2018

мне надо без, я делал с ее помощью,но по видемому где то допустил ошибку 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

"без" - у Вас гораздо больше шансов допустить не одну, а сразу много ошибок.

 

Но, в принципе, ЕвгенийП изложил самый прстой вариант переделки: посмотриеть в библиотеке и сделать так же. Есть еще более правильный вариант: изучить дэйташит и, основываясь на нем, самостоятельно написать библиотеку. Но он обычно бывает сложнее.

gentlemanOP
Offline
Зарегистрирован: 29.07.2018

я делал как в библиотеке, то есть ,практически скопировал ее, но видемо где то ошибка , не могу понять где 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

gentlemanOP пишет:

не могу понять где 

Ну, если уж Вы,  человек, который видит эту библиотеку, не можете понять, то нам-то как понимать, если мы понятия не имеем, что за библиотека и никогда её не видели? Мы и подавно не поймём.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Не поленитесь, создайте комментарии к Вашей программе. Нам станет понятнее, ну и может Вы сами найдете ошибку.

kalapanga
Offline
Зарегистрирован: 23.10.2016

Автор, прекращайте заниматься ерундой. Если Вам нужно работать с этим датчиком - используйте библиотеку!

Ну а для начала посмотрите на вызов функции в строке 68 и на саму функцию - строки 118, 120.

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

gentlemanOP пишет:

мне надо без

Библиотеки для того и пишутся, чтобы те, кто не умеет делать сам, могли ими пользоваться. Ты, похоже, не умеешь, но зачем-то тебе обязательно надо без библиотеки. Зачем? Чем она тебя не устраивает? Можешь толково объяснить?

И, да, тебе тут уже говорили, пока ты будешь сидеть как партизан и секретить что там за библиотека, тебе никто и ничто не поможет.

gentlemanOP
Offline
Зарегистрирован: 29.07.2018

Привет,мне по заданию мне надо не пользоваться библиотеками.

у меня 3 сенцора уже без библиотек,остался толко APDS-9301.
я бы с удовольствием бы оставил библиотеки, если бы мог.
И я к сожалению скинул не тот код, в этом я эксперементировал,
 

https://github.com/sparkfun/APDS-9301_Breakout/tree/master/Libraries/Ard...

с этого сайта я взял библиотеки.

 

 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

gentlemanOP, так кому задали задание, Вам или кому-то другому?

И не надо делать вид, будто Вы считаете, что форум нужен для того, чтобы кто-то делал задания за нерадивых студентов.

gentlemanOP
Offline
Зарегистрирован: 29.07.2018

ДА мне. я решил сделат все  с 0 , сообщу вам о успехах 

gentlemanOP
Offline
Зарегистрирован: 29.07.2018
status setTwoRegisters(uint8_t regAddress, uint16_t newVal);
status setHighThreshold(unsigned int threshold);
status setCyclesForInterrupt(uint8_t cycles);
status enableInterrupt(interruptEnable intMode);

unsigned int getLowThreshold();
unsigned int getHighThreshold();
unsigned int readCH0Level();
unsigned int readCH1Level();

uint8_t address;
uint8_t getIDReg();
uint8_t getRegister(uint8_t regAddress);
uint16_t getTwoRegisters(uint8_t regAddress);
uint8_t getCyclesForInterrupt();
  
  
  gain getGain();
  status clearIntFlag();
  float readLuxLevel();
  intTime getIntegrationTime();
  void lightInt()
    {
      lightIntHappened = true;
    }

void setup() 
{
      delay(5);    // The CCS811 wants a brief delay after startup.
      Serial.begin(115200);
      Wire.begin();

      begin(0x39);
      setGain(LOW_GAIN);
      setIntegrationTime(INT_TIME_13_7_MS);
      setLowThreshold(0);
      setHighThreshold(50); 
      setCyclesForInterrupt(1);
      enableInterrupt(INT_ON);
      clearIntFlag();


       pinMode(INT_PIN, INPUT_PULLUP);
      attachInterrupt(digitalPinToInterrupt(2), lightInt, FALLING);
      Serial.println(getLowThreshold());
      Serial.println(getHighThreshold());
}

void loop()
{
     static unsigned long outLoopTimer = 0;
     clearIntFlag();
      if (millis() - outLoopTimer >= 1000)
      {
        outLoopTimer = millis();
    
        Serial.print("Luminous flux: ");
        Serial.println(readCH0Level(),6);

        if (lightIntHappened)
        {
          Serial.println("Interrupt");
          lightIntHappened = false;
        }
      }
    }
    
 


status begin(uint8_t address)
{
//   this->address = address;
  powerEnable(POW_ON);
 status result = setGain(HIGH_GAIN);
 if (setIntegrationTime(INT_TIME_402_MS) != SUCCESS) result = I2C_FAILURE;
 return result;
  return SUCCESS;
}

status powerEnable(powEnable powEn)
{
  if (powEn == POW_OFF) return setRegister(CONTROL_REG, 0);
  else                  return setRegister(CONTROL_REG, 3);
}

status setRegister(uint8_t regAddress, uint8_t newVal)
{
  Wire.beginTransmission(address);
  Wire.write(regAddress);
  Wire.write(newVal);
  if (Wire.endTransmission() == 0) return SUCCESS;
  else return I2C_FAILURE;

}
status setGain(gain gainLevel)
{
  uint8_t regVal = getRegister(TIMING_REG);
  if (gainLevel == LOW_GAIN) regVal &= ~0x10;
  else                       regVal |= 0x10;
  return setRegister(TIMING_REG, regVal);
}
uint8_t getRegister(uint8_t regAddress)
{
  Wire.beginTransmission(address);
  Wire.write(regAddress);
  Wire.endTransmission(false);
  Wire.requestFrom(address, (uint8_t)1);
  return Wire.read();
}
status setIntegrationTime(intTime integrationTime)
{
  uint8_t regVal = getRegister(TIMING_REG);
  regVal &= ~0x03;
  if (integrationTime == INT_TIME_13_7_MS)      regVal |= 0x00;
  else if (integrationTime == INT_TIME_101_MS)  regVal |= 0x01;
  else if (integrationTime == INT_TIME_402_MS)  regVal |= 0x02;
  return setRegister(TIMING_REG, regVal);
}
status setLowThreshold(unsigned int threshold)
{
  int retVal = setTwoRegisters(THRESHLOWLOW_REG, threshold);
  if (retVal == 0) return SUCCESS;
  else             return I2C_FAILURE;
}
status setTwoRegisters(uint8_t regAddress, uint16_t newVal)
{
  Wire.beginTransmission(address);
  Wire.write(0x20 | regAddress);
  Wire.write((uint8_t)newVal);
  Wire.write((uint8_t)(newVal>>8));
  if (Wire.endTransmission() == 0) return SUCCESS;
  else return I2C_FAILURE;
}
status setHighThreshold(unsigned int threshold)
{
  int retVal = setTwoRegisters(THRESHHILOW_REG, threshold);
  if (retVal == 0) return SUCCESS;
  else             return I2C_FAILURE;
}
status setCyclesForInterrupt(uint8_t cycles)
{
  uint8_t regVal = getRegister(INTERRUPT_REG);
  regVal &= ~0x0F; // clear lower four bits of register
  cycles &= ~0xF0; // ensure top four bits of data are clear
  regVal |= cycles; // Sets any necessary bits in regVal.
  return setRegister(INTERRUPT_REG, regVal);
}
status enableInterrupt(interruptEnable intMode)
{
  uint8_t regVal = getRegister(INTERRUPT_REG);
  // This is not a typo- OFF requires bits 4&5 to be cleared, but
  //  ON only requires bit 4 to be set. I dunno why.
  if (intMode == INT_OFF) regVal &= ~0x30;
  else                    regVal |= 0x10;
  return setRegister(INTERRUPT_REG, regVal);
}
status clearIntFlag()
{
  Wire.beginTransmission(address);
  Wire.write(0xC0);
  status retVal;
  if (Wire.endTransmission() == 0) return SUCCESS;
  else return I2C_FAILURE;
}
uint8_t getIDReg()
{
  return getRegister(ID_REG);
}
gain getGain()
{
  uint8_t regVal = getRegister(TIMING_REG);
  regVal &= 0x10;
  if (regVal != 0) return HIGH_GAIN;
  else             return LOW_GAIN;
}
intTime getIntegrationTime()
{
  uint8_t regVal = getRegister(TIMING_REG);
  regVal &= 0x03;
  if (regVal == 0x00)       return INT_TIME_13_7_MS;
  else if (regVal == 0x01)  return INT_TIME_101_MS;
  else                      return INT_TIME_402_MS;
}

uint8_t getCyclesForInterrupt()
{
  uint8_t regVal = getRegister(INTERRUPT_REG);
  regVal &= ~0x0F;
  return regVal;
}

unsigned int getLowThreshold()
{
  unsigned int retVal = getRegister(THRESHLOWHI_REG)<<8;
  retVal |= getRegister(THRESHLOWLOW_REG);
  return retVal;
}
unsigned int getHighThreshold()
{
  unsigned int retVal = getRegister(THRESHHIHI_REG)<<8;
  retVal |= getRegister(THRESHHILOW_REG);
  return retVal;
}

unsigned int readCH0Level()
{
  return getTwoRegisters(DATA0LOW_REG);
}

unsigned int readCH1Level()
{
  return getTwoRegisters(DATA1LOW_REG);
}

float readLuxLevel()
{
  unsigned int ch1Int = readCH1Level();
  unsigned int ch0Int = readCH0Level();
  float ch0 = (float)readCH0Level();
  float ch1 = (float)readCH1Level();
  switch (getIntegrationTime())
  {
    case INT_TIME_13_7_MS:
    
    if ((ch1Int >= 5047) || (ch0Int >= 5047)) 
    {
      return 1.0/0.0;
    }
    break;
    case INT_TIME_101_MS:
    if ((ch1Int >= 37177) || (ch0Int >= 37177)) 
    {
      return 1.0/0.0;
    }
    break;
    case INT_TIME_402_MS:
    if ((ch1Int >= 65535) || (ch0Int >= 65535))
    { 
      return 1.0/0.0;
    }
    break;
  }
  float ratio = ch1/ch0;
  switch (getIntegrationTime())
  {
    case INT_TIME_13_7_MS:
    ch0 *= 1/0.034;
    ch1 *= 1/0.034;
    break;
    case INT_TIME_101_MS:
    ch0 *= 1/0.252;
    ch1 *= 1/0.252;
    break;
    case INT_TIME_402_MS:
    ch0 *= 1;
    ch1 *= 1;
    break;
  }

  if (getGain() == LOW_GAIN) 
  {
    ch0 *= 16;
    ch1 *= 16;
  }
  
  float luxVal = 0.0;
  if (ratio <= 0.5)
  {
    luxVal = (0.0304 * ch0) - ((0.062 * ch0) * (pow((ch1/ch0), 1.4)));
  }  
  else if (ratio <= 0.61)
  {
    luxVal = (0.0224 * ch0) - (0.031 * ch1);
  }
  else if (ratio <= 0.8)
  {
    luxVal = (0.0128 * ch0) - (0.0153 * ch1);
  }
  else if (ratio <= 1.3)
  {
    luxVal = (0.00146 * ch0) - (0.00112*ch1);
  }

  return luxVal;
  return 0;
}



uint16_t getTwoRegisters(uint8_t regAddress)
{
  Wire.beginTransmission(address);
  Wire.write(0x20 | regAddress);
  Wire.endTransmission(false);
  Wire.requestFrom(address, (uint8_t)2);
  uint16_t regVal = Wire.read();
  return regVal | (Wire.read()<<8);
}

 

gentlemanOP
Offline
Зарегистрирован: 29.07.2018
к сожалению как и было на видаче 
65535
65535
Luminous flux: 1223223
Luminous flux: 1223223
Luminous flux: 1223223
 так и осталось ,придется все таки с библиотекой делать , сапасибо вам за помощь
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

gentlemanOP пишет:
придется все таки с библиотекой делать
А как же задание?

gentlemanOP
Offline
Зарегистрирован: 29.07.2018

на самом деле буду пытаться , но если нет то нет

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Понятно.

kalapanga
Offline
Зарегистрирован: 23.10.2016

Попробую ещё раз намекнуть... Вызвав в самом начале, в строке 33 функцию begin, Вы быстренько попадёте в функцию setRegister. Сами проследите как. Теперь вопрос - строка 89 - чему равна переменная address? Ответ - она равна нулю. Ничего другого Вы ей нигде не присвоили. То же самое касается getRegister. Если бы Вы проверяли значения, возвращаемые Вашими функциями, то ошибка всплыла бы на стадии инициализации устройства.

gentlemanOP
Offline
Зарегистрирован: 29.07.2018

Spasibo 

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Доброго времени суток, если не затруднит объясните почему в строке 215 при присвоении switchPointer = current_menu; выпадает ошибка о несовместимости типов

(sketch_aug14a.ino:215:22: error: invalid conversion from 'unsigned char' to 'switchVariants' [-fpermissive] Ошибка компиляции.)

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

//настройка параметров работы функций
#define BTN_LOCK_TIME         30           /*время обработки дребезга в милисекундах (10-100)*/
#define BTN_LONG_TIME         1000         /*время фиксации длинного нажатия в милисекундах (1000 - 2500)*/
 
//настройки портов
#define BTN_PORT        PORTB                    /*порт чтения кнопок*/
#define BTN_DDR         DDRB
#define BTN_PIN         PINB 

#define BTN_LINE_DN     (1<<0)                /*пины чтения кнопок*/
#define BTN_LINE_UP     (1<<1)
#define BTN_LINE_OK     (1<<2)
#define BTN_LINE_LEFT   (1<<3)
#define BTN_LINE_RIGHT  (1<<4)
#define BTN_LINE_CANSEL (1<<5)

//глобальные переменные
volatile uint8_t BtnFlags;                         //байт флагов нажатия кнопки    
    #define BTN_SHRT_DN      (1<<0)                /*бит короткого нажатия кнопки up*/ 
    #define BTN_SHRT_UP      (1<<1)                /*бит короткого нажатия кнопки dn*/ 
    #define BTN_SHRT_OK      (1<<2)                /*бит короткого нажатия кнопки up*/ 
    #define BTN_SHRT_LEFT    (1<<3)                /*бит короткого нажатия кнопки left*/ 
    #define BTN_SHRT_RIGHT   (1<<4)                /*бит короткого нажатия кнопки right*/ 
    #define BTN_SHRT_CANSEL  (1<<5)                /*бит короткого нажатия кнопки right*/

//#######################################################################################################################
uint8_t buttonCount = 0;          // счетчик нажатий кнопки

unsigned char current_menu=0; //Переменная указывает на текущее меню
unsigned char current_poz=0; //Переменная указывает на текущий Punkt меню/подменю
char last_item;
unsigned char f;

//#######################################################################################################################
//------------------------------------------
typedef void (*FuncPtr)(void);
//указатель на функции
FuncPtr FPtr;
//Структура описывает текущее состояние меню и подменю
struct Menu_State{
   uint8_t menu;//1,2,3,4
   uint8_t submenu;//1,2,3
}MN;

typedef struct _selection
{
  unsigned char ent_f : 4; //Флаг входа 4 бита — обычно ID меню в которое надо войти
  unsigned char esc_f : 4; //Флаг выхода 4 бита — обычно ID меню в которое надо вернуться
}SELECTION;

typedef struct _menu {
  //unsigned char id; //Номер меню/подменю
  //unsigned char num_selections; //Количество Punktов данного меню/подменю
  SELECTION *m; //Указатель намассив пунктов данного меню/подменю
} PAGE_MENU;

enum switchVariants : byte  {  // Определения для переключателя пунктов меню;
  MAIN_MENU, MENU_MANUAL, MENU_AUTO, MENU_SETUP, MENU_DEBUG//, EXITSAVE
};
switchVariants switchPointer = MAIN_MENU; // С чего начнем цикл;

enum manuState : byte {  // Определения для переключателя ручного режима;
  EDIT_PARAM, HEAT_ZONE, COOL_ZONE, STOP_PROCESS, EXIT_PROCESS
};
manuState mode = EDIT_PARAM; // С чего начнем цикл;

static SELECTION menu_m0[]={
{MENU_MANUAL , MAIN_MENU},// изд 521(1)
};
static SELECTION menu_m1[]={
{MENU_AUTO, MAIN_MENU}, //Punkt 2
};
static SELECTION menu_m2[]={
{MENU_SETUP, MAIN_MENU} //Punkt 1
};
static SELECTION menu_m3[]={
{MENU_DEBUG, MAIN_MENU}
};

static PAGE_MENU menu[] = {
  menu_m0, //Меню 1
  menu_m1, //Меню 2
  menu_m2, //Меню 3
  menu_m3  //Меню 4
};

const uint8_t MN000[] PROGMEM="REWORK v05\0";
//меню 1
const uint8_t MN100[] PROGMEM="SETTINGS\0";
//подпункт меню
const uint8_t MN101[] PROGMEM="STEPS:\0";
const uint8_t MN102[] PROGMEM="DWELL:\0";
const uint8_t MN103[] PROGMEM="PWR:\0";
const uint8_t MN104[] PROGMEM="RAMP:\0";
const uint8_t MN105[] PROGMEM="TARGET:\0";
//меню 2
const uint8_t MN200[] PROGMEM="All\0";
//подпункт меню 2
const uint8_t MN201[] PROGMEM="ON\0";
const uint8_t MN202[] PROGMEM="OFF\0";
//меню 3
const uint8_t MN300[] PROGMEM="Auto\0";
//подпункт меню 3
const uint8_t MN301[] PROGMEM="Left\0";
//меню 4
const uint8_t MN400[] PROGMEM="Blink\0";
//подпункт меню 4
const uint8_t MN401[] PROGMEM="Fast\0";
//Массивы указателей на строки меню, хранящиеся на флэш
const uint8_t *MENU[] ={
    MN100,  //menu 1 string
    MN200,  //menu 2 string
    MN300,  //menu 3 string
    MN400 //menu 4 string
};
const uint8_t *SUBMENU[] ={
    MN101, MN102, MN103, MN104, MN105,  //подпункты меню 1
    MN201, MN202,                       //подпункты меню 2
    MN301,                              //подпункты меню 3
    MN401,                              //подпункты меню 4
};

//Структура меню
//[0] -Number of level 0 menu items
//[1]...[n] number of second level menu items
//Eg. MSTR2[1] shows that menu item 1 has 3 submenus
const uint8_t MSTR2[] PROGMEM ={
  4,  // количество пунктов меню
  5,  //Количество подпунктов в пункте меню 1
  2,  //Количество подпунктов в пункте меню 2
  1,  //Количество подпунктов в пункте меню 3
  1 //Количество подпунктов в пункте меню 4
  }; 
//Прототипы функций
//Инициализация Timer2 
void init_timer2(void);
//Начальное меню
void menu_Init(void);
//Назначаем порты для кнопок и светодиодов
void ports_Init(void);
//Функции для каждого пункта меню
void func101(void);
void func102(void);
void func103(void);
void func104(void);
void func105(void);
void func201(void);
void func202(void);
void func301(void);
void func401(void);

//#define NULL_FUNC  (void*)0

//Массив указателей на функции во флэш
const FuncPtr FuncPtrTable[] PROGMEM=
{   
  func101, func102, func103, func104, func105,  //functions for submenus of menu 1
  func201, func202,     //functions for submenus of menu 2
  func301,             //functions for submenus of menu 3
  func401              //functions for submenus of menu 4
};
//SubMenu and Function table pointer update
uint8_t MFIndex(uint8_t, uint8_t);
//------------------------------------------
uint8_t pageNum = 0;          // счетчик нажатий кнопки

ISR(TIMER2_COMPA_vect)
{
    BtnExe();
}

//#######################################################################################################################

void setup() {
  //Serial.begin(9600);
  lcd.begin(20, 4);
  lcd.home();
  //Приветствие
  CopyStringtoLCD(MN000, 3, 1);
  _delay_ms(100);
  lcd.clear();
  //Настройка таймера 2
  ports_Init();
  init_timer2(); // каждые 100 Гц
  sei(); // разрешаем прерывания глобально interrupts(); 
}

void loop() {
  
  char BtnMask = BtnGet();

  /*
  lcd.clear();
  //Display menu item
  CopyStringtoLCD(MENU[MN.menu-1], 0, 0 );
  //Display submenu item
  CopyStringtoLCD(SUBMENU[MFIndex(MN.menu, MN.submenu)], 0, 1 );
  //Assign function to function pointer
  FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[MFIndex(MN.menu, MN.submenu)]);
  */

  if (BtnMask == BTN_SHRT_OK)     
  { 
       current_menu=menu[buttonCount].m[0].ent_f;
      
       switchPointer = current_menu;
    
  }//обработка короткого нажатия ВВЕРХ
  
  if (BtnMask == BTN_SHRT_CANSEL)   
  { 
       
  }//обработка короткого нажатия ВЛЕВО
    
  switch (switchPointer)  // Все делаем в одном операторе и одной функции;
  {
    case MAIN_MENU:  /***************** Главное меню ***************/
    
    startMenu(); //формирование меню
    
    if (BtnMask == BTN_SHRT_UP)     
    { 
    
    }//обработка короткого нажатия ВВЕРХ
    
    if (BtnMask == BTN_SHRT_DN)     { }//обработка короткого нажатия ВНИЗ
    
    if (BtnMask == BTN_SHRT_RIGHT) //обработка короткого нажатия ВПРАВО
    {
       buttonCount++;  // с каждым нажатием buttonCount++ пока buttonCount<4
       if (buttonCount > 3) buttonCount = 0;
    }
    
    if (BtnMask == BTN_SHRT_LEFT)   { }//обработка короткого нажатия ВЛЕВО

    break;
    
    case MENU_MANUAL: /***************** Ручной режим ***************/
    
      switch (mode) { // Выбор режима работы ручного режима
        case EDIT_PARAM: // Режим редактирования

        break;

        case HEAT_ZONE:
        
        break;
        
        case COOL_ZONE:

        break;
        
        case STOP_PROCESS:
          
        break;
      }
          
          
    break;
    
    case MENU_AUTO: /***************** Автоматический режим ***************/

    break;
    
    case MENU_SETUP: /***************** Настройки ***************/

    break;
    
    case MENU_DEBUG: /***************** Настройки ***************/
    
    break;
  }
}

//####################################################################################################################### 
//-----------------------------------------------------------------------------------------------------------------------
//функция настройки библиотеки работы с кнопками
void ports_Init(void)
{    
    BTN_DDR &= ~(BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_OK| BTN_LINE_LEFT| BTN_LINE_RIGHT| BTN_LINE_CANSEL);    // кнопки на ввод
    BTN_PORT |= (BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_OK| BTN_LINE_LEFT| BTN_LINE_RIGHT| BTN_LINE_CANSEL);    //подтяжка вкл
}
//-----------------------------------------------------------------------------------------------------------------------
static void init_timer2(void)
{
  TCCR2B=0; // таймер2 остановлен
  TCNT2=0; //счётный регистр обнулён
  OCR2B=0;
  TIFR2&=0xff; //отчистить флаги прерываний
  TCCR2A = (1<<WGM21);    // Режим CTC (сброс по совпадению)
  TCCR2B = (1<<CS20)|(1<<CS21)|(1<<CS22); // CLK/1024
  OCR2A = 155;
  TIMSK2 = (1<<OCIE2A);  // Разрешить прерывание по совпадению
}
//-----------------------------------------------------------------------------------------------------------------------
//функция чтения данных о нажатии кнопок
char BtnGet (void)
{
    cli();
    char temp = BtnFlags;
    BtnFlags = 0;
    sei();
    return temp;
}
 
 
//-----------------------------------------------------------------------------------------------------------------------
//ФУНКЦИЯ ОБРАБОТКИ НАЖАТИЙ КЛАВИШ (вызывать в прерывании с частотой 100 Гц)
//короткое нажатие устанавливает бит BTN_SHRT_X глобальной переменной BtnFlags
//длинное нажатие устанавливает бит BTN_LONG_X глобальной переменной BtnFlags
void BtnExe (void)
{    
    static unsigned char BtnLockBit = 0;             //защелка (защита от дребезга)
    static unsigned char BtnLockCount = 0;            //счетчик защелки (защита от дребезга)
    static unsigned char BtnLongCount = 0;            //счетчик длинного нажатия
    static unsigned char BtnLastState= 0;            //последнее состояние кнопок перед отпусканием
 
    char mask = 0;
    
    if (! (BTN_PIN & BTN_LINE_DN))        mask = BTN_SHRT_DN;
    if (! (BTN_PIN & BTN_LINE_UP))        mask = BTN_SHRT_UP;
    if (! (BTN_PIN & BTN_LINE_OK))        mask = BTN_SHRT_OK;
    if (! (BTN_PIN & BTN_LINE_LEFT))      mask = BTN_SHRT_LEFT;
    if (! (BTN_PIN & BTN_LINE_RIGHT))     mask = BTN_SHRT_RIGHT;
    if (! (BTN_PIN & BTN_LINE_CANSEL))    mask = BTN_SHRT_CANSEL;
    
    if (mask){                                    //опрос состояния кнопки
        if (BtnLockCount < (BTN_LOCK_TIME/10)){    //клавиша нажата
            BtnLockCount++;
            return;                                //защелка еще не дощитала - возврат
        }
        BtnLastState = mask;
        BtnLockBit =1;                            //нажатие зафиксировано                
        //if (BtnLongCount >= (BTN_LONG_TIME/10))                                
        //    return;                                //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше        
        //if (++BtnLongCount >= (BTN_LONG_TIME/10))
        //    BtnFlags |= (BtnLastState<<4);        //счетчик досчитал до максимума - устанавливаем биты длинного нажатия 
    }            
    else{                                        //клавиша отжата            
        if (BtnLockCount){
            BtnLockCount --;
            return;                                //защелка еще не обнулилась - возврат
        }
        if (! BtnLockBit)                        //СТАТИЧЕСКИЙ ВОЗВРАТ
            return;                                
        BtnLockBit =0;                            //отжатие зафиксировано
        if (BtnLongCount < (BTN_LONG_TIME/10))
            BtnFlags |= BtnLastState;            //установка бита короткого нажатия
        //BtnLongCount = 0;                        //сброс счетчика длительности нажатия
    }
}    

void CopyStringtoLCD(const uint8_t *FlashLoc, uint8_t x, uint8_t y)
{
  uint8_t i;
  lcd.setCursor(x,y);
  for(i=0;(uint8_t)pgm_read_byte(&FlashLoc[i]);i++)
  {
    lcd.write((uint8_t)pgm_read_byte(&FlashLoc[i]));
  }
}
//------------------------------------------

void menu_Init(void)
{
  MN.menu=1;//MN.menu=buttonCount+1;
  MN.submenu=1;
  lcd.clear();
  CopyStringtoLCD(MENU[(MN.menu-1)], 0, 0 );
  CopyStringtoLCD(SUBMENU[(MN.submenu-1)], 0, 1 );
  //FPtr=(FuncPtr)pgm_read_word(&FuncPtrTable[0]);
}
//------------------------------------------
uint8_t MFIndex(uint8_t mn, uint8_t sb)
{
  uint8_t p=0;//points to menu in table of function pointer 
  for(uint8_t i=0; i<(mn-1); i++)
  {
    p=p+pgm_read_byte(&MSTR2[i+1]);
  }
  p=p+sb-1;
  return p;
}

//------------------------------------------
void func101(void)
{

}
void func102(void)
{

}
void func103(void)
{

}
void func104(void)
{

}
void func105(void)
{

}
void func201(void)
{

}
void func202(void)
{

}
void func301(void)
{

}
void func302(void)
{

}
void func401(void)
{

}
void func402(void)
{

}

void setString(unsigned char *bcount) {
  static uint8_t pos_y_curs = 4;
  
  lcd.setCursor(0, *bcount);
  lcd.write(62);
  if (bcount == 0) *bcount = pos_y_curs;
  lcd.setCursor(0, *bcount - 1);
  lcd.write(32);
}

void startMenu(){
  
  setString(&buttonCount); // включаем отображение стрелки выбора меню
  
  lcd.setCursor(1, 0); // 1 строка
  lcd.print(F("PY HO ")); // ручной режим
  lcd.setCursor(1, 1); // 2 строка
  lcd.print(F("ABTOMAT  ECK")); // автоматический режим
  lcd.setCursor(1, 2); // 3 строка
  lcd.print(F("HACTPO K ")); // настройки
  lcd.setCursor(1, 3); // 4 строка
  lcd.print(F("OT A KA")); // отладка
}

 

xDriver
xDriver аватар
Offline
Зарегистрирован: 14.08.2015

потому что пытаетесь типу switchVariants присвоить unsigned char

я не смотрел внимательно может поможет

switchPointer = (switchVariants) current_menu;

да и init_timer2 объявлена как void, а реализация как static void, думаю тоже ругнется.

BuonanotteMasha
BuonanotteMasha аватар
Offline
Зарегистрирован: 02.01.2018

Спасибо,  помогло.  Насчет static void забыл убрать когда переносил код, буду внимательнее