ARDUINO разрядное устройство с меню 1602, по любой кнопке уходит в сброс.

Arleen Lasleur

✩✩✩✩✩✩✩
13 Мар 2021
2
0
Хало. сабж.
C++:
#include <LiquidCrystal.h>

#define D0_Out     DDRD  |=B00000001            // GPIO dir cfg                // ====================================
#define D3_Out     DDRD  |=B00001000                                           // hardware cfg
#define D5_Out     DDRD  |=B00100000                                           // FET gate: D0  D3  D5  D6
#define D6_Out     DDRD  |=B01000000                                           // BTN:      D10 D11 D12 D13  (Ent Up Dn Esc)
#define D10_In     DDRB  &=B11111011                                           // BATT:     A3  A2  A1  A0
#define D11_In     DDRB  &=B11110111                                           // ====================================
#define D12_In     DDRB  &=B11101111
#define D13_In     DDRB  &=B11011111
#define FET1_Off   PORTD &=B11111110            // GPIO macros
#define FET2_Off   PORTD &=B11110111
#define FET3_Off   PORTD &=B11011111
#define FET4_Off   PORTD &=B10111111
#define FET1_On    PORTD |=B00000001
#define FET2_On    PORTD |=B00001000
#define FET3_On    PORTD |=B00100000
#define FET4_On    PORTD |=B01000000
#define BTN1_PU    PORTB |=B00000100
#define BTN2_PU    PORTB |=B00001000
#define BTN3_PU    PORTB |=B00010000
#define BTN4_PU    PORTB |=B00100000
#define BTN_ENT !((PINB  & B00000100)>>2)       // key macros
#define BTN_UP  !((PINB  & B00001000)>>3)
#define BTN_DN  !((PINB  & B00010000)>>4)
#define BTN_ESC !((PINB  & B00100000)>>5)
void delay_us(uint16_t tic_us){
  tic_us *= 4; //1us = 4 цикла
  __asm__ volatile (
      "1: sbiw %0,1" "\n\t" //; вычесть из регистра значение N
      "brne 1b"      
      : "=w" (tic_us)
      : "0" (tic_us)
      );
}
uint16_t AnRead(uint8_t An_pin){                // ADC macros
  ADMUX=An_pin;  
  delay_us(10);    
  ADCSRA=B11000110;    //B11000111-125kHz B11000110-250kHz
  while (ADCSRA & (1 << ADSC));
  An_pin = ADCL;
  uint16_t An = ADCH;
  return (An<<8) + An_pin;
}
#define BAT1_Read (AnRead(B01000011))
#define BAT2_Read (AnRead(B01000010))
#define BAT3_Read (AnRead(B01000001))
#define BAT4_Read (AnRead(B01000000))

LiquidCrystal lcd(1,2,4,7,8,9);

byte btnstate[4]={0,0,0,0};

unsigned long prevtime[5]   = {0,0,0,0,0},             // 5th for idletimer???                     // ============
              passtime[4]   = {0,0,0,0};                                                           // memory cfg
boolean       finished[4]   = {0,0,0,0},                                                           // ============
              ena_selftest  =  false,
              kbhit         =  false;
float         mAh[4]        = {0,0,0,0},
              Res[4]        = {10.0,10.0,10.0,10.0},   // Resistor R1 value [Ohm]
              ResB[4]       = {10.1,10.1,10.1,10.1},   // Measured B1 circuit resistance [Ohm]
              current[4]    = {0.0,0.0,0.0,0.0},
              Bstart[4]     = {0.0,0.0,0.0,0.0},
              BattBefore[4] = {0.0,0.0,0.0,0.0},       // voltage before Rx
              Rw[4]         = {0,0,0,0},               // internal resistance
              vdif[4]       = {0,0,0,0},
              vsum[4]       = {0,0,0,0},
              cal[4]        = {2.00000,                // voltage dividers ratio, for calibration
                               2.00000,
                               2.00000,
                               2.00000},
              battLow       =  3.0,                    // End of measurement - voltage level
              voltRef       =  5.03;                   // Reference voltage (pin 5V)
int           poj[4]        = {0,0,0,0},               // mAh float intval for LCD
              mode          =  0,
              selmode       =  1,
              interval      =  5000,                   // Measurement Interwal (ms)
              c_meas        =  0;                      // measurement cycle counter

void setup(){
  // FET gate        // keys
  D0_Out; FET1_Off;    D10_In; BTN1_PU;        // setup GPIO
  D3_Out; FET2_Off;    D11_In; BTN2_PU;
  D5_Out; FET3_Off;    D12_In; BTN3_PU;
  D6_Out; FET4_Off;    D13_In; BTN4_PU;

  lcd.begin(16,2);            delay(200);     // wait init
  lcd.print("LCDM init Ok."); delay(2000);
  //key_event();
}

void key_event(){
  kbhit=1;  prevtime[5]=millis();
}

void fet_event(byte n,boolean b_on){
  switch(n){
    case 0: if(b_on) FET1_On; else FET1_Off; break;
    case 1: if(b_on) FET2_On; else FET2_Off; break;
    case 2: if(b_on) FET3_On; else FET3_Off; break;
    case 3: if(b_on) FET4_On; else FET4_Off; break;
  }
}

void discharge() {
  /*
  byte i;
//for(i=0;i<4;i++) BattBefore[i] = cal[i] * analogRead(VBATPIN[i]) * voltRef / 1024.0; // Batt voltage
  BattBefore[0] = cal[0] * BAT1_Read * voltRef / 1024.0; // Batt voltage
  BattBefore[1] = cal[1] * BAT2_Read * voltRef / 1024.0;
  BattBefore[2] = cal[2] * BAT3_Read * voltRef / 1024.0;
  BattBefore[3] = cal[3] * BAT4_Read * voltRef / 1024.0;
 
  for(i=0;i<4;i++){
    if (BattBefore[i] >= battLow && !finished[i]){
      fet_event(i,1);
      lcd.setCursor(0, 0);  lcd.print(i); lcd.print(":"); lcd.print(BattBefore[i]); lcd.print("V");
    }
    if ((BattBefore[i] < battLow) || finished[i]){                  // Disconnect load, print the result
      fet_event(i,0);
      finished[i] = true;
      lcd.setCursor(0, 0);  lcd.print(i); lcd.print(":"); lcd.print("END");
    }
  }
  delay(interval/4);
  lcd.clear();
  */
}

void captest(){
/*
  byte i;
//  for(i=0;i<4;i++) BattBefore[i] = cal[i] * analogRead(VBATPIN[i]) * voltRef / 1024.0; // B1 voltage
  BattBefore[0] = cal[0] * BAT1_Read * voltRef / 1024.0;
  BattBefore[1] = cal[1] * BAT2_Read * voltRef / 1024.0;
  BattBefore[2] = cal[2] * BAT3_Read * voltRef / 1024.0;
  BattBefore[3] = cal[3] * BAT4_Read * voltRef / 1024.0;

  for(i=0;i<4;i++){
    if (BattBefore[i] >= battLow && !finished[i]){
      fet_event(i,1);
      passtime[i] = millis() - prevtime[i];
      current[i] = (BattBefore[i]) / Res[i]; // Current calculation
      mAh[i] = mAh[i] + (current[i] * 1000.0) * (passtime[i] / 3600000.0); // Capacity sum
      prevtime[i] = millis();
      if(c_meas>0 && c_meas<5)  vsum[i] = vsum[i] + BattBefore[i];   // 4 x voltage measurement
      if(c_meas==6){
        vsum[i] = vsum[i]/4;
        vdif[i] = Bstart[i]/vsum[i];
        Rw[i]=(vdif[i]-1)*ResB[i]; // Internal resistance
      }
      poj[i] = mAh[i];
      lcd.clear(); lcd.home(); lcd.print(BattBefore[i]); lcd.print("V");
      lcd.setCursor(9, 0); lcd.print(current[i]); lcd.print("A");
      lcd.setCursor(0, 1); lcd.print(poj[i]); lcd.print("mAh");
      if(c_meas>6){
        lcd.setCursor(9, 1); lcd.print(Rw[i]);
      }
      c_meas++;
      delay(interval);
    }
    if ((BattBefore[i]<battLow) || finished[i]){   // Disconnects load, prints the result
      fet_event(i,0);
      finished[i] = true;
      poj[i] = mAh[i];
      lcd.clear(); lcd.home(); lcd.print(i); lcd.print(" - end");
      lcd.setCursor(0, 1); lcd.print(poj[i]); lcd.print("mAh ");
      lcd.setCursor(8, 1); lcd.print("Rw:"); lcd.print(i); lcd.print(Rw[i]);
      delay(interval*2);
    }
  }
  if(finished[0] && finished[1] && finished[2] && finished[3]) mode=3;
  */
}

void showcap(){
  if(BTN_UP){  key_event(); delay(40); mode=5; }
  if(!kbhit) return;
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print("1: "); lcd.print(poj[0]);
  lcd.setCursor(0, 0); lcd.print("2: "); lcd.print(poj[1]);
  lcd.setCursor(9, 1); lcd.print("3: "); lcd.print(poj[2]);
  lcd.setCursor(9, 1); lcd.print("4: "); lcd.print(poj[3]);
}

void showintr(){
  if(BTN_DN){  key_event(); delay(40); mode=4; }
  if(!kbhit) return;
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print("1: "); lcd.print(Rw[0]);
  lcd.setCursor(0, 0); lcd.print("2: "); lcd.print(Rw[1]);
  lcd.setCursor(9, 1); lcd.print("3: "); lcd.print(Rw[2]);
  lcd.setCursor(9, 1); lcd.print("4: "); lcd.print(Rw[3]);
}

void setcutoff(){
  if(BTN_UP){  key_event(); delay(70); if(battLow<4.1) battLow+=0.1; }
  if(BTN_DN){  key_event(); delay(70); if(battLow>3.0) battLow-=0.1; }
  if(BTN_ENT){ key_event(); delay(40); mode=0; }
  if(!kbhit) return;
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Cut voltage:");
  lcd.setCursor(0,1);
  lcd.print(battLow);
  lcd.print("V");
}

void menu(){
  if(BTN_UP){  key_event(); delay(40); if(selmode<3) selmode++; }
  if(BTN_DN){  key_event(); delay(40); if(selmode>1) selmode--; }
  if(BTN_ENT){ key_event(); delay(40); mode=selmode; }
  if(!kbhit) return;
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("SELECT MODE:");
  lcd.setCursor(0,1);
  switch(selmode){
    case 1: lcd.print("Capacity test"); break;
    case 2: lcd.print("Discharge");     break;
    case 3: lcd.print("Set cutoff V");  break;
  }
}

void keyproc(){
  if(kbhit) return;
  if (BTN_ESC){ kbhit=1; switch(mode){
    case 1:
    case 2:
    case 3: selmode=mode; mode=0; break;
  } }
  if (BTN_UP) { kbhit=1; switch(mode){
    case 0: if(selmode<3) selmode++; break;
  } }
  if (BTN_DN) { kbhit=1; switch(mode){
    case 0: if(selmode>1) selmode--; break;
  } }
  if (BTN_ENT){ kbhit=1; switch(mode){
    case 0: mode=selmode; break;
  } }
  if(kbhit) key_event();
}

void lcdproc(){
  //lcd.clear();
  lcd.setCursor(0,0);
  switch(mode){
    case 0:    lcd.print("SELECT MODE:");  break;
    case 1:    lcd.print("CT");            break;
    case 2:    lcd.print("DC");            break;
    case 3:    lcd.print("SCV");           break;
  }
  lcd.setCursor(0,1);
  switch(mode){
    case 0:    switch(selmode){   case 1: lcd.print("Capacity test"); break;
                                  case 2: lcd.print("Discharge");     break;
                                  case 3: lcd.print("Set cutoff V");  break;  }  break;
    case 1:    lcd.print("1 2 3 4");       break;
    case 2:    lcd.print("1 2 3 4");       break;
    case 3:    lcd.print("xxx V");         break;
  }
}

void loop() {
  byte i;
  /*
  switch(mode){
    case 0: menu();      break;
    case 1: captest();   break;
    case 2: discharge(); break;
    case 3: setcutoff(); break;
    case 4: showcap();   break;
    case 5: showintr();  break;
  }
//  if(ena_selftest && (millis()-prevtime[5]>=25000)){
//    for(i=0;i<4;i++) BattBefore[i]=battLow-0.1;
//  }
    */

//  if(!kbhit && (BTN_ENT || BTN_UP || BTN_DN || BTN_ESC)) key_event();
  if( kbhit && (millis()-prevtime[5]>=500)) kbhit=0;
  lcd.setCursor(15,1);
  if(kbhit) lcd.print("k"); else lcd.print(" ");

  keyproc();
  lcdproc();

}
что я упускаю?

UPD FYI: никаких средств отладки нет, JTAG нет, ничего нет. У меня абсолютно отсутствует способ поймать переполнение стека и любые проблемы с памятью, чисто на мысленном эксперименте пишу. Если у вас есть удобный способ виртуалить Atmega168 и экран, дайте ссылку.
 
Изменено:

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
@Arleen Lasleur, Proteus чем не устраивает? И МК и экран есть. Ежели прям вот отладку надо,то Microchip Studio, она же в прошлом Atmel Studio 7.0
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,969
632
44
Вопрос: что произойдет, если вы сначала объявляете массив длинной 5, а потом обращаетесь к элементу по индексу 5?
Код:
unsigned long prevtime[5]   = {0,0,0,0,0},
Код:
if( kbhit && (millis()-prevtime[5]>=500)) kbhit=0;
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
@PiratFox,он и не будет ругаться. Тем массивы и опасны,что для компилятора это лишь указатель на первый элемент. Компилятору фиолетово какой адрес читается через указатель.
prevtime[5] и *(prevtime+5) одна суть.
 
Изменено:

PiratFox

★★★★★✩✩
13 Фев 2020
1,706
474
это лишь указатель на первый элемент.
Как же на первый. В строке

unsigned long prevtime[5] = {0,0,0,0,0},

число 5 - это как раз размерность массива. И при её превышении в обращениях к этому массиву нормальный компилер это замечает и ругается. Например в IDE Keil. А так то я согласен, обращение к несуществующему элементу, которое прохлопал компилятор, конечно опасно. Ибо последствия непредсказуемы.:D
 
Изменено:

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
@PiratFox,вAVR-GCC и XC8 не видит проблемы. Напоролся сам недавно,когда библиотеку писал. Пару вечеров мучался искал ошибку.
 

PiratFox

★★★★★✩✩
13 Фев 2020
1,706
474
@te238s, да, видимо от компилера всё зависит. Не помню, какой там в Keil, но он реагирует. Для интереса проверил в avr studio, тоже не видит ошибки. Чёрт его знает, тут не угадаешь. :rolleyes: А ошибка, в общем-то, фатальная.
 

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
@PiratFox,я не эксперт в языке Си,но как понял это прямо не описано в спецификации и каждый создатель компилятора по своему решает быть или не быть)
И ладно если ошибка явная,как в этом случае,прям в тексте кода. У меня обращение к элементу массива происходило через переменную,которая менялась в цикле. И в упор не разберешся,пока в уме или дебаггере по шагам не проследить все значения)
На то он и опыт) теперь от и до перепроверяю такие места на стадии написания.

long prevtime[5] = {0,0,0,0,0},
Это означает: мне нужно 5 байт памяти, адрес первого байта укажи в указателе prevtime. По сути означает что программист забрал в свое распоряжение кусок памяти,который компилятор уже не может никак использовать. Соответственно,компилятор снимает с себя всю ответственность))
Указатели хорошая вещь,но опасная)
 
  • Лойс +1
Реакции: PiratFox

te238s

★★✩✩✩✩✩
14 Ноя 2021
374
97
@Геннадий П, IntelliSense) полезная вещь,подсказывает иногда. А компилятор молчит. Вот чем думают архитекторы Си? Казалось бы возьми и запрети так делать,но нет,не ищут лёгких путей)