Чем выше тактовая частота МК /рез, тем точнее может быть установлена скорость. При частоте кварца 4 МГц мы с приемлемой точностью можем получить скорости обмена не более 28 800 бод. Правда, при выборе специального кварца (например, 3,6864 МГц) можно получить с нулевой ошибкой весь набор скоростей вплоть до 115 200, но зато для других целей такие частоты неудобны. Для получения скоростей передачи выше указанных (стандартно COM-порт позволяет установить скорости, как указано ранее до 256 кбод) придется увеличивать частоту. Так, при кварце 8 МГц и общем коэффициенте деления, равном единице, мы получим скорость 250 000, что отличается от стандартных 256 000 на приемлемые 2,4 %.
Теперь перейдем к собственно процессу приему/передачи данных. В общем случае наша задача формулируется так: контроллер все время ожидает команды от компьютера, и при получении ее должен послать в ответ несколько байтов. Такой процесс можно организовать различным образом.
С UART связаны прерывания, причем в силу важности предмета тут их аж целых три: «передача завершена» (ТХ Complete), «регистр передатчика пуст» (ТХ UDR Empty) и «прием завершен» (RX Complete). Для их использования можно поступить следующим образом (примеры приведены для семейства Classic). Сначала вы инициализируете прерывание «прием закончен» (для чего надо установить бит RXCIE в регистре UCR). Возникновение этого прерывания означает, что в регистре данных udr имеется принятый байт. Процедуру обработки этого прерывания иллюстрирует листинг 16.1.
UART_RXC:
in temp,UDR ;принятый байт — в переменной temp
cbi UCR,RXCIE ;запрещаем прерывание «прием закончен»
…
<анализируем команду, если это не та команда — опять разрешаем прерывание «прием закончен» и выходим из процедуры
sbi UCR,RXCIE
reti
В противном случае готовим данные, самый первый посылаемый байт должен быть в переменной temp>
…
sbi UCR,UDRIE ;разрешение прерывания «регистр данных пуст»
reti
Далее у нас почти немедленно возникает прерывание «регистр данных пуст». Обработчик этого прерывания состоит в том, что мы посылаем байт, содержащийся в переменной temp, и готовим данные для следующей посылки (листинг 16.2).
UART_DRE:
out UDR,temp ;посылаем байт
cbi UCR,UDRIE ;запрещаем прерывание «регистр данных пуст»
…
<готовим данные, следующий байт — в temp. Если же был отправлен последний нужный байт, то опять разрешаем прерывание «прием закончен» и далее выходим из процедуры, иначе выполняем следующий оператор:>
sbi UCR,UDRIE ;разрешаем прерывание «регистр данных пуст»
reti
Для семейства Mega (USART) вместо UCR в текст примеров надо подставить UCSRB. Обратим внимание на то, что после обработки первого прерывания переменная temp здесь может содержать подготовленный для отправки байт, и не должна в промежутках между прерываниями использоваться еще где-то. В противном случае ее надо сохранять, например, в стеке, или все же отвести для этого дела специальный регистр. Как видите, все довольно сложно.
Однако, как и в случае записи в EEPROM (см.
Out_com: ;посылка байта из temp с ожиданием готовности
sbis UCSRA,UDRE ;ждем готовности буфера передатчика
rjmp out_com
out UDR,temp ;собственно посылка байта
ret ;возврат из процедуры Out_com
In_com: ;прием байта в temp с ожиданием готовности
sbis UCSRA,RXC ;ждем готовности буфера приемника
rjmp in_com
in temp,UDR ;собственно прием байта
ret ;возврат из процедуры In_com
Для семейства Classic надо заменить все UCSRA на USR. Для сформулированной ранее задачи непрерывного ожидания внешних команд обращение к процедуре In_com при этом вставляется в пустой цикл в конце программы: