Хало. сабж.
что я упускаю?
UPD FYI: никаких средств отладки нет, JTAG нет, ничего нет. У меня абсолютно отсутствует способ поймать переполнение стека и любые проблемы с памятью, чисто на мысленном эксперименте пишу. Если у вас есть удобный способ виртуалить Atmega168 и экран, дайте ссылку.
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 и экран, дайте ссылку.
Изменено: