Снятие показаний с датчика с высокой частотой

я не знаю, что он там напереводил, разбираем по правилам русского языка, мы же русские люди:
Аналоговый выход *2 - 4-20ма (точка)

ДАЛЕЕ ПАРАМЕТРЫ АНАЛОГОВОГО ВЫХОДА 4 - 20 МА:
сопротивление нагрузки …

1 лайк

Сорян. В походных условиях, поспешил, поверил) по ходу не прокатило)

судя из даташита это я заблуждался, датчик имеет три режима выхода:

  1. Токовая петля (основной)
  2. Датчик напряжения, выход по АЦП в дифф. режиме ±5, аналоговая земля изолирована
  3. Датчик напряжения, выход на АЦП в обычном режиме 1-5 вольт

Если у датчика есть “выход по АЦП”, так не нужно морочить себе и окружающим голову, а нужно снимать с датчика показания прямо в цифре.

тут я оговорился, конечно для АЦП

PS русский языка такой неоднозначный

Пока такое решение от аналога, чтобы тему подвести ближе к концу.

Подключение датчика:

Спойлер

Можно сопротивление увеличить до 200 Ом, но мне разрешения хватает

Скетч ардуино:

#include <Wire.h>
#include <Adafruit_ADS1X15.h>

Adafruit_ADS1115 ads;

void setup() {
  Serial.begin(115200);                  // Инициализация последовательного порта на 115200 бод
  Wire.begin();                          // Запускаем библиотеку Wire для I2C
  ads.begin();                           // Инициализация ADS1115
  ads.setGain(GAIN_ONE);                 // Установка усиления
  ads.setDataRate(RATE_ADS1115_860SPS);  // Установка скорости выборки 860 SPS
}

void loop() {
  Serial.write(0xFF);  // Контрольная точка

  int16_t adc = ads.readADC_SingleEnded(0);  // Читаем значение с первого канала (A0) 
  // Передача данных через UART
  uint8_t highByte = (adc >> 8) & 0xFF;  // Старший байт
  uint8_t lowByte = adc & 0xFF;          // Младший байт
  // Преобразуем 16-разрядное значение в два байта
  Serial.write(highByte);  // Отправляем старший байт
  Serial.write(lowByte);   // Отправляем младший байт



  // добавляем в двух-байтовом формате мсек
  unsigned long ms = millis();  // Текущие миллисекунды
  // Выделяем старший (high) и младший (low) байты
  uint8_t highByte2 = (ms >> 8) & 0xFF;  // Старший байт
  uint8_t lowByte2 = ms & 0xFF;          // Младший байт
  // Передача байтов
  Serial.write(highByte2);  // Старший байт
  Serial.write(lowByte2);   // Младший байт

  // delay(1);  // Задержка. при необходимости
}

Главное замечание по коду скетча: все же надо заголовок (проверочный код) ставить 2-х байтовым иначе возникают “проскоки”.

Добавил может временно миллисекунды. Скорость вывода в порт при этом можно сказать не меняется, но интереснее иметь время. Если убрать работу ADS скорость возрастает в разы.

Спойлер

Главная часть работы программы на VisualBasic.net:

   Private Sub serialPort_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles serialPort.DataReceived
       If receivingData Then
           Dim bytesToRead As Integer = serialPort.BytesToRead         ' количество байт в порту
           serialPort.Read(buffer, kol, bytesToRead)                   ' считываем по байтово и заполняем массив buffer байтами
           kol = kol + bytesToRead

           Label1.Text = kol
       End If
   End Sub

Результаты обработки затухающего колебания по количеству точек:

В принципе амплитуду видно явным образом. При особом желании, которого у меня нет, можно перейти на другой АЦП приведенный выше.

Забыл добавить. По фреймам не стал выводить, контрольную сумму тоже

Спасибо всем

поясните эту фразу. Если убрать что?

Из скетча убрать получение данных. Проверил, что именно “тормозит” кроме меня

Если бы вы перевели АДС в continuous mode, а не запускали каждый раз конверсию в блокирующем режиме - у вас все работало бы быстрее.

Лучше покажите этот же график, где по Х нанесено время. Это даст возможность оценить, какая у вас реальная скорость чтения АЦП.

Добавка - нашел эти данные в спойлере, примерно 400 SPS вместо 860-ти. Переходите в continuous mode, скорость должна вырасти.

Если правильно понял, что за режим, то не ускорилось. Или неверно истолковал (поместил в цикл в скетче, не стал пока убирать время)

void loop() {

 while(true){
 


  Serial.write(0xFF);  // Контрольные точки
  Serial.write(0xFF);  // Контрольные точки

  int16_t adc = ads.readADC_SingleEnded(0);  // Читаем значение с первого канала (A0) - ЗДЕСЬ ТОРМОЗИТ
  // Передача данных через UART
  uint8_t highByte = (adc >> 8) & 0xFF;  // Старший байт
  uint8_t lowByte = adc & 0xFF;          // Младший байт
  // Преобразуем 16-разрядное значение в два байта
  Serial.write(highByte);  // Отправляем старший байт
  Serial.write(lowByte);   // Отправляем младший байт



  // добавляем в двух-байтовом формате мсек
  unsigned long ms = millis();  // Текущие миллисекунды
  // Выделяем старший (high) и младший (low) байты
  uint8_t highByte2 = (ms >> 8) & 0xFF;  // старший байт
  uint8_t lowByte2 = ms & 0xFF;          // младший байт
  // Передача байтов
  Serial.write(highByte2);  // Сначала высший байт
  Serial.write(lowByte2);   // Затем низший байт

  }

  // delay(1);  // Задержка. при необходимости
}

Похоже нет. Я, честно говоря, вообще не вижу что вы изменили по сравнению с прошлым вариантом.
В библиотеке есть пример использования непрерывного режима, посмотрите. Смысл в том, что вам не нужно пинать АДС для выполнения каждого замера, вы запускаете непрерывное преобразование в фоне и потом просто читаете результаты.

2 лайка

Можно и без библиотеки, там два байта конфигурации просто установить и потом соответственно читать, пишешь в нулевой регистр и читаешь пока не отдаст два байта, будет быстрее (может быть)

по крайней мере тогда у него печать результатов будет идти параллельно с измерением нового значения, а не последовательно, как сейчас

Не могу понять почему не работает с проверкой получения новых данных через new_data

#include <Adafruit_ADS1X15.h>
Adafruit_ADS1115 ads;

#ifndef IRAM_ATTR
#define IRAM_ATTR
#endif

constexpr int READY_PIN = 0; //пробовал разные пины

volatile bool new_data = false;
void IRAM_ATTR NewDataReadyISR() {
  new_data = true;
}

void setup(void) {
  Serial.begin(115200);                  //скорость передачи
  ads.setGain(GAIN_ONE);                 // Установка усиления (можно изменить в зависимости от вашего датчика)
  ads.setDataRate(RATE_ADS1115_860SPS);  // Установка скорости выборки 860 SPS

  if (!ads.begin()) {
    while (1)
      ;
  }  //ждем подключения


  pinMode(READY_PIN, INPUT);
  // With default COMP_POL=0, get a rising edge every time a new sample is ready.
  attachInterrupt(digitalPinToInterrupt(READY_PIN), NewDataReadyISR, RISING);


  // Старт в continuous режиме
  ads.startADCReading(ADS1X15_REG_CONFIG_MUX_SINGLE_0, true);
}

void loop(void) {

  if (!new_data) {
    return;
  }


  Serial.write(0xFF);  // Контрольные точки
  Serial.write(0xFF);  // Контрольные точки

  //Передача измерения в двухбайтовом формате
  int16_t adc = ads.getLastConversionResults();  //Снимаем точки в continuous режиме
  // Передача данных через UART
  uint8_t highByte = (adc >> 8) & 0xFF;  // Старший байт
  uint8_t lowByte = adc & 0xFF;          // Младший байт
  // Преобразуем 16-разрядное значение в два байта
  Serial.write(highByte);  // Отправляем старший байт
  Serial.write(lowByte);   // Отправляем младший байт

  //Передача мсек в двухбайтовом формате
  unsigned long ms = millis();  // Текущие миллисекунды
  // Выделяем старший (high) и младший (low) байты
  uint8_t highByte2 = (ms >> 8) & 0xFF;  // старший байт
  uint8_t lowByte2 = ms & 0xFF;          // младший байт
  // Передача байтов
  Serial.write(highByte2);  // Сначала высший байт
  Serial.write(lowByte2);   // Затем низший байт

  new_data = false;

}

Если через delay, то данные нормально идут с интервалом 1,5 мсек, но понятно, что раз в n-мсек повторное значение, т.к. в буфере данные не успевают обновиться

Спойлер
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1115 ads;

void setup(void) {
  Serial.begin(115200);                  //скорость передачи
  ads.setGain(GAIN_ONE);                 // Установка усиления (можно изменить в зависимости от вашего датчика)
  ads.setDataRate(RATE_ADS1115_860SPS);  // Установка скорости выборки 860 SPS

  if (!ads.begin()) {
    while (1)
      ;
  }  //ждем подключения

  // Старт в continuous режиме
  ads.startADCReading(ADS1X15_REG_CONFIG_MUX_SINGLE_0, true);
}

void loop(void) {

  Serial.write(0xFF);  // Контрольные точки
  Serial.write(0xFF);  // Контрольные точки

  //Передача измерения в двухбайтовом формате
  int16_t adc = ads.getLastConversionResults();  //Снимаем точки в continuous режиме
  // Передача данных через UART
  uint8_t highByte = (adc >> 8) & 0xFF;  // Старший байт
  uint8_t lowByte = adc & 0xFF;          // Младший байт
  // Преобразуем 16-разрядное значение в два байта
  Serial.write(highByte);  // Отправляем старший байт
  Serial.write(lowByte);   // Отправляем младший байт

  //Передача мсек в двухбайтовом формате
  unsigned long ms = millis();  // Текущие миллисекунды
  // Выделяем старший (high) и младший (low) байты
  uint8_t highByte2 = (ms >> 8) & 0xFF;  // старший байт
  uint8_t lowByte2 = ms & 0xFF;          // младший байт
  // Передача байтов
  Serial.write(highByte2);  // Сначала высший байт
  Serial.write(lowByte2);   // Затем низший байт


  delay(1);  // Задержка необходима
}

Может потому что

Надо не наобум “пробовать”, а знать, какой пин подходит для этого. Прерывания работают не на всех пинах.
Напомните, какой контроллер у вас? Нано?

Да, нано. ADS подключен к А4 (SDA) и А5 (SCL). На ADS к A0 датчик

На Нано для прерывания можно использовать пины 2 и 3.

А у вас в коде пин 0 - это вообще грубейшая ошибка. Мало того что на этом пине не работают прерывания - пин 0(а также пин1) заняты соединением с ПК. Если вы повесите что-то на эти пины - у вас перестанет работать Serial

Да, PIN0 просто уже пробовал в скетче ради интереса, т.к. не нашел описания, но не по железу подключал.

То есть здесь указать 3? Это не работало (понимаю, что явно здесь неверно что-то)

constexpr int READY_PIN = 0;

А по железу на ардуино надо что-то подключение менять?

Или где можно это почитать…?

По-моему нет.
Насколько я вижу, вы постарались повторить пример из библиотеки. На первый взгляд все верно.