Уменьшить размер скетча (кода) ARDUINO

Yurchik26
Offline
Зарегистрирован: 16.03.2013

Помогите пожалуйста уменьшить код.

#define PIN_out       2    // Выход на RF модуль (digital)
#define Btn0000_Pin   3    // Вход, на котором кнопка (digital)

#define DeviceFunction  0  // Поле DevFunc 16-битного пакета

#define InWait_TimeOut            4   // seconds - время между пакетами,
                                      // когда от датчика нет срабатываний
#define AccelerateTimes           40  // times of accelerated trasmission
                                      // (кол-во ускоренных передач пакетов,
                                      // когда датчик сработал)
                                      
#define lvl_0    LOW
boolean lvl_1 = !lvl_0;


#define pilotPeriod     1200
#define HPeriod         500
#define LPeriod         2000


void setup() {    
   DDRB |= (1<<PIN_out);
   DDRB &= ~(1<<Btn0000_Pin);
}

void sendPacket16(byte DevFunc, byte Data, byte pilotPeriods = 7);

byte eventID = 0;
byte transmissionID = 0;
byte AccelerationCounter = 0;
unsigned long LastTransmissionTC;

void loop()
{
  unsigned long TC = millis();  
  boolean SensorEvent = digitalRead(Btn0000_Pin);
  if(SensorEvent)
  {
    eventID++;
    AccelerationCounter = AccelerateTimes;
  }
  
  unsigned long tDW;
  unsigned long curTimeOut = 500 + ((unsigned long)InWait_TimeOut * 1000 - 500) *
      (tDW = AccelerateTimes - AccelerationCounter) / AccelerateTimes * tDW / AccelerateTimes;
  if(TC - LastTransmissionTC >= curTimeOut) 
  {
    byte dataByte = transmissionID << 4 | eventID & 0x0F;  
    transmissionID++;
    sendPacket16(DeviceFunction, dataByte, 7);
    if(AccelerationCounter) AccelerationCounter--;
    LastTransmissionTC = millis();
  }
}


void sendPacket16(byte DevFunc, byte Data, byte pilotPeriods)
{
  unsigned long pilotPeriod_half = pilotPeriod / 2;
  unsigned long HPeriod_half = HPeriod / 2;
  unsigned long LPeriod_half = LPeriod / 2;
  unsigned long lastChangeMicros;
  unsigned long m;
  
  word PacketData = (word)Data << 8;
  PacketData |= (DevFunc & 0x0F) << 3;
  byte even_parity = 0;
  byte count1 = bitRead(PacketData,3);
  byte b;
  for(byte i = 4; i < 16; i+=2)
                                {
                                   even_parity ^= b = bitRead(PacketData,i);
                                   count1 += b;
                                   count1 += bitRead(PacketData, i+1);
                                }
  PacketData |= count1 & 0x03;
  bitWrite(PacketData, 2, even_parity); 
  digitalWrite(PIN_out, lvl_0);
  lastChangeMicros = micros();
  
  for(byte i = 0; i < pilotPeriods; i++)
  {
    while((m = micros()) - lastChangeMicros < pilotPeriod_half) ;
    digitalWrite(PIN_out, lvl_1);
    lastChangeMicros = m;
    while((m = micros()) - lastChangeMicros < pilotPeriod_half) ;
    digitalWrite(PIN_out, lvl_0);
    lastChangeMicros = m;
  }

  for(byte n = 0; n < 16; n++)
  {
    boolean cur_bit = bitRead(PacketData,n);
    unsigned long cur_period_half = cur_bit ? HPeriod_half : LPeriod_half;
    while( (m = micros()) - lastChangeMicros < cur_period_half );
    digitalWrite(PIN_out, lvl_1);
    lastChangeMicros = m;
    while( (m = micros()) - lastChangeMicros < cur_period_half );
    digitalWrite(PIN_out, lvl_0);
    lastChangeMicros = m;
  }
}

Спасибо!!!

Yurchik26
Offline
Зарегистрирован: 16.03.2013

Минимум на 160 байт

tmr
Offline
Зарегистрирован: 19.05.2014

sendPacket16 вызывается один раз в цикле loop, т.ч. нет смысла выделять его в отдельную ф-цию. Но тут вероятно компилятор сообразит и м.б. уменьшения кода не последует, нужно проверять.

Возможно удастся сэкономить, если переписать millis() вручную на таймере. Обычно встроенные ф-ции сильно перегружены, а в библиотеках ардуино взаимодействие с таймерами реализовано из рук вон плохо.

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

Тип long это оверхед для 8битного МК, "по возможности избегайте этого".

Yurchik26
Offline
Зарегистрирован: 16.03.2013

А кто нибуь сможет подсказать как это (digitalWrite(PIN_out, lvl_0);) Заменить на типо этого (PORTD |= (1 << PD1);PORTD &= ~ (1 << PD1); ) Впринципе если это все заменить, должно хватить места

tmr
Offline
Зарегистрирован: 19.05.2014

Кстати да - вместо digitalRead\digitalWrite можно брать значения непосредственно из регистров. Port Registers

Yurchik26
Offline
Зарегистрирован: 16.03.2013

Вот их как раз и не пойму, записать низкий или высокий уровень, могу. А вот типо digitalWrite(PIN_out, lvl_0) тоесть сигнал lvl_0 не могу, точнее не знаю. Подскажите

Yurchik26
Offline
Зарегистрирован: 16.03.2013

Тольько так чтоли? или есть что то более изящное? Если так сделать, то остается минимум 104 байта убрать

if(lvl_0 == LOW)
  {
  PORTB &= ~(1<<5);
  }
else
 {
  PORTB |= (1<<5); 
 }

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Моя недолгая возня, но - надо проверять:

Скетч использует 1 720 байт (5%) памяти устройства. Всего доступно 32 256 байт.
Скетч использует 1 690 байт (5%) памяти устройства. Всего доступно 32 256 байт.
Скетч использует 1 652 байт (5%) памяти устройства. Всего доступно 32 256 байт.
Скетч использует 1 620 байт (5%) памяти устройства. Всего доступно 32 256 байт.
Скетч использует 1 510 байт (4%) памяти устройства. Всего доступно 32 256 байт.

Собственно, поправленный код:

#define PIN_out       2    // Выход на RF модуль (digital)
#define Btn0000_Pin   3    // Вход, на котором кнопка (digital)

#define DeviceFunction  0  // Поле DevFunc 16-битного пакета

#define InWait_TimeOut            4   // seconds - время между пакетами,
                                      // когда от датчика нет срабатываний
#define AccelerateTimes           40  // times of accelerated trasmission
                                      // (кол-во ускоренных передач пакетов,
                                      // когда датчик сработал)
                                      
//#define lvl_0    LOW
//#define lvl_1  HIGH


#define pilotPeriod     1200
#define pilotPeriod_half (pilotPeriod/2)
#define HPeriod         500
#define HPeriod_half (HPeriod/2)
#define LPeriod         2000
#define LPeriod_half (LPeriod/2)

uint8_t btnBit, pinOutBit;
uint8_t btnPort, pinOutPort;
volatile uint8_t *btnPIR, *pinOutPOR;

#define OUTPIN_LOW() *pinOutPOR &= ~pinOutBit
#define OUTPIN_HIGH() *pinOutPOR |= pinOutBit


void setup() 
{    
   DDRB |= (1<<PIN_out);
   DDRB &= ~(1<<Btn0000_Pin);

  btnBit = digitalPinToBitMask(Btn0000_Pin);
  btnPort = digitalPinToPort(Btn0000_Pin);
  btnPIR = portInputRegister(btnPort);

  pinOutBit = digitalPinToBitMask(PIN_out);
  pinOutPort = digitalPinToPort(PIN_out);
  pinOutPOR = portOutputRegister(pinOutPort);
   
}

void sendPacket16(byte DevFunc, byte Data, byte pilotPeriods = 7);

byte eventID = 0;
byte transmissionID = 0;
byte AccelerationCounter = 0;
unsigned long LastTransmissionTC;


void loop()
{
  
  unsigned long TC = millis();  
  boolean SensorEvent = (*btnPIR & btnBit);//digitalRead(Btn0000_Pin);
  if(SensorEvent)
  {
    eventID++;
    AccelerationCounter = AccelerateTimes;
  }
  
  unsigned long tDW = AccelerateTimes - AccelerationCounter;
  unsigned long curTimeOut = 500 + ((unsigned long)InWait_TimeOut * 1000 - 500) *
      tDW / AccelerateTimes * tDW / AccelerateTimes;
  if(TC - LastTransmissionTC >= curTimeOut) 
  {
    byte dataByte = (transmissionID << 4) | (eventID & 0x0F);  
    transmissionID++;
    sendPacket16(DeviceFunction, dataByte, 7);
    if(AccelerationCounter) 
      AccelerationCounter--;
      
    LastTransmissionTC = millis();
  }
}


void sendPacket16(byte DevFunc, byte Data, byte pilotPeriods)
{
  unsigned long lastChangeMicros;
  unsigned long m;
  
  word PacketData = (word)Data << 8;
  PacketData |= (DevFunc & 0x0F) << 3;
  byte even_parity = 0;
  byte count1 = (PacketData & (1 << 3)); //bitRead(PacketData,3);
  byte b;
  for(byte i = 4; i < 16; i+=2)
  {
     even_parity ^= b = (PacketData & (1 << i)); //bitRead(PacketData,i);
     count1 += b;
     count1 += (PacketData & (1 << (i+1)));//bitRead(PacketData, i+1);
  }
  PacketData |= count1 & 0x03;
  //bitWrite(PacketData, 2, even_parity); 
  PacketData &= ~(1 << 2);
  if(even_parity)
    PacketData |= (1 << 2);
  
  OUTPIN_LOW();//digitalWrite(PIN_out, lvl_0);
  lastChangeMicros = micros();
  
  for(byte i = 0; i < pilotPeriods; i++)
  {
    while((m = micros()) - lastChangeMicros < pilotPeriod_half) ;
    OUTPIN_HIGH();//digitalWrite(PIN_out, lvl_1);
    lastChangeMicros = m;
    while((m = micros()) - lastChangeMicros < pilotPeriod_half) ;
    OUTPIN_LOW();//digitalWrite(PIN_out, lvl_0);
    lastChangeMicros = m;
  }

  for(byte n = 0; n < 16; n++)
  {
    boolean cur_bit = (PacketData & (1 << n));//bitRead(PacketData,n);
    /*unsigned long*/ uint16_t cur_period_half = cur_bit ? HPeriod_half : LPeriod_half;
    while( (m = micros()) - lastChangeMicros < cur_period_half );
    OUTPIN_HIGH();//digitalWrite(PIN_out, lvl_1);
    lastChangeMicros = m;
    while( (m = micros()) - lastChangeMicros < cur_period_half );
    OUTPIN_LOW();//digitalWrite(PIN_out, lvl_0);
    lastChangeMicros = m;
  }
}

Заодно убрал варнинги, на которые ругался компилятор.

Yurchik26
Offline
Зарегистрирован: 16.03.2013

Спасибо.  Но вопрос про регистры остался открытым (для личного познания)

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Yurchik26 пишет:

Спасибо.  Но вопрос про регистры остался открытым (для личного познания)

Посмотрите поправленный код, там как раз это и делается, просто вычисляется в setup номер бита и порта. То же самое можно прописать жёстко, если пин менять не надо - ещё подсократится код.

tmr
Offline
Зарегистрирован: 19.05.2014

Не более изящно, но чуть более наглядно PORTD = (0<<PD2) или PORTD = PORTD & B11111011 для простоты PORTD &= B11111011

Yurchik26
Offline
Зарегистрирован: 16.03.2013

Ох чтот не пойму регистры в коде, можно эти регистры отдельно написать? Чтоб было более наглядно. 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Yurchik26 пишет:

Ох чтот не пойму регистры в коде, можно эти регистры отдельно написать? Чтоб было более наглядно. 

Вот тут - переменные, в которых всё, что надо:

uint8_t btnBit, pinOutBit;
uint8_t btnPort, pinOutPort;
volatile uint8_t *btnPIR, *pinOutPOR;

Вот это - вычисление на основе переданного номера пина разных параметров - порт, битовая маска, регистр:

  btnBit = digitalPinToBitMask(Btn0000_Pin);
  btnPort = digitalPinToPort(Btn0000_Pin);
  btnPIR = portInputRegister(btnPort);

  pinOutBit = digitalPinToBitMask(PIN_out);
  pinOutPort = digitalPinToPort(PIN_out);
  pinOutPOR = portOutputRegister(pinOutPort);

Вот это - запись в порт, сконфигурированный на выход, высокого или низкого уровня:

#define OUTPIN_LOW() *pinOutPOR &= ~pinOutBit
#define OUTPIN_HIGH() *pinOutPOR |= pinOutBit

Вот это - чтение из порта, сконфигурированного на вход:

(*btnPIR & btnBit)

Если не надо менять пин в настройках - можно жёстко юзать нужные порты МК, суть от этого не поменяется, выше вам пример дали.

Yurchik26
Offline
Зарегистрирован: 16.03.2013

Теперь понял. Спасибо большое

fogary
Offline
Зарегистрирован: 05.03.2016

Разве вот этот цикл:

while( (m = micros()) - lastChangeMicros < cur_period_half );

не равнозначен:

delay(cur_period_half);

Если это так, то переменные m и lastChangeMicros как бы и не нужны становяться. Или использование delay() сведет всю "экономию" на переменных и циклах к нулю?