Формула последовательного регистра COM
Я работаю над 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));
@gowb0w, 👍0
1 ответ
Лучший ответ:
Здесь:
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. (он есть в формуле из таблицы данных).
- устаревшее преобразование из строковой константы в 'char*'
- Как запрограммировать ардуино на чистом C/C++?
- Количество элементов в массиве char
- Регистры ввода-вывода SAM3X8E (Arduino Due)
- как быстро loop() работает в Arduino
- Arduino: как получить тип платы в коде
- Как вызвать функции C из скетча ардуино?
- Как преобразовать полезную нагрузку byte* в строку