Генератор пишет код настройки периферии классических AVR так, как его пишут вручную по даташиту: регистр за регистром, с именами битов из avr/io.h и комментарием к каждой строке. Числа — делитель скорости USART, предделитель и вершину счёта таймера, делитель АЦП — он считает по формулам даташита и сразу проверяет: достижима ли скорость, укладывается ли период в таймер, попадает ли частота АЦП в окно 50–200 кГц и не занят ли один вывод двумя блоками. Имена регистров, битов и векторов прерываний берутся из файлов описания устройств Microchip, сверенных с даташитом и заголовками — тех же, по которым построены страницы регистров ATmega328P и остальных микроконтроллеров.
Коротко
- USART: UBRR = f / (16 · BAUD) − 1, с U2X = 1 — f / (8 · BAUD) − 1; 12 бит, 0…4095.
- Таймер, CTC и быстрый ШИМ: f = f_CPU / (N · (TOP + 1)); у 8-битных таймеров TOP до 255, у 16-битных — до 65 535.
- АЦП: f_ADC = f_CPU / (2…128), для 10 бит — 50–200 кГц; при 16 МГц делитель 128 и 125 кГц, 104 мкс на преобразование.
- INT0/INT1: биты ISCn1:0 — 00 низкий уровень, 01 любое изменение, 10 спад, 11 фронт.
- Векторы — имена из avr-libc:
USART_RX_vectу ATmega328P,USART_RXC_vectу ATmega8/16/32,USART0_RX_vectу ATmega2560.
Что генерирует инструмент
На выходе — один файл .c: #define F_CPU, подключение <avr/io.h> и <avr/interrupt.h>, функции gpio_init(), uart_init(), timerN_init(), adc_init(), ext_int_init(), вспомогательные uart_putc(), uart_getc(), adc_read(), обработчики ISR() с именами векторов из заголовков пака и main(), который всё это вызывает и разрешает прерывания sei(). При приёме по прерыванию обработчик кладёт байты в кольцевой буфер на 64 байта, а uart_getc() забирает их без ожидания (−1, если буфер пуст) — по схеме «один писатель, один читатель» с барьерами компилятора из статьи о прерываниях и общих данных. Стиль записи битов выбирается: (1 << CS10), _BV(CS10) или шестнадцатеричное число с именами битов в комментарии.
Порядок записи в регистры — тот, что рекомендует даташит. Делитель USART пишется до включения приёмника и передатчика, у ATmega8/16/32 сначала UBRRH, потом UBRRL (запись младшего байта сразу перезапускает делитель). Регистр с битами выбора тактирования таймера (TCCRnB) записывается последним: таймер запускается уже настроенным. Флаги внешних прерываний сбрасываются после смены режима ISC — смена режима может сама выставить флаг.
Собрать файл можно так:
avr-gcc -mmcu=atmega328p -Os -o main.elf atmega328p_init.c
avr-objcopy -O ihex -R .eeprom main.elf main.hex
Как устроен тулчейн и откуда берутся avr/io.h и -mmcu, рассказано в статье об avr-gcc, прошивку загружает avrdude.
USART: делитель и ошибка скорости
Генератор скорости USART делит частоту процессора на 16 (или на 8 при U2X = 1) и на UBRR + 1. Режим «авто» выбирает тот вариант, где ошибка меньше; при равной ошибке остаётся U2X = 0 — приёмник с 16 выборками на бит терпимее к расхождению частот. Допустимую ошибку генератор берёт из таблиц 20-2 и 20-3 даташита ATmega328P: для кадра с 8 битами данных без чётности ±2 % при U2X = 0 и ±1,5 % при U2X = 1.
| Скорость, бод | 8 МГц, U2X = 0 | 8 МГц, U2X = 1 | 16 МГц, U2X = 0 | 16 МГц, U2X = 1 |
|---|---|---|---|---|
| 9600 | 51 (0,2 %) | 103 (0,2 %) | 103 (0,2 %) | 207 (0,2 %) |
| 19 200 | 25 (0,2 %) | 51 (0,2 %) | 51 (0,2 %) | 103 (0,2 %) |
| 38 400 | 12 (0,2 %) | 25 (0,2 %) | 25 (0,2 %) | 51 (0,2 %) |
| 57 600 | 8 (−3,5 %) | 16 (2,1 %) | 16 (2,1 %) | 34 (−0,8 %) |
| 115 200 | 3 (8,5 %) | 8 (−3,5 %) | 8 (−3,5 %) | 16 (2,1 %) |
| 250 000 | 1 (0,0 %) | 3 (0,0 %) | 3 (0,0 %) | 7 (0,0 %) |
Значения — из таблиц 20-6 и 20-7 даташита ATmega328P (у ATmega8 те же числа: 8 МГц — в таблице 62, 16 МГц — в таблице 63 даташита 2486AA). Таблицу для любой частоты кварца и запас приёмника по кадру считает калькулятор скорости UART.
У ATmega8, ATmega16 и ATmega32 регистр UCSRC делит адрес с UBRRH: запись идёт в UCSRC, только если старший бит URSEL равен 1. Генератор ставит его сам; если забыть, формат кадра уйдёт в старшие биты делителя. В ATmega328P и ATmega2560 регистры раздельные, а UBRR0 записывается как 16-битное число.
Таймер: CTC и быстрый ШИМ
В режиме CTC счётчик считает от нуля до значения в OCRnA (у 16-битных таймеров режим 4) и сбрасывается; на каждом совпадении вызывается прерывание TIMERn_COMPA_vect (у таймеров с одним регистром TCCRn — ATmega8 T2, ATmega16/32 T0 и T2 — TIMERn_COMP_vect и регистр OCRn), а при включённом переключении вывода на OCnA выходит меандр половинной частоты. Генератор перебирает предделители и берёт тот, где ошибка периода наименьшая, а при равной — меньший предделитель: так вершина счёта больше, а шаг точнее. Тот же расчёт, с перебором всех вариантов, есть в калькуляторе таймера.
| Таймер | f_CPU | Период | N | TOP | Регистры |
|---|---|---|---|---|---|
| 0 (8 бит) | 16 МГц | 1 мс | 64 | 249 | TCCR0A = (1 << WGM01), TCCR0B = (1 << CS01) | (1 << CS00) |
| 1 (16 бит) | 16 МГц | 1 мс | 1 | 15 999 | TCCR1B = (1 << WGM12) | (1 << CS10) |
| 2 (8 бит) | 16 МГц | 4 мс | 256 | 249 | TCCR2B = (1 << CS22) | (1 << CS21) |
| 1 (16 бит) | 8 МГц | 1 с | 256 | 31 249 | TCCR1B = (1 << WGM12) | (1 << CS12) |
Для ШИМ у 16-битных таймеров берётся режим 14: вершина в ICRn, а заполнение задаётся в OCRnA, OCRnB (у ATmega2560 ещё и OCRnC), так что частоту можно выбрать любую. Регистр ICRn записывается только после того, как биты WGMn3:0 выбрали режим с вершиной в ICRn (ATmega328P, раздел 16.6, и так же в остальных даташитах), поэтому генератор сначала задаёт режим при остановленном таймере, потом ICRn и OCRnx и в конце включает тактирование. 8-битные таймеры ATmega328P, ATmega2560 и ATtiny85 могут то же самое в режиме 7 (вершина в OCRnA), но тогда выход только один — OCnB; в режиме 3 вершина фиксирована, 0xFF, и частота — только f_CPU / (N · 256). У таймеров ATmega8/16/32 с одним регистром TCCRn второго варианта нет. Заполнение неинвертирующего быстрого ШИМ — (OCR + 1) / (TOP + 1); ноль так не получить, поэтому для 0 % выход таймера отключают.
Генератор предупредит, если разрешение ШИМ меньше 6 бит: при 1 МГц на 16 МГц у таймера всего 16 шагов. Подробнее о режимах и регистрах — в статье о таймерах AVR, биты конкретного таймера — на странице регистров, например таймера 1 ATmega328P.
АЦП и внешние прерывания
Делитель АЦП в режиме «авто» — наименьший, при котором частота АЦП не выше 200 кГц: 128 при 16 и 20 МГц, 64 при 8 МГц, 8 при 1 МГц. Если задать делитель вручную и частота выйдет за 200 кГц, генератор предупредит, что 10 бит не гарантированы, а за пределами 50 кГц – 1 МГц — что результат будет неверным. Время преобразования, код по напряжению и опорные напряжения подробно считает калькулятор АЦП AVR. Входы ADC6 и ADC7 ATmega328P и ATmega8 — отдельные аналоговые выводы, они есть только в 32-выводных корпусах TQFP и QFN; в DIP-28 их нет. Цифровой входной буфер выбранного канала отключается битом ADCnD в DIDR0 (у ATmega2560 для ADC8–ADC15 — в DIDR2), если такой регистр у микроконтроллера есть.
Опорные напряжения у разных серий кодируются по-разному: у ATmega328P REFS1:0 = 11 — внутренние 1,1 В, у ATmega8/16/32 тот же код — 2,56 В, у ATmega2560 1,1 В — это 10, а у ATtiny85 есть третий бит REFS2, и внешнее опорное подаётся на PB0. Генератор берёт коды из таблиц своего даташита, поэтому ошибка «скопировал ADMUX с другой меги» исключена.
Для INT0 и INT1 режим срабатывания задают биты ISCn1:0: в EICRA у ATmega328P и ATmega2560, в MCUCR у ATmega8/16/32 и ATtiny85. Разрешение — в EIMSK, GICR или GIMSK. Подтяжка на выводе нужна, если к нему подключена кнопка на землю: тогда нажатие — это спад. Для пробуждения из Power-down у ATmega328P, ATmega8/16/32 и ATtiny85 годится только низкий уровень INT0/INT1 — фронт или спад будит лишь из Idle (таблицы режимов сна в даташитах); у ATmega2560 фронты INT0–INT3 обнаруживаются асинхронно и будят из любого режима (2549Q, раздел 15). Подробнее — в статье о режимах сна AVR.
Проверки и типичные ошибки
| Проверка | Что сообщает генератор |
|---|---|
| Скорость USART | UBRR вне 0…4095 — ошибка; отклонение больше допустимого по даташиту — предупреждение |
| Период и частота таймера | период длиннее, чем 2⁸ или 2¹⁶ тактов при N = 1024, или короче двух тактов — ошибка; заметная неточность и малое разрешение ШИМ — предупреждение |
| Частота АЦП | выше 200 кГц — предупреждение, вне 50 кГц – 1 МГц — ошибка |
| Выводы | один вывод у двух блоков (ADC1 и INT0 на PB2 у ATtiny85) — ошибка; GPIO на выводе периферии, RESET, JTAG, выводы кварца — предупреждение или пояснение |
| Частота процессора | выше предельной для микроконтроллера — предупреждение |
Чаще всего код из интернета не работает по одной из этих причин: обработчик прерывания назван не тем вектором (avr-gcc выдаст только предупреждение о неверно названном обработчике — misspelled signal handler, а прерывание уйдёт на сброс), забыт sei(), регистр из чужой серии (TIMSK1 у ATmega8, где он называется TIMSK), фьюз CKDIV8 делит частоту на 8 и все расчёты сдвигаются. Последнее проверьте в калькуляторе фьюзов AVR: с завода ATmega328P работает от внутреннего RC-генератора на 1 МГц.
Код сгенерирован по данным регистров, а не по готовым примерам, но перед прошивкой в устройство сверяйте его с даташитом своего микроконтроллера — особенно если меняли фьюзы тактирования. Карточки микроконтроллеров с выводами и векторами: ATmega328P, ATmega8, ATmega2560, ATtiny85; все AVR — в разделе AVR.
Частые вопросы
Что делает генератор кода AVR?
Пишет функции инициализации на C для выбранных блоков: USART, одного таймера в режиме CTC или быстрого ШИМ, АЦП, внешних прерываний INT0 и INT1 и выводов GPIO. Значения регистров он считает сам — UBRR, предделитель и TOP таймера, делитель АЦП, — а имена регистров и битов берёт из тех же данных, что и страницы регистров сайта. Каждое имя регистра, бита и вектора сверено с заголовками avr/io*.h пака Microchip и avr-libc; код рассчитан на avr-gcc с avr-libc, без Arduino, но перед прошивкой его стоит собрать и проверить на своей плате.
Какие микроконтроллеры поддерживаются?
ATmega328P (Arduino Uno и Nano), ATmega8, ATmega16, ATmega32, ATmega2560 (Arduino Mega) и ATtiny85. Это контроллеры, для которых на сайте есть данные регистров, сверенные с даташитом. ATtiny85 без USART, а его таймер 1 и таймер 0 ATmega8 генератор не настраивает: они устроены иначе.
Почему при 16 МГц скорость 115200 даёт ошибку?
Делитель USART целый: при U2X = 0 ближайшее UBRR = 8 даёт 111 111 бод (−3,5 %), при U2X = 1 UBRR = 16 — 117 647 бод (+2,1 %). Обе ошибки больше рекомендованных даташитом 2 и 1,5 % для 8 бит данных. Для точных скоростей берут кварцы 7,3728, 11,0592, 14,7456 или 18,432 МГц — тогда ошибка 0 %.
Как переделать код под Arduino IDE?
Функции инициализации можно вызывать из setup(), но ядро Arduino само занимает таймер 0 (millis, delay), настраивает таймеры 1 и 2 под analogWrite, а если в скетче используется Serial, подключает свой обработчик приёма USART. Поэтому в Arduino IDE не трогайте таймер 0 (сломаются millis() и delay()), а USART с прерыванием включайте только без Serial — иначе компоновщик сообщит о повторном определении вектора.
Что значит предупреждение о выводе RESET или JTAG?
PC6 у ATmega328P и PB5 у ATtiny85 — вывод сброса: портом он становится только с запрограммированным фьюзом RSTDISBL, после чего прошить микросхему по ISP уже нельзя. У ATmega16 и ATmega32 с завода включён JTAG (фьюз JTAGEN), и выводы PC2–PC5 не работают как порт, пока его не выключить фьюзом или битом JTD.
Источники
- Microchip. ATmega48A/PA/88A/PA/168A/PA/328/P Data Sheet (DS40002061B) — 13.2.1, таблица 13-2 — ISC01:00; 15.7.2, 16.9.2–16.9.3 — частота CTC и быстрого ШИМ; таблицы 15-8, 15-9, 16-4, 16-5, 18-8, 18-9 — режимы WGM и предделители таймеров 0, 1, 2; таблица 20-1 — UBRR; таблицы 20-2, 20-3 — допустимая ошибка приёмника; таблицы 20-6, 20-7 — UBRR при 8 и 16 МГц (эталон тестов); 24.4 — частота АЦП 50–200 кГц; таблица 24-3 — опорные
- Microchip (Atmel). ATmega8 datasheet (2486AA) — таблицы 31 и 32 — ISC в MCUCR; общий адрес UBRRH и UCSRC, бит URSEL; таблица 63 — UBRR при 16 МГц; таблица 74 — опорные 00/01/11
- Microchip (Atmel). ATmega16 (2466T) и ATmega32 (2503Q) datasheets — таймер 0 с регистром TCCR0: таблицы 38 и 42 (ATmega16) — WGM01:00 и CS02:00; таблица 83 — опорные; выводы JTAG на PC2–PC5. ATmega32 — doc2503.pdf, те же разделы. Регистры сайта сверены с ATmega16A (8154C) и ATmega32A (DS40002072A)
- Microchip (Atmel). ATmega640/1280/1281/2560/2561 datasheet (2549Q) — таблица 26-3 — опорные 1,1 и 2,56 В; таблица 26-4 — входы ADC8–ADC15 через MUX5; четыре USART и таймеры 3, 4, 5
- Microchip (Atmel). ATtiny25/45/85 datasheet (2586Q) — таблица 9-2 — ISC01:00 в MCUCR; таблица 10-3 — ADC3 на PB3; таблица 17-3 — REFS2:0
- Microchip. ATmega_DFP 3.6.299 и ATtiny_DFP 3.4.278 (packs.download.microchip.com) — файлы ATDF — регистры, биты, векторы прерываний и выводы; заголовки avr/io*.h — с ними сверены все имена регистров, битов и векторов в коде (лицензия Apache-2.0 и BSD)
- avr-libc. Reference manual: <avr/interrupt.h>, <avr/sfr_defs.h> — макрос ISR(vector) и имена векторов <имя>_vect; _BV(bit) = (1 << bit)
Встроить калькулятор на свой сайт
Скопируйте код и вставьте его в HTML страницы, статьи или вики. Виджет бесплатный, без рекламы, счётчиков и cookie. Условие одно — ссылка на GAW под рамкой остаётся на месте. Подробнее о виджетах
<iframe src="https://gaw.ru/embed/avr-init/" title="Генератор кода инициализации периферии AVR" width="100%" height="640" style="border:1px solid #e3e5e9;border-radius:8px" loading="lazy" allow="clipboard-write"></iframe>
<p style="margin:6px 0 0;font-size:14px">Калькулятор: <a href="https://gaw.ru/tools/avr-init/">Генератор кода инициализации периферии AVR</a> — GAW.ru</p>Автоподстройка высоты рамки
Если сайт разрешает скрипты, добавьте этот код один раз в любом месте страницы: рамка будет менять высоту вместе с результатом расчёта.
<script>window.addEventListener("message",function(e){if(e.origin!=="https://gaw.ru"||!e.data||e.data.type!=="gaw:embed-height")return;var f=document.querySelectorAll('iframe[src^="https://gaw.ru/embed/"]');for(var i=0;i<f.length;i++)if(f[i].contentWindow===e.source)f[i].style.height=e.data.height+"px"})</script>Обновлено .
Нашли ошибку в расчёте?