Print this page

Программный UART для любого микроконтроллера. Ч1

01/02/2012 - 22:15
 
   Иногда возникает ситуация, когда аппаратных ресурсов микроконтроллера не хватает или требуемый ресурс в его составе отсутствует. Решить эту проблему можно двумя способами – заменить используемый микроконтроллер на другой или реализовать требуемый ресурс программно. Оба способа имеют свои достоинства и недостатки, однако второй вариант часто более предпочтительный, а иногда и единственно возможный. Например, как в случае с 1-Wire интерфейсом, который не поддерживается аппаратно ни в одном 8-ми разрядном микроконтроллере AVR. 
   В этой статье рассмотрена реализация программного UART`а, которую можно модифицировать под любой микроконтроллер, программируемый на Си. Во второй части статьи будет рассмотрена реализация программного UART`а модифицированного под микроконтроллер AVR. Материал написан на основе IAR`овского апноута, найденного на  просторах интернета. 

  Требования 

   Для использования кода программного UART`а, необходимо выполнение следующих требований:
1. Наличие Си компилятора под используемый микроконтроллер
2. Наличие у микроконтроллера таймерного прерывания. 
3. Наличие у микроконтроллера двух выводов, состояние которых можно программно читать и изменять. 

   Возможности

В данном коде реализованы следующие функции.
 
1. void flush_input_buffer( void )
Очистка входного (приемного) буфера.  
 
 2. char kbhit( void )
Тестирование входного буфера на наличие данных.
 
3. char getchar( void )
Чтение символа из входного буфера. 
Принимаемые данные сохраняются в кольцевом буфере, емкость которого задается с помощью макроопределения.
Если на момент вызова данной функции входной буфер пуст, функция ожидает поступление данных. При этом в цикле выполняется пользовательская функция idle(). Про нее написано ниже.
 
4. void turn_rx_on( void )
Разрешает прием данных по UART`у. По умолчанию прием данных разрешен.
 
 5. void turn_rx_off( void )
Запрещает прием данных по UART`у. 
Прием и передача данных выполняется в обработчике прерывания таймера. Запрещение приема данных уменьшает время выполнения обработчика. 
 
6. void putchar( char )
Запись символа в последовательный порт
 
7. void init_uart( void )
Инициализация программного  UART`a. Устанавливает внутренние флаги, настраивает выводы микроконтроллера и таймер.

   Ограничения

   Данная программная реализация UART`а основана на использовании прерывания таймера. Разрядность таймера и режим работы значения не имеют, главное чтобы частота его прерываний могла быть установлена в три раза выше требуемой скорости обмена. 
   Например, требуется скорость 9600 бит в секунду. Тогда прерывания таймера должны происходить с частотой 9600*3 = 28800 Гц. Или в пересчете на временной интервал – каждые 34,72 микросекунды. 
   Это накладывает скоростные ограничения на возможности применения программного UART`a, особенно в микроконтроллерах с низкой тактовой частотой. 
   Если установить слишком высокую скорость обмена, код обработчика прерывания таймера не будет успевать выполняться между вызовами прерываний, что приведет к ошибкам приема/передачи, а то и к полной потере связи. 
  Также высокая частота прерываний таймера будет негативно влиять на производительность остальной части программы. (Для аналогии можно привести ситуацию, когда вы пытаетесь выполнять свою работу, а вас постоянно отвлекают на посторонние дела.)

   Применение

   Код программного UART`a из IAR`овского апноута записан в сишном файле. Подключить его к проекту можно  двумя путями:
– скопировать этот код в один из сишных файлов своего проекта
– написать к сишному файлу заголовочный и подключить к проекту полноценный модуль
Второй путь более грамотный, поэтому программный UART во второй части статьи я подключаю к проекту именно так. 
 
   Однако это еще не все. 
   Для переносимости кода в нем не реализовано несколько платформенно-зависимых функций, которые вам потребуется написать. Функции перечислены в списке ниже. 
В принципе ничего сложного в этом нет. 
 
1. void get_rx_pin_status( void )
Возвращает состояние приемного вывода (receive pin). 
 
2. void set_tx_pin_high( void )
Устанавливает на передающем выводе (transmit pin) логическую единицу. 
 
3. void set_tx_pin_low( void )
Устанавливает на передающем выводе логический ноль. 
 
4. void idle( void )
Фоновая пользовательская функция. Выполняется, когда ожидается прием данный. 
 
5. void timer_set( int BAUD_RATE )
Устанавливает частоту прерываний таймера. Частота прерываний должна быть в 3 раза выше требуемой скорости обмена! 
Функции передается значение требуемой скорости обмена, а она должна устанавливать соответствующую частоту таймерных прерываний.
 
6. void set_timer_interrupt( timer_isr )
Разрешает прерывания таймера.
 
 
   Для экономии памяти и увеличения производительности кода некоторые из этих функций можно заменить макросами. Например, функции 1, 2, 3 и 6. 
   Функцию 4 можно оставить пустой. 
   
И последнее что нужно сделать, это поместить код функции void timer_isr(void) в прерывание таймера. Сделать это можно опять-таки двумя способами:
- поместить вызов функции timer_isr() в код обработчика прерывания
- сделать из самой функции timer_isr() обработчик прерывания
 
Второй вариант более грамотный, поскольку требует меньших накладных расходов – оперативной памяти и процессорного времени. Впрочем, ты и так должен знать, к чему приводит вызов функций из прерываний
Программный UART вторая часть...

Файлы

software-uart.rar

Related items