ПОМОГИТЕ с уменьшением размера кода для Attiny13a

Я делаю отличный рождественский подарок в виде персонализированного печатного значка. Все отлично работает с подключенным uno, но его сердце на самом деле Attiny13a, где я ТОЛЬКО перемещаюсь 1024 байта (в моем коде 1944) 64 байта переменных (мне каким-то образом удалось скопировать несколько вещей при запуске, поэтому я едва добираюсь до 59 байт)

Дело в том, как я могу сделать это еще меньше??

void setup() {
  pinMode(3, INPUT_PULLUP);
}

void charlie(int a[])
{

  if(a[0] < 0){

    pinMode(5, INPUT);
  }else
  {
    pinMode(5, OUTPUT);
    digitalWrite(5, a[0]);    
  }   
  if(a[1] < 0){

    pinMode(6, INPUT);
  }else
  {
    pinMode(6, OUTPUT);
    digitalWrite(6, a[1]);    
  }
  if(a[2] < 0){

    pinMode(2, INPUT);
  }else
  {
    pinMode(2, OUTPUT);
    digitalWrite(2, a[2]);    
  }
  if(a[3] < 0){

    pinMode(4, INPUT);
  }else
  {
    pinMode(4, OUTPUT);
    digitalWrite(4, a[3]);    
  }
}

void copy(int* src, int* dst, int len) {
    memcpy(dst, src, sizeof(src[0])*len);
}
void resetP()
{
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(2, INPUT);
  pinMode(4, INPUT);  
}
void loop() {

  int koz1[4] = {-2,LOW,HIGH,-2};
  //int koz2[4] = {-2,HIGH,LOW,-2};

  int koz2[4];
  copy(koz1, koz2, 4);
  koz2[1] = HIGH;
  koz2[2] = LOW;

  int koz3[4] = {LOW,HIGH,-2,-2};
  //int koz4[4] = {HIGH,LOW,-2,-2};
  int koz4[4];
  copy(koz3, koz4, 4);
  koz4[0] = HIGH;
  koz4[1] = LOW;


  int koz5[4] = {LOW, -2,-2,HIGH};
  //int koz6[4] = {HIGH, -2,-2,LOW};
  int koz6[4];
  copy(koz5, koz6, 4);
  koz4[0] = HIGH;
  koz4[3] = LOW;

  int cap[4] = {-2, HIGH,-2,LOW};


  int oko1[4] = {LOW, -2,HIGH,-2};
  //int oko2[4] = {HIGH, -2,LOW,-2};

  int oko2[4];
  copy(oko1, oko2, 4);
  oko2[0] = HIGH;
  oko2[2] = LOW;


  // put your main code here, to run repeatedly:

  static long oldTime = 0;  
  long Ctime = millis();  
  long diffT = Ctime - oldTime;
  oldTime = Ctime;


  static bool holdButt = false;
  static long holdTime = 0;
  static long shortPressATime = 0;
  //static long longPressATime = 0;
  static bool kozichOn = true;

  //charlie(oko1);
  //charlie(oko2);


  if(digitalRead(3) == LOW)
  {
    holdButt = true;
    holdTime = holdTime + diffT;
  }
  else if (holdButt && digitalRead(3) == HIGH){
    holdButt = false;
    if(holdTime > 1000){
      //longPressATime = 5000;
      kozichOn = !kozichOn;
    }
    else
    {      
      shortPressATime = 5000;
    }
    holdTime = 0;
  }

  if(shortPressATime > 0)
  {
    shortPressATime = shortPressATime - diffT;
    /*charlie(koz1);
    charlie(koz2);
    charlie(koz3);
    charlie(koz4);
    charlie(koz5);
    charlie(koz6);
    charlie(cap);
    */
    if(((round(shortPressATime/100) / 2) & 1) == 0){
      charlie(oko1);
      charlie(oko2);
      resetP();
    }
    else{

    }

  }

  /*
  else if (longPressATime > 0)
  { 
    longPressATime = longPressATime - diffT;   
    charlie(oko1);
    delay(5000/longPressATime);

    charlie(oko2);
    delay(5000/longPressATime);

    longPressATime = longPressATime - 5000/longPressATime;
    longPressATime = longPressATime - 5000/longPressATime;
  }*/
  else{
    if(kozichOn){
      charlie(koz1);
      charlie(koz2);
      charlie(koz3);
      charlie(koz4);
      charlie(koz5);
      charlie(koz6);
      charlie(cap);
    }
    charlie(oko1);
    charlie(oko2);
  }
  resetP();
}

РЕДАКТИРОВАТЬ: Ребята, вы потрясающие вместе с теми, кто на форумах arduino, похоже, я наконец-то добился этого, я попытаюсь оптимизировать немного больше, так как его 1010 байтов 98%. Но я благодарю вас всех. Вы научили меня за 1 час больше практических вещей, чем я мог прочитать за неделю.

void setup() {
  pinMode(3, INPUT_PULLUP);
}

void charlie(byte a[])
{



  if(a[0] == 0x0F){

    pinMode(5, INPUT);
  }else
  {
    pinMode(5, OUTPUT);
    digitalWrite(5, a[0]);    
  }   
  if(a[1] == 0x0F){

    pinMode(6, INPUT);
  }else
  {
    pinMode(6, OUTPUT);
    digitalWrite(6, a[1]);    
  }
  if(a[2] == 0x0F){

    pinMode(2, INPUT);
  }else
  {
    pinMode(2, OUTPUT);
    digitalWrite(2, a[2]);    
  }
  if(a[3] == 0x0F){

    pinMode(4, INPUT);
  }else
  {
    pinMode(4, OUTPUT);
    digitalWrite(4, a[3]);    
  }
}
/*
void copy(int* src, int* dst, int len) {
    memcpy(dst, src, sizeof(src[0])*len);


}
*/
/*
void resetP()
{
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(2, INPUT);
  pinMode(4, INPUT);  
}
*/

void loop() {

  byte koz1[4] = {0x0F,LOW,HIGH,0x0F};
  //int koz2[4] = {null,HIGH,LOW,null};

  byte koz2[4];
  //copy(koz1, koz2, 4);
  memcpy(koz2, koz1, sizeof(koz1[0])*4);
  koz2[1] = HIGH;
  koz2[2] = LOW;

  byte koz3[4] = {LOW,HIGH,0x0F,0x0F};
  //int koz4[4] = {HIGH,LOW,2,2};
  byte koz4[4];
  //copy(koz3, koz4, 4);
  memcpy(koz4, koz3, sizeof(koz3[0])*4);
  koz4[0] = HIGH;
  koz4[1] = LOW;


  byte koz5[4] = {LOW, 0x0F,0x0F,HIGH};
  //int koz6[4] = {HIGH, 2,2,LOW};
  byte koz6[4];
  //copy(koz5, koz6, 4);
  memcpy(koz6, koz5, sizeof(koz5[0])*4);
  koz4[0] = HIGH;
  koz4[3] = LOW;

  byte cap[4] = {0x0F, HIGH,0x0F,LOW};


  byte oko1[4] = {LOW, 0x0F,HIGH,0x0F};
  //int oko2[4] = {HIGH, 2,LOW,2};

  byte oko2[4];
  //copy(oko1, oko2, 4);
  memcpy(oko2, oko1, sizeof(oko1[0])*4);
  oko2[0] = HIGH;
  oko2[2] = LOW;


  // put your main code here, to run repeatedly:

  static uint16_t oldTime = 0;  
  uint16_t Ctime = millis();  
  uint16_t diffT = Ctime - oldTime;
  oldTime = Ctime;


  static bool holdButt = false;
  static uint16_t holdTime = 0;
  static uint16_t shortPressATime = 0;
  //static long longPressATime = 0;
  static bool kozichOn = true;

  //charlie(oko1);
  //charlie(oko2);


  if(digitalRead(3) == LOW)
  {
    holdButt = true;
    holdTime = holdTime + diffT;
  }
  else if (holdButt && digitalRead(3) == HIGH){
    holdButt = false;
    if(holdTime > 1000){
      //longPressATime = 5000;
      kozichOn = !kozichOn;
    }
    else
    {      
      shortPressATime = 5000;
    }
    holdTime = 0;
  }




  if(shortPressATime > 0)
  {
    shortPressATime = shortPressATime - diffT;
    if(((uint16_t(shortPressATime/128) / 2) & 1) == 0){
      charlie(oko1);
      charlie(oko2);

    }
    else{

    }



  }
  else{
    if(kozichOn){
      charlie(koz1);
      charlie(koz2);
      charlie(koz3);
      charlie(koz4);
      charlie(koz5);
      charlie(koz6);
      charlie(cap);
    }
    charlie(oko1);
    charlie(oko2);
  }
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(2, INPUT);
  pinMode(4, INPUT);
}

, 👍0

Обсуждение

какова желаемая функциональность?, @jsotola


2 ответа


2

Первое, что я бы попробовал, это избавиться от ядра Arduino и вместо этого программировать на avr-libc уровень:

  • используйте прямой доступ к порту вместо digitalRead()/digitalWrite()
  • настройте таймер и измеряйте время в единицах переполнения таймера вместо использования millis().

Кроме того, используйте int8_t для всех небольших целых чисел (особенно в массивах) и uint16_t для управления временем, если вам не нужно обрабатывать длительности, превышающие 65 535 единиц времени. .


Обновление: вот моя попытка перевести ваш код на простой C + avr-libc. Обратите внимание, что, поскольку я не знаю распиновку ядра, вы используя (что такое контакт 6?), я делаю один. Я также реализовал Мишеля Предложение Кейзера о включении дублированного кода в функцию, который я назвал set_pin(). Полностью не проверено:

#include <stdbool.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>

#define INPUT 0x0f
#define LOW   0x00
#define HIGH  0x01

// Настройте Таймер 0 на подсчет миллисекунд, предполагая, что F_CPU = 8 МГц.
static void init_timer() {
  OCR0A  = 125 - 1;     // период = 125*64 = 8000 циклов процессора
  TCCR0A = _BV(WGM01);  // CTC, ВЕРХ = OCR0A
  TCCR0B = _BV(CS00)    // часы @ F_CPU/64
         | _BV(CS01);   // то же самое
  TIMSK0 = _BV(TOIE0);  // разрешаем прерывание по переполнению таймера
}

volatile uint16_t millis_counter;

// Считаем миллисекунды при каждом переполнении таймера.
ISR(TIM0_OVF_vect) {
  ++millis_counter;
}

// Чтение счетчика миллисекунд, избегая условий гонки.
static uint16_t millis() {
  uint16_t millis_counter_copy;
  ATOMIC_BLOCK(ATOMIC_FORCEON) {
    millis_counter_copy = millis_counter;
  }
  return millis_counter_copy;
}

static void setup() {
  PORTB |= _BV(PB4);  // подтягивание на PB4
  init_timer();
  sei();
}

// Установите вывод как INPUT, LOW или HIGH.
static void set_pin(uint8_t pin_mask, uint8_t state) {
  if (state == INPUT) {
    DDRB &= ~pin_mask;     // ВХОД
    PORTB &= ~pin_mask;    // без подтягивания
  } else {
    if (state)
      PORTB |= pin_mask;   // ВЫСОКИЙ
    else
      PORTB &= ~pin_mask;  // НИЗКИЙ
    DDRB |= pin_mask;      // ВЫХОД
  }
}

static void charlie(uint8_t a[])
{
  set_pin(_BV(PB0), a[0]);
  set_pin(_BV(PB1), a[1]);
  set_pin(_BV(PB2), a[2]);
  set_pin(_BV(PB3), a[3]);
}

void loop() {

  uint8_t koz1[4] = {INPUT,LOW,HIGH,INPUT};

  uint8_t koz2[4];
  memcpy(koz2, koz1, sizeof(koz1[0])*4);
  koz2[1] = HIGH;
  koz2[2] = LOW;

  uint8_t koz3[4] = {LOW,HIGH,INPUT,INPUT};
  uint8_t koz4[4];
  memcpy(koz4, koz3, sizeof(koz3[0])*4);
  koz4[0] = HIGH;
  koz4[1] = LOW;

  uint8_t koz5[4] = {LOW, INPUT,INPUT,HIGH};
  uint8_t koz6[4];
  memcpy(koz6, koz5, sizeof(koz5[0])*4);
  koz4[0] = HIGH;
  koz4[3] = LOW;

  uint8_t cap[4] = {INPUT, HIGH,INPUT,LOW};

  uint8_t oko1[4] = {LOW, INPUT,HIGH,INPUT};
  uint8_t oko2[4];
  memcpy(oko2, oko1, sizeof(oko1[0])*4);
  oko2[0] = HIGH;
  oko2[2] = LOW;

  static uint16_t oldTime = 0;  
  uint16_t Ctime = millis();  
  uint16_t diffT = Ctime - oldTime;
  oldTime = Ctime;

  static bool holdButt = false;
  static uint16_t holdTime = 0;
  static uint16_t shortPressATime = 0;
  static bool kozichOn = true;

  if (bit_is_clear(PINB, PB4))
  {
    holdButt = true;
    holdTime = holdTime + diffT;
  }
  else if (holdButt && bit_is_set(PINB, PB4)){
    holdButt = false;
    if(holdTime > 1000){
      kozichOn = !kozichOn;
    }
    else
    {      
      shortPressATime = 5000;
    }
    holdTime = 0;
  }

  if(shortPressATime > 0)
  {
    shortPressATime = shortPressATime - diffT;
    if(((shortPressATime/128 / 2) & 1) == 0){
      charlie(oko1);
      charlie(oko2);
    }
  }
  else{
    if(kozichOn){
      charlie(koz1);
      charlie(koz2);
      charlie(koz3);
      charlie(koz4);
      charlie(koz5);
      charlie(koz6);
      charlie(cap);
    }
    charlie(oko1);
    charlie(oko2);
  }
  DDRB &= ~(_BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3));
}

int main(void) {
  setup();
  for (;;)
    loop();
}

При компиляции с помощью avr-gcc 5.4.0 я получаю 642 байта флэш-памяти и 31 байт Оперативная память (данные + BSS, не считая стека).

,

Я предлагаю отказаться от ArduinoIDE и перейти на Atmel Studio. У меня был хороший опыт использования его с USBasp и использования avrdude (поставляется как часть Arduino IDE) для прямой загрузки программы в ATTiny13a., @Filip Franik

Сделал это спасибо, спасибо за предложение, я слышал об этом, но мне это кажется еще сложнее, как будто я знаю С# и аналогичный bcz разработки игр, но idek то, что использует студия atmel, но я попробую это в будущем проект. Еще раз большое спасибо., @Nejcraft hraje

Я попробую ваш перевод, я прототипировал на ардуино, так что должно было быть 0,1,2,4 плексирование 3 - кнопка подтягивания, @Nejcraft hraje


-1

Когда я его компилирую, я получаю:

Sketch uses 2630 bytes (8%) of program storage space. Maximum is 32256 bytes.
Global variables use 64 bytes (3%) of dynamic memory, leaving 1984 bytes for local variables. Maximum is 2048 bytes.

Я удалил все закомментированные строки и изменил целые числа на байты (согласно ответу Эдгара Боне для начала.

Затем я получаю код (добавленный в конце) и следующие результаты:

Sketch uses 2432 bytes (7%) of program storage space. Maximum is 32256 bytes.
Global variables use 24 bytes (1%) of dynamic memory, leaving 2024 bytes for local variables. Maximum is 2048 bytes.

Согласно спецификациям, AtTiny85 имеет 8 КБ памяти программ и 512 байт SRAM, так что вы должны быть в безопасности.

Обратите внимание, однако, если вы хотите подсчитать память SRAM (24 байта, учитываемых IDE), вам также необходимо добавить:

  1. Байты для глубины вызова функций (например, loop вызывает copy, а это вызывает memcpy, общая память предназначена для copy : + 2 (байт*) + 2 (байт*) + 1 (байт) байт, а для memcpy: + dst (2) + src (2) + sizeof (1) байт. самый «худший» вызов (поэтому проверьте самый глубокий вызов со всеми добавленными аргументами). Все это добавляется в так называемый стек.
  2. Также необходимо добавить стоимость локальных переменных (один раз для каждой функции), так как они также добавляются в стек.
  3. Если вы используете динамические переменные (malloc), вы также должны их добавить, но это не используется в вашем скетче.

Байты, используемые для элементов с 1 по 3, не упоминаются (поскольку они выделяются во время выполнения).

void setup() {
  pinMode(3, INPUT_PULLUP);
}

void charlie(byte a[])
{
  if(a[0] < 0){

    pinMode(5, INPUT);
  }else
  {
    pinMode(5, OUTPUT);
    digitalWrite(5, a[0]);    
  }   
  if(a[1] < 0){

    pinMode(6, INPUT);
  }else
  {
    pinMode(6, OUTPUT);
    digitalWrite(6, a[1]);    
  }
  if(a[2] < 0){

    pinMode(2, INPUT);
  }else
  {
    pinMode(2, OUTPUT);
    digitalWrite(2, a[2]);    
  }
  if(a[3] < 0){

    pinMode(4, INPUT);
  }else
  {
    pinMode(4, OUTPUT);
    digitalWrite(4, a[3]);    
  }
}

void copy(byte* src, byte* dst, byte len) {
    memcpy(dst, src, sizeof(src[0])*len);
}

void resetP()
{
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(2, INPUT);
  pinMode(4, INPUT);  
}
void loop() {

  byte koz1[4] = {-2,LOW,HIGH,-2};
  byte koz2[4];
  copy(koz1, koz2, 4);
  koz2[1] = HIGH;
  koz2[2] = LOW;

  byte koz3[4] = {LOW,HIGH,-2,-2};
  byte koz4[4];
  copy(koz3, koz4, 4);
  koz4[0] = HIGH;
  koz4[1] = LOW;


  byte koz5[4] = {LOW, -2,-2,HIGH};
  byte koz6[4];
  copy(koz5, koz6, 4);
  koz4[0] = HIGH;
  koz4[3] = LOW;

  byte cap[4] = {-2, HIGH,-2,LOW};
  byte oko1[4] = {LOW, -2,HIGH,-2};

  byte oko2[4];
  copy(oko1, oko2, 4);
  oko2[0] = HIGH;
  oko2[2] = LOW;

  static long oldTime = 0;  
  long Ctime = millis();  
  long diffT = Ctime - oldTime;
  oldTime = Ctime;

  static bool holdButt = false;
  static long holdTime = 0;
  static long shortPressATime = 0;
  static bool kozichOn = true;

  if(digitalRead(3) == LOW)
  {
    holdButt = true;
    holdTime = holdTime + diffT;
  }
  else if (holdButt && digitalRead(3) == HIGH){
    holdButt = false;
    if(holdTime > 1000){
      //longPressATime = 5000;
      kozichOn = !kozichOn;
    }
    else
    {      
      shortPressATime = 5000;
    }
    holdTime = 0;
  }

  if(shortPressATime > 0)
  {
    shortPressATime = shortPressATime - diffT;

    if(((round(shortPressATime/100) / 2) & 1) == 0){
      charlie(oko1);
      charlie(oko2);
      resetP();
    }
    else{
    }
  }
  else{
    if(kozichOn){
      charlie(koz1);
      charlie(koz2);
      charlie(koz3);
      charlie(koz4);
      charlie(koz5);
      charlie(koz6);
      charlie(cap);
    }
    charlie(oko1);
    charlie(oko2);
  }
  resetP();
}
,

На самом деле я использую Attiny13a, у которого всего 1024 байта, с помощью форума arduino я получил отличные 1218 байт, что очень близко к цели, теперь я попытаюсь реализовать это. РЕДАКТИРОВАТЬ: с вашим улучшением я очень близок к 1074 байтам., @Nejcraft hraje

Значит нужно уменьшить размер кода (Flash), а не SRAM? Это две разные вещи., @Michel Keijzers

Извините, но я вернулся к проблеме, мне нужно различать 3 значения, и когда я использую байты, мне нужно изменить функцию, чтобы она была ifs (== 2), но затем я вернулся к 1246, @Nejcraft hraje

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

Сделай это. Спасибо, @Nejcraft hraje

Добро пожаловать ... если вы считаете ответ полезным, проголосуйте за него (нажмите стрелку вверх рядом с вопросом); если вы считаете, что ответы решили вашу проблему, также примите их (нажмите галочку рядом с ответом). Удачи с вашим проектом., @Michel Keijzers

@eternaldownvoter: пожалуйста, напишите, что можно улучшить., @Michel Keijzers