- Родительская категория: Статьи
- Категория: Программирование
- Автор: ARV
- Просмотров: 27902
WinAVR: консольный ввод-вывод
Методика «программирования кликами мышки» настолько прочно въелась в сознание соверменных пользователей компьютеров, что многие начинающие программисты микроконтроллеров считают WinAVR очень сложным и неудобным, а CVAVR напротив — очень простым и удобным. Мое мнение о CVAVR негативное, но сейчас не об этом. Я попробую показать, что решение многих типовых задач в WinAVR может быть ничуть не сложнее, чем использование плодов Code Wizard из CVAVR.
Речь пойдет о консольном вводе-выводе. Я имею ввиду организацию обмена информаци-ей между микроконтроллером и терминальной программой. Последняя имеется в любой версии Windows и называется Hyper Terminal или как-то похоже, для большинства реальных задач этого более чем достаточно. Подключение традиционно осуществляется через СОМ-порт, причем совершенно безразлично, как именно он реализован: будет ли это аппаратный RS-232 порт материнской платы, шнур-переходник USB-RS232 или микросхема FTDI в связке с микроконтроллером.
{ads2}Основная проблема видится именно в программе для микроконтроллера. Почитатели CVAVR, пару раз кликнув мышкой, при помощи Wizard-а получают заготовку программы, в которой функции sprintf и scanf уже работают через USART. Я докажу, что при использовании WinAVR аналогичный результат будет достигаться ничуть не сложнее.
Итак, скачиваем архив, в котором я приготовил три файла. Эти файлы вы должны будете скопировать в папку вашего проекта, хотя файл avr_helper.h я бы рекомендовал разместить в папке с «системными» заголовочниками (в папку avr\include\ внутри папки, куда установлен WinAVR), т. к. он содержит ряд универсальных макросов, которые будут вам полезны чаще, чем требуется консольный ввод-вывод.
Файл com_io.c должен быть включен в состав проекта для компиляции: если вы работаете с makefile, то допишите его в строчку с другими исходниками, а если пользуетесь AVR Studio, то добавьте его к проекту традиционным способом. Пользователям Eclipse вообще никаких усилий прикладывать не придется — все исходники из папки проекта автоматически (по умолчанию) добавляются к списку компилируемых.
Другой файл com_io.h должен быть немного отредактирован, а затем подключен директи-вой #include в каждом файле проекта, где будет требоваться работа с консольным вводом-выводом. Редактирование этого файла выполняет задачу CVAVR-овского Wizard-а по настройке требуемых параметров ввода-вывода:
Как видите, каждый макрос содержит исчерпывающее описание в комментариях, надеюсь, никаких вопросов не возникнет. Скорость обмена рекомендую задавать из ряда стандартных, а при компиляции проекта смотреть за Warning-ами — там может быть предупреждение о том, что заданная скорость недостижима при выбранной тактовой частоте.
Собственно говоря, это все, что нужно сделать (!!!), чтобы в вашем проекте все функции семейства printf выводили через USART в терминал, а все функции семейства scanf — вводили данные из консоли (разумеется, для работы ввода константа ONLY_OUT должна содержать нулевое значение).
Хочу предупредить сразу о некоторых моментах, которые могут удивить начинающих программистов:
- Для поддержки printf и scanf автоматически подключаются библиотеки, которые увеличивают результирующий код примерно на 1,5 килобайта (прибавка может быть разной для разных типов микроконтроллеров).
- По умолчанию sprintf и scanf не поддерживают работу с числами float и double – если необходимо использовать их при вводе-выводе, следует подключить принудительно библиотеку поддержки «плавающей точки» (см. документацию к WinAVR). Поддержка плавучки прибавит к вашему проекту еще килобайт-другой.
- В соответствии со стандартом Си функции printf и scanf – это блокирующие функции, в них нет никакой «встроенной» буфферизации. Это означает буквально следующее: если вы задали скорость обмена 300 бод и решили вывести строку из 100 символов, то этот процесс займет больше 3-х секунд. При вводе функция scanf не вернет управление, пока не будут введены все требуемые ею данные.
- По умолчанию сделано так, что к каждому символу '\n' автоматически добавляется символ '\r'. Если это вам не требуется, вы должны в файле com_io.c найти и модифицировать функцию uart_putchar.
- В моем коде не учтена возможность наличия в микроконтроллере более чем одного модуля UART/USART. Если в используемом вами МК имеется два или более таких модулей, вам придется подкорректировать макросе INIT(7) в файле com_io.c, изменив наименования регистров на нужные, например, UCSRA заменить на UCSR0A или UCSR1A в зависимости от номера используемого USART.
Надеюсь, теперь все на самом деле убедились, что необходимость во всяких автоматических генераторах исходников не так уж и велика. В отличие от «библиотек» CVAVR исходный код рассматриваемого модуля полностью открыт и доступен для правки, поэтому несложно модифицировать его под любые ваши потребности, например, реализовать вывод в один модуль USART, а ввод — в другой.
Отдельное примечание для любителей все тестировать «в протеусе». Из версии в версию протеус тянет одну и ту же ошибку в своем симуляторе AVR: при выполнении аппаратного сброса он не устанавливает регистры UART/USART в состояние, предписываемое даташитом. Поэтому в файле com_io.c в макросе INIT(7) вы можете видеть как бы «лишние» операторы, задающие начальные значения регистрам — без этого симуляция в протеусе работать не будет, хотя «в железе» все отлично и без этих операторов. Если пара лишних байт в вашем коде не является решающей, рекомендую не менять в коде ничего для «совместимости с протеусом».
В заключение статьи предлагаю небольшой примерчик, знаменитый хелловорд:
{ads1}
{code}#include
#include "com_io.h"
int main(void){
printf("\nI like WinAVR!\n");
return 0;
}{/code}
И вот попробуйте теперь сказать, что консольный ввод-вывод в WinAVR – это сложно!
Комментарии
У меня вопрос, почему то, если заканчивать строку printf("\nI like WinAVR!\n"); на \n то выходной файл весит около 400байт, а если убрать /n, то 1,3килобайта. Почему так? Обязательно в makefail настройка printf должна стоять normal, если поставить mini то файл выходной с /n будет весить примерно 1.3 килобайта. Или если например выводить число printf("/n%d",1 23); то тоже файл весит 1.3килобайта. Можно как нибуть выводить числа, и чтоб код выходного файла весил меньше килобайта?
что касается "экономного" вывода, то мне видится лишь один способ: использовать itoa и другие функции работы со строками для самостоятельной подготовки выводимого текста - так можно достичь заметного эффекта.
RSS лента комментариев этой записи