11.05.2022г. ВНИМАНИЕ! Если у вас не отображаются иллюстрации к статьям, для просмотра сайта используйте TOR браузер

ATmega8: работа на Си с USART/UART через прерывание

разделы: AVR, UART, дата: 16 августа 2015г.


UART для передачи использует два
провода, один на прием, другой
на передачу. Поэтому протокол
является полнодуплексным. Однако,
регистр данных UDR один.

Работа с UART через прерывания мне показалась более эффективной нежели через циклы ожидания. Потому что, программа кроме того что принимает или передает что-либо через UART, она, как правило, занята еще какими-то задачами, будь то опрос датчиков или вывод информации на дисплей. И в таком случае возникает совсем не простая проблема эффективного переключения между задачами. И если, например, ожидание приема корректных данных затянется то микроконтроллер по сути подвиснет. Делать прерывание ожидания по таймауту, это лишний код которого можно избежать, если реализовать рабту с UART через прерывания. Ниже приведен исходник эхо-программы которая читает строку через UART и посылает ее обратно. Строка должна оканчиваться символом двоеточия. В программе используется USART_RXC вектор, который срабатывает когда на порт что-то поступило. Обработчик прерывания это "что-то" переносит в рабочий буфер. Если принятый байт является символом двоеточия, то устанавливается флаг done, по которому главная программа понимает что были приняты какие-то данные. Конечно, следовало бы принятую строку заносить в сетк, но в данном случае решил исходник не усложнять.


Читать дальше

ATmega8: работа на Си с USART/UART

разделы: AVR, UART, дата: 2 августа 2015г.

Работа с UART на ATmega несколько проще чем с таймерами, но на мой взгляд, в целом эта тема более мутная, хотя и более интересная. Зависит от того, с какой стороны посмотреть.

Так же как и с таймерами, для работы c USART имеется набор прерываний:

и регистров:

Читать дальше

ATmega8: Blink без delay на Си

разделы: AVR, дата: 30 июля 2015г.

Нулевой таймер на ATmega8 не имеет апаратного ШИМ'а, поэтому ему трудно придумать применение кроме как простого счетчика. На 16MГц кварце и делителем на 64, прерывание по переполнению счетчика будет вызаваться с частотой 1КГц, т.е. каждый вызов будет равняться одной миллисекунде. Разрядности unsigned long для счетчика должно хватить на 49 дней. В целом, такой счетчик мало годится для построения часов, но в качестве таймера для расчета разных задержек подойдет вполне.

/* timer.c LED Blink whitout delay via 8-bit Timer0 for AVR ATmega8 */
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile unsigned long millis;

ISR(TIMER0_OVF_vect)
{
	millis++;
}

int main(void)
{
        DDRB |= (1<<PB5); //  pinMode(13,OUTPUT); в Wiring

        TIMSK =(1<<TOIE0);  // timer0 enable
        TCCR0 = (1<<CS01) | (1<<CS00); // prescaler 1/64

	volatile unsigned  long curTime, lastTime, period;

	millis=0;
	lastTime=0;
	period=1000; // 1 sec

        sei();

        for (;;)
	{
		curTime=millis;
		if ((curTime -lastTime)> period)
		{
			PORTB ^= (1<<PB5);
			lastTime=curTime;
		}
	}

        return 0;
}

Читать дальше

ATmega8: таймер на компараторе, CTC режим

разделы: AVR, дата: 30 июля 2015г.

Второй 8-битный таймер ATmega8 - TIMER2. Кроме перывания по переполнению счетчика, расмотренное в предыдущем посте, TIMER2 имеет второе прерывание по значению компаратора. Т.е. не надо будет ждать переполнения счетчика, прерывание сработает когда счетчик достигнет определенного значения. Это позволяет более точно устанавливать частоту срабатывания и по сути является производным генератором частоты. Штука архиполезная, позволяет выставлять значения портов по какой либо-функции или наоборот снимать показания с портов с некой периодичностью. Используется для PWM, но PWM оставим на потом, сейчас будет полезно разобраться с CTC режимом работы компаратора, когда его можно использовать как счетчик.

CTC режим (Clear Timer on Compare Match Mode), это режим при котором зачение таймера сбрасывается при достижении занчения определенного в регистре OCR2. Для TIMER2 данный режим устанавливается в TCCR2 регистре флагом WGM21:

Читать дальше

ATmega8: счетчик на прерывании Timer/Counter overflow

разделы: AVR, дата: 28 июля 2015г.

Если посмотреть таблицу прерываний для ATmega8 из предыдущего поста, то видно, что почти половина из них, это прерывания для работы с таймерами/cчетчиками. Также для их конфигурации отведена значительная часть регистров:

Также для их конфигурации отведена значительная часть регистров:

Читать дальше

ATmega8: Вектора прерываний

разделы: AVR, дата: 27 июля 2015г.


В отсутствии многозадачного режима,
вектора прервываний это единнственный
способ реализовать многозадачность

В одном из предыдущих постов я дизассемлировал blink написаный на Си, и затем переписывал программу на ассемблере. Помнится тогда я выбросил таблицу прерываний под предлогом, что прерывания здесь не используются. Однако, в дальнейшем они будут активно использоваться и поэтому с ней следует разобраться.

Делать все буду на примере ATmega8, мне пока этот микроконтроллер кажется наиболее привлекательным.

В начале каждой программы на ассемблере должна идти таблица векторов прерываний, т.е. ссылок на продпрограммы, которые будут обрабатывать то или иное прерывание. Прерывание, это в свою очередь какое-то событие, при котором ход программы прерывается, и процесор бросается обработать это событите. Как не трудно догадаться, обрабатывать он это событие будет, с помощью той подпрограммы, ссылку на которую, мы запишем в таблице векторов прерывание.

Для каждой модели микроконтроллера набор прерываний свой, порядок их чередования задан на аппаратном уровне. Поэтому перед написанием первой программы для микроконтроллера, следует ознакомиться с этой таблицой в оффициальной документации. Дока на ATmega8: ATmega8/L datasheet. На странице 46 находим такую табличку:

Читать дальше

ATmega8: прошивка через USB-TTL конвертер FT232RL

разделы: AVR, Программаторы, дата: 22 июля 2015г.

Некоторое время назад, я описывал. как c помощью Arduino прошивать ATMega8 по ISP и как на ATMega8 прошить загрузчик Arduino превратив ATMega8 тем самым в Arduino NG. Однако, обзаведясь Arduino Pro Mini(тот который без USB) я понял, что также как Arduino Pro Mini можно прошивать и ATMega8.

Предположим, что загрузчик Arduino уже прошит в ATmega8 так, как описывалось в упомянутом выше посте. Добавлю только, что первый раз, когда ATMega8 работала еще от внутреннего RC-контура, прошивка прошла гладко, затем повторно загрузчик прошивался на 8MГц кварце, в то время как пршивка загрузчика на 16МГц кварце валилась. Я к тому, что не забывайте ставить конденсаторы на кварц, я работал без них.

Итак, после того, как загрузчик прошит, Arduino можно убрать, и подключить ATMega8 к USB-TTL конвертеру по схеме:

VCC < -- > VCC
GND < -- > GND
TX < --> RX
RX < -- > TX

Я использовал FT232RL, но как пониимаю, аналогично можно использовать любой TTL конвертер. Должно получться примерно как на фото:

Читать дальше

Blink на ассемблере AVR на примере ATtiny13

разделы: AVR, ATtiny13A, АССЕМБЛЕР, дата: 18 марта 2014г.

Если разобраться в предыдущем посте: дизассемблирование blink.hex, где подробно разобрана реализация blink на ассемблере AVR, то проблем с написанием собственного варианта Blink на ассемблере не будет. Вообще-то программа там уже выложена. Осталось только разобраться с преобразованием исходников в hex файлы.

Мой вариант blink.asm:

.equ DDRB, 0x17
.equ PB0, 0x00
.equ PORTB, 0x18
.org 0x00 ; начало
        sbi     DDRB, PB0;   порт PB0 на передачу
        ldi     r25, 0x01;   r25=1
; главный цикл
loop:
        in      r24, PORTB;  r24=PORTB
        eor     r24, r25;    r24 = r24 xor r25
        out     PORTB, r24;  PORTB=r25
        ldi     r18, 0x3F;   r18=0x3F
        ldi     r19, 0x0D;   r19=0x0D
        ldi     r24, 0x03;   r24=0x03
sleep:
        subi    r18, 0x01;  (r18r19r24)-1  вычитание трехбайтного целого числа
        sbci    r19, 0x00
        sbci    r24, 0x00
        brne    sleep;     если значение в r24 не равно нулю, то переход на начало операции вычитания
        rjmp    loop;      возврат на начало главного цикла

Компиляция:

avr-as -mmcu=attiny13 -o blink.o blink.asm
avr-ld -o blink.elf blink.o
avr-objcopy --output-target=ihex blink.elf blink.hex

Смотрим, все ли в порядке:

$ avr-objdump -m avr -D blink.hex

blink.hex:     file format ihex


Disassembly of section .sec1:

00000000 <.sec1>:
   0:   b8 9a           sbi     0x17, 0 ; 23
   2:   91 e0           ldi     r25, 0x01       ; 1
   4:   88 b3           in      r24, 0x18       ; 24
   6:   89 27           eor     r24, r25
   8:   88 bb           out     0x18, r24       ; 24
   a:   2f e3           ldi     r18, 0x3F       ; 63
   c:   3d e0           ldi     r19, 0x0D       ; 13
   e:   81 e0           ldi     r24, 0x03       ; 3
  10:   21 50           subi    r18, 0x01       ; 1
  12:   30 40           sbci    r19, 0x00       ; 0
  14:   80 40           sbci    r24, 0x00       ; 0
  16:   e1 f7           brne    .-8             ;  0x10
  18:   f5 cf           rjmp    .-22            ;  0x4

Читать дальше

Дизассемблирование blink.hex

разделы: AVR, ATtiny13A, АССЕМБЛЕР, дата: 18 марта 2014г.

Ассемблер считается сложным языком программирования. Хотя, припоминая, к слову, функциональное программирование, где нет ни переменных, ни циклов, а вместо них одни рекурсии и функции, я бы поспорил. Но, мне кажется, что я знаю причину такого мнения. Если взять рядовую книжку по предмету, то прежде чем написать свой blink, сперва придется прочитать добрую сотню страниц, если не больше, про архитектуру, регистры, шины, порты и т.д. Не самое легкое чтиво, надо сказать. Взяв для сравнения книжку Кернигана&Ритчи мы найдем "Hello World!" на первой же странице. Весомый аргумент в пользу Си, на мой взгляд.

В предыдущем посте я упоминал, что размер прошивки с программой Blink написанной на Си для ATtiny45 составляет 82 байта. В AVR каждая инструкция вместе с аргументом занимает два байта, т.е. одно слово. 82 делим на 2, получаем 41 ассемблерная инструкция. Наверно, должен сразу оговориться. Если вы не получаете за это деньги, то изучать Ассемблер нет никакого практического смысла, языка Си хватит "за глаза" для написания своих прошивок. НО... иногда желание заглянуть "под капот" бывает слишком сильным;)

Если уж экспериментировать с ассемблером, то для начала, разумно будет выбрать чип попроще. Мой выбор пал на ATtiny13. Его флеш-память составляет всего 1 Кбайт. Опять же 1024 делим пополам, получаем размер программы до 500 инструкций, что для ассемблера совсем немного. По правде говоря, многие устройства работают на этом чипе, на мой взгляд один из самых популярных микроконтроллеров. По счастливой случайности, распиновка ATtiny13 совпадает с распиновкой ATtiny45, следовательно и исходник blink.c не меняется:

// blink.c for AVR ATtiny 13/25/45/85

#include <avr/io.h>
#define F_CPU 1000000UL // частота резонатора 1МГц
#include <util/delay.h>
int main(void) {
 // макрос _BV(число) заменяет конструкцию (1 << число)
 DDRB |= _BV(PB0); // аналог pinMode(PB0,OUTPUT); в Wiring
 for (;;) {
  PORTB ^= _BV(PB0); // инвертируем состояние порта PB0
  _delay_ms(1000); // ждем 1 секунду
 }
 return 0;
}

Ах, чуть не забыл. Про книжки по ассемблеру AVR.

    Для меня очень полезны оказались материалы:
  1. AVR Assemble User Guid
  2. 8-bit AVR Instruction Set.
  3. Юрий Ревич "Практическое программирование микроконтроллеров Atmel AVR на языке ассемблера" 2-е издание. 2011г.

Читать дальше

ATtiny45: blink на чистом Си

разделы: AVR, дата: 7 марта 2014г.

Немного раньше, я расказывал о том, как с помощью Arduino IDE программировать младшее семейство микроконтролеров AVR на примере ATtiny45. В последующем посте я обратил внимание на то, что вес прошивки составил 802 байта. Для ATtiny45 эта цифра не выглядит страшно, но в лишний раз подумаешь что бы связываться c ATtiny 25/24 с их двумя килобатами флеш-памяти. Давайте напишем Blink на Си и посмотрим на размер бинарника.

Как видно на 5-ом пине назначен порт PB0. На него и будем подключать светодиод.

Исходник:

// blink.c for AVR ATtiny 25/45/85

#include <avr/io.h>
#define F_CPU 1000000UL // частота резонатора 1МГц
#include <util/delay.h>
int main(void) {
 // макрос _BV(число) заменяет конструкцию (1 << число)
 DDRB |= _BV(PB0); // аналог pinMode(PB0,OUTPUT); в Wiring
 for (;;) {
  PORTB ^= _BV(PB0); // инвертируем состояние порта PB0
  _delay_ms(1000); // ждем 1 секунду
 }
 return 0;
}

Компиляция:

$ avr-gcc -mmcu=attiny45 -Wall -Os -o blink.elf blink.c
$ avr-objcopy -O ihex blink.elf blink.hex

Читать дальше