Сегодня решил перейти на последнюю версию, что-то меня бес попутал, столкнулся с забавной проблемой. Обычная библиотека для работы с UART, в ней практически ни чего нет, просто отправляем данные и принимаем через регистры. Различные варианты ее работали надежно, а тут шлет какую-то ерунду, с обычным Serial проблем нет. Понятно, что проблема с кодировкой, проверил кодировку в порядке, пытался исправить ее в Arduino IDE, так же менял в на UTF-8 в Visual Studio и Notepad++, без полезно. В итоге думал возвращаться на 1.0.x для AVR, пока не нашел в сети краткое сообщение, о том, что человек был вынужден перейти на 1.6.5 для корректной работы с ESP8266 и библиотеки Blynk (он пробовал 1.6.7 и 1.6.6). И о чудо, все заработало как часы. Возможно данный пост, будет кому-то полезен, я потратил 2 часа на поиск проблемы. В начале грешил на себя, так как код был переписан под конкретную реализацию. Сейчас перешел на 1.6.5, пока проблем нет. Так, что если Вы работаете с регистрами, Си и т.д. не спешите использовать версию 1.6.7. Удачи!
Сейчас не отвечу, удалил версию 1.6.7, ближе к вечеру попробую понять. Что он мне только не слал, когда начал пробовать переводить кодировки, и не понятные символы и даже русские символы. Вот код, в сообщение не влазит, оставил основное, остальное в прищепке, там ни чего особенного. Он всегда работал как часы на 1.0.x, на Мегах, Нанах, Леонардах и т.д, как и в версии 1.6.5. Код (C++): // UARTHeadRX - буфер RX для хранения "головы массива" // UARTTailRX - буфер RX для хранения "хвоста массива" static volatile uint8_t UARTHeadRX[UARTNumber],UARTTailRX[UARTNumber]; // UARTBufferRX - буфер RX для хранения данных static uint8_t UARTBufferRX[RXBufferSize][UARTNumber]; // UARTHeadTX - буфер TX для хранения "головы массива" // UARTBufferTX - буфер TX для хранения "хвоста массива" static volatile uint8_t UARTHeadTX[UARTNumber],UARTTailTX[UARTNumber]; // UARTBufferTX - буфер X для хранения данных static uint8_t UARTBufferTX[TXBufferSize][UARTNumber]; /// <summary> /// Прерывание по опустошению буфера UART /// </summary> #if defined(ARDUINO_MEGA_2560) || defined(ARDUINO_PRO_MICRO) ISR(USART1_UDRE_vect) { #if defined(ARDUINO_MEGA_2560) uint8_t t = UARTTailTX[1]; if (UARTHeadTX[1] != t) { if (++t >= TXBufferSize) { t = 0; } UDR1 = UARTBufferTX[t][1]; UARTTailTX[1] = t; } if (t == UARTHeadTX[1]) { UCSR1B &= ~(1<<UDRIE1); } #endif #if defined(ARDUINO_PRO_MICRO) uint8_t t = UARTTailTX[0]; if (UARTHeadTX[0] != t) { if (++t >= TXBufferSize) { t = 0; } UDR1 = UARTBufferTX[t][0]; UARTTailTX[0] = t; } if (t == UARTHeadTX[0]) { UCSR1B &= ~(1<<UDRIE1); } #endif } #endif /// <summary> /// Прерывание по завершению приема по каналу UART /// </summary> #if defined(ARDUINO_PRO_MINI) ISR(USART_RX_vect) { StoreUARTInBuf(UDR0, 0); } #endif #if defined(ARDUINO_PRO_MICRO) ISR(USART1_RX_vect) { StoreUARTInBuf(UDR1, 1); } #endif #if defined(ARDUINO_MEGA_2560) ISR(USART0_RX_vect) { StoreUARTInBuf(UDR0, 0); } ISR(USART1_RX_vect) { StoreUARTInBuf(UDR1, 1); } ISR(USART2_RX_vect) { StoreUARTInBuf(UDR2, 2); } ISR(USART3_RX_vect) { StoreUARTInBuf(UDR3, 3); } #endif /// <summary> /// Инициализируем и открываем UART порт /// </summary> /// <param name="port">Номер порта</param> /// <param name="baud">Скорость работы порта</param> void UARTOpen(uint8_t port, uint32_t baud) { // U2X - Удвоение скорости обмена. Если этот разряд установлен в «1», коэффициент деления предделителя контроллера скорости передачи уменьшается с 16 до 8, удваивая тем самым скорость асинхронного обмена по последовательному каналу. В USART разряд U2X используется только при асинхронном режиме работы. В синхронном режиме он должен быть сброшен. // UBRRL и UBRRH - регистры скорости передачи // RXEN - Разрешение приема. При установке этого разряда в «1» разрешается работа приемника USART/UART и переопределяется функционирование вывода RXD. // TXEN - Разрешение передачи. При установке этого разряда в «1» разрешается работа передатчика UART и переопределяется функционирование вывода TXD // RXCIE - Разрешение прерывания по завершению приема. Если данный разряд установлен в «1», то при установке флага RXC регистра UCSRA генерируется прерывание. //TODO: При скорости 56700 убрать U2X. uint8_t h = ((F_CPU / 4 / baud -1) / 2) >> 8; uint8_t l = ((F_CPU / 4 / baud -1) / 2); switch (port) { #if defined(ARDUINO_PRO_MINI) case 0: UCSR0A = (1<<U2X0); UBRR0H = h; UBRR0L = l; UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); break; #endif #if defined(ARDUINO_PRO_MICRO) case 1: UCSR1A = (1<<U2X1); UBRR1H = h; UBRR1L = l; UCSR1B |= (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1); break; #endif #if defined(ARDUINO_MEGA_2560) case 0: UCSR0A = (1<<U2X0); UBRR0H = h; UBRR0L = l; UCSR0B |= (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); break; case 1: UCSR1A = (1<<U2X1); UBRR1H = h; UBRR1L = l; UCSR1B |= (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1); break; case 2: UCSR2A = (1<<U2X2); UBRR2H = h; UBRR2L = l; UCSR2B |= (1<<RXEN2)|(1<<TXEN2)|(1<<RXCIE2); break; case 3: UCSR3A = (1<<U2X3); UBRR3H = h; UBRR3L = l; UCSR3B |= (1<<RXEN3)|(1<<TXEN3)|(1<<RXCIE3); break; #endif } } /// <summary> /// Отправляем данные по UART, включаем прерывание по опустошению буфера UART /// </summary> /// <param name="port">Номер порта</param> void UARTSendData(uint8_t port) { // UDRIE - Разрешение прерывания при очистке регистра данных UART. Если данный разряд установлен в «1», то при установке флага UDRE в регистра UCSRA генерируется прерывание. #if defined(ARDUINO_PRO_MINI) UCSR0B |= (1<<UDRIE0); #endif #if defined(ARDUINO_PRO_MICRO) //TODO: Заменить switch на if. switch (port) { case 1: UCSR1B |= (1<<UDRIE1); break; } #endif #if defined(ARDUINO_MEGA_2560) switch (port) { case 0: UCSR0B |= (1<<UDRIE0); break; case 1: UCSR1B |= (1<<UDRIE1); break; case 2: UCSR2B |= (1<<UDRIE2); break; case 3: UCSR3B |= (1<<UDRIE3); break; } #endif } /// <summary> // // Сохраняем отправляемый байт в буфер TX /// </summary> /// <param name="port">Номер порта</param> /// <param name="a">Отправляемый байт</param> void UARTSerialize(uint8_t port,uint8_t a) { #if defined(ARDUINO_PRO_MICRO) port = 0; #endif uint8_t t = UARTHeadTX[port]; if (++t >= TXBufferSize) { t = 0; } UARTBufferTX[t][port] = a; UARTHeadTX[port] = t; } /// <summary> /// Сохраняем полученные данные в буфер RX /// </summary> /// <param name="portnum">Номер порта</param> static inline void StoreUARTInBuf(uint8_t data, uint8_t port) { #if defined(ARDUINO_PRO_MICRO) port = 0; #endif // Получаем номер "головы массива" RX uint8_t h = UARTHeadRX[port]; // Проверяем, увеличивая номер "головы массива" RX головы на 1 и если номер "головы массива", станет равным или больше размера буфера, обнуляем переменную h в 0 if (++h >= RXBufferSize) { h = 0; } // Проверяем номер "головы массива" RX и номер "хвоста массива" RX если равен, это ошибка if (h == UARTTailRX[port]) { return; } // Сохраняем полученный байт в буфер RX для хранения данных UARTBufferRX[UARTHeadRX[port]][port] = data; // Сохраняем новый номер "головы массива" RX UARTHeadRX[port] = h; } } Вот вызов Код (C++): UARTSerialize(UART_DEBUG_PORT, '?'); UARTSerialize(UART_DEBUG_PORT, 'E'); UARTSendData(UART_DEBUG_PORT); Платы тестировал на Atmega32u4, Ардуино Леонардо и Микро (все оригинал). В коде определяется по параметру ARDUINO_PRO_MICRO.
Залил на версию 1.6.7 перед тем как копаться в исходниках, на мое удивление - работает. Проверил работает на Нано, Микро, странно код 1 в 1. Файлы лежат в локальном свн, поэтому любые изменения с ними отслеживаются. Понять, что было не могу, получается зря, поднял переполох.