Вставь принт пробела между выводом значений.
Спойлер
if(millis() - last_millis >= 1000)
{
last_millis = millis();
Serial.print("COMP:\t ");
Serial.print(val_01);
Serial.print(" ");
Serial.print(Index);
Serial.print(" ");
Serial.println((float)(timer1-timer0));
}
@mihail14 , для интервалов, измеряемых мсекундами или десятками мс, нужно использовать функцию micros() , а не миллис().
Прошли 40 мс, считываем значение по и2с, затем в оставшееся время делаем другие дела, но так чтоб суммарное время было не более скажем 38 мс. Если не укладываемся в это время, то нужно или интервал опроса увеличить, или задачи делить на части. Например, дисплей 2004 не весь обновлять, а по одной строке. Или нужно в сериал на скорости 9600 бод строку в сотню байт отправить, чтоб не было тормозов, нужно сначала 64 байта отправить, а через 40 мс остальные 36 байт.
На Arduino AVR интервалы изначально неточные: чередуются приращения на одну и на две единицы так, чтобы за секунду набиралось общее приращение на 1000 единиц.
Или даже по одному символу, как, например, здесь:
Оказывается, можно было обойтись без переменной value_.
Вместо:
ISR(TIMER1_COMPA_vect)
{
sei();
value_ = ADS.readADC_Differential_0_3();
reading_is_allowed = true;
}
Записать:
ISR(TIMER1_COMPA_vect)
{
sei();
(volatile) ADS.readADC_Differential_0_3();
reading_is_allowed = true;
}
Правда, это работает только в новой версии IDE (1.8.57.0). В старой версии IDE (1.6.7) это почему-то не работает.
Ещё раз всем огромное спасибо. Особенно участнику с ником [Дим-мычъ].
Подскажите, пожалуйста, как мне теперь замерить время между прерываниями, т.е. убедиться, что они происходят через 40 мс. Вставил строку измерения в обработчик прерывания после sei():
/***************************************************************************************************
ПОДКЛЮЧЕНИЕ БИБЛИОТЕК
****************************************************************************************************/
#include <ADS1X15.h> // Подключаем библиотеку by Rob Tillaart
/***************************************************************************************************
МАКРООПРЕДЕЛЕНИЯ
****************************************************************************************************/
#define array_size 2 // Размер массива для скользящего среднего
#define false 0
#define true 1
/***************************************************************************************************
АДРЕС АЦП ADS1115
****************************************************************************************************/
ADS1115 ADS(0x48); // Вывод ADDR ADS1115 подключен к GND
// ADS1115 ADS(0x49); // Вывод ADDR ADS1115 подключен к VDD
// ADS1115 ADS(0x4A); // Вывод ADDR ADS1115 подключен к SDA
// ADS1115 ADS(0x4B); // Вывод ADDR ADS1115 подключен к SCL
/***************************************************************************************************
ОБЪЯВЛЕНИЕ ГЛОБАЛЬНЫХ ПЕРЕМЕННЫХ
****************************************************************************************************/
float voltage_ADS [array_size]; // Объявляем массив напряжений для скользящего среднего
float voltage_average; // Усредненное значение напряжения в мкВ
int code[array_size]; // Объявляем массив результатов преобразования АЦП (коды)
bool array_is_full = false; // флаг заполнения массива
// array_is_full = false - массив не заполнен
// array_is_full = true - массив заполнен
volatile bool reading_is_allowed = false; // флаг разрешения чтения результата преобразования
// reading_is_allowed = false - чтение запрещено
// reading_is_allowed = true - чтение разрешено
unsigned char Index = 0; // Индекс элементов массива. Первоначальное значение = 0
unsigned long timer0 = 0;
unsigned long timer1;
float val_01 = 0;
volatile unsigned int value_ = 0;
volatile bool ADCflg = false;
/***************************************************************************************************
ФУНКЦИЯ SETUP
****************************************************************************************************/
void setup(void)
{
/******************************************************************************************/
/* Инициируем последовательное соединение Ардуино с ПК
и задаём скорость передачи данных в бит/c (бод) */
Serial.begin(115200);
Serial.print("ADS1X15_LIB_VERSION: ");
Serial.println(ADS1X15_LIB_VERSION);
delay(100);
Wire.begin();
// Wire.setClock(100000);
/***************************************************************************************************
НАСТРОЙКА АЦП ADS1115
****************************************************************************************************/
/* Настраиваем параметры АЦП ADS1115 */
/* Инициализируем микросхему ADS1115 и задаём её параметры конфигурации по умолчанию */
ADS.begin();
/* Задаём к-т усиления */
//ADS.setGain(16); //к-т усиления 16, максимальное напряжение ±0.256V, 1 бит = 0.0078125mV
// ADS.setGain(8); //к-т усиления 8, максимальное напряжение ±0.512V, 1 бит = 0.015625mV
// ADS.setGain(4); //к-т усиления 4, максимальное напряжение ±1.024V, 1 бит = 0.03125mV
// ADS.setGain(2); //к-т усиления 2, максимальное напряжение ±2.048V, 1 бит = 0.0625mV
ADS.setGain(1); //к-т усиления 1, максимальное напряжение ±4.096V, 1 бит = 0.125mV
// ADS.setGain(0); //к-т усиления 2/3, максимальное напряжение ±6.144V, 1 бит = 0.1875mV (DEFAULT)
/* Задаём скорость преобразования */
// ADS.setDataRate(7); //скорость преобразования максимум 860SPS (Самая быстрая)
// ADS.setDataRate(6); //скорость преобразования максимум 475SPS
// ADS.setDataRate(5); //скорость преобразования максимум 250SPS
ADS.setDataRate(4); //скорость преобразования максимум 128SPS (DEFAULT)
// ADS.setDataRate(3); //скорость преобразования максимум 64SPS
// ADS.setDataRate(2); //скорость преобразования максимум 32SPS
// ADS.setDataRate(1); //скорость преобразования максимум 16SPS
// ADS.setDataRate(0); //скорость преобразования максимум 8SPS (Самая медленная)
/* Задаём режим преобразования */
// ADS.setMode(0); //непрерывный режим
ADS.setMode(1); //однократный режим
ADS.requestADC_Differential_0_3();
/***************************************************************************************************
НАСТРОЙКА ТАЙМЕРА
****************************************************************************************************/
/* Настраиваем Таймер1 на прерывание по совпадению A.
Таймер1 будет вызывать прерывание каждые 40 мс (частота 25 Гц).
Он-лайн калькулятор: http://rcl-radio.ru/?p=111487&ysclid=m0oc5vjb9o687744588 */
cli();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// (16000000/((624+1)x1024))=25 Hz
OCR1A = 624;
TCCR1B |= (1 << WGM12);
// Prescaler 1024
TCCR1B |= (1 << CS12) | (1 << CS10);
TIMSK1 |= (1 << OCIE1A);
sei();
}
/***************************************************************************************************
ФУНКЦИЯ LOOP
****************************************************************************************************/
void loop(void)
{
static unsigned long last_millis = 0;
if (ADS.isReady() && ADCflg)
{
// val_01 = (ADS.toVoltage(ADS.getValue()))*1000000;
val_01 = ADS.toVoltage(value_ ) * 1000000 ; //
//timer0 = micros();
//ADS.requestADC_Differential_0_3();//не будет работать - раскомментировать эту строчку
//timer1 = micros();
ADCflg = false;
Serial.println((float)(timer0));
if(millis() - last_millis >= 1000)
{
last_millis = millis();
Serial.print("COMP:\t ");
Serial.print(val_01);
Serial.print(" ");
Serial.print(Index);
Serial.print(" ");
//Serial.println((float)(timer1-timer0));
}
}
//delay (1000);
}
ISR(TIMER1_COMPA_vect)
{
sei();
timer0 = millis() - timer0;
value_ = ADS.readADC_Differential_0_3();
ADCflg = true;
//timer1 = millis(); // останавливаем отсчет времени
//Serial.println((float)(timer1));
//ADS.requestADC_Differential_0_1(); // запуск преобразования для дифференциального чтения между входами 0 и 1 АЦП
//ADS.requestADC_Differential_0_3(); // запуск преобразования для дифференциального чтения между входами 0 и 3 АЦП
//ADS.requestADC_Differential_1_3(); // запуск преобразования для дифференциального чтения между входами 1 и 3 АЦП
//ADS.requestADC_Differential_2_3(); // запуск преобразования для дифференциального чтения между входами 2 и 3 АЦП
//timer0 = timer1;
//reading_is_allowed = true; // выставляем флаг "чтение результата преобразования разрешено"
//TCNT1 = 0; // Обнуляем счетный регистр TCNT1 таймера/счетчика T1
Index++;
}
Выводится какая-то ерунда.
Попробуйте так
Спойлер
void loop(void)
{
static unsigned long last_millis = 0;
static unsigned long micros_save[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static byte cycle = 0;
if (ADS.isReady() && ADCflg)
{
if(cycle < 10)
micros_save[cycle++] = micros();
// val_01 = (ADS.toVoltage(ADS.getValue()))*1000000;
val_01 = ADS.toVoltage(value_ ) * 1000000 ; //
//timer0 = micros();
//ADS.requestADC_Differential_0_3();//не будет работать - раскомментировать эту строчку
//timer1 = micros();
ADCflg = false;
Serial.println((float)(timer0));
if(millis() - last_millis >= 1000)
{
last_millis = millis();
Serial.print("COMP:\t ");
Serial.print(val_01);
Serial.print(" ");
Serial.print(Index);
Serial.print(" ");
for(byte i = 0; i < 10; i++)
Serial.println(micros_save[i]);
//Serial.println((float)(timer1-timer0));
}
}
//delay (1000);
}
А так
Спойлер
void loop(void)
{
static unsigned long last_millis = 0;
static unsigned long micros_save[4] = {0, 0, 0, 0};
static byte cycle = 0;
if (ADS.isReady() && ADCflg)
{
if(cycle < 4)
micros_save[cycle++] = micros();
// val_01 = (ADS.toVoltage(ADS.getValue()))*1000000;
val_01 = ADS.toVoltage(value_ ) * 1000000 ; //
//timer0 = micros();
//ADS.requestADC_Differential_0_3();//не будет работать - раскомментировать эту строчку
//timer1 = micros();
ADCflg = false;
Serial.println((float)(timer0));
if(millis() - last_millis >= 1000)
{
last_millis = millis();
Serial.print("COMP:\t ");
Serial.print(val_01);
Serial.print(" ");
Serial.print(Index);
Serial.print(" ");
for(byte i = 0; i < 4; i++)
Serial.println(micros_save[i]);
//Serial.println((float)(timer1-timer0));
}
}
//delay (1000);
}
Всё получилось в такой версии:
ISR(TIMER1_COMPA_vect)
{
sei();
static unsigned long prev_time = 0;
unsigned long _time = micros();
unsigned long _period = _time - prev_time;
prev_time = _time;
Serial.println(_period, DEC);
//timer0 = millis() - timer0;
value_ = ADS.readADC_Differential_0_3();
array_is_full = true;
reading_is_allowed = true;
//Serial.println((float)(timer1));
//ADS.requestADC_Differential_0_1(); // запуск преобразования для дифференциального чтения между входами 0 и 1 АЦП
//ADS.requestADC_Differential_0_3(); // запуск преобразования для дифференциального чтения между входами 0 и 3 АЦП
//ADS.requestADC_Differential_1_3(); // запуск преобразования для дифференциального чтения между входами 1 и 3 АЦП
//ADS.requestADC_Differential_2_3(); // запуск преобразования для дифференциального чтения между входами 2 и 3 АЦП
//timer0 = timer1;
//reading_is_allowed = true; // выставляем флаг "чтение результата преобразования разрешено"
//TCNT1 = 0; // Обнуляем счетный регистр TCNT1 таймера/счетчика T1
Index++;
}
Так в моём примере она и так закоментирована.
Результат правильный, вывод подправил
4-ре замера подряд. Разницу видно.
Спойлер
void loop(void)
{
static unsigned long last_millis = 0;
static unsigned long micros_save[4] = {0, 0, 0, 0};
static byte cycle = 0;
if (ADS.isReady() && ADCflg)
{
if(cycle < 4)
micros_save[cycle++] = micros();
// val_01 = (ADS.toVoltage(ADS.getValue()))*1000000;
val_01 = ADS.toVoltage(value_ ) * 1000000 ; //
//timer0 = micros();
//ADS.requestADC_Differential_0_3();//не будет работать - раскомментировать эту строчку
//timer1 = micros();
ADCflg = false;
//Serial.println((float)(timer0));
if(millis() - last_millis >= 1000)
{
last_millis = millis();
Serial.print("COMP:\t ");
Serial.print(val_01);
Serial.println();
for(byte i = 0; i < 4; i++)
Serial.println(micros_save[i]);
//Serial.println((float)(timer1-timer0));
}
}
//delay (1000);
}
P.S. Подправил
Понимаю, что совать всё подряд в обработчик прерывания не следует, но, думаю, что для проверки можно.
Ну да, их там две ))
ОК. Спасибо за помощь.
интересно, с какой целью таймер приводится к типу флоат перед печатью.
Думаю, просто для единообразия
Единообразия с чем?