Почему я не могу распечатать значения логических переменных (0 и 1) с помощью функции println?

исходный код:

int buttonPin = 8;
boolean buttonState = 0;

void setup()
{
   Serial.begin(9600);
   pinMode (buttonPin, INPUT);
}

void loop()
{
   buttonState = digitalRead(buttonPin);
   Serial.println(buttonState);
   delay(500);
}

Но когда вместо логического значения я указываю тип данных int для переменной buttonState, он дает желаемый результат, т.е. 1 при нажатии и 0, когда не нажимается. Связано ли это с тем, что эти переменные, когда они указаны с разными типами данных, дают разные значения функции println() для преобразования их в значения ASCII?

, 👍3

Обсуждение

У меня работает нормально. Какую версию IDE вы используете и, что более важно, какая версия пакета плат AVR установлена?, @Majenko

У меня также нет проблем с приведенным выше кодом., @Rudy

После тестирования вашего эскиза с использованием boolean, bool и byte все они работали правильно. Используя bool с IDE версии 1.0.6.2 и GCC версии 4.2.1, размер двоичного эскиза увеличился на 108 байт (ой). Если boolean вам не подходит, попробуйте использовать byte. Оба типа переменных занимают один байт памяти., @VE7JRO


1 ответ


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

3

Во-первых, вы не должны использовать boolean с digitalRead.

Прототип функции в Arduino.h:

int digitalRead(uint8_t);

Таким образом, правильный тип данных для buttonState в вашем коде — int. Тогда другая проблема исчезнет. Я предполагаю, что дело в том, что используемая вами версия IDE не имеет перегруженной функции для Serial.println, которая принимает аргумент boolean, а компилятор преобразуя его в byte, и в этом случае он будет печататься как 0x00 (LOW) или 0x01 (HIGH), которые не являются печатными символами.

К сожалению, в документации по digitalRead на сайте Arduino не упоминается тип данных, он просто упоминает, что возвращает HIGH или LOW, что не очень помогает вам определить, какой тип данных использовать. Кстати, ни одно из этих значений по сути не является логическим. Если бы они сказали, что он возвращает true или false, вы могли бы разумно поместить результат в логическое поле.

Я пытался убедить разработчиков Arduino улучшить документацию в этом отношении, и они это сделали отказался делать. Я поднимал этот вопрос почти 4 года назад, а конкретно эту задачу никому даже не поручили.


Если вы настаиваете на использовании логического типа, разумным способом печати будет следующий:

Serial.println(buttonState ? "HIGH" : "LOW");

В ответ на некоторые комментарии...

У меня работает нормально. – Маженко

...

boolean — это определение типа для bool. bool преобразуется в int, а не в byte - Маженко

То, что вы подразумеваете под «является определением типа для bool», в некоторых (более поздних) версиях IDE.

Глядя, например, на предварительную версию Arduino 0023, я вижу в файле Wiring.h:

typedef uint8_t boolean;
typedef uint8_t byte;

Итак, вы можете ясно видеть, что логическое значение и байт - это одно и то же, и, следовательно, использование логического значения будет рассматриваться как байт. Теперь, если вы посмотрите на класс Print в этом выпуске:

class Print
{
  private:
    void printNumber(unsigned long, uint8_t);
    void printFloat(double, uint8_t);
  public:
    virtual void write(uint8_t) = 0;
    virtual void write(const char *str);
    virtual void write(const uint8_t *buffer, size_t size);

    void print(const String &);
    void print(const char[]);
    void print(char, int = BYTE);
    void print(unsigned char, int = BYTE);
    void print(int, int = DEC);
    void print(unsigned int, int = DEC);
    void print(long, int = DEC);
    void print(unsigned long, int = DEC);
    void print(double, int = 2);

    void println(const String &s);
    void println(const char[]);
    void println(char, int = BYTE);
    void println(unsigned char, int = BYTE);
    void println(int, int = DEC);
    void println(unsigned int, int = DEC);
    void println(long, int = DEC);
    void println(unsigned long, int = DEC);
    void println(double, int = 2);
    void println(void);
};

Итак, вы можете видеть, что перегрузка для print и println обрабатывает беззнаковый символ (фактически uint8_t), который нужно напечатать с помощью Обработка по умолчанию BYTE, а не обработка DEC.

BYTE объявлен:

#define BYTE 0

А пишется так:

void Print::print(unsigned long n, int base)
{
  if (base == 0) write(n);
  else printNumber(n, base);
}

Это сводится к тому, что и byte, и boolean будут записаны как «двоичные» байты, а не преобразованы в десятичные.

Как говорит Маженко, сегодня ситуация изменилась, и boolean теперь эквивалентен bool, который повышен до int.


ElectroManiac не ответил на вопрос о том, какую версию IDE он/она использует, однако я хочу сказать, что для некоторых версий IDE мое объяснение верно.


Да, и присвоение возврата digitalRead логическому значению вполне допустимо...

Да, для bool, но вопрос был о boolean. Хотя мы знаем, прочитав код и прочитав документацию, что digitalRead вернет 0 или 1, тот факт, что тип возвращаемого значения — int , означает, что компилятор потенциально может увидеть, что вы вставляете 16. -битное возвращаемое значение в 8-битную переменную, что может привести к усечению данных.

Я должен признать, что не получаю предупреждения при компиляции с помощью Arduino IDE, однако вероятность усечения определенно существует. Тестовая программа, написанная на C++ и скомпилированная с флагом -Wconversion, выдает подходящее предупреждение:

warning: conversion to ‘uint8_t {aka unsigned char}’ from ‘int’ may alter its value [-Wconversion]

(Если вы помещаете результат в bool, предупреждение не выдается, однако это не та версия IDE, которую использует OP).

,

разве HIGH/LOW, true/false или 0/1 не одно и то же для микроконтроллера? Подобно тому, как эти значения интерпретируются микроконтроллером r как одни и те же бит 0 и бит 1., @MrDeepThought

Зависит от того, что вы подразумеваете под «то же самое». Внутренне они есть. Однако для компилятора разные типы могут означать, что он вызывает другую функцию для печати, особенно когда вы используете перегруженные функции C++, примером которых является println., @Nick Gammon

Я не могу получить полное представление о функции print() или println() с сайта Arduino., @MrDeepThought

Например, если вы указываете номер типа INT, например 123, разделяет ли он число на отдельные цифры, например 1, 2 и 3, а затем преобразует его в двоичные данные для интерпретации Arduino, а затем преобразует эти цифры в символ ASCII, представляющий это же число. а затем распечатывает его на экране! И поскольку print() принимает все типы данных (будучи перегруженной функцией),, @MrDeepThought

и поскольку логическое значение возвращает тип данных BYTE (бит 0 и бит 1) в качестве аргумента для print(), оно преобразует его в символы ASCII, которые не могут быть распечатаны последовательным монитором Arduino. Я прав?, @MrDeepThought

И если я ошибаюсь, не могли бы вы рассказать мне о своих знаниях о функции print()?, @MrDeepThought

boolean — это определение типа для bool. bool повышается до int, а не до byte (["тип bool может быть преобразован в int со значением false, равным 0, и true, равным 1."](https://en.cppreference.com /w/cpp/language/implicit_conversion)). В Gnu C bool — это макрос, задающий внутренний (специфичный для GCC) тип _Bool, а не byte. В Gnu C++ bool — это встроенный внутренний тип., @Majenko

Да, и присвоение возврата digitalRead типу bool совершенно допустимо, поскольку *"нулевое значение (для целого числа, перечисления с плавающей запятой и перечисления без области видимости), а также нулевой указатель и значения нулевого указателя на член становятся ложными. Все остальные значения становятся истинными».*. А поскольку LOW просто равен 0 и HIGH 1, они прекрасно сопоставляются с false и true в bool., @Majenko

Хотя было бы неплохо иметь перегруженную функцию print типа bool - возможно, такую, которая печатает Y и N, или, возможно, T и F., @Majenko

@Маженко (и другие) видят исправленный ответ о том, для чего boolean является определением типа., @Nick Gammon

*Например, если вы задаете номер типа INT, например 123, он разделяет число на отдельные цифры, например 1,2 и 3, а затем преобразует его в двоичные данные для интерпретации Arduino* - это не имеет ничего общего с Arduino per се. Этот вопрос о том, как печатаются переменные, а это совсем другой вопрос., @Nick Gammon