Формула последовательного регистра COM

c

Я работаю над atmega328p, учусь использовать его регистры вместо кодирования с помощью обычного кода Arduino.

Я нашел эту формулу для получения скорости передачи данных на последовательном порту (используя протокол USART):

как я могу набрать это на языке C? или конкретно в arduino IDE?

--

Я провел некоторые исследования и обнаружил, что это можно записать таким образом:

float _baudrate = (16000000/(16*9600));

затем я преобразую значение в int (потому что мне нужно целочисленное значение)

int _baudrate_int = (int)_baudrate;enter code here

Все это, конечно, для скорости 9600 бод.

Но когда я это делаю, я не понимаю почему, код не вычисляет правильно. У меня должно быть 103-104, а я получаю 710.

Это сработает, если я вручную введу (16*9600) product. То есть 153600

float _baudrate = (16000000/153600);

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

где моя ошибка в этой строке кода?

float _baudrate = (16000000/(16*9600));

, 👍0


1 ответ


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

0

Здесь:

float _baudrate = (16000000/(16*9600)

за исключением отсутствующих скобок и точки с запятой, у вас есть целое число переполнение. Проблема в том, что на Arduino на базе AVR int доступен только 16-битная длина. Константы 16 и 9600 достаточно малы, чтобы поместиться int, им неявно дается тип int. Затем их Умножение также выполняется с типом int, а произведение переполняется и обертывается по модулю 216 до 22528.

Вы можете исправить это, указав один или оба этих числа как L суффикс, который заставит их использовать тип данных long. В качестве альтернативы, если Если вам нужно вычисление с плавающей точкой, вы можете использовать .0 в качестве суффикса.

Не то чтобы avr-libc предоставлял заголовочный файл с некоторыми макросами для этого расчет, который затем выполняется препроцессором: <util/setbaud.h>: Вспомогательные макросы для скорости передачи данных расчеты. Вы можете использовать их следующим образом:

#define BAUD 9600
#include <util/setbaud.h>

void set_baud_rate() {
    UBRR0 = UBRR_VALUE;
#if USE_2X
    UCSR0A |= _BV(U2X0);
#else
    UCSR0A &= ~_BV(U2X0);
#endif
}

Редактировать:

Отвечая на вопрос в комментарии: да, суффикс L создает long константа, и таким образом это похоже на создание long переменной (за исключением того, что это константа, а не переменная).

Я предлагаю вам взглянуть на строку ниже из setbaud.h. В случае где U2X0 не требуется, значение регистра скорости передачи данных вычисляется как:

#define UBRR_VALUE (((F_CPU) + 8UL * (BAUD)) / (16UL * (BAUD)) -1UL)

Несколько вещей, на которые следует обратить внимание:

  • Все это вычисляется с помощью целых чисел, без плавающей точки. На самом деле, вычисления выполняются компилятором во время сборки, а не Ардуино.
  • Суффикс UL означает unsigned long
  • Добавление 8 перед делением на 16 — это способ округлить результат до Ближайшее целое число, вместо округления до нуля. Равенства округляются в большую сторону.
  • В конце есть -1UL, так как это требуется для оборудования UART. (он есть в формуле из таблицы данных).
,