Я пытаюсь организовать свою библиотеку UART и украсить ее немного путем добавления некоторого #define s, таким образом, я могу настроить ее позже, не имея необходимость рыть глубоко в код, но я, может казаться, не получаю следующий бит работы кода:
#define FOSC 8000000
#define BAUDRATE 9600
#define BRGVAL (FOSC/2)/(16*BAUDRATE)-1
void uart_init(){
U1BRG = BRGVAL;
}
После вычисления BRGVAL становится 25.0416667, и потому что это не целое число, я получаю соблюдающее предупреждение для него, когда я присваиваю это в U1BRG:
UART.c: В функции 'uart_init':
UART.c:24: предупреждение: целочисленное переполнение в выражении
... и код просто не работает над целевыми аппаратными средствами. (Если я вручную вставил U1BRG = 25, он работает как очарование хотя),
Там какой-либо путь состоит в том, чтобы преобразовать тип той константы в целое число для создания компилятора счастливым?
Большое спасибо, гамза.
Целочисленное переполнение означает, что вы превысили верхний предел значения int, которое, вероятно, будет 32767, если вы получаете эту ошибку. Это не имеет ничего общего с плавающей точкой; указанные вами операции на самом деле являются целочисленными математическими операциями, поэтому дробная часть деления в любом случае отбрасывается.
Попробуйте что-то вроде этого:
#define FOSC 8000000L
#define BAUDRATE 9600L
#define BRGVAL ((unsigned int)((FOSC/2)/(16*BAUDRATE)-1))
void uart_init(){
U1BRG = BRGVAL;
}
Суффикс L превращает эти константы в тип long
вместо типа int
. Приведение (unsigned int)
преобразуется в тип U1BRG и сообщает компилятору, что вы понимаете, что значение long
впишется в unsigned int
и, таким образом, скроет любые предупреждения, которые он может вам бросить.
Обычно отключать предупреждения компилятора - плохая практика, но в этом случае ясно, что, хотя вам понадобится long
для хранения промежуточных значений в вычислениях, конечный результат будет соответствовать беззнаковым int
.
Из вашего примера не ясно, является ли U1BRG глобальной переменной или константой, определяемой #. В любом случае простое приведение к целому числу должно работать:
U1BRG = (int)BRGVAL;
Вы не смогли указать на это, какой тип данных у U1BRG? Если это int
, приведите его как показано
#define FOSC 8000000 #define BAUDRATE 9600 #define BRGVAL ((long)(FOSC/2)/(16*BAUDRATE)-1) void uart_init(){ U1BRG = BRGVAL; }
Edit: Исправлено, чтобы принять во внимание комментарий Адама Лисса о том, что беззнаковое int слишком мало для сохранить результат макроса, я изменил его, чтобы сделать его длинным
... Спасибо Адаму за предупреждение ...
Надеюсь, это поможет, С уважением , Том.
Я бы, вероятно, использовал это:
#define BRGVAL ((int)(FOSC/2)/(16*BAUDRATE)-1)
Мне нравится ответ Филиппа, но я думаю, что лучшим решением будет сократить формулу и изменить макрос на:
#define BRGVAL (FOSC/32/BAUDRATE-1)
При этом вы устраняете cast, чтобы компилятор мог продолжать предупреждать вас, если вы выберете низкую скорость передачи данных, что приведет к слишком большому значению делителя для 16-битного int.