Проблемы с кодировкой UART на СИ в Arduino IDE 1.6.7

Тема в разделе "Флудилка", создана пользователем Alex19, 22 фев 2016.

Метки:
  1. Alex19

    Alex19 Гуру

    Сегодня решил перейти на последнюю версию, что-то меня бес попутал, столкнулся с забавной проблемой.

    Обычная библиотека для работы с 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.

    Удачи!
     
  2. Unixon

    Unixon Оракул Модератор

    Так как именно они там сломали кодировку?
     
  3. Alex19

    Alex19 Гуру

    Сейчас не отвечу, удалил версию 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.
     

    Вложения:

    • UART.zip
      Размер файла:
      3,7 КБ
      Просмотров:
      275
  4. Alex19

    Alex19 Гуру

    Залил на версию 1.6.7 перед тем как копаться в исходниках, на мое удивление - работает. Проверил работает на Нано, Микро, странно код 1 в 1.

    Файлы лежат в локальном свн, поэтому любые изменения с ними отслеживаются.

    Понять, что было не могу, получается зря, поднял переполох:(.