TCCR1B' не был объявлен в этой области

Я пытаюсь использовать MS5540C (цифровой датчик давления). и пример кода имеет эту строку:

 TCCR1B = (TCCR1B & 0xF8) | 1; //генерирует сигнал MCLK

Я немного новичок в IoT, но могу проверить SPI.h и убедиться, что объявления действительно нет.

Я использую Arduino UNO WiFi Rev 2. (Кажется, его контакты совсем не такие, как у UNO) Я отметил в комментариях, что я использую контакты 32,33,34 вместо 11,12,13

Я не уверен на 100 %, о чем спрашивать… кроме Есть ли заменяющий вызов/функция/метод, который должен заменить эту строку? ..или я что-то совсем другое упускаю. В нынешнем виде... когда программа запускается, ее результаты противоречивы. Я просто комментирую ошибочную строку, чтобы она скомпилировалась.

Полный скетч источник: Электроника будущего

/*
Модуль миниатюрного барометра MS5540C
Эта программа будет считывать ваш MS5440C или совместимый датчик давления каждые 5 секунд и показывать вам слова калибровки, коэффициенты калибровки,
необработанные значения и компенсированные значения температуры и давления.
После того, как вы прочитаете калибровочные коэффициенты, вы можете определить их в заголовке любого скетча, который вы пишете для датчика.

  Uno Pins:
  MS5540 sensor attached to pins 10 - 13:
  MOSI: pin 11
  MISO: pin 12
  SCK: pin 13
  MCLK: pin 9 (or use external clock generator on 32kHz)
  CS is not in use, but might be pin 10

  ==[ addendum start]=============================
  Uno WiFi Rev2 Pins:
  MOSI: pin 32
  MISO: pin 33
  SCK: pin 34
  MCLK: pin 9 (or use external clock generator on 32kHz)
  ==[ addendum end ]=============================

  created 29 February 2012
  by MiGeRA
*/

/*
  Calibration of my sensor example ...

  Calibration word 1 = 46958
  Calibration word 2 = 65369
  Calibration word 3 = 39392
  Calibration word 4 = 45914
  c1 = 23479
  c2 = 2074
  c3 = 717
  c4 = 615
  c5 = 1021
  c6 = 25
*/

#include <SPI.h>

const int clock = 9;

void setup() {
  Serial.begin(9600);
  SPI.begin(); //подробности см. в библиотеке SPI на arduino.cc
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV32); //делим 16 МГц для связи на 500 кГц

  pinMode(clock, OUTPUT);
  delay(100);
}

void loop()
{
  Serial.println("=====================================================================");
  TCCR1B = (TCCR1B & 0xF8) | 1; //генерирует сигнал MCLK

  analogWrite (clock, 128) ;
  resetsensor(); //сбрасывает датчик - осторожно: потом mode = SPI_MODE0!

  //Калибровочное слово 1
  unsigned int result1 = 0;
  unsigned int inbyte1 = 0;
  SPI.transfer(0x1D); // отправляем первый байт команды, чтобы получить калибровочное слово 1
  SPI.transfer(0x50); //отправляем второй байт команды, чтобы получить калибровочное слово 1
  SPI.setDataMode(SPI_MODE1); //изменить режим, чтобы слушать
  result1 = SPI.transfer(0x00); // отправляем фиктивный байт для чтения первого байта слова
  result1 = result1 << 8; // сдвиг возвращаемого байта
  inbyte1 = SPI.transfer(0x00); // отправляем фиктивный байт для чтения второго байта слова
  result1 = result1 | inbyte1; //объединяем первый и второй байт слова
  Serial.print("Calibration word 1 = ");
  Serial.print(result1, HEX);
  Serial.print(" ");
  Serial.println(result1);

  resetsensor(); //сбрасывает датчик

  //Калибровочное слово 2; см. комментарии к калибровочному слову 1
  unsigned int result2 = 0;
  byte inbyte2 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0x60);
  SPI.setDataMode(SPI_MODE1);
  result2 = SPI.transfer(0x00);
  result2 = result2 << 8;
  inbyte2 = SPI.transfer(0x00);
  result2 = result2 | inbyte2;
  Serial.print("Calibration word 2 = ");
  Serial.print(result2, HEX);
  Serial.print(" ");
  Serial.println(result2);

  resetsensor(); //сбрасывает датчик

  //Калибровочное слово 3; см. комментарии к калибровочному слову 1
  unsigned int result3 = 0;
  byte inbyte3 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0x90);
  SPI.setDataMode(SPI_MODE1);
  result3 = SPI.transfer(0x00);
  result3 = result3 << 8;
  inbyte3 = SPI.transfer(0x00);
  result3 = result3 | inbyte3;
  Serial.print("Calibration word 3 = ");
  Serial.print(result3, HEX);
  Serial.print(" ");
  Serial.println(result3);

  resetsensor(); //сбрасывает датчик

  //Калибровочное слово 4; см. комментарии к калибровочному слову 1
  unsigned int result4 = 0;
  byte inbyte4 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0xA0);
  SPI.setDataMode(SPI_MODE1);
  result4 = SPI.transfer(0x00);
  result4 = result4 << 8;
  inbyte4 = SPI.transfer(0x00);
  result4 = result4 | inbyte4;
  Serial.print("Calibration word 4 = ");
  Serial.print(result4, HEX);
  Serial.print(" ");
  Serial.println(result4);

  // теперь мы делаем битовый сдвиг, чтобы извлечь коэффициенты калибровки
  //из калибровочных слов;
  long c1 = (result1 >> 1) & 0x7FFF;
  long c2 = ((result3 & 0x003F) << 6) | (result4 & 0x003F);
  long c3 = (result4 >> 6) & 0x03FF;
  long c4 = (result3 >> 6) & 0x03FF;
  long c5 = ((result1 & 0x0001) << 10) | ((result2 >> 6) & 0x03FF);
  long c6 = result2 & 0x003F;

  Serial.print("c1 = ");
  Serial.println(c1);
  Serial.print("c2 = ");
  Serial.println(c2);
  Serial.print("c3 = ");
  Serial.println(c3);
  Serial.print("c4 = ");
  Serial.println(c4);
  Serial.print("c5 = ");
  Serial.println(c5);
  Serial.print("c6 = ");
  Serial.println(c6);

  resetsensor(); //сбрасывает датчик

  //Давление:
  unsigned int presMSB = 0; //первый байт значения
  unsigned int presLSB = 0; //последний байт значения
  unsigned int D1 = 0;
  SPI.transfer(0x0F); //отправляем первый байт команды для получения значения давления
  SPI.transfer(0x40); //отправляем второй байт команды для получения значения давления
  delay(35); //ждем окончания конвертации
  SPI.setDataMode(SPI_MODE1); //изменить режим, чтобы слушать
  presMSB = SPI.transfer(0x00); // отправляем фиктивный байт для чтения первого байта значения
  presMSB = presMSB << 8; // сдвигаем первый байт
  presLSB = SPI.transfer(0x00); // отправляем фиктивный байт для чтения второго байта значения
  D1 = presMSB | presLSB; //объединяем первый и второй байт значения
  Serial.print("D1 - Pressure raw = ");
  Serial.println(D1);

  resetsensor(); //сбрасывает датчик

  // Температура:
  unsigned int tempMSB = 0; //первый байт значения
  unsigned int tempLSB = 0; //последний байт значения
  unsigned int D2 = 0;
  SPI.transfer(0x0F); // отправляем первый байт команды для получения значения температуры
  SPI.transfer(0x20); //отправляем второй байт команды для получения значения температуры
  delay(35); //ждем окончания конвертации
  SPI.setDataMode(SPI_MODE1); //изменить режим, чтобы слушать
  tempMSB = SPI.transfer(0x00); // отправляем фиктивный байт для чтения первого байта значения
  tempMSB = tempMSB << 8; // сдвигаем первый байт
  tempLSB = SPI.transfer(0x00); // отправляем фиктивный байт для чтения второго байта значения
  D2 = tempMSB | tempLSB; //объединяем первый и второй байт значения
  Serial.print("D2 - Temperature raw = ");
  Serial.println(D2); //вуаля!

  //расчет реальных значений с помощью калибровочных коэффициентов и математических расчетов
  //в даташите. const ДОЛЖЕН быть длинным
  const long UT1 = (c5 << 3) + 20224;
  const long dT = D2 - UT1;
  const long TEMP = 200 + ((dT * (c6 + 50)) >> 10);
  const long OFF  = (c2 * 4) + (((c4 - 512) * dT) >> 12);
  const long SENS = c1 + ((c3 * dT) >> 10) + 24576;
  const long X = (SENS * (D1 - 7168) >> 14) - OFF;
  long PCOMP = ((X * 10) >> 5) + 2500;
  float TEMPREAL = TEMP / 10;
  float PCOMPHG = PCOMP * 750.06 / 10000; // мбар*10 -> мм рт.ст. === ((мбар/10)/1000)*750/06

  /*
    Serial.print("UT1 = ");
    Serial.println(UT1);
    Serial.print("dT = ");
    Serial.println(dT);
    Serial.print("TEMP = ");
    Serial.println(TEMP);
    Serial.print("OFFP = ");
    Serial.println(OFF);
    Serial.print("SENS = ");
    Serial.println(SENS);
    Serial.print("X = ");
    Serial.println(X);
  */

  Serial.print("Real Temperature in C = ");
  Serial.println(TEMPREAL);

  Serial.print("Compensated pressure in mbar = ");
  Serial.println(PCOMP);
  Serial.print("Compensated pressure in mmHg = ");
  Serial.println(PCOMPHG);

  //компенсация 2-го порядка только для T < 20°С или T > 45°С

  long T2 = 0;
  float P2 = 0;

  if (TEMP < 200)
  {
    T2 = (11 * (c6 + 24) * (200 - TEMP) * (200 - TEMP) ) >> 20;
    P2 = (3 * T2 * (PCOMP - 3500) ) >> 14;
  }
  else if (TEMP > 450)
  {
    T2 = (3 * (c6 + 24) * (450 - TEMP) * (450 - TEMP) ) >> 20;
    P2 = (T2 * (PCOMP - 10000) ) >> 13;
  }

  if ((TEMP < 200) || (TEMP > 450))
  {
    const float TEMP2 = TEMP - T2;
    const float PCOMP2 = PCOMP - P2;

    float TEMPREAL2 = TEMP2 / 10;
    float PCOMPHG2 = PCOMP2 * 750.06 / 10000; // мбар*10 -> мм рт.ст. === ((мбар/10)/1000)*750/06

    Serial.print("2-nd Real Temperature in C = ");
    Serial.println(TEMPREAL2);

    Serial.print("2-nd Compensated pressure in mbar = ");
    Serial.println(PCOMP2);
    Serial.print("2-nd Compensated pressure in mmHg = ");
    Serial.println(PCOMPHG2);
  }

  delay(5000);
}

void resetsensor() //эта функция делает скетч немного короче
{
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
}

, 👍0

Обсуждение

Вы сами написали этот код или где-то скопировали его части? Если хотя бы, дайте ссылку на этот источник, @chrisl

@chrisl Я добавил источник выше. Если вы скопируете текст... обратите внимание на символ, который представляет собой сочетание букв "f" и "l"!... т.е. в "float"... просто перепечатайте его., @Chris Catignani


1 ответ


Лучший ответ:

3

Во время написания этого ответа я узнал об эмуляции регистров Arduino Uno Wifi. Uno Wifi — это другой чип, чем Uno, поэтому у вас разные регистры. Но Uno Wifi задумывался как замена, поэтому эмуляция регистров сопоставляет старые имена регистров с новыми регистрами, так что вы можете просто повторно использовать старый код для Uno. В моей Arduino IDE (v1.8.9) у меня была встроенная плата Uno Wifi, в которой эмуляция регистров, кажется, включена без опции конфигурации (я мог бы скомпилировать ваш скетч даже для Uno Wifi). Через менеджер плат я установил ядро «Arduino megaAVR Boards», которое содержит Arduino Uno Wifi rev2. Если вы выберете эту плату в выборе платы, вы получите возможность выбрать эмуляцию регистра. Для старого кода нужна эмуляция ATmega328. После этого ваш старый код должен скомпилироваться.

Это делает остальную часть моего ответа ненужной, но, поскольку я уже потратил некоторое время на его написание, я оставлю его в ответе для информации и на тот случай, если вы не хотите использовать эмуляцию регистра.


Вы получаете ошибку, потому что скопированный вами скетч сделан для Arduino Uno, а не для Arduino Uno Wifi. В то время как в первом используется чип ATmega328P, последний построен на базе ATmega4809 (вы можете найти эту информацию здесь на Arduino. магазин копий). Это разные чипы, поэтому вы не можете просто повторно использовать код, созданный для Uno, в Uno Wifi.

TCCR1B — регистр управления B таймера 1. Это имя относится к микросхеме ATmega328P. У ATmega4809 таймеров даже больше, чем у 328P, но они, похоже, настраиваются через другие регистры. См. спецификации на сайте продукта ATmega4809. Аппаратное обеспечение таймера и его регистры описаны в более общем Техническое описание семейства megaAVR 0. На первый взгляд кажется, что отличается от 328P не только описание регистра, но и расположение разных конфигураций. Это означает, что каждый код, который использует прямые манипуляции с регистрами для таймера, должен быть переписан для 4809.

К счастью, я вижу здесь только 1 строку, которая делает следующее: Строка, вызвавшая ошибку компилятора. (В библиотеке SPI, скорее всего, уже есть подходящие определения для 4809). У вас есть линия

TCCR1B = (TCCR1B & 0xF8) | 1;

Это очищает 3 младших бита (оставляя остальные без изменений) и устанавливает для младшего значащего бита значение 1. Согласно главе 16.11.2 таблицы данных 328P (описание регистра TCCR1B), эти 3 бита являются выбор часов. Битовый код 001 (установлен только младший значащий бит) означает, что таймер включен, но без предварительного масштабирования.

Честно говоря, я не уверен, действительно ли эта строка что-то делает, так как сразу после этого вызывается analogWrite(), и я думал, что эта функция перезапишет настройки таймера. Но другие сообщения (например, этот) предполагают, что он, по крайней мере, не перезаписывает выбор часов.

Я не знаю, какой таймер используется для вывода ШИМ на этот контакт, но сейчас я предполагаю, что первый таймер типа B. Если вы посмотрите в таблицу данных семейств (как указано выше), источник тактового сигнала второй таймер (TCB) настраивается с помощью регистра TCB0.CTRLA (см. главу 20.5.1). Биты 1 и 2 настраивают предварительный делитель (двоичный 00 для отсутствия предварительного делителя), бит 0 включает таймер. Таким образом, вы можете снова записать двоичный код 001 в этот регистр, оставив остальные нетронутыми. Поэтому я предлагаю вам использовать эту строку вместо старой

TCB0.CTRLA = (TCB0.CTRLA & 0xF8) | 1;

Это должно сделать то же самое со вторым таймером, что было сделано в исходном скетче. Если для этого используется первый таймер, то вам придется заменить TCB0 на TCA0.SINGLE (я правда не знаю, зачем нужен этот SINGLE) и изменить 0xF8 на 0xF0, так как TCA имеет 3 бита для выбора источника синхронизации.

,

Я могу быть немного выше моей головы. У меня есть правильная плата в boardmanager. Я также попытался изменить эмуляцию. Я все еще получаю ошибку! Сначала я подумал, что препроцессор усложняет код. Калибровочные слова постоянно меняются. Теперь я вижу, что мне придется разобраться с регистрами, часами и т. д. и т. д., @Chris Catignani

Я думаю, что эмуляция не распространяется на таймеры, @Juraj

@Juraj Но старый код компилируется для меня только с эмуляцией регистров. Разве это не означает, что он также выполняет эмуляцию регистров таймера?, @chrisl