Глобальная переменная меняет свое значение при повторном запуске цикла
У меня проблема с глобальной переменной CalibrationValue. Первоначально он имеет правильное значение и также правильно отображается на выходе. Как только функция цикла перезапускается, значение переменной оказывается неверным, хотя оно и не перезаписывается. Может кто-то мне помочь, пожалуйста? На изображении печатаются следующие значения:
- новое значение ИИ
- неверное значение калибровки (!)
- sumOfValues (необходим для расчета калибровочного значения) правильный
- numValues (необходимо для расчета калибровочного значения) правильно
- Текст и значение калибровки (правильно!)
int op_mode_Pin = 7; // Цифровой входной контакт, который передает op_mode_Ardui
int op_mode_Ardui; // Режим оператора Arduino
int returnValue1 = 12; // Первое цифровое возвращаемое значение для передачи веса коробки
int returnValue2 = 13; // Второе цифровое возвращаемое значение для передачи веса коробки
int sensorPin = A0; // Выбираем входной контакт для потенциометра
long weightValue = 0; // Переменная для хранения значения с датчика
long calibrationValue = 0; // Значение, которое заполняется в процессе калибровки
int numValues = 50; // Количество взятых значений для расчета среднего
int thresBoxWeight = 300; // Вес для разделения тяжелых и легких ящиков
unsigned long sumOfValues; // Сумма взятых значений
unsigned long aveOfValues; // Среднее значение
char stringBuffer[30]; // Буфер для объединения строки и переменных
void setup() {
// Инициируем последовательную связь с экраном
Serial.begin(9600);
// Инициируем некоторые переменные
//значение веса = 0;
//значение калибровки = 0;
// число значений = 50;
//thresBoxWeight = 300;
// Установить входные контакты для op_mode_Ardui
pinMode(op_mode_Pin, INPUT); // устанавливает цифровой вывод 7 в качестве входа
// Установить выходные контакты для объявления Box
pinMode(returnValue1, OUTPUT); // устанавливает цифровой вывод 12 в качестве выхода
pinMode(returnValue2, OUTPUT); // устанавливает цифровой вывод 13 в качестве выхода
}
void loop() {
Serial.println(analogRead(sensorPin));
Serial.println(calibrationValue);
// Сброс переменных Sum и Average для следующего цикла
sumOfValues = 0;
aveOfValues = 0;
op_mode_Ardui = digitalRead(op_mode_Pin);
if (op_mode_Ardui == HIGH){
for (int i=0; i<numValues; i++){
weightValue = analogRead(sensorPin); // считываем значение с датчика
sumOfValues = sumOfValues + weightValue; // Строим сумму всех значений
}
Serial.println(sumOfValues);
Serial.println(numValues);
calibrationValue = sumOfValues / numValues;
sprintf(stringBuffer, "Calibration accomplished with value: %d", calibrationValue); // Объединяем текст и переменную для вывода
Serial.println(stringBuffer); // вывод текста и переменной на экран
delay(3000);
}
}
@Gary77, 👍1
1 ответ
Лучший ответ:
Это:
sprintf(stringBuffer, "Calibration accomplished with value: %d", calibrationValue);
является переполнением буфера: функция sprintf()
записывает 40-байтовый
строку в 30-байтовый буфер. Что бы ни случилось, оно останется в памяти
после того, как буфер будет перезаписан sprintf()
. Видимо это
оказалось codingValue
. Вы должны использовать
snprintf()
, а не sprintf()
, так как первый предназначен для
предотвратить такое переполнение.
Или, что еще лучше, придерживайтесь Serial.print[ln]()
:
Serial.print("Calibration accomplished with value: ");
Serial.println(calibrationValue);
ОБНОВЛЕНО: вы можете заметить, что 13108 совпадает с 0x3334, который на
архитектура с прямым порядком байтов хранится в памяти как 0x34 0x33. Это
коды ASCII для "43", которые являются частью того, что sprintf()
записал в прошлом
конец буфера.
- Сохранение файла .txt на SD-карту и чтение данных каждого содержимого в файл txt, а затем сохранение его в переменной
- Объявленная переменная внутри void setup не видится в void loop
- Хранить переменную?
- Сбросить переменную каждую 1 секунду на Arduino.
- Глобальный или локальный
- Использование одной и той же переменной между операторами if в loop()
- Использование переменной для индексации массива
- Функция управления сервоприводами
интересно, что переполнение буфера в
stringBuffer
перезаписывает переменную, определенную выше в файле. В большинстве компиляторов ваши глобальные переменные размещаются в памяти примерно в том порядке, в котором вы их объявляете. (Оптимизация компиляторов на 32- и 64-битных платформах может привести к некоторому изменению порядка, чтобы структуры переменного размера помещались в меньший объем памяти при соблюдении выравнивания по словам/длинным словам/двойному выравниванию, но большинство Arduino представляют собой 8-битные устройства, в которых нет такой вещи, как выравнивание по словам.), @Duncan CЭто сработало. Я никогда не думал, что переполнение может повлиять на глобальные переменные. Спасибо., @Gary77
На машине реального режима, такой как Arduino, переполнение буфера уничтожает все, что находится в ОЗУ. Глобальные переменные, данные в куче, что угодно. И ничего не мешает., @Duncan C
@DuncanC: я не знаю, как компоновщик определяет порядок распределения. Я попытался скомпилировать код OP с помощью avr-g++ 7.3.0, поставляемого с Arduino IDE 1.8.13, и раздел .bss содержит
timer0_fract
,timer0_millis
,timer0_overflow_count
,stringBuffer
,sumOfValues
,caulibationValue
иSerial
, в этом порядке. Если я удаляю-flto
из командной строки компилятора, я получаю другое распределение, начиная сstringBuffer
,aveOfValues
(который был оптимизирован с помощью -flto),sumOfValues
,CalibrationValue
, @Edgar Bonet