Browse Source

Объединение с домашним архивом.

Vladimir N. Shilov 8 years ago
parent
commit
3c7f716c8f

+ 67 - 0
Array of arrays in PROGMEM for AVR MCUs.c

@@ -0,0 +1,67 @@
+/*
+  http://snippets.artvolk.sumy.ua/view/141/massiv-massivov-v-progmem-dlya-mikrokontrollerov-avr
+
+  Когда совсем запутался с массивами массивов, хранимых во флеш-памяти
+  микроконтроллера AVR решил набросать такую демку и проверить всё в
+  симуляторе с отладчиком. Вроде бы разобрался, возможно, кому-нибудь ещё
+  пригодится.
+
+  Особенно понравился доступ к массивам не так: a[2], а вот так: 2[a]
+  (это работает для любых массивов в C) :-)
+
+*/
+
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+
+#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))
+
+const uint8_t array1[] PROGMEM = {1,2,3,4,5};
+const uint8_t array2[] PROGMEM = {6,7,8,9,10,11,12};
+
+const uint8_t* my_arrays[] PROGMEM = {
+    array1,
+    array2
+};
+
+uint8_t* current;
+uint8_t x, size;
+
+int main(void)
+{
+    /*
+        Description: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=38003
+    */
+    x = pgm_read_byte(&array1[3]); // read 4rd element of first array
+
+    // Read using pointer to array1
+    current = (uint8_t*)array1;
+    x = pgm_read_byte(current + 2); // read 3rd element of first array
+
+    // Size of one array
+    size = NUM_ELEM(array1);
+
+    // Read using pointer to array2
+    current = (uint8_t*)array2;
+    x = pgm_read_byte(current+1); // read 2nd element of second array
+
+    // Read using pointer from pointer table in Flash
+    current = (uint8_t*)pgm_read_word(my_arrays+1);
+    x = pgm_read_byte(current+5); // read #6 element of second array
+
+    // Read using pointer from pointer table in Flash (different syntax)
+    current = (uint8_t*)pgm_read_word(&my_arrays[1]);
+    x = pgm_read_byte(current+6); // read #7 element of second array
+
+    x = pgm_read_byte(&current[5]); // read #6 element of second array
+
+    x = pgm_read_byte(&2[current]); // freaky one :)
+
+    // Size of pointer arrays
+    size = NUM_ELEM(my_arrays);
+
+    while(1)
+    {
+
+    }
+}

+ 138 - 0
C.txt

@@ -1,3 +1,21 @@
+Порты у ARM Cortex-M шестнадцатибитные.
+
+И что??? Это не повод для извращений...
+Код:
+#define LCD_DATA            (*(__IO uint8_t *)((uint32_t)&(GPIOС->ODR)))
+
+И юзаем как обычно... 
+Можно и обе половинки юзать... как восьмибитные...
+Код:
+#define LCD_DATA_L            (*(__IO uint8_t *)((uint32_t)&(GPIOС->ODR)))
+#define LCD_DATA_H            (*(__IO uint8_t *)((uint32_t)&(GPIOС->ODR) + 1))
+
+-------------------
+
+char Version_str[] = "void118's superproject " __DATE__ ", " __TIME__;
+
+-------------------
+
 [FAQ] Изменение и чтение отдельных битов
 
 имеем порт J, в codevision работать с ним как PORTJ.n нельзя,
@@ -78,6 +96,126 @@ volatile struct               //flags
 использование:
 Flag.Tick = TRUE;
 
+===============================================================================
+int a;		// Целое
+int *a;		// Указатель на целое
+int **a;	// Указатель на указатель на целое
+int a[10];	// Массив из десяти целых
+int *a[10];	// Массив из десяти указателей на целые
+int (*a)[10];	// Указатель на массив из десяти целых
+int (*a)(int);	// Указатель на функцию, которая берет целый аргумент и возвращает целое
+int (*a[10])(int); // Массив из десяти указателей на функции, которые берут целый аргумент и возвращают целое
+===============================================================================
+В каких случаях используется ключевое слово static?
+
+   Полностью отвечают на этот вопрос довольно редко. Спецификатор static в 
+языке Си используется в трёх случаях:
+(а) Переменная, описанная внутри тела функции как статическая, сохраняет 
+    свое значение между вызовами функции.
+(b) Переменная, описанная как статическая внутри модуля, но снаружи тела 
+    функции, доступна для всех функций в пределах этого модуля и не доступна 
+    функциям любых  других модулей. То есть, это локализованная глобальная 
+    переменная.
+(с) Функции, описанные внутри модуля как статические, могут быть вызваны 
+    только другими функциями из этого модуля. То есть, область видимости 
+    функции локализована модулем, внутри которого она описана.
+
+   Большинство кандидатов отвечают правильно на первую часть. Умеренное 
+число кандидатов справляется со второй частью, ну и небольшое количество 
+понимают ответ (с). Это серьёзный недостаток кандидата, если он не 
+понимает важность и преимущества ограничения области видимости данных и 
+кода.
+===============================================================================
+Что означает ключевое слово const?
+   Как только интервьюируемый говорит: «Const - значит константа», я понимаю, что имею дело с непрофессионалом. Дэн Сакс в прошлом году дал исчерпывающее объяснение спецификатору const, так что каждый читатель ESP должен быть досконально ознакомлен с тем, что const может сделать для вас и чего он не может. Если вы не читали эту рубрику, достаточно будет сказать, что const означает «только для чтения». Хотя этот ответ не совсем справедливо отражает предмет разговора, я бы принял его в качестве правильного. 
+   Если кандидат даст правильный ответ, то я задам ему следующие дополнительные вопросы:
+
+Что означают следующие объявления? 
+const int a;		// целочисленная константа (только для чтения)
+int const a;		// целочисленная константа (только для чтения)
+const int *a;		// указатель на целочисленную константу
+int * const a;		// константный указатель на целое
+const int * const a;	// константный указатель на целочисленную константу
+
+===============================================================================
+Используя директиву #define, как бы вы описали именованную константу, которая возвращает число секунд в году? Високосными годами следует пренебречь.
+
+#define SECONDS_PER_YEAR (60UL * 60UL * 24UL * 365UL)
+===============================================================================
+Напишите «стандартный» макрос MIN. То есть, макрос, который берет два аргумента и возвращает меньший из них. 
+
+#define MIN(A,B)       ((A) <=  (B) ? (A) : (B))
+===============================================================================
+Что означает ключевое слово volatile? Приведите три различных примера его использования. 
+
+   Ключевое слово volatile информирует компилятор о том, что переменная может быть изменена не только из текущего выполняемого кода, но и из других мест. Тогда компилятор будет избегать определенных оптимизаций этой переменной. 
+
+Примеры volatile переменных:
+(а) Регистры в периферийных устройствах (например, регистры состояния)
+(b) Глобальные переменные, используемые в обработчиках прерываний.
+(с) Глобальные переменные, используемые совместно несколькими задачами в многопотоковом приложении.
+===============================================================================
+Дана целая переменная «а», напишите два фрагмента кода. Первый должен установить 3-ий бит этой переменной. Второй должен очищать его. В обоих случаях, другие биты должны остаться без изменений.
+
+(с) Используйте #define и битовые маски. Это хорошо переносимый метод и его стоит использовать. Оптимальное решение этой проблемы, на мой взгляд, было бы таким:
+
+#define BIT3       (0?1 << 3)
+static int a;
+void set_bit3(void) 
+{
+   a |= BIT3;
+}
+
+void clear_bit3(void) 
+{
+   a &= ~BIT3;
+}
+===============================================================================
+В некотором проекте требуется установить целую переменную по абсолютному адресу  0?67a9 к значению 0xaa55.
+
+ptr = (int *)0?67a9;
+*ptr = 0xaa55;
+
+Более запутывающий вариант выглядит так:
+
+*(int * const)(0?67a9) = 0xaa55;
+===============================================================================
+использование указателя на массив функций
+
+typedef enum {GEAR_DOWN = 0, WTG_FOR_TKOFF, RAISING_GEAR, GEAR_UP, LOWERING_GEAR} State_Type;
+ 
+/*Этот массив содержит указатели на функции, вызываемые в определенных состояниях*/
+void (*state_table[])() = {GearDown, WtgForTakeoff, RaisingGear, GearUp, LoweringGear};
+ 
+State_Type curr_state;
+
+mainn () {
+...
+ state_table[curr_state]();
+...
+}
+
+
+void InitializeLdgGearSM(void)
+{
+   curr_state = GEAR_DOWN;
+   timer = 0.0;
+   /*Остановка аппаратуры, выключение лампочек и т.д.*/
+}
+ 
+void GearDown(void)
+{
+   /* Переходим в состояние ожидания, если самолет
+  не на земле и поступила команда поднять шасси*/
+   if ((gear_lever == UP) && (prev_gear_lever == DOWN) && (squat_switch == UP)) {
+      timer = 2.0;
+      curr_state = WTG_FOR_TKOFF;
+   };
+   prev_gear_lever = gear_lever; 
+}
+
+...
+
 ===============================================================================
 
 Си для микроконтроллеров и чайников.

+ 9 - 0
C_unions_bits.txt

@@ -1,3 +1,12 @@
+	union _word
+	{
+		uint16_t	word;
+		uint8_t		byte[2];
+	} wrd;
+
+	wrd.byte[0] = data;
+	wrd.byte[1] = reg;
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=67601
 
    typedef union { 

+ 113 - 0
avr/adc.txt

@@ -0,0 +1,113 @@
+АЦП включается установкой бита ADEN (бит 7) в регистре управления АЦП -
+ADCSR (или ADCSRA)
+
+Режим непрерывных измерений активизируется установкой бита ADFR (бит 5)
+этого же регистра.
+В ряде моделей Mega (к ним относится ATmega8535) этот бит носит
+наименование ADATE, и управление режимом работы производится сложнее: там
+добавляются несколько режимов запуска через различные прерывания (в т. ч.
+прерывание от компаратора, при наступлении различных событий от таймера и
+т. п.), и выбирать их следует, задавая биты ADTS регистра SFIOR, а
+установка бита ADATE разрешает запуск АЦП по этим событиям. Так как нулевые
+значения всех битов ADTS (по умолчанию)  означают режим непрерывного
+преобразования, то в случае, когда вы их значения не трогали, функции битов
+ADATE и ADFR в других моделях будут совпадать.
+
+Если выбран режим запуска не от внешнего источника, то преобразование
+запускается установкой бита adcs (бит 6 того же регистра adcsr/adcsra). При
+непрерывном режиме установка этого бита запустит первое преобразование,
+затем они будут  автоматически повторяться. В режиме однократного
+преобразования, а также  независимо от установленного режима при запуске
+через прерывания (в тех моделях, где это. возможно) установка бита adcs
+просто запускает одно преобразование. При  наступлении прерывания,
+запускающего преобразование, бит adcs устанавливается аппаратно. Отметив,
+что преобразование начинается по фронту первого тактового импульса
+(тактового сигнала АЦП, а не самого контроллера!) после установки adcs.
+Само преобразование занимает 13 (или 14 для дифференциального входа)
+периодов тактового сигнала АЦП, кроме первого после включения АЦП
+преобразования, которое займет 25 тактов.
+
+По окончании одиночного преобразования бит adcs аппаратно сбрасывается.
+Кроме того, по окончании любого преобразования (и в одиночном, и в
+непрерывном режиме) устанавливается бит adif (бит 4, флаг прерывания).
+Разрешение  прерывания АЦП осуществляется установкой бита adie (бит 3) все
+того же регистра adcsr/adcsra.
+
+Для работы с АЦП необходимо еще установить его тактовую частоту. Это
+делается тремя младшими битами регистра adcsr/adcsra под названием
+adps0..2. Коэффициент деления частоты тактового генератора МК
+устанавливается по степеням двойки, все нули в этих трех битах
+соответствуют коэффициенту 2, все единицы - 128. Напомним, что оптимальная
+частота преобразования лежит в диапазоне 50-200 кГц, так что, например,
+для тактовой частоты МК, равной 4 МГц, коэффициент может иметь значение
+только 32 (состояние битов adpso...2 = 101, частота 125 кГц) или 64
+(состояние битов adpso...2 = 110, частота 62,5 кГц). При тактовой частоте
+16 МГц в допустимый диапазон укладывается только коэффициент 128.
+
+Выборка источника опорного напряжения производится битами REFS1..0 регистра
+ADMUX (старшие биты 7 и 6), причем их нулевое значение (по умолчанию)
+соответствует внешнему источнику. Напряжение этого внешнего источника может
+лежать в пределах от 2 В до напряжения питания аналоговой части AVCC (а
+оно, в свою очередь, не должно отличаться от питания цифровой части более
+чем на 0,3 В в большую или меньшую сторону). Можно выбрать в качестве
+опорного и питание самой аналоговой части, причем двояким способом: либо
+просто соединить выводы AREF и AVCC микросхемы, либо установить биты
+refs1..0 в состояние 01 (тогда соединение осуществляется внутренними
+схемами, но заметим, что внешний опорный источник при этом должен быть
+отключен). Предусмотрен и встроенный источник (задается refs1..0 в
+состоянии 11, при этом к выводу AREF рекомендуется подключать фильтрующий
+конденсатор), имеющий номинальное напряжение 2,56 В с большим разбросом от
+2,4 до 2,7 В.
+
+Результат преобразования АЦП оказывается в регистрах adch:adcl. Поскольку
+результат 10-разрядный, то по умолчанию старшие 6 битов в регистре adch
+оказываются равными нулю. Чтение этих регистров производится, начиная с
+младшего adcl, после чего регистр adch блокируется, пока не будет прочитан.
+Следовательно, даже если момент между чтением регистров попал на фронт
+14(15) такта АЦП, когда данные в них должны меняться, значения прочитанной
+пары будут соответствовать друг другу, пусть и результат этого
+преобразования пропадет. В противоположном порядке читать эти регистры не
+рекомендуется. Но бит adlar (бит 5 регистра admux) предоставляет интересную
+возможность: если его установить в 1, то результат преобразования в
+регистрах adch:adcl выравнивается влево: бит 9 результата окажется в
+старшем бите adch, а незначащими будут младшие 6 битов регистра adcl. В
+этом случае, если хватает 8-разрядного разрешения результата, можно
+прочесть только значение adch.
+
+Выбор каналов и режимов их взаимодействия в АЦП производится пятью битами
+MUX0..4 в регистре admux. В некоторых моделях (семейство Tiny) этих битов
+всего три (MUX0..2), а, например, в ATmega8 - четыре (MUX0..3), в
+зависимости от общего числа каналов, В любом случае их значения от 0 до
+максимального номера канала (которых в большинстве случаев 8, так что
+значения оказываются в пределах от 000 до 111, старшие биты, если они есть,
+равны 0) выбирают нужный канал в обычном (недифференциальном) режиме, когда
+измеряемое напряжение отсчиты- вается от "земли" (аналоговой). А последние
+два значения этих битов для семейства Mega (11110 и 11111 в большинстве
+моделей или 1110 и 1111 для ATmega8) выбирают режимы, когда вход АЦП
+подсоединяется к опорному источнику компаратора (1,22 В) или к "земле"
+соответственно, что может использоваться для автокалибровки устройства. В
+имеющих АЦП моделях Tiny (а также в "классическом" AT90S8535) такого режима
+нет.
+
+Наконец, остальные комбинации разрядов MUX предназначены для установки
+различных дифференциальных режимов - в тех моделях, где они присутствуют, в
+других случаях эти биты зарезервированы (как в моделях Atmega8, ATmegal63 и
+др.). В дифференциальном режиме АЦП измеряет напряжение между двумя
+выбранными выводами (например, между ADC0 и ADC1), причем не все выводы
+могут быть в таком режиме задействованы. В том числе дифференциальные входы
+АЦП можно подключать к одному и тому же входу для коррекции нуля. Дело в
+том, что в ряде моделей на входе АЦП имеется встроенный усилитель, с
+коэффициентом 1х, 20х и 100х (коэффициент выбирается теми же битами
+MUX0..4), и такой режим используется для его калибровки — в дальнейшем
+значение выхода при соединенных входах можно просто вычесть.
+
+Для недифференциального режима АЦП, когда напряжение отсчитывается от
+"земли", результат преобразования определяется формулой: Ка = 1024Uвх/Uref,
+где Ка — значение выходного кода АЦП, Uвх и Uref - входное и опорное
+напряжения. Дифференциальному измерению соответствует такая формула: Ка =
+512(Upos - Uneg)/Vref, где Upos и Uneg - напряжения на положительном и
+отрицательном входах соответственно. Если напряжение на отрицательном входе
+больше, чем на положительном, то результат в дифференциальном режиме
+становится отрицательным и выражается в дополнительном коде от $200 (-512)
+до $3FF (-1). Реальная точность преобразования в дифференциальном режиме
+равна 8 разрядам.

+ 450 - 0
avr/ariphmetic.asm

@@ -0,0 +1,450 @@
+;***
+; двухбайтное сравнение
+	ldi	r16,low(777)
+	cpi	zh,high(777)
+	cpc	zl,r16
+
+==========
+
+.def dataL = r4		; multiplicand low byte
+.def dataH = r5		; multiplicand high byte
+.def KoeffL = r2	; multiplier low byte
+.def koeffH = r3	; multiplier high byte
+.def temp = r16		; result byte 0 (LSD)
+.def temp1 = r17	; result byte 1
+.def temp2 = r18	; result byte 2 (MSD)
+
+;**************************************************************************
+; умножение двух 16-разрядных величин, только для Mega
+; исходные величины dataH-dataL и KoeffH-KoeffL
+; результат 3 байта temp2:temp1:temp
+Mul16:
+	clr	temp2		; очистить старший
+	mul	dataL,KoeffL	; умножаем младшие
+	mov	temp,r0		; в R0 младший результата операции mul
+	mov	temp1,r1	; в R1 старший результата операции mul
+	mul	dataH,KoeffL	; умножаем старший на младший
+	add	temp1,r0	; в R0 младший результата операции mul
+	adc	temp2,r1	; в R1 старший результата операции mul
+	mul	dataL,KoeffH	; умножаем младший на старший
+	add	temp1,r0	; в R0 младший результата операции mul
+	adc	temp2,r1	; в R1 старший результата операции mul
+	mul	dataH,KoeffH	; умножаем старший на старший
+	add	temp2,r0	; 4-й разряд нам тут не требуется, но он - в R1
+	ret
+;**************************************************************************
+
+==================================
+
+;***************************************************************************
+; перемножение двух 16-разрядных величин,
+; результат 3 байта
+mpy16u:	clr	tmp2
+	ldi	count,16	;init loop counter
+m16u_1:	lsr	KoeffH
+	ror	KoeffL
+
+	brcc	noad8		;if bit 0 of multiplier set
+	add	tmpm,IzmL	;add multiplicand Low to byte 2 of res
+	adc	tmp2,IzmH	;add multiplicand high to byte 3 of res
+noad8:	ror	tmp2		;rotate right result byte 2
+	ror	tmpm		;rotate result byte 1 and multiplier High
+	ror	temp		;rotate result byte 0 and multiplier Low
+	dec	count		;decrement loop counter
+	brne	m16u_1		;if not done, loop more
+	ret
+
+;***************************************************************************
+; перемножение двух 16-разрядных величин, результат 4 байта, рабочая
+; множимое KoeffH:KoeffL, множитель IzmH:IzmL, результат tmp3:tmp2:tmpm:temp
+; использует count
+; слов:	14 + return. циклов: 153 + return + rcall
+mpy16u:	clr	tmp3		;clear 2 highest bytes of result
+	clr	tmp2
+	ldi	count,16	;init loop counter
+m16u_1:	lsr	KoeffH
+	ror	KoeffL
+	brcc	noad8		;if bit 0 of multiplier set
+	add	tmp2,IzmL	;add multiplicand Low to byte 2 of res
+	adc	tmp3,IzmH	;add multiplicand high to byte 3 of res
+noad8:	ror	tmp3		;shift right result byte 3
+	ror	tmp2		;rotate right result byte 2
+	ror	tmpm		;rotate result byte 1 and multiplier High
+	ror	temp		;rotate result byte 0 and multiplier Low
+	dec	count		;decrement loop counter
+	brne	m16u_1		;if not done, loop more
+	ret
+
+==================================
+;***************************************************
+;* Mutiply 32x32 -> 64 bit
+;*     A        B         C
+;*  R24:R21 x R5:R2 -> R15:R8
+;*
+;*  88 cycles + 4 (RET) = 92 Cycles
+;*
+mult32:
+		clr	R16
+		mul	R21,R2	; умножили A1 на Б1
+		movw	R8,R0	; рез положили в Ц1-2
+		clr	R10
+		clr	R11
+		clr	R12
+		clr	R13
+		clr	R14
+		clr	R15
+		mul	R22,R2	; умн А2 на Б1
+		add	R9,R0	; рез1 доб к Ц2
+		adc	R10,R1	; рез2 доб к Ц3
+		mul	R23,R2	; умн А3 на Б1
+		add	R10,R0	; рез1 доб к Ц3
+		adc	R11,R1	; рез2 доб к Ц4
+		mul	R24,R2	; А4 умн на Б1
+		add	R11,R0  ; рез1 доб к Ц4
+		adc	R12,R1  ; рез2 доб к Ц5
+
+		mul	R21,R3
+		add	R9,R0
+		adc	R10,R1
+		adc	R11,R16
+		adc	R12,R16
+		adc	R13,R16
+		mul	R22,R3
+		add	R10,R0
+		adc	R11,R1
+		adc	R12,R16
+		adc	R13,R16
+		mul	R23,R3
+		add	R11,R0
+		adc	R12,R1
+		adc	R13,R16
+		mul	R24,R3
+		add	R12,R0
+		adc	R13,R1
+
+		mul	R21,R4
+		add	R10,R0
+		adc	R11,R1
+		adc	R12,R16
+		adc	R13,R16
+		adc	R14,R16
+		mul	R22,R4
+		add	R11,R0
+		adc	R12,R1
+		adc	R13,R16
+		adc	R14,R16
+		mul	R23,R4
+		add	R12,R0
+		adc	R13,R1
+		adc	R14,R16
+		mul	R24,R4
+		add	R13,R0
+		adc	R14,R1
+
+		mul	R21,R5
+		add	R11,R0
+		adc	R12,R1
+		adc	R13,R16
+		adc	R14,R16
+		adc	R15,R16
+		mul	R22,R5
+		add	R12,R0
+		adc	R13,R1
+		adc	R14,R16
+		adc	R15,R16
+		mul	R23,R5
+		add	R13,R0
+		adc	R14,R1
+		adc	R15,R16
+		mul	R24,R5
+		add	R14,R0
+		adc	R15,R1
+		ret
+==================================
+;***************************************************
+;* Mutiply 24x16 -> 40 bit (3*2=5 Bytes)
+;*     A        B         C
+;*  R23:R21 x R3:R2 -> R12:R8
+;*
+;*  30 cycles + 4 (RET) = 34 Cycles
+;*
+mul24x16:
+		clr	R16
+		mul	R21,R2	; A1*B1
+		movw	R8,R0	; Rez->C1C2
+		clr	R10
+		clr	R11
+		clr	R12
+		mul	R22,R2	; A2*B1
+		add	R9,R0	; C2+=Rez1
+		adc	R10,R1	; C3+=Rez2
+		mul	R23,R2	; A3*B1
+		add	R10,R0	; C3+=Rez1
+		adc	R11,R1	; C4+=Rez2
+
+		mul	R21,R3	; A1*B2
+		add	R9,R0	; C2+=Rez1
+		adc	R10,R1	; C3+=Rez2
+		adc	R11,R16	; C4+=C flag
+		adc	R12,R16 ; C5+=C flag
+		mul	R22,R3	; A2*B2
+		add	R10,R0	; C3+=Rez1
+		adc	R11,R1	; C4+=Rez2
+		adc	R12,R16	; C5+=C flag
+		mul	R23,R3	; A3*B2
+		add	R11,R0	; C4+=Rez1
+		adc	R12,R1	; C5+=Rez2
+		ret
+
+;***************************************************************************
+;*
+;* "mpy16u8" - 16x8 Bit Unsigned Multiplication
+;*
+;* This subroutine multiplies 16-bit and 8-bit register variables
+;* mp16uH:mp16uL and mc16uL
+;* The result is placed in m16u2:m16u1:m16u0.
+;*
+;* Number of words	:13 + return
+;* Number of cycles	:137? + return
+;* Low registers used	:1 (R0)
+;* High registers used  :5 (mc16uL,mp16uL/m16u0,mp16uH/m16u1,m16u2,mcnt16u)
+;*
+;***************************************************************************
+
+;***** Subroutine Register Variables
+
+.def	mc16uL	=r16		;multiplicand low byte
+.def	mp16uL	=r18		;multiplier low byte
+.def	mp16uH	=r19		;multiplier high byte
+.def	m16u0	=r18		;result byte 0 (LSB)
+.def	m16u1	=r19		;result byte 1
+.def	m16u2	=r20		;result byte 2
+.def	mcnt16u	=r22		;loop counter
+
+;***** Code
+
+mpy16u8:clr	R0
+	clr	m16u2		;clear high byte of result
+	ldi	mcnt16u,16	;init loop counter
+m16u_1:	lsr	mp16uH
+	ror	mp16uL
+
+	brcc	noad8		;if bit 0 of multiplier set
+	add	m16u1,mc16uL	;add multiplicand Low to byte 1 of res
+	adc	m16u2,R0	;add multiplicand high to byte 2 of res
+noad8:	ror	m16u2		;rotate right result byte 2
+	ror	m16u1		;rotate result byte 1 and multiplier High
+	ror	m16u0		;rotate result byte 0 and multiplier Low
+	dec	mcnt16u		;decrement loop counter
+	brne	m16u_1		;if not done, loop more
+	ret
+
+==================================
+
+;*************************************************************************
+; div32x8 - 32/8 деление беззнаковых чисел
+; Делимое и результат в countHH (старший), countTH,
+; countTM, countTL (младший)
+; делитель в cikle
+; требуется четыре рабочих регистра dremL — dremHH
+; из диапазона R16-R31 для хранения остатка
+div32x8:
+	clr	temp 		; "ZERO"
+	clr	dremL		;clear remainder Low byte
+	clr	dremM		;clear remainder
+	clr	dremH		;clear remainder
+	sub	dremHH,dremHH	;clear remainder High byte and carry
+	ldi	cnt,33		;init loop counter
+d_1:	rol	countTL		;shift left dividend
+	rol	countTM
+	rol	countTH
+	rol	countHH
+	dec	cnt		;decrement counter
+	brne	d_2		;if done
+	ret			;return
+d_2:	rol	dremL		;shift dividend into remainder
+	rol	dremM
+	rol	dremH
+	rol	dremHH
+	sub	dremL,cikle	;remainder = remainder — divisor
+	sbc	dremM,temp
+	sbc	dremH,temp
+	sbc	dremHH,temp
+	brcc	d_3		;if result negative
+	add	dremL,cikle	;restore remainder
+	adc	dremM,temp
+	adc	dremH,temp
+	adc	dremHH,temp
+	clc			;clear carry to be shifted into result
+	rjmp d_1		;else
+d_3:	sec			; set carry to be shifted into result
+	rjmp d_1
+; ************************************************************** конец 32/8
+
+====================================
+;***************************************************************************
+;*
+;* "div24u16" - 24/16 Bit Unsigned Division
+;* (по сути это 24/24)
+;* Эта процедура делит 3-х байтное число на 2-х байтное
+;* "dd16uH:dd16uM:dd16uL" (dividend) and "dv16uH:dv16uL" (divisor).
+;* The result is placed in "dres16uH:dres16uM:dres16uL" and the remainder in
+;* "drem16uH:drem16uM:drem16uL".
+;*
+;* Number of words	:25 (50 bytes)
+;* Number of cycles	:?/? (Min/Max)
+;* Low registers used	:7 (drem16uL,drem16uM,drem16uH,dres16uL/dd16uL,dres16uM/dd16uM,dres16uH/dd16uH,ZERO)
+;* High registers used  :3 (dv16uL,dv16uH,dcnt16u)
+;*
+;***************************************************************************
+
+;***** Subroutine Register Variables
+
+.def	ZERO	=R12
+.def	drem16uL=r13
+.def	drem16uM=r14
+.def	drem16uH=r15
+.def	dres16uL=r16
+.def	dres16uM=r17
+.def	dres16uH=r18
+.def	dd16uL	=r16
+.def	dd16uM	=r17
+.def	dd16uH	=r18
+.def	dv16uL	=r19
+.def	dv16uH	=r20
+.def	dcnt16u	=r21
+
+;***** Code
+
+div24u:	clr	ZERO
+	clr	drem16uL	;clear remainder Low byte
+	clr	drem16uM	;clear remainder Middle byte
+	sub	drem16uH,drem16uH;clear remainder High byte and carry
+	ldi	dcnt16u,25	;init loop counter
+d24u_1:	rol	dd16uL		;shift left dividend
+	rol	dd16uM
+	rol	dd16uH
+	dec	dcnt16u		;decrement counter
+	brne	d24u_2		;if done
+	ret			;    return
+d24u_2:	rol	drem16uL	;shift dividend into remainder
+	rol	drem16uM
+	rol	drem16uH
+	sub	drem16uL,dv16uL	;remainder = remainder - divisor
+	sbc	drem16uM,dv16uH
+	sbc	drem16uH,ZERO
+	brcc	d24u_3		;if result negative
+	add	drem16uL,dv16uL	;    restore remainder
+	adc	drem16uM,dv16uH
+	adc	drem16uH,ZERO
+	clc			;    clear carry to be shifted into result
+	rjmp	d24u_1		;else
+d24u_3:	sec			;    set carry to be shifted into result
+	rjmp	d24u_1
+
+; *************************************************************************
+; процедура деления 24/8 отличается от 24/16 только тем,
+; что старший байт делителя всегда равен 0
+; *************************************************************************
+; div24u8 - 24/8 деление беззнаковых чисел
+; Делимое и результат в countH (старший), countTM, countTL (младший)
+; делитель в divisor, использует R0, cnt
+; требуется три рабочих регистра dremL — dremH для хранения остатка
+; 25 слов, 5+24*(17-19)+5+4=(408-456)+14=422--470 тактов
+; + 3 такта на rcall :-)
+div24u8:clr	R0
+	clr	dremL		;clear remainder Low byte
+	clr	dremM		;clear remainder Midle byte
+	sub	dremH,dremH	;clear remainder High byte and carry
+	ldi	cnt,25		;init loop counter
+d_1:	rol	countTL		;shift left dividend
+	rol	countTM
+	rol	countTH
+	dec	cnt		;decrement counter
+	brne	d_2		;if done
+	ret			;return
+d_2:	rol	dremL		;shift dividend into remainder
+	rol	dremM
+	rol	dremH
+	sub	dremL,divisor	;remainder = remainder — divisor
+	sbc	dremM,R0
+	sbc	dremH,R0
+	brcc	d_3		;if result negative
+	add	dremL,divisor	;restore remainder
+	adc	dremM,R0
+	adc	dremH,R0
+	clc			;clear carry to be shifted into result
+	rjmp d_1		;else
+d_3:	sec			; set carry to be shifted into result
+	rjmp d_1
+; ************************************************************** конец 24/8
+
+
+;***************************************************************************
+;*
+;* "div16u8" - 16/8 Bit Unsigned Division
+;*
+;* This subroutine divides the 16-bit / 8-bit numbers
+;* "dd16uH:dd16uL" (dividend) and "dv16uL" (divisor).
+;* The result is placed in "dres16uH:dres16uL" and the remainder in
+;* "drem16uH:drem16uL".
+;*
+;* Number of words	:19
+;* Number of cycles	:235/251 (Min/Max)
+;* Low registers used	:2 (drem16uL,drem16uH)
+;* High registers used  :4 (dres16uL/dd16uL,dres16uH/dd16uH,dv16uL,dcnt16u)
+;*
+;***************************************************************************
+
+;***** Subroutine Register Variables
+
+.def	drem16uL=r14
+.def	drem16uH=r15
+.def	dres16uL=r16
+.def	dres16uH=r17
+.def	dd16uL	=r16
+.def	dd16uH	=r17
+.def	dv16uL	=r18
+.def	dcnt16u	=r19
+
+;***** Code
+
+div16u:	clr	R0
+	clr	drem16uL	;clear remainder Low byte
+	sub	drem16uH,drem16uH;clear remainder High byte and carry
+	ldi	dcnt16u,17	;init loop counter
+d16u_1:	rol	dd16uL		;shift left dividend
+	rol	dd16uH
+	dec	dcnt16u		;decrement counter
+	brne	d16u_2		;if done
+	ret			;    return
+d16u_2:	rol	drem16uL	;shift dividend into remainder
+	rol	drem16uH
+	sub	drem16uL,dv16uL	;remainder = remainder - divisor
+	sbc	drem16uH,R0	;
+	brcc	d16u_3		;if result negative
+	add	drem16uL,dv16uL	;    restore remainder
+	adc	drem16uH,R0
+	clc			;    clear carry to be shifted into result
+	rjmp	d16u_1		;else
+d16u_3:	sec			;    set carry to be shifted into result
+	rjmp	d16u_1
+
+
+====================================
+;******************************
+; делим двубайтное число на 10
+; вход: JobH:JobL
+; выход: XH:XL, остаток может быть в JobL
+; использует:
+DIV16_10:
+	clr	XL		; инициируем счётчик десятков
+	clr	XH
+	sbiw	X,1
+DIV16_10_l1:
+	adiw	X,1		; увеличили счётчик
+	sbiw	JobL,10		; уменьшили исходное число
+	brsh	DIV16_10_l1	; если остаток > 0 -- ещё на круг
+;	inc	JobL		; если нужен остаток
+
+	ret

+ 260 - 0
avr/avr.inc

@@ -0,0 +1,260 @@
+;------------------------------------------------;
+; Push/Pop register pair
+;
+; 	pushw	Z
+
+.macro	pushw
+	push	@0H
+	push	@0L
+.endm
+
+.macro	popw
+	pop	@0L
+	pop	@0H
+.endm
+
+
+;------------------------------------------------;
+; Load/store word from/to direct memory/immediate
+;
+;	ldsw	Z,mem
+;	ldiw	Z,imm
+
+.macro	ldiw
+	ldi	@0L,low(@1)
+	ldi	@0H,high(@1)
+.endm
+
+.macro	ldsw
+	lds	@0L,@1
+	lds	@0H,@1+1
+.endm
+
+.macro	lddw
+	ldd	@0L,@1
+	ldd	@0H,@1+1
+.endm
+
+.macro	stsw
+	sts	@0,@1L
+	sts	@0+1,@1H
+.endm
+
+.macro	stdw
+	std	@0,@1L
+	std	@0+1,@1H
+.endm
+
+
+;------------------------------------------------;
+; Store immediate into indirect memory via r16
+;
+;	sti	Z,imm
+;	stdi	Z+d,imm
+
+.macro	sti
+	ldi	r16,@1
+	st	@0,r16
+.endm
+
+.macro	stdi
+	ldi	r16,@1
+	std	@0,r16
+.endm
+
+
+;------------------------------------------------;
+; add/sub/subc/cp/cpc/lsl/lsr/rol/ror to register pair
+;
+
+.macro	addiw
+	subi	@0L,low(-(@1))
+	sbci	@0H,high(-(@1))
+.endm
+
+.macro	subiw
+	subi	@0L,low(@1)
+	sbci	@0H,high(@1)
+.endm
+
+.macro	addw
+	add	@0L,@1L
+	adc	@0H,@1H
+.endm
+
+.macro	adcw
+	adc	@0L,@1L
+	adc	@0H,@1H
+.endm
+
+.macro	subw
+	sub	@0L,@1L
+	sbc	@0H,@1H
+.endm
+
+.macro	sbcw
+	sbc	@0L,@1L
+	sbc	@0H,@1H
+.endm
+
+.macro	cpw
+	cp	@0L,@1L
+	cpc	@0H,@1H
+.endm
+
+.macro	cpcw
+	cpc	@0L,@1L
+	cpc	@0H,@1H
+.endm
+
+.macro	andw
+	and	@0L,@1L
+	and	@0H,@1H
+.endm
+
+.macro	andiw
+	andi	@0L,low(@1)
+	andi	@0H,high(@1)
+.endm
+
+.macro	orw
+	or	@0L,@1L
+	or	@0H,@1H
+.endm
+
+.macro	oriw
+	ori	@0L,low(@1)
+	ori	@0H,high(@1)
+.endm
+
+.macro	lslw
+	lsl	@0L
+	rol	@0H
+.endm
+
+.macro	lsrw
+	lsr	@0H
+	ror	@0L
+.endm
+
+.macro	rolw
+	rol	@0L
+	rol	@0H
+.endm
+
+.macro	rorw
+	ror	@0H
+	ror	@0L
+.endm
+
+.macro	clrw
+	clr	@0L
+	clr	@0H
+.endm
+
+.macro	comw
+	com	@0L
+	com	@0H
+.endm
+
+.macro	movew
+	mov	@0L, @1L
+	mov	@0H, @1H
+.endm
+
+
+;------------------------------------------------;
+; Store immediate into direct memory via r16
+;
+;	stsi	var,imm
+
+.macro	stsi
+	ldi	r16,@1
+	sts	@0,r16
+.endm
+
+
+;------------------------------------------------;
+; Output port immediate via r16
+;
+;	outi	port,var
+
+.macro	outi
+	ldi	r16,@1
+	out	@0,r16
+.endm
+
+
+;------------------------------------------------;
+; Add immediate to register
+
+.macro	addi
+	subi	@0,-(@1)
+.endm
+
+
+;------------------------------------------------;
+; Long branch
+
+
+.macro	rjne
+	breq	PC+2
+	rjmp	@0
+.endm
+
+.macro	rjeq
+	brne	PC+2
+	rjmp	@0
+.endm
+
+.macro	rjcc
+	brcs	PC+2
+	rjmp	@0
+.endm
+
+.macro	rjcs
+	brcc	PC+2
+	rjmp	@0
+.endm
+
+.macro	rjtc
+	brts	PC+2
+	rjmp	@0
+.endm
+
+.macro	rjts
+	brtc	PC+2
+	rjmp	@0
+.endm
+
+
+.macro	retcc
+	brcs	PC+2
+	ret
+.endm
+
+.macro	retcs
+	brcc	PC+2
+	ret
+.endm
+
+.macro	reteq
+	brne	PC+2
+	ret
+.endm
+
+.macro	retne
+	breq	PC+2
+	ret
+.endm
+
+
+;------------------------------------------------;
+; Move single bit between two registers
+;
+;	bmov	dstreg,dstbit,srcreg.srcbit
+
+.macro	bmov
+	bst	@2,@3
+	bld	@0,@1
+.endm

BIN
avr/avrasm.pdf


+ 21 - 0
avr/bcd2ascii.asm

@@ -0,0 +1,21 @@
+; Вход R16
+; Выход R16 младший полубайт - выходит на печать последним
+; R17 старший полубайт - выходит на печать первым.
+BCD2ASCII:
+	MOV	R17,R16
+	ANDI	R16,0x0F
+	subi	R16,-0x30
+	ANDI	R17,0xF0
+	SWAP	R17
+	subi	R17,-0x30
+
+	RET
+
+;
+r16 = 0x23
+r16 & 0x0f == 0x03
+r16 + 0x30 == 0x33 == '3'
+
+r17 & 0xf0 == 0x20
+r17 swap == 0x02
+r17 + 0x30 == 0x32 == '2'

+ 61 - 0
avr/bin16bcd5.asm

@@ -0,0 +1,61 @@
+;===================================================================
+;"bin16BCD5"- преобразование 16-битного двоичного
+;значения в упакованный BCD формат
+;===================================================================
+;Количество слов кода            :25 + возврат
+;Количество циклов               :25/176 (Мин/Макс) + возврат
+;Использованные младшие регистры :нет
+;Использованные старшие регистры :4(fbinL,fbinH/tBCD0,tBCD1,tBCD2)
+;Использованные указатели        :нет
+
+
+;Вход
+.def    fbinL   =r16            ;двоичное значение, младший байт
+.def    fbinH   =r17            ;двоичное значение, старший байт
+
+;Выход
+.def    tBCD0   =r17            ;BCD значение, цифры 1 и 0
+.def    tBCD1   =r18            ;BCD значение, цифры 3 и 2
+.def    tBCD2   =r19            ;BCD значение, цифра 4
+;Примечание: Переменные fbinH и tBCD0 должны размещаться в одном
+;регистре.
+
+
+bin16BCD5:	ldi     tBCD2,-1
+b16BCD5_l1:	inc     tBCD2
+
+        	subi    fbinL,low(10000)
+        	sbci    fbinH,high(10000)
+
+        	brsh    b16BCD5_l1
+
+        	subi    fbinL,low(-10000)
+        	sbci    fbinH,high(-10000)
+
+        	ldi     tBCD1,-0x11
+
+b16BCD5_l2:	subi    tBCD1,-0x10
+        	subi    fbinL,low(1000)
+	       	sbci    fbinH,high(1000)
+
+	    	brsh 	b16BCD5_l2
+
+	    	subi    fbinL,low(-1000)
+        	sbci    fbinH,high(-1000)
+
+b16BCD5_l3:	inc     tBCD1
+        	subi    fbinL,low(100)
+        	sbci    fbinH,high(100)
+
+	    	brsh 	b16BCD5_l3
+
+	    	subi    fbinL,-100
+        	ldi     tBCD0,-0x10
+
+b16BCD5_l4:	subi    tBCD0,-0x10
+        	subi    fbinL,10
+
+	    	brsh 	b16BCD5_l4
+	    	subi    fbinL,-10
+        	add     tBCD0,fbinL
+        	ret

+ 294 - 0
avr/bin2bcd.asm

@@ -0,0 +1,294 @@
+;===================================================================
+;"bin16BCD5"- преобразование 16-битного двоичного
+;значения в упакованный BCD формат
+;===================================================================
+;Количество слов кода            :25 + возврат
+;Количество циклов               :25/176 (Мин/Макс) + возврат
+;Использованные младшие регистры :нет
+;Использованные старшие регистры :4(fbinL,fbinH/tBCD0,tBCD1,tBCD2)
+;Использованные указатели        :нет
+
+
+;Вход
+.def    fbinL   =r16            ;двоичное значение, младший байт
+.def    fbinH   =r17            ;двоичное значение, старший байт
+
+;Выход
+.def    tBCD0   =r17            ;BCD значение, цифры 1 и 0
+.def    tBCD1   =r18            ;BCD значение, цифры 3 и 2
+.def    tBCD2   =r19            ;BCD значение, цифра 4
+;Примечание: Переменные fbinH и tBCD0 должны размещаться в одном
+;регистре.
+
+
+bin16BCD5:	ldi     tBCD2,-1
+b16BCD5_l1: 	inc     tBCD2
+
+        	subi    fbinL,low(10000)
+        	sbci    fbinH,high(10000)
+
+        	brsh    b16BCD5_l1
+
+        	subi    fbinL,low(-10000)
+        	sbci    fbinH,high(-10000)
+
+        	ldi     tBCD1,-0x11
+
+b16BCD5_l2:	subi    tBCD1,-0x10
+        	subi    fbinL,low(1000)
+	       	sbci    fbinH,high(1000)
+
+	    	brsh 	b16BCD5_l2
+
+	    	subi    fbinL,low(-1000)
+        	sbci    fbinH,high(-1000)
+
+b16BCD5_l3:	inc     tBCD1
+        	subi    fbinL,low(100)
+        	sbci    fbinH,high(100)
+
+	    	brsh 	b16BCD5_l3
+
+	    	subi    fbinL,-100
+        	ldi     tBCD0,-0x10
+
+b16BCD5_l4:	subi    tBCD0,-0x10
+        	subi    fbinL,10
+
+	    	brsh 	b16BCD5_l4
+	    	subi    fbinL,-10
+        	add     tBCD0,fbinL
+        	ret
+
+-=-=-=-=-=-=-
+Для нижних регистров:
+
+;******************************
+; "bin16BCD5"- преобразование 16-битного двоичного значения в упакованный BCD формат
+; Вход -- job1:job0
+; Выход -- job3:job2:job1 (дес тыс:тыс,сот:дес,ед)
+; использует temp и tmp1 и cnt1
+BIN16BCD5:
+	ser	temp
+	mov	job3,temp	; -1 в десятки тысяч
+	ldi	temp,low(10000)
+	ldi	tmp1,high(10000)
+b16BCD5_l1:
+	inc	job3		; увеличили счётчик десятков тысяч
+	sub	job0,temp
+	sbc	job1,tmp1	; уменьшили исходное на 10000
+	brsh	b16BCD5_l1	; больше 0? повторим
+	add	job0,temp	; меньше. восстановим из минусов
+	adc	job1,tmp1
+
+	ldi	temp,-0x11
+	mov	job2,temp	; по -1 в тысячи и в сотни
+	ldi	temp,low(1000)
+	ldi	tmp1,high(1000)
+	ldi	cnt1,0x10
+b16BCD5_l2:
+	add	job2,cnt1	; увеличили счётчик тысяч
+	sub	job0,temp
+	sbc	job1,tmp1	; уменьшили исходное на 1000
+	brsh	b16BCD5_l2	; больше 0? повторим
+	add	job0,temp	; меньше. восстановим из минуса
+	adc	job1,tmp1
+
+	ldi	temp,100
+	clr	tmp1
+b16BCD5_l3:
+	inc	job2		; увеличили счётчик сотен
+	sub	job0,temp
+	sbc	job1,tmp1	; уменьшили на 1000
+	brsh	b16BCD5_l3	; больше 0? потоврим
+	add	job0,temp	; меньше. восстановим
+
+	ldi	temp,-0x10
+	mov	job1,temp
+	ldi	tmp1,10
+b16BCD5_l4:
+	sub	job1,temp	; увеличили счётчик десятков
+	sub	job0,tmp1	; уменьшили на 10
+	brsh	b16BCD5_l4	; больше 0? повторим
+	add	job0,tmp1	; меньше, восстановим
+	add	job1,job0	; остаток - единицы, к десяткам
+
+	ret
+
+;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+;******************************
+; "BIN2BCD6"- преобразование 20-битного двоичного значения (0x0F423F) (0b11110100001000111111)
+; в упакованный BCD формат (000000 - 999999)
+; Вход -- job2:job1:job0
+; Выход -- job3:job2:job1 (сот тыс,дес тыс:тыс,сот:дес,ед)
+; использует temp,tmp1 и cnt1,cnt2
+BIN2BCD6:
+	; считаем сотни тысяч
+	ldi	temp,-0x11
+	mov	job3,temp	; по -1 в десятки тысяч и в сотни тысяч
+	ldi	temp,0xa0
+	ldi	tmp1,0x86
+	ldi	cnt1,0x01	; загрузили 100000
+	ldi	cnt2,0x10
+b2bcd6_l1:
+	add	job3,cnt2	; увеличили счётчик сотен тысяч
+	sub	job0,temp
+	sbc	job1,tmp1
+	sbc	job2,cnt1	; уменьшили исходное на 100000
+	brsh	b2bcd6_l1	; остаток >= 100000? повторим
+	add	job0,temp	; нет, восстановим
+	adc	job1,tmp1
+	adc	job2,cnt1
+	; считаем десятки тысяч
+	ldi	temp,low(10000)
+	ldi	tmp1,high(10000)
+	clr	cnt1		; загрузили 10000
+b2bcd6_l2:
+	inc	job3		; увеличили счётчик десятков тысяч
+	sub	job0,temp
+	sbc	job1,tmp1
+	sbc	job2,cnt1	; уменьшили остаток на 10000
+	brsh	b2bcd6_l2	; >= 10000? повторим
+	add	job0,temp	; меньше. восстановим из минусов
+	adc	job1,tmp1
+	; считаем тысячи
+	ldi	temp,-0x11
+	mov	job2,temp	; по -1 в тысячи и в сотни
+	ldi	temp,low(1000)
+	ldi	tmp1,high(1000)
+b2bcd6_l3:
+	add	job2,cnt2	; увеличили счётчик тысяч
+	sub	job0,temp
+	sbc	job1,tmp1	; уменьшили остаток на 1000
+	brsh	b2bcd6_l3	; >= 1000? повторим
+	add	job0,temp	; меньше. восстановим из минуса
+	adc	job1,tmp1
+	; считаем сотни
+	ldi	temp,100
+b2bcd6_l4:
+	inc	job2		; увеличили счётчик сотен
+	sub	job0,temp
+	sbc	job1,cnt1	; уменьшили на 100
+	brsh	b2bcd6_l4	; >= 100? повторим
+	add	job0,temp	; меньше. восстановим
+	; считаем десятки. в остатке - единицы
+	ldi	temp,-0x10
+	mov	job1,temp
+	ldi	tmp1,10
+b2bcd6_l5:
+	sub	job1,temp	; увеличили счётчик десятков
+	sub	job0,tmp1	; уменьшили на 10
+	brsh	b2bcd6_l5	; >= 10? повторим
+	add	job0,tmp1	; меньше, восстановим
+	add	job1,job0	; остаток - единицы, к десяткам
+
+	ret
+
+;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+;******************************
+; "BIN2BCD4"- преобразование 14-битного двоичного значения в упакованный BCD формат
+; Вход -- job1:job0
+; Выход -- job2:job1 (тыс,сот:дес,ед)
+; использует temp и tmp1 и cnt1
+BIN2BCD4:
+	; тысячи
+	ldi	temp,-0x11
+	mov	job2,temp	; по -1 в тысячи и в сотни
+	ldi	temp,low(1000)
+	ldi	tmp1,high(1000)
+	ldi	cnt1,0x10
+b2BCD4_l1:
+	add	job2,cnt1	; увеличили счётчик тысяч
+	sub	job0,temp
+	sbc	job1,tmp1	; уменьшили исходное на 1000
+	brsh	b2BCD4_l1	; >= 1000? повторим
+	add	job0,temp	; меньше. восстановим из минуса
+	adc	job1,tmp1
+	; сотни
+	ldi	temp,100
+	clr	tmp1
+b2BCD4_l2:
+	inc	job2		; увеличили счётчик сотен
+	sub	job0,temp
+	sbc	job1,tmp1	; уменьшили на 100
+	brsh	b16BCD4_l2	; >= 100? потоврим
+	add	job0,temp	; меньше. восстановим
+	; десятки
+	ldi	temp,-0x10
+	mov	job1,temp
+	ldi	tmp1,10
+b2BCD4_l3:
+	sub	job1,temp	; увеличили счётчик десятков
+	sub	job0,tmp1	; уменьшили на 10
+	brsh	b16BCD4_l3	; >= 10? повторим
+	add	job0,tmp1	; меньше, восстановим
+	add	job1,job0	; остаток - единицы, к десяткам
+
+	ret
+
+;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+;******************************
+;"bin16BCD3"- преобразование 16-битного двоичного
+;значения 0..999 в упакованный BCD формат
+;
+;Количество слов кода            :12 + возврат
+;Количество циклов               :14/70 (Мин/Макс) + возврат
+;Использованные младшие регистры :нет
+;Использованные старшие регистры :3(fbinL,fbinH/tBCD0,tBCD1)
+;Использованные указатели        :нет
+;
+;Вход
+.def    fbinL   =r16            ;двоичное значение, младший байт
+.def    fbinH   =r17            ;двоичное значение, старший байт
+;
+;Выход
+.def    tBCD0   =r17            ;BCD значение, цифры 1 и 0
+.def    tBCD1   =r18            ;BCD значение, цифра 2
+;Примечание: Переменные fbinH и tBCD0 должны размещаться в одном
+;регистре.
+
+bin16BCD3:	ldi     tBCD1,-0x01
+
+b16BCD5_l1:	inc     tBCD1
+        	subi    fbinL,low(100)
+        	sbci    fbinH,high(100)
+	    	brsh 	b16BCD5_l1
+
+	    	subi    fbinL,-100
+        	ldi     tBCD0,-0x10
+
+b16BCD5_l2:	subi    tBCD0,-0x10
+        	subi    fbinL,10
+	    	brsh 	b16BCD5_l2
+
+	    	subi    fbinL,-10
+        	add     tBCD0,fbinL
+
+        	ret
+
+;;; вариант для нижних регистров
+; Вход job1:job0, Выход job2:job1 (сот дес ед); портит temp,tmp1
+BIN16BCD3:
+	ser	temp
+	mov	job2,temp	; ldi -1 > job2, сотни
+	ldi	temp,100
+	clr	tmp1
+b16BCD3_l1:
+	inc	job2		; увеличили счётчик сотен
+	sub	job0,temp	;
+	sbc	job1,tmp1	; уменьшили исходное число на 100
+	brsh	b16BCD3_l1	; если остаток > 0 -- ещё один круг
+	add	job0,temp	; восстанавливаем мл. байт из отрицательного значения
+				; job1:job0 теперь должны быть < 100
+	ldi	temp,-0x10
+	mov	job1,temp	; инициируем счётчик десятков
+	ldi	tmp1,10
+b16BCD3_l2:
+	sub	job1,temp	; увеличили сч. десятков (+ 0x10)
+	sub	job0,tmp1	; вычли из нашего остатка 10 (0x0A)
+	brsh	b16BCD3_l2	; если остаток > 0 -- ещё на круг
+	add	job0,tmp1	; восстанавливаем мл. байт из отрицательного значения
+	add	job1,job0	; добавили единицы к сч. десятков.
+
+	ret

+ 68 - 0
avr/delay.asm

@@ -0,0 +1,68 @@
+#ifndef F_CPU
+	#error "F_CPU must be defined!"
+#endif
+
+#if F_CPU < 4000000
+	#warning "F_CPU too low, possible wrong delay"
+#endif
+
+#define CYCLES_PER_US (F_CPU/1000000)
+#define C4PUS (CYCLES_PER_US/4)
+#define DVUS(x) (C4PUS*x)
+
+.macro DELAY_uS
+	ldi	XH, HIGH(DVUS(@0))
+	ldi	XL, LOW(DVUS(@0))
+	rcall	Wait4xCycles
+.endm
+
+
+.macro DELAY_mS
+	ldi	YL,low(@0)
+	ldi	YH,high(@0)
+	rcall	WaitMiliseconds
+.endm
+
+
+;------------------------------------------------------------------------------
+; Input : XH:XL - number of CPU cycles to wait (divided by four)
+;------------------------------------------------------------------------------
+Wait4xCycles:
+	sbiw   XH:XL, 1
+	brne   Wait4xCycles
+	ret
+
+;------------------------------------------------------------------------------
+; Input : temp - number of miliseconds to wait
+;------------------------------------------------------------------------------
+;WaitMiliseconds:
+;	push temp
+;WaitMsLoop:
+;	ldi    XH,HIGH(DVUS(500))
+;	ldi    XL,LOW(DVUS(500))
+;	rcall  Wait4xCycles
+;	ldi    XH,HIGH(DVUS(500))
+;	ldi    XL,LOW(DVUS(500))
+;	rcall  Wait4xCycles
+;	dec    temp
+;	brne   WaitMsLoop
+;	pop    temp
+;	ret
+
+;------------------------------------------------------------------------------
+; Input : YH:YL - number of miliseconds to wait, использует Temp
+; таймер каждую милисекунду отнимает 1 от Y, пока тот не достигнет 0
+;------------------------------------------------------------------------------
+WaitMiliSeconds:
+	ldi	temp,1<<SE
+	out	MCUCR,temp	; IDLE SLEEP
+WMS_SLL:
+	sleep			; спим.
+	tst	YL
+	brne	WMS_SLL		; спим до сл. прерывания
+	tst	YH
+	brne	WMS_SLL		; спим до сл. прерывания
+	clr	temp
+	out	MCUCR,temp	; со сна
+
+	ret

+ 435 - 0
avr/float.inc

@@ -0,0 +1,435 @@
+; ************* Floating point library for AVR microprocessors *************
+;
+; Assembler     AVRASM v. 1.21
+; Processor     AT90S2313, AT90S8515
+; Code Size     256 words (512 bytes)
+; **************************************************************************
+; Author        Y.Andrienko
+; Phone         (057-2) 44-85-40, 98-07-58
+; FIDO          2:461/44.14
+; E-mail        yurik@aqua.kharkov.ua, aya@apexmail.com
+;
+; Last modification     - 28.09.1999
+; **************************************************************************
+; Floating point number format: 3-bytes
+; 1st - order - bit 7 - number sign (1 - negative number)
+;                   6 - order sign (1 - positive order)
+;                   0..5 - order value
+; 2nd - mantissa low byte
+; 3d  - mantissa high byte
+
+; !!! This variables must be defined in main programm !!!
+
+;.def  Float1O =r16
+;.def  Float1L =r17
+;.def  Float1H =r18
+;
+;.def  Float2O =r19
+;.def  Float2L =r20
+;.def  Float2H =r21
+
+;.def  FTempO  =r22
+;.def  FTempL  =r23
+;.def  FTempH  =r24
+;.def  FCnt    =r25
+
+
+; ************************************************************************
+; Fix2Float - translate fixed format number to floating point format
+; Float2Fix - translate floating point number to fixed format
+; FNeg      - negate floating point number
+; SwapFl    - exchange Float1 and Float2
+; FAdd      - floating point addition Float2=Float2+Float1
+; FSub      - floating point substraction Float2=Float2-Float1
+; FMul      - floating point multiplication Float2=Float2*Float1
+; FDiv      - floating point division Float2=Float1/Float2
+;*************************************************************************
+
+; translate number from fix to floating point format
+; Input - 2-byte number in Float2L,Float2H
+; Output - 3-byte floating point number in Float2
+;
+; high registers used - Float2O,Float2L,Float2H
+
+Fix2Float:
+        clc                     ; clear carry
+        tst     Float2L         ; check number for 0
+        brne    Fx2Fl_A
+        tst     Float2H
+        brne    Fx2Fl_A
+        ldi     Float2O,$40     ; if Float2L=Float2H=0 set number to 0
+        ret
+Fx2Fl_A:
+        ldi     Float2O,$50     ; if fixed num # 0 set order to 50H
+Fx2Fl_B:
+        sbrc    Float2H,7       ; skip if bit 7#0
+        ret                     ; else return
+        rol     FLoat2L         ; shift number left
+        rol     Float2H
+        dec     Float2O         ; and decrement order
+        rjmp    Fx2Fl_B         ; continue while bit 7#1
+
+
+
+; translate floating point number to fixed format
+; Input - Float2
+; Output - Float2L, Float2H
+; carry=1 if overflow
+;
+; registers used - Float2O, Float2L, Float2H
+
+Float2Fix:
+        sbrc    Float2O,7       ; check number sign
+        rjmp    SetOverflow     ; for negative number set overflow and return
+        sbrs    Float2O,6       ; check order sign
+        rjmp    Float2eq0       ; for neg.order set number to 0
+        andi    Float2O,$3f     ; mask sign bits
+        cpi     Float2O,$11     ; check maximal order
+        brlo    Fl2Fx_A         ; jump if order<11H
+        rjmp    SetOverflow     ; else set overflow and return
+Fl2Fx_A:
+        subi    Float2O,$10
+        neg     Float2O         ; Float2O=10H-Float2O
+Fl2Fx_C:
+        clc                     ; clear carry
+        tst     Float2O         ; check order
+        brne    Fl2Fx_B
+        ret                     ; return if order 0
+Fl2Fx_B:
+        ror     Float2H         ; shift right
+        ror     Float2L
+        dec     Float2O         ; decrement order
+        rjmp    Fl2Fx_C         ; repeat while order # 0
+
+Float2eq0:
+        clr     Float2L
+        clr     Float2H
+        ret
+
+; Change sign of floating point number Float2=-Float2
+; Input - Float2
+; Output - Float2
+; registers used - Float2O,Float2L,Float2H
+
+FNeg:
+        neg     Float2O
+        subi    Float2O,$80
+        neg     Float2O
+        clc
+        ret
+
+; Swap Float1 and Float2 numbers
+; (Thanks for A.Redchhuk)
+SwapFl:
+;       it is                        it was
+        eor Float1O,Float2O        ; push    Float1O
+        eor Float2O,Float1O        ; mov     Float1O,Float2O
+        eor Float1O,Float2O        ; pop     Float2O
+
+        eor Float1L,Float2L        ; push    Float1L
+        eor Float2L,Float1L        ; mov     Float1L,Float2L
+        eor Float1L,Float2L        ; pop     Float2L
+
+        eor Float1H,Float2H        ; push    Float1H
+        eor Float2H,Float1H        ; mov     Float1H,Float2H
+        eor Float1H,Float2H        ; pop     Float2H
+        ret
+
+; Floating point addition Float2=Float1+Float2
+; Input - Float1, Float2
+; Output - Float2
+; registers used - Float1O, Float1L, Float1H, Float2O, Float2L, Float2H
+
+FAdd:
+        sbrc    Float1O,7       ; skip if Float1>0
+        rjmp    FAdd_A          ; jump if Float1<0
+        sbrs    Float2O,7       ; skip if Float2<0
+        rjmp    FAdd_B          ; jump if FLoat1 and Float2 < 0
+
+; if numbers signs not equal (Float1>0,Float2<0 or Float1<0, Float2>0)
+; if Float1>0 Float2<0  result = Float1-Float2
+FAdd_C:
+        rcall   FNeg            ; change Float2 sign
+        rcall   SwapFl
+        rjmp    FSub            ; and continue in substraction programm
+; If Float1<0,Float2>0 result = Float2-Float1
+FAdd_X:
+        rcall   SwapFl          ; Change Float1 sign
+        rcall   FNeg
+        rcall   SwapFl
+        rjmp    FSub
+FAdd_A:
+        sbrs    Float2O,7       ; skip if Float1<0 and Float2<0
+        rjmp    FAdd_X
+; if numbers signs are equal
+FAdd_B:
+        tst     Float1H         ; check Float1 for 0
+        brne    FAdd_D
+        tst     Float1L
+        brne    FAdd_D
+        ret                     ; if Float1=0 result =Float2
+FAdd_D:
+        tst     Float2H         ; check Float2 for 0
+        brne    FAdd_E
+        tst     Float2L
+        brne    FAdd_E
+        rjmp    Fl1toFl2        ; if Float2=0 copy Float1 as result and return
+FAdd_E:
+        cp      Float2O,Float1O ; compare orders
+        breq    FAdd_G          ; if orders are equal
+        brlo    FAdd_F          ; if Float2O<Float1O
+        rcall   SwapFl          ; else swap numbers
+FAdd_F:
+        sub     Float2O,Float1O
+        neg     Float2O         ; Float2O=Float1O-Float2O
+        cpi     Float2O,$10
+        brlo    FAdd_H          ; if Float1O-Float2O<16
+        rjmp    Fl1toFl2        ; else copy Float1 as result and return
+FAdd_H:
+        clc                     ; clear carry
+        ror     Float2H         ; shift Float2 right
+        ror     Float2L
+        dec     Float2O         ; decrement order
+        brne    FAdd_H          ; repeat while orders not equal
+; if orders are equal
+FAdd_G:
+        add     Float2L,Float1L ; add numbers
+        adc     Float2H,Float1H
+        brcs    FAdd_I          ; jump if carry set
+FAdd_J:
+        mov     Float2O,Float1O ; copy order value
+        ret                     ; and return
+FAdd_I:
+        ror     FLoat2H         ; shift number
+        ror     Float2L
+        inc     Float1O         ; increment order
+        rjmp    FAdd_J
+
+; Floating point numbers substraction Float2=Float1-Float2
+; Input - Float1, Float2
+; Output - Float2
+; registers used - Float1O, Float1L, Float1H, Float2O, Float2L, Float2H
+
+FSub:
+        sbrc    Float1O,7       ; skip if Float1>0
+        rjmp    FSub_A          ; jump if Float1<0
+        sbrs    Float2O,7       ; skip if Float2<0
+        rjmp    FSub_B          ; jump if Float1>0 and Float2>0
+
+; if numbers signs not equal
+FSub_C:
+        rcall   SwapFl
+        rcall   FNeg            ; change sign of 2nd number
+        rcall   SwapFl
+        rjmp    FAdd            ; and continue in substraction programm
+FSub_A:
+        sbrs    Float2O,7       ; skip if Float2<0 and Float1<0
+        rjmp    FSub_C          ; jump if Float2>0 (Float1<0)
+
+; if signs of numbers are equal
+FSub_B:
+        tst     Float1H         ; check Float1 for 0
+        brne    FSub_D
+        tst     Float1L
+        brne    FSub_D
+        ret                     ; if Float1=0  result = Float2 - return
+FSub_D:
+        tst     Float2H         ; check Float2 for 0
+        brne    FSub_E
+        tst     Float2L
+        brne    FSub_E
+        rcall   Fl1toFl2        ; if FLoat2=0, result = -Float1, copy an return
+        rjmp    FNeg            ; change sign and return
+FSub_E:
+        clt
+        cp      Float1O,Float2O ; compare orders
+        breq    FSub_G          ; if orders are equal
+        brlo    FSub_F          ; if Float1O<Float2O
+        set                     ; set flag
+        rcall   SwapFl          ; swap numbers if Float1O>Float2O
+FSub_F:
+        sub     Float1O,Float2O
+        neg     Float1O         ; Float1O=Float2O-Float1O
+        cpi     Float1O,$10
+        brlo    FSub_H          ; if Float2O-Float1O<16
+        ret                     ; else result=Float2
+
+; equalize orders
+FSub_H:
+        clc
+        ror     Float1H         ; shift Float right
+        ror     Float1L
+        dec     Float1O
+        brne    FSub_H          ; repeat before orders not equal
+        brtc    FSub_G          ;
+        rcall   SwapFl          ; swap again
+        clt
+FSub_G:
+        cp      Float2L,Float1L
+        cpc     Float2H,Float1H
+        brlo    FSub_I
+FSub_J:
+        sub     Float2L,Float1L ; add numbers
+        sbc     Float2H,Float1H
+        sbrc    Float2H,7       ; skip if MSB=0
+        ret                     ; else return
+        rjmp    Fx2Fl_B         ; normalise result
+FSub_I:
+        rcall   SwapFl          ; swap numbers
+        rcall   FNeg            ; change result sign
+        rjmp    FSub_J
+
+        ror     FLoat2H         ; shift number
+        ror     Float2L
+        inc     Float2O         ; increment order
+        rcall   FNeg            ; and change sign
+        ret                     ; else return
+
+
+; Floating point multiplication Float2 = Float1 * Float2
+; Input - Float1, Float2
+; Output - Float2
+; registers used - Float1O, Float1L, Float1H, Float2O, Float2L, Float2H
+;                  FTempO, FTempL, FCnt
+;
+FMul:
+        tst     Float1H         ; check Float1 for 0
+        brne    FMul_A
+        tst     Float1L
+        brne    FMul_A
+        rjmp    SetRes0         ; if Float1=0, set Float2=0 and return
+FMul_A:
+        tst     Float2H         ; check Float2 for 0
+        brne    FMul_B
+        tst     Float2L
+        brne    FMul_B
+        ret                     ; if Float2=0 - return
+
+FMul_B:
+        mov     FTempO,Float1O  ; Find result sign
+        eor     FTempO,Float2O  ; FTempO bit 7 equal result sign
+        cbr     Float1O,$80     ; reset numbers signs
+        cbr     Float2O,$80
+        bst     FTempO,7        ; save result sign in T
+        add     Float2O,Float1O ; add orders
+        ldi     Float1O,$40     ;
+        add     Float2O,Float1O
+        bld     Float2O,7
+
+; 16x16 bits unsigned multiplication from ****AVR200**** application note
+FMul_D:
+        clr     FTempO          ;clear 2 highest bytes of result
+        clr     FTempL
+        ldi     FCnt,16         ;init loop counter
+        lsr     Float2H
+        ror     Float2L
+FMul_E:
+        brcc    FMul_F          ;if bit 0 of multiplier set
+        add     FTempO,Float1L  ;add multiplicand Low to byte 2 of res
+        adc     FTempL,Float1H  ;add multiplicand high to byte 3 of res
+FMul_F:
+        ror     FTempL          ;shift right result byte 3
+        ror     FTempO          ;rotate right result byte 2
+        ror     Float2H         ;rotate result byte 1 and multiplier High
+        ror     Float2L         ;rotate result byte 0 and multiplier Low
+        dec     FCnt            ;decrement loop counter
+        brne    FMul_E          ;if not done, loop more
+; after multiplication - normalise result
+FMul_H:
+        sbrc    FTempL,7
+        rjmp    FMul_G          ; jump if result is normalised
+        rol     Float2L         ; shift number left
+        rol     Float2H
+        rol     FTempO
+        rol     FTempL
+        dec     Float2O         ; decrement result order
+        rjmp    FMul_H
+FMul_G:
+        bld     Float2O,7       ; restore result sign from T
+        mov     Float2L,FTempO  ; copy mantissa to result
+        mov     Float2H,FTempL
+        ret
+
+; Floating point division  Float2 = Float1/Float2
+; Input - Float1, Float2
+; Output - Float2
+; registers used - Float1O, Float1L, Float1H, Float2O, Float2L, Float2H
+;                  FTempO, FTempL, FTempH, FCnt
+
+FDiv:
+        mov     FTempO,Float1L  ; Check Float1 for 0
+        or      FTempO,Float1H
+        tst     FTempO
+        brne    FDiv_A
+        rjmp    SetRes0         ; if Float1=0 - result = 0
+FDiv_A:
+        sbrs    Float2H,7
+        rjmp    SetOverflow     ; if Float2 not normalized or 0 - overflow
+        ldi     FCnt,$10        ; bits counter
+        mov     FTempO,Float1O
+        andi    FTempO,$80      ; select sign bit
+        add     FTempO,Float2O  ;
+        bst     FTempO,7        ; store result sign in T
+        mov     FTempO,Float1O  ; read 1st number order
+        sub     FTempO,Float2O  ; substract orders
+        subi    FTempO,-$41     ; add 41H
+        bld     FTempO,7        ; restore result sign
+        clr     Float1O         ; clear orders
+        clr     Float2O
+        clr     FTempH
+        ldi     FTempL,1
+; main division cykle
+FDiv_C:
+        sbrs    FTempL,0
+        rjmp    FDiv_D
+        sub     Float1L,Float2L
+        sbc     Float1H,Float2H
+        sbc     Float1O,Float2O ; set carry
+        rjmp    FDiv_E
+FDiv_D:
+        add     Float1L,Float2L
+        adc     Float1H,Float2H
+        adc     Float1O,Float2O
+FDiv_E:
+        andi    Float1O,$01
+        push    Float1O         ; save order
+        clc
+        eor     Float1O,Float2O
+        brne    FDiv_F
+        sec
+FDiv_F:
+        pop     Float1O         ; restore order
+        rol     FTempL
+        rol     FTempH
+        clc                     ; clear carry
+        rol     Float1L
+        rol     Float1H
+        mov     Float1O,FTempH
+        rol     Float1O
+        dec     FCnt            ; decremet counter
+        brne    FDiv_C          ; repeate while FCnt#0
+        mov     Float2L,FTempL  ; copy result
+        mov     Float2H,FTempH
+        mov     Float2O,FTempO
+        rjmp    Fx2Fl_B         ; normalise result
+
+; Common subroutines
+
+; Set overflow flag and return
+SetOverflow:
+        sec
+        ret
+
+; Copy Float1 to Float2
+Fl1toFl2:
+        mov     Float2O,Float1O
+        mov     Float2H,Float1H
+        mov     Float2L,Float1L
+        ret
+
+; Set result to 0 (Float2=0)
+SetRes0:
+        clr     Float2L         ; set result=0
+        clr     Float2H
+        ldi     Float2O,$40
+        ret

+ 19 - 0
avr/hex2ascii.asm

@@ -0,0 +1,19 @@
+;-----------------------------------------------
+; HEX TO ASCII
+;-----------------------------------------------
+;I think, this was the smallest (only 10 words).
+
+;input: R16 = 8 bit value 0 ... 255
+;output: R18, R17, R16 = digits
+;bytes: 20
+
+Hex2Ascii:	LDI r18,-1+'0'
+_bcd1:		INC r18
+			SUBI r16,100
+			BRCC _bcd1
+			LDI r17,10+'0'
+_bcd2:		DEC r17
+			SUBI r16,-10
+			BRCS _bcd2
+			SBCI r16,-'0'
+			RET

+ 117 - 0
avr/knopki.txt

@@ -0,0 +1,117 @@
+Для кнопки надо выбраную ножку I/O подключить через кнопку на землю. Сам же
+вывод надо сконфигурировать как вход с подтяжкой (DDRxy=0 PORTxy=1). Тогда,
+когда кнопка не нажата, через подтягивающий резистор, на входе будет высокий
+уровень напряжения, а из бит PINху будет при чтении отдавать 1. Если кнопку
+нажать, то вход будет положен на землю, а напряжение на нем упадет до нуля, а
+значит из PINxy будет читаться 0. По нулям в битах регистра PINх мы узнаем
+что кнопки нажаты.
+
+ Пунктиром показан дополнительный подтягивающий резистор. Несмотря на то, что
+внутри AVR на порт можно подключить подтяжку, она слабоватая — 100кОм. А
+значит ее легко придавить к земле помехой или наводкой, что вызовет ложное
+срабатывание. А еще эти внутренние подтягивающие резисторы очень любят гореть
+от наводок. У меня уже с десяток микроконтроллеров с убитыми PullUp
+резисторами. Все работает, но только нет подтяжки — сгорела. Вешаешь снаружи
+резистор и работает как ни в чем ни бывало. Поэтому, для ответственных схем я
+настоятельно рекомендую добавить внешнюю подтяжку на 10кОм — даже если
+внутреннюю накроет, внешняя послужит. В процессе обучения на это можно
+забить.
+===============================================================================
+
+если кнопка нажата и флага1 нет - ставим флаг и выход.
+если кнопка нажата и есть флаг1 - увеличиваем счётчик. если счётчик переполнился - фиксируем удержание.
+	если есть флаг удержания, счётчик не переполнен но достиг порога - можно фикисровать срабатывани атовповтора (при необходимости)
+
+если кнопка отпущена но есть флаг1 и при этом счётчик >= порога и нет флага удержания - фиксируем нажатие.
+сьросим флаг1, счётчик времени.
+
+флаги 2 и 3 сбросят п/п обработки
+
+
+кнопка нажата
+	флаг1 есть?
+		нет: установим и дальше
+		да: считаем время нажатия
+	переполнилось время нажатия?
+		да: удержание. ставим флаг3,
+
+кнопка отпущена
+	время нажатия >= 0.5сек?
+		да: есть флаг 3?
+			нет: ставим флаг2
+	сбросим флаг1, сбросим время нажатия
+
+	; *** начало бработки кнопки ***
+	sbic	ButPort,BTN1	; кнопка 1 нажата?
+	rjmp	T0L2		; нет, на обработку ненажатой кнопки
+	sbrs	flagb,BTN1P	; была нажата раньше?
+	rjmp	T0L4		; нет, вкл флаг и дальше...
+	inc	TIKB		; да, увеличим счётчик
+	brne	T0L3		; переполнения нет - на выход
+	mov	temp,flagb	; переполнение...
+	sbi	temp,1<<BTN1H
+	mov	flagb,temp	; установили флаг удержания
+	rjmp	T0L3		; дальше...
+T0L2:	sbrs	flagb,BTN1P	; кнопка не нажата
+	rjmp	T0L5
+	ldi	temp,64		; ~0.5 сек
+	cp	TIKB,temp	; тики достигли порога срабатывания?
+	brlo	T0L5		; нет, на очистку
+	mov	temp,flagb	; да, ставим флаг
+	cbi	temp,1<<BTN1R
+	mov	flagb,temp	; установили флаг отпускания
+T0L5:	clr	TIKB		; очистим тики кнопок
+	mov	temp,flagb
+	cbi	temp,1<<BTN1P
+	mov	flagb,temp	; сбросили флаг нажатия
+	rjmp	T0L3		; дальше...
+T0L4:	sbi	temp,1<<BTN1P
+	mov	flagb,temp	; установили флаг нажатия
+	; *** закончили обратоку кнопки ***
+T0L3:
+
+===============================================
+каждый раз -- всё с начала, нихера не помню, нихера не выходит...
+
+ещё раз:
+
+предположим, опрос кнопки идёт в таймере с периодичнойстью 1-10 мс.
+пороги -- антидребезг = 50 мс, срабатывания = 100 мс, длинное нажатие =
+500 мс, удержание = 2 с.
+
+опрос кнопок:
+  кнопка нажата (
+     флага нет (
+	счётчик достиг порога антидребезга (
+	  ставим флага нажатия
+	  очищаем счётчик	// можно не делать.
+	) не достиг (
+	  увеличиваем счётчик
+	)
+     ) флаг есть (
+	счётчик меньше времени удержания (
+	    увеличивает счётчик
+	)
+     )
+  ) кнопка не нажата (
+     флаг есть (
+	сбросить флаг
+	счётчик меньше времени срабатывания (
+	    очистить
+	)
+     ) флага нет (
+	 очистить счётчик
+     )
+  )
+// 10 проверок, 7(6) действий
+
+
+обработка кнопок:
+  тут просто проверяем время нажатия/удержания.
+  сначала двойные комбинации, потом одиночные.
+  непонятно как обрабатывать удержание, если должна быть реакция и на
+  нажатие...
+
+кроме того -- ещё нужен обратный счётчик.
+после фиксации факта срабатывания или отпцскания -- заводим счётчик паузы,
+и ока он не дотикает до 0 -- кнопку не обрабатываем.

+ 30 - 0
avr/macro.inc

@@ -0,0 +1,30 @@
+; Тут будут макросы ===========================================================
+
+; Загрузка числа в порт
+.MACRO 	OUTI		; Это описание макроса. Везде где outi встретится в
+			; коде, то заменяется на этот кусок кода,
+	LDI	R17,@1	; причем @0,@1 это параметры, они заменятся введенными
+			; параметрами макроса. Данный макрос тупо копирует
+	OUT	@0,R17	; введенное число сначала в регистр R17, а из него регистр
+.ENDM
+
+; сохраняем в стек SREG и R16
+.MACRO PUSHF
+	PUSH	R16
+	IN	R16,SREG
+	PUSH	R16
+.ENDM
+
+; восстанавливаем из стека SREG и R16
+.MACRO POPF
+	POP	R16
+	OUT	SREG,R16
+	POP	R16
+.ENDM
+
+; 16-ти разрядное сравнение регистровой пары R с числом
+.macro	CPIW
+	ldi	R16,High(@0)
+	cpi	RL,Low(@0)
+	cpc	RH,R16
+.endm

+ 27 - 0
avr/pwm.txt

@@ -0,0 +1,27 @@
+; иницалзация ШИМ
+; для начала, пины PB1 (OC1A) и PB2 (OC1B) настроим на выход
+	ldi	temp,0b00000110
+	out	DDRB,temp
+; Выставляем для обоих каналов ШИМ режим вывода ОС** сброс при совпадении.
+; COM1A = 10 и COM1B = 10
+; Также ставим режим FAST PWM 8bit (таймер 16ти разрядный и допускает
+; большую разрядность ШИМ сигнала. Вплоть до 10 бит.  WGM = 0101
+; Осталось только запустить таймер на частоте МК CS = 001
+	ldi	temp,2<<COM1A0|2<<COM1B0|0<<WGM11|1<<WGM10
+	out 	TCCR1A,temp
+	ldi	temp,0<<WGM13|1<<WGM12|1<<CS10
+	out 	TCCR1B,temp
+; Готово! Теперь ШИМ таймера1 генерит сигнал на выходаx OC1А и OC1B
+; Закинем в регистры сравнения первого и второго канала число 255/3=85
+; и 255/2 = 128. Так как ШИМ у нас 8ми разрядный, то заброс идет только
+; в младший разряд. Старший же остается нулем. Но регистры сравнения
+; тут у нас 16ти разрядные поэтому грузить надо оба байта сразу.
+; Не забыв запретить прерывания (это важно!!! ибо атомарный доступ)
+	clr	temp
+	out	OCR1AH,temp
+	ldi	temp,85
+	out	OCR1AL,temp
+	clr	temp
+	out	OCR1BH,temp
+	ldi	temp,128
+	out	OCR1BL,temp

+ 189 - 0
avr/random.txt

@@ -0,0 +1,189 @@
+IvanM - Apr 20, 2010 - 06:16 PM
+Post subject: Efficient pseudorandom MLS number generator 1.625 cycle/bit
+ Two years ago I posted very fast pseudorandom number generator. It is based on MLS generator - shift register with feedback. It is faster than other implementation as it calulates 8 random bits at once.
+ I've stored shift register in GPIOR registers as they offered faster acces, but it can be rewritten to use RAM.
+ I have version with 15 bit feedback register (periode 32767, [15 14] polynome) and 23 bit register (periode 8,388,607 [23 14] polynome).31 bit version can be written with minor mods, but I did not need such long periode. Each length supports 8 bits and 16 bit output.
+ Size and timing for 15 bit register (including C call):
+ 8 bit rnd, 26 bytes 19 cycles
+ 16 bit rnd 40 bytes 26 cycles
+ Size and timing for 23 bit register (including C call):
+ 8 bit rnd, 30 bytes 21 cycles
+ 16 bit rnd, 44 bytes 28 cycles
+ actual calculation takes 7 cycles per output byte in all 4 cases, rest is call overhead, so it can be optimized if more random bytes is needed at once.
+ Asm routine was written following Rowley Crossworks register convention.
+ Note1: shift registers has to be initialized with seed >1 as bit 0 is not used.
+ Note2: to make periode practically infinite, occasionally alter shift reg. bits with bit 0 of ADC result (1 bit is enough)
+
+ C usage example:
+
+ unsigned int rnd16(void);
+ unsigned int w[200];
+
+ GPIOR0=2;GPIOR1=0; // initialize seed
+ for (i=1;i<200;i=++) w[i]=rnd16();
+
+ Enjoy, Ivan
+
+
+Code:
+
+ ;RND.asm
+ ; Pseudo Random Number Generator functions  8/16 bit  15/23 bit Maximum Lengts Sequences
+ ; (c) Ivan Mellen, Oct 2008
+ ; imellen at embeddedsignals dot com
+
+ ; C interface
+ ;unsigned char rnd8(void);    // 8 bit rnd, 26 bytes 19 cycles  [15 14] MLS
+ ;unsigned int rnd16(void);    //16 bit rnd  40 bytes 26 cycles  [15 14] MLS
+ ;unsigned char rnd8_23(void); // 8 bit rnd, 30 bytes 21 cycles  [23 14] MLS
+ ;unsigned int rnd16_23(void); //16 bit rnd, 44 bytes 28 cycles  [23 14] MLS
+
+
+
+ ; Crossworks C /ASM interface:
+ ; R27 (and R26 for int) input / output from function
+ ; asm fun can use R20-27,R0-1, R30-31
+
+ #include <avr.h>
+
+ ; Go to code section.
+         code
+         even
+
+ ;-------------------------------------------------------------------
+ ;unsigned char rnd8(void); //8 bit rnd, 26 bytes 19 cycles (7c iteration) [15 14] MLS
+ ; periode: 32,767  (4096 unique bytes, remaining 7 iteration shifted version)
+
+   public _rnd8
+
+ _rnd8 proc
+         in r27,17  ;L  reg17 is L
+         in r26,18  ;H  reg 18 is H
+         ldi r24,0 ;this will save cycles in multi byte version
+
+         mov r23,r27 ;AL=L
+         mov r22,r26 ;AH=H
+
+         lsl r23
+         rol r22  ;AH:AL <<1
+
+         eor r26,r22 ;AH=AH eor H
+
+         lsl r26; C<-AH.7, AH<<1   new L byte
+         adc r27,r24 ;L.0 <-C
+
+
+         out 17,r26  ; new L.1-7 is eor product0-6 (msb eor is in r27.0)
+         out 18,r27  ;old L is new H   also return value (top 8 bits HL)
+         ret
+         endproc
+ ;-------------------------------------------------------------------
+ ;unsigned int rnd16(void); //16 bit rnd   40 bytes 26 cycles (14c iteration) [15 14] MLS
+ ; periode: 32767  (2048 unique words, remaining 15 iterations shifted version)
+      public _rnd16
+
+ _rnd16 proc
+         in r27,17  ;L  reg17 is L
+         in r26,18  ;H  reg 18 is H
+         ldi r24,0 ;this will save cycles in multi byte version
+
+         mov r23,r27 ;AL=L
+         mov r22,r26 ;AH=H
+
+         lsl r23
+         rol r22  ;AH:AL <<1
+
+         eor r26,r22;AH=AH eor H
+
+         lsl r26; C<-AH.7, AH<<1   new L byte    new L
+         adc r27,r24 ;L.0 <-C   ;first 8 bits    new H  1st return value (high part)
+
+         ; get 2nd byte
+
+         mov r23,r26 ;AL=L
+         mov r22,r27 ;AH=H
+
+         lsl r23
+         rol r22  ;AH:AL <<1
+
+         eor r27,r22 ;AH=AH eor H
+
+         lsl r27; C<-AH.7, AH<<1   new L byte
+         adc r26,r24 ;L.0 <-C  ;first 8 bits    new H  2nd return value (low part)
+
+         out 17,r27  ; new L.1-7 is eor product0-6 (msb eor is in r26.0)
+         out 18,r26  ;old L is new H   also return value (top 8 bits HL)
+         ret
+         endproc
+
+
+ ;-------------------------------------------------------------------
+ ;unsigned char rnd8_23(void); //8 bit rnd, 30 bytes 21 cycles (7c iteration)  [23 14] MLS
+ ; periode: 8,388,607  (1,0485,576 unique bytes, remaining 7 iteration shifted version)
+   public _rnd8_23
+
+ _rnd8_23 proc
+         in r26,17  ;L  GPIOR0 is L
+         in r27,18  ;H  GPIOR1 is M
+         in r25,19  ;H  GPIOR2 is H
+         ldi r24,0 ;this will save cycles in multi byte version
+
+         mov r20,r26 ;L2=L
+         mov r21,r27 ;M2=M
+
+         lsl r20
+         rol r21  ;M2:L2 <<1
+
+         eor r21,r25 ;M2 = M2 eor H
+
+         lsl r21; C<-M2.7, M2<<1   new L byte
+         adc r26,r24 ;L.0 <-C      new M byte
+                           ; M  is new H byte (also output)
+
+         out 17,r21  ; new L.1-7 is eor product6-0 (msb eor is in r27.0)
+         out 18,r26  ;old L + bit 0 from eor bit 7 is new M
+         out 19,r27  ;old M is new H   also return value (top 8 bits HML)
+         ret
+         endproc
+
+ ;-------------------------------------------------------------------
+ ;unsigned int rnd16_23(void); //16 bit rnd, 44 bytes 28 cycles (14c iteration)  [23 14] MLS
+ ; periode: 8,388,607  (524288 unique words, remaining 15 iteration shifted version)
+   public _rnd16_23
+
+ _rnd16_23 proc
+         in r26,17  ;L  GPIOR0 is L
+         in r25,18  ;H  GPIOR1 is M
+         in r27,19  ;H  GPIOR2 is H
+         ldi r24,0 ;this will save cycles in multi byte version
+
+         mov r20,r26 ;L2=L
+         mov r21,r25 ;M2=M
+
+         lsl r20
+         rol r21  ;M2:L2 <<1
+
+         eor r27,r21 ;H = M2 eor H
+
+         lsl r27; C<-H.7, H<<1     new L byte 27
+         adc r26,r24 ;L.0 <-C      new M byte 26
+                           ; M  is new H byte 25
+    ; get 2nd byte -----------------
+         mov r20,r27 ;L2=L
+         mov r21,r26 ;M2=M
+
+         lsl r20
+         rol r21  ;M2:L2 <<1
+
+         eor r25,r21 ;H = M2 eor H
+
+         lsl r25; C<-H.7, H<<1     new L byte 25
+         adc r27,r24 ;L.0 <-C      new M byte 27(also output)
+                           ; M  is new H byte 26(also output)
+
+         out 17,r25  ; new L.1-7 is eor product6-0 (msb eor is in r27.0)
+         out 18,r27  ;old L + bit 0 from eor bit 7 is new M
+         out 19,r26  ;old M is new H
+         ret
+         endproc
+============================================================================================

+ 42 - 0
avr/soft_uart.asm

@@ -0,0 +1,42 @@
+; оригинал для attiny13 9.6 MHz
+;;; Soft UART -- Побитно передаем байт из TXB
+; на линии всегда 1. стартовый бит = 0. потом 8 бит данных, стоп-бит = 1.
+; данные инверсные - 0=1, 1=0. хотя в этом алгоритме -- прямые
+; похоже, что инверсия только на физ. уровне. т.е. у нас -- прямые...
+; проверить в протеусе!!!
+SoftUART:
+	PUSHF
+	push	tmp1
+
+	cbi	PortB,TX	; стартовый бит
+	ldi	tmp1,8		; 8 бит данных
+
+LOSL:	push	temp		; 2 | 115 тактов для 38400, 73 для 57600 (ошибка -0.4%)
+	ldi	temp,11		; 1 | 27 для 38400, 11 для 57600, 6 для 115200
+LOS0:	nop			; 1 \ для 38400 и 115200 - 1 nop
+	nop			; 1 | для 57600 - 3 nop-а
+	nop			; 1 | - осталось 108/66 тактов
+	dec	temp		; 1 |
+	brne	LOS0		; 2 / 1
+	pop	temp		; 2 |
+;	nop			; 1 | Для 115200
+	nop			; 1 | --- конец цикла задержки. вход и выход - 7 тактов
+
+	lsr	TXB		; 1	мл бит вперёд
+	brcc	LOUT0		; 1/2	если C не установлен - выводим 0
+	sbi	PortB,TX	; 2	вывели 1
+	rjmp	LOEC		; 2	конец цикла
+LOUT0:	cbi	PortB,TX	; 2	вывели 0
+	nop			; 1	для выравнивания тактов
+LOEC:	nop			; 1	для круглого счёта
+	dec	tmp1		; 1
+	brne	LOSL            ; 2, 1 при выходе
+; 10 тактов == 2,083 мкс на 1 бит, 9 тактов == 1,875 мкс на 1 бит
+; 83.3 - 57600; 125 - 38400; 250 - 19200; 500 - 9600; 41.6 - 115200
+; на скорости 57600 можно успеть передать 28 байт за время 1-го прервания
+; ~56 байт, 42-10=32 такта, 32-... (ошибка +1%)
+	sbi	PortB,TX	; стоповый бит
+
+	pop	tmp1
+	POPF
+	ret

+ 127 - 0
avr/spi.txt

@@ -0,0 +1,127 @@
+Аппаратный вариант
+
+Для работы с аппаратным SPI его нужно сначала, естественно,
+инициализировать. Посмотрим, как это будет выглядеть для ATmega8535 (а
+также для многих других МК того же класса, например, ATmega8515, ATmega16 и
+пр., у которых выводы аппаратного SPI совпадают с интерфейсом
+SPI-программирования и занимают старшие 4 бита порта В). Заодно
+инициализируем и вывод для управления  "выбором кристалла" — в большинстве
+случаев он в интерфейсе SPI играет важную роль (например, микросхемы
+памяти, которые мы рассмотрим далее, высокий уровень на этом выводе, кроме
+всего прочего, устанавливает в состояние с низким  потреблением). Часто для
+этого выбирают вывод /SS, который в режиме "мастера" не  задействован (не
+забудем, что его нужно сконфигурировать на выход!), но мы для разнообразия
+выберем вывод РВО — часто требуется управлять несколькими  устройствами,
+одного вывода /SS тогда все равно недостаточно, и младшие биты  порта В,
+идущие подряд, оказываются более удобными (листинг 11.1).
+
+[ Листинг 11.1 ]
+.equ	CS =	РВ0
+.equ	MOSI =	PB5
+.equ	MISO =	РВ6
+.equ	SCK =	PB7	;разряды порта В, используемые интерфейсом SPL.
+
+Листинг 11.2 иллюстрирует инициализацию в режиме 0 ("мастер", DORD = 0 —
+старший бит первым, SPR1 и SPR0 = 0 — скорость fрез/4).
+
+[ Листинг 11.2 ]
+	ldi	temp,(1<<SPE)+(1<<MSTR)
+	out	SPCR,temp
+	ldi	temp,(l<<SCK)+(1<<MOSI)+(1<<CS)+(1<<PB4)
+	out	DDRB,temp	;SCK,MOSI,CS, SS - выходы
+	sbi	PORTB,CS	;сразу устанавливаем в 1
+
+Листинг 11.3 иллюстрирует инициализацию в режиме 3 ("мастер", DORD = 0 —
+старший бит первым, SPR1 и SPR0 = 0 — скорость fрез/4).
+
+[ Листинг 11.3 ]
+	ldi temp, (1«SPE) + (1«MSTR) + (1«CP0L) + (1«CPHA)
+	out SPCR,temp
+	ldi temp, (1«SCK) + (1«M0SI) + (1«CS) + (1«PB4)
+	>out DDRB,temp ;SCK,MOSI,CS, SS - выходы
+	ser temp ;0xFF
+	out PORTB,temp ;PB7..0 — высокий уровень, весь порт В
+
+Процедура записи-чтения тогда будет выглядеть очень просто (листинг 11.4).
+
+[ Листинг 11.4 ]
+WR_spi: ;запись-чтение SPI, в temp данные на входе и на выходе
+	out SPDR,temp	; начать передачу
+wait_spi:
+	sbis SPSR,SPIF	; ожидаем конца передачи
+	rjmp wait_spi
+	in temp,SPDR	; чтение данных
+	ret
+
+При работе с большинством устройств через SPI, к сожалению, этой простой
+процедурой дело не ограничивается — чаще всего требуется, по крайней мере,
+вовремя правильно установить "выбор кристалла", причем иногда (если
+интерфейс у  ведомого устройства недостаточно скоростной) с формированием
+искусственных  задержек и прочими сложностями, сильно загромождающими
+программу.
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+Программный вариант
+
+Программный вариант процедур чтения-записи более громоздок, но зато
+позволяет задействовать любые удобные выводы портов МК (в том числе и
+таких, которые вообще аппаратного SPI не имеют) и не требует особой
+инициализации, кроме формирования направления работы соответствующих
+выводов. Листинг 11.5  иллюстрирует, как будет выглядеть чтение-запись в
+варианте, соответствующем  режиму 0.
+
+[ Листинг 11,5 ]
+.equ	CS	= 0	; выводы PortB
+.equ	MOSI	= 1
+.equ	MISO	= 2
+.equ	SCK	= 3
+...
+; инициализация SPI
+; установка MOSI, SCK, CS на выход
+	ldi	temp,(1<<CS)|(1<<MOSI)|(1<<SCK)
+	out	DDRB,temp
+	cbi	PORTB,SCK
+	cbi	PORTB,MOSI
+	sbi	PORTB,CS
+...
+;чтение-запись
+RW_spi:	;запись/чтение через SPI. посылаемый байт в data_out,
+; принимаемый в data_in
+	cli			; на случай, если в программе есть длинные
+				; прерывания, иначе можно удалить
+	ldi	temp,8		; счетчик бит
+	clr	data_in
+spi_Loop:
+	lsl	data_out	;старший бит в перенос
+	brcc	put_0		; если в переносе 0 — перейти
+	sbi	PORTB,mosi
+	nop			; задержка на один такт
+	rjmp	r_bit
+
+put_0:
+	cbi PORTB,mosi
+	nop ; задержка на один такт
+r_bit:
+	sbi	PORTB,sck	; выдали строб и подождали
+	nop			; задержка на один такт
+	sbic	PINB,miso	; читаем бит с miso
+	rjmp	r1_bit
+	clc			; если 0 — сбросим перенос
+	rjmp	rend_bit
+r1_bit:
+	sec			; если 1 — установим перенос
+rend_bit:
+	rol	data_in		; перенос во входной байт
+	cbi	PORTB,sck	; выдали строб и подождали
+	nop
+	dec	temp
+	brne	spi_loop
+	sei			; если команды cli нет, то тоже можно удалить
+	ret
+
+При тактовой частоте МК 4 МГц такая процедура обеспечит скорость передачи
+порядка 0,5 МГц. Пустые операции (пор) нужны, чтобы сформировать задержку
+(-250 не при 4 МГц) между формированием данных на линиях MISO и MOSI и
+моментом их чтения (перепадом на SCK). Если быстродействие ведомого
+позволяет, то эти операции можно убрать.

+ 231 - 0
avr/subroutine.asm

@@ -0,0 +1,231 @@
+;---------------------------------------;
+;                                       ;
+; Подпрограмки, которые я успел наваять ;
+;                                       ;
+;---------------------------------------;
+
+ LSB (Least Significant Bit) - младший значащий бит,
+ MSB (Most Significant Bit) - старший значащий бит.
+
+; байты для вывода 0-9A-F на индикаторы, без точки, общий катод
+LEDnd:	.DB	0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
+; байты для вывода 0-9A-F на индикаторы, с точкой
+ledwd:	.DB	0xf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef,0xf7,0xfc,0xb9,0xde,0xf9,0xf1
+"A" - 0x77
+"b" - 0x7C
+"c" - 0x58, "C" - 0x39
+"d" - 0x5E
+"E" - 0x79
+"F" - 0x71
+"r" - 0x50
+"h" - 0x56, "H" - 0x76
+"i" - 0x04, "I" - 0x06
+"J" - 0x1E
+"L" - 0x38
+"P" - 0x73
+"u" - 0x1C, "U" - 0x3E
+"Y" - 0x6E
+
+;*******************************************************************
+; вывод в компорт байт в HEX-виде
+; исходный байт а r17, портим r16
+OUTHEX: push	r17
+	andi	r17,0b11110000	; старший полубайт
+	swap	r17
+	rcall	TOASCII
+	mov	r16,r17
+	rcall	USART_TX	; выводим старший байт
+	pop	r17
+	andi	r17,0b00001111	; младший полубайт
+	mov	r16,r17
+	rcall	TOASCII
+	mov	r16,r17
+	rcall	USART_TX	; выводим младший байт
+	ret
+
+;*******************************************************************
+; переводит младший полубайт в ASCII-код символа
+; исходный и итоговый байт в r16
+TOASCII:
+	andi	R16,0x0F	; очищаем ненужные биты
+	cpi	R16,0x0A
+	brsh	ADDA
+	subi	R16,-0x30	; ASCII '0'
+	ret
+ADDA:	subi	R16,-0x37	; + 0x0A = ASCII 'A'
+	ret
+
+;*******************************************************************
+; вывод байта в уарт (не моё, из мануала :-)
+USART_TX:
+	sbis	UCSRA,UDRE	; Wait for empty transmit buffer
+	rjmp	USART_TX
+	out	UDR,r16		; Put data (r16) into buffer, sends the data
+	ret
+
+;*******************************************************************
+; работа с EEPROM
+;в ZH:ZL - адрес EEPROM куда писать
+;в temp - записываемый байт
+WriteEEP:
+	sbic	EECR,EEWE	; ждем очистки бита
+	rjmp	WriteEEP	; разрешения записи EEWE
+	cli			; запрещаем прерывания
+	out	EEARH,ZH	; старший байт адреса
+	out	EEARL,ZL	; младший байт адреса
+	out	EEDR,temp	; данные
+	sbi	EECR,EEMWE	; взводим предохранитель
+	sbi	EECR,EEWE	; записываем байт
+	sei			; разрешаем прерывания
+	ret			; (конец WriteEEP)
+
+; в ZH:ZL - адрес откуда читать
+; возврат temp - прочтенный байт
+ReadEEP:
+	sbic	EECR,EEWE	; ожидание очистки флага записи
+	rjmp	ReadEEP
+	out	EEARH,ZH	; старший адреса
+	out	EEARL,ZL	; младший адреса
+	sbi	EECR,EERE	; бит чтения
+	in	temp,EEDR	; чтение
+	ret			; конец ReadEEP
+
+;*******************************************************************
+; sleep
+SPIM:	ldi	temp,(1<<SE)	; ко сну
+	out	MCUCR,temp
+	sleep			; спим. тупой идл
+	clr	temp
+	out	MCUCR,temp	; со сна
+	ret
+
+;*******************************************************************
+; маленький, простенький диспетчер :-)
+; если delay > 0 -- будем спать, пока обработчик прерываний не доведёт
+; счётчик до 0. по флагам можем вызывать разные подпрограммы
+; минимальный шаг задержки == периоду таймера
+DISPATCHER:
+	PUSHF
+	sbrc	flags,SADC	; сброшен - простой сон
+	rcall	MEASURE
+	outi	MCUCR,1<<SE	; простой режим сна
+SLL:	sleep			; спим.
+	tst	delay		; если сч не 0
+	brne	SLL		; спим до сл. прерывания
+	outi	MCUCR,0		; со сна
+	POPF
+	ret
+; и в обработчике прерываний от таймера:
+	tst	delay		; сч пустой?
+	breq	PC+2		; да, не трогаем
+	dec	delay		; иначе - уменьшаем
+
+
+;*******************************************************************
+; ADC Noise Reduction Mode
+ADCNR:	ldi	temp,1<<SE|1<<SM0
+	out	MCUCR,temp
+	sleep			; пока проц спит, АЦП меряет сигнал
+	clr	temp
+	out	MCUCR,temp	; со сна
+	ret
+
+;*******************************************************************
+;запись через SPI. посылаемый байт в data_out
+; этот конкрентный случай - для регистров 595
+RW_SPI:	ldi	temp,8		; счетчик бит
+SPIL:	cbi	PORTB,SCK	; выдали строб
+	lsl	data_out	; старший бит в перенос
+	brcc	PUT_0		; если в переносе 0 — перейти
+	sbi	PORTB,MOSI	; выдали 1
+	rjmp	SPIE
+PUT_0:	cbi	PORTB,MOSI
+	nop			; задержка на один такт
+SPIE:	sbi	PORTB,sck	; защёлкнули строб
+	dec	temp
+	brne	SPIL
+	ret
+; пример использования:
+	cbi	PORTB,LCH
+	ldi	data_out,0x3f
+	rcall	RW_SPI
+	ldi	data_out,0x06
+	rcall	RW_SPI
+	sbi	PORTB,LCH	; регистры - на экран!
+
+;***************************************************************************
+;* "bin2BCD24" - 24-bit Binary to 8xBCD conversion
+;*
+;* This subroutine converts a 24-bit number (fbinH:fbinL) to a 8-digit
+;* packed BCD number represented by 4 bytes (tBCD3:tBCD2:tBCD1:tBCD0).
+;* MSD of the 8-digit number is placed in the lowermost nibble of tBCD3.
+;*
+;* Low registers used	:4 (tBCD0,tBCD1,tBCD2,tBCD3)
+;* High registers used  :4 (fbinL,fbinM,fbinH,tmp1,temp)
+;* Pointers used	:Z
+;* портим: temp, tmp1
+;***************************************************************************
+.equ	AtBCD0	= 0
+.equ	AtBCD3	= 3
+.def	tBCD0	= r0	;BCD value digits 0 and 1
+.def	tBCD1	= r1	;BCD value digits 2 and 3
+.def	tBCD2	= r2	;BCD value digits 4 and 5
+.def	tBCD3	= r3	;BCD value digits 6 and 7
+.def	fbinH	= r10	;binary value High byte
+.def	fbinH	= r11	;binary value Middle byte
+.def	fbinL	= r12	;binary value Low byte
+; ZL, ZH
+bin2BCD24:
+	ldi	tmp1,24		; Init loop counter
+	clr	tBCD3		; clear result (4 bytes)
+	clr	tBCD2
+	clr	tBCD1
+	clr	tBCD0
+	clr	ZH		; clear ZH (not needed for AT90Sxx0x)
+bBCDx_1:lsl	fbinL		; shift input value
+	rol	fbinM		;
+	rol	fbinH		; through all bytes
+	rol	tBCD0
+	rol	tBCD1
+	rol	tBCD2
+	rol	tBCD3
+	dec	tmp1		; decrement loop counter
+	brne	bBCDx_2		; if counter not zero
+	ret			; return
+bBCDx_2:ldi	r30,AtBCD3+1	; Z points to result MSB + 1
+bBCDx_3:
+	ld	temp,-Z		; get (Z) with pre-decrement
+	subi	temp,-$03	; add 0x03
+	sbrc	temp,3		; if bit 3 not clear
+	st	Z,temp		; store back
+	ld	temp,Z		; get (Z)
+	subi	temp,-$30	; add 0x30
+	sbrc	temp,7		; if bit 7 not clear
+	st	Z,temp		; store back
+	cpi	ZL,AtBCD0	; done all three?
+	brne	bBCDx_3		; loop again if not
+	rjmp	bBCDx_1
+
+;***************************************************************************
+; Исправленная процедура из 204-го аппнота
+; родная нормально преобразовывает только числа от 0 до 99
+; входное число в R16, выход: R17(сотни) и R16(десятки и единицы)
+; в R17 копятся десятки, в R18 сотни, в R16 - остаток, единицы.
+; потом R17 складывается с R16, а R18 переносится в R17
+bin2bcd8:
+	push	R18
+	clr	R18
+	clr	R17		;clear result MSD
+bBCD8_1:subi	R16,10		;input = input - 10
+	brcs	bBCD8_2		;abort if carry set
+	subi	R17,-$10 	;tBCDH = tBCDH + 10
+	cpi	R17,0xA0
+	brlo	bBCD8_1
+	inc	R18
+	subi	R17,0xA0
+	rjmp	bBCD8_1		;loop again
+bBCD8_2:subi	R16,-10		;compensate extra subtraction
+	add	R16,R17
+	mov	R17,R18
+	pop	R18
+	ret

+ 20 - 0
avr/svetik.txt

@@ -0,0 +1,20 @@
+Светодиод подключается на порт двумя способами. По схеме Порт-земля или
+Порт-Питание. В первом случае для зажигания диода надо выдать в порт лог1 —
+высокий уровень (примерно равен Vcc). Во втором случае для зажжения диода
+требуется выдать в порт лог0 — низкий уровень (около нуля). Для AVR разницы
+вроде бы нет, а вот многие старые серии микроконтроллеров вниз тянули куда
+лучше чем вверх, так что схема Порт-Питание распространена чаще. Я применяю и
+ту и другую схему исходя из удобства разводки печатной платы. Ну, а на
+программном уровне разницы особой нет.
+
+ Вывод порта для работы со светодиодом надо сконфигурировать на выход
+(DDRxy=1) и тогда в зависимости от значения в PORTxy на ножке будет либо
+высокий либо низкий уровень напряжения.
+
+ Светодиод надо подключать через резистор. Дело в том, что прямое
+сопротивление светодиода очень мало. И если не ограничивать ток через него,
+то он просто напросто может сгореть нафиг. Либо, что вероятней, пожечь вывод
+микроконтроллера, который, к слову, может тянуть что то около 20-30мА. А для
+нормального свечения обычному светодиоду (всякие термоядерные ультраяркие
+прожектора мы не рассматриваем сейчас, эти монстры могут и ампер сожрать)
+надо около 3…15мА.

+ 174 - 0
avr/templates/ATmega32.asm

@@ -0,0 +1,174 @@
+; Автор:	shilow@ukr.net
+; Дата:
+; Название:
+; Версия:
+; Имя файла:
+; Для AVR:	ATmega32A
+; Тактовая частота:
+; Выполняемые функции:
+;
+;
+
+;******************************
+.listmac	; развернём макросы
+; инклуды
+.nolist
+.include "m32Adef.inc"
+.list
+
+;******************************
+; опредления
+.def temp = r16		; рабочая переменная
+
+;******************************
+; константы
+.equ a = 0		; sample
+
+;******************************
+; ячейки в СОЗУ, 2KB
+.DSEG
+;.ORG	SRAM_START
+Sample:	.byte	30
+
+;******************************
+; константы в EEPROM, 1KB
+.ESEG
+smpl1:	.DW	0x0000	; sample 1
+smpl2:	.DB	0x05	; sample 2
+
+;******************************
+; память программ, 32KB
+.CSEG
+.ORG 0
+
+;******************************
+; Таблица векторов прерываний
+	jmp	RESET		; Reset Handler
+	jmp	EXT_INT0	; IRQ0 Handler
+	jmp	EXT_INT1	; IRQ1 Handler
+	jmp	EXT_INT2	; IRQ2 Handler
+	jmp	TIM2_COMP	; Timer2 Compare Handler
+	jmp	TIM2_OVF	; Timer2 Overflow Handler
+	jmp	TIM1_CAPT	; Timer1 Capture Handler
+	jmp	TIM1_COMPA	; Timer1 CompareA Handler
+	jmp	TIM1_COMPB	; Timer1 CompareB Handler
+	jmp	TIM1_OVF	; Timer1 Overflow Handler
+	jmp	TIM0_COMP	; Timer0 Compare Handler
+	jmp	TIM0_OVF	; Timer0 Overflow Handler
+	jmp	SPI_STC		; SPI Transfer Complete Handler
+	jmp	USART_RXC	; USART RX Complete Handler
+	jmp	USART_UDRE	; UDR Empty Handler
+	jmp	USART_TXC	; USART TX Complete Handler
+	jmp	ADCC		; ADC Conversion Complete Handler
+	jmp	EE_RDY		; EEPROM Ready Handler
+	jmp	ANA_COMP	; Analog Comparator Handler
+	jmp	TWI		; Two-wire Serial Interface Handler
+	jmp	SPM_RDY		; Store Program Memory Ready Handler
+
+;
+;******************************
+;;;;; Первичная инициализация
+RESET:
+; Set Stack Pointer to top of RAM
+	ldi	temp,high(RAMEND)
+	out	SPH,temp
+	ldi	temp,low(RAMEND)
+	out	SPL,temp
+; выкл. аналог, компаратор
+	ldi	temp,1<<ACD
+	out	ACSR,temp
+; Enable interrupts
+	sei
+
+;******************************
+;;;;; Основная программа
+BEGIN:
+	rjmp	BEGIN
+
+;******************************
+;;;;; Подпрограммы
+
+;******************************
+;;;;; Обработчики прерываний
+
+; IRQ0 Handler
+EXT_INT0:
+	reti
+
+; IRQ1 Handler
+EXT_INT1:
+	reti
+
+; IRQ2 Handler
+EXT_INT2:
+	reti
+
+; Timer2 Compare Handler
+TIM2_COMP:
+	reti
+
+; Timer2 Overflow Handler
+TIM2_OVF:
+	reti
+
+; Timer1 Capture Handler
+TIM1_CAPT:
+	reti
+
+; Timer1 CompareA Handler
+TIM1_COMPA:
+	reti
+
+; Timer1 CompareB Handler
+TIM1_COMPB:
+	reti
+
+; Timer1 Overflow Handler
+TIM1_OVF:
+	reti
+
+; Timer0 Compare Handler
+TIM0_COMP:
+	reti
+
+; Timer0 Overflow Handler
+TIM0_OVF:
+	reti
+
+; SPI Transfer Complete Handler
+SPI_STC:
+	reti
+
+; USART RX Complete Handler
+USART_RXC:
+	reti
+
+; UDR Empty Handler
+USART_UDRE:
+	reti
+
+; USART TX Complete Handler
+USART_TXC:
+	reti
+
+; ADC Conversion Complete Handler
+ADCC:
+	reti
+
+; EEPROM Ready Handler
+EE_RDY:
+	reti
+
+; Analog Comparator Handler
+ANA_COMP:
+	reti
+
+; Two-wire Serial Interface Handler
+TWI:
+	reti
+
+; Store Program Memory Ready Handler
+SPM_RDY:
+	reti
+
+.exit

+ 244 - 0
avr/templates/ATmega64.asm

@@ -0,0 +1,244 @@
+; Автор:	shilow@ukr.net
+; Дата:
+; Название:
+; Версия:
+; Имя файла:
+; Для AVR:	ATmega64
+; Тактовая частота:
+; Выполняемые функции:
+;
+;
+
+;******************************
+.listmac	; развернём макросы
+; инклуды
+.nolist
+.include "m64def.inc"
+.list
+
+;******************************
+; опредления
+.def temp = r16		; рабочая переменная
+
+;******************************
+; константы
+.equ a = 0		; sample
+
+;******************************
+; ячейки в СОЗУ, 4KB
+.DSEG
+;.ORG	SRAM_START
+Sample:	.byte	30
+
+;******************************
+; константы в EEPROM, 2KB
+.ESEG
+smpl1:	.DW	0x0000	; sample 1
+smpl2:	.DB	0x05	; sample 2
+
+;******************************
+; память программ, 64KB
+.CSEG
+.ORG 0
+
+;******************************
+; Таблица векторов прерываний
+	jmp	RESET		; Reset Handler
+	jmp	EXT_INT0	; IRQ0 Handler
+	jmp	EXT_INT1	; IRQ1 Handler
+	jmp	EXT_INT2	; IRQ2 Handler
+	jmp	EXT_INT3	; IRQ3 Handler
+	jmp	EXT_INT4	; IRQ4 Handler
+	jmp	EXT_INT5	; IRQ5 Handler
+	jmp	EXT_INT6	; IRQ6 Handler
+	jmp	EXT_INT7	; IRQ7 Handler
+	jmp	TIM2_COMP	; Timer2 Compare Handler
+	jmp	TIM2_OVF	; Timer2 Overflow Handler
+	jmp	TIM1_CAPT	; Timer1 Capture Handler
+	jmp	TIM1_COMPA	; Timer1 CompareA Handler
+	jmp	TIM1_COMPB	; Timer1 CompareB Handler
+	jmp	TIM1_OVF	; Timer1 Overflow Handler
+	jmp	TIM0_COMP	; Timer0 Compare Handler
+	jmp	TIM0_OVF	; Timer0 Overflow Handler
+	jmp	SPI_STC		; SPI Transfer Complete Handler
+	jmp	USART0_RXC	; USART0 RX Complete Handler
+	jmp	USART0_DRE	; USART0,UDR Empty Handler
+	jmp	USART0_TXC	; USART0 TX Complete Handler
+	jmp	ADCCCH		; ADC Conversion Complete Handler
+	jmp	EE_RDY		; EEPROM Ready Handler
+	jmp	ANA_COMP	; Analog Comparator Handler
+	jmp	TIM1_COMPC	; Timer1 CompareC Handler
+	jmp	TIM3_CAPT	; Timer3 Capture Handler
+	jmp	TIM3_COMPA	; Timer3 CompareA Handler
+	jmp	TIM3_COMPB	; Timer3 CompareB Handler
+	jmp	TIM3_COMPC	; Timer3 CompareC Handler
+	jmp	TIM3_OVF	; Timer3 Overflow Handler
+	jmp	USART1_RXC	; USART1 RX Complete Handler
+	jmp	USART1_DRE	; USART1,UDR Empty Handler
+	jmp	USART1_TXC	; USART1 TX Complete Handler
+	jmp	TWI		; Two-wire Serial Interface Handler
+	jmp	SPM_RDY		; SPM Ready Handler
+
+;
+;******************************
+;;;;; Первичная инициализация
+RESET:
+; Set Stack Pointer to top of RAM
+	ldi	temp,high(RAMEND)
+	out	SPH,temp
+	ldi	temp,low(RAMEND)
+	out	SPL,temp
+; выкл. аналог, компаратор
+	ldi	temp,1<<ACD
+	out	ACSR,temp
+; Enable interrupts
+	sei
+
+;******************************
+;;;;; Основная программа
+BEGIN:
+	rjmp	BEGIN
+
+;******************************
+;;;;; Подпрограммы
+
+;******************************
+;;;;; Обработчики прерываний
+
+; IRQ0 Handler
+EXT_INT0:
+	reti
+
+; IRQ1 Handler
+EXT_INT1:
+	reti
+
+; IRQ2 Handler
+EXT_INT2:
+	reti
+
+; IRQ3 Handler
+EXT_INT3:
+	reti
+
+; IRQ4 Handler
+EXT_INT4:
+	reti
+
+; IRQ5 Handler
+EXT_INT5:
+	reti
+
+; IRQ6 Handler
+EXT_INT6:
+	reti
+
+; IRQ7 Handler
+EXT_INT7:
+	reti
+
+; Timer2 Compare Handler
+TIM2_COMP:
+	reti
+
+; Timer2 Overflow Handler
+TIM2_OVF:
+	reti
+
+; Timer1 Capture Handler
+TIM1_CAPT:
+	reti
+
+; Timer1 CompareA Handler
+TIM1_COMPA:
+	reti
+
+; Timer1 CompareB Handler
+TIM1_COMPB:
+	reti
+
+; Timer1 Overflow Handler
+TIM1_OVF:
+	reti
+
+; Timer0 Compare Handler
+TIM0_COMP:
+	reti
+
+; Timer0 Overflow Handler
+TIM0_OVF:
+	reti
+
+; SPI Transfer Complete Handler
+SPI_STC:
+	reti
+
+; USART0 RX Complete Handler
+USART0_RXC:
+	reti
+
+; USART0,UDR Empty Handler
+USART0_DRE:
+	reti
+
+; USART0 TX Complete Handler
+USART0_TXC:
+	reti
+
+; ADC Conversion Complete Handler
+ADCCCH:
+	reti
+
+; EEPROM Ready Handler
+EE_RDY:
+	reti
+
+; Analog Comparator Handler
+ANA_COMP:
+	reti
+
+; Timer1 CompareC Handler
+TIM1_COMPC:
+	reti
+
+; Timer3 Capture Handler
+TIM3_CAPT:
+	reti
+
+; Timer3 CompareA Handler
+TIM3_COMPA:
+	reti
+
+; Timer3 CompareB Handler
+TIM3_COMPB:
+	reti
+
+; Timer3 CompareC Handler
+TIM3_COMPC:
+	reti
+
+; Timer3 Overflow Handler
+TIM3_OVF:
+	reti
+
+; USART1 RX Complete Handler
+USART1_RXC:
+	reti
+
+; USART1,UDR Empty Handler
+USART1_DRE:
+	reti
+
+; USART1 TX Complete Handler
+USART1_TXC:
+	reti
+
+; Two-wire Serial Interface Handler
+TWI:
+	reti
+
+; SPM Ready Handler
+SPM_RDY:
+	reti
+
+.exit

+ 151 - 0
avr/templates/ATmega8535.asm

@@ -0,0 +1,151 @@
+; Автор:	shilow@ukr.net
+; Дата:
+; Название:
+; Версия:
+; Имя файла:
+; Для AVR:	ATmega8535
+; Тактовая частота:
+; Выполняемые функции:
+;
+;
+
+;******************************
+.listmac	; развернём макросы
+; инклуды
+.nolist
+.include "m8535def.inc"
+.list
+
+;******************************
+; опредления
+.def temp	= r16	; рабочая переменная
+
+;******************************
+; константы
+.equ a		= 0	; sample
+
+;******************************
+; ячейки в СОЗУ
+.DSEG
+;.ORG	SRAM_START
+Sample:		.byte	30
+
+;******************************
+; константы в EEPROM
+.ESEG
+smpl1:		.DW	0x0000	; sample 1
+smpl2:		.DB	0x05	; sample 2
+
+;******************************
+; память программ
+.CSEG
+.ORG 0
+;******************************
+; Таблица векторов прерываний
+	rjmp	RESET		; Reset Handler
+	rjmp	EXT_INT0	; IRQ0 Handler
+	rjmp	EXT_INT1	; IRQ1 Handler
+	rjmp	TIM2_COMP	; Timer2 Compare Handler
+	rjmp	TIM2_OVF	; Timer2 Overflow Handler
+	rjmp	TIM1_CAPT	; Timer1 Capture Handler
+	rjmp	TIM1_COMPA	; Timer1 Compare A Handler
+	rjmp	TIM1_COMPB	; Timer1 Compare B Handler
+	rjmp	TIM1_OVF	; Timer1 Overflow Handler
+	rjmp	TIM0_OVF	; Timer0 Overflow Handler
+	rjmp	SPI_STC		; SPI Transfer Complete Handler
+	rjmp	USART_RXC	; USART RX Complete Handler
+	rjmp	USART_UDRE	; UDR Empty Handler
+	rjmp	USART_TXC	; USART TX Complete Handler
+	rjmp	ADCC		; ADC Conversion Complete Handler
+	rjmp	EE_RDY		; EEPROM Ready Handler
+	rjmp	ANA_COMP	; Analog Comparator Handler
+	rjmp	TWSI		; Two-wire Serial Interface Handler
+	rjmp	EXT_INT2	; IRQ2 Handler
+	rjmp	TIM0_COMP	; Timer0 Compare Handler
+	rjmp	SPM_RDY		; Store Program Memory Ready Handler
+
+;******************************
+;;;;; Первичная инициализация
+RESET:
+; Set Stack Pointer to top of RAM
+	ldi	temp,high(RAMEND)
+	out	SPH,temp
+	ldi	temp,low(RAMEND)
+	out	SPL,temp
+; выкл. аналог, компаратор
+	ldi	temp,1<<ACD
+	out	ACSR,temp
+; Enable interrupts
+	sei
+;******************************
+;;;;; Основная программа
+BEGIN:
+	rjmp	BEGIN
+
+;******************************
+;;;;; Подпрограммы
+
+;******************************
+;;;;; Обработчики прерываний
+
+EXT_INT0:	; IRQ0 Handler
+	reti
+
+EXT_INT1:	; IRQ1 Handler
+	reti
+
+TIM2_COMP:	; Timer2 Compare Handler
+	reti
+
+TIM2_OVF:	; Timer2 Overflow Handler
+	reti
+
+TIM1_CAPT:	; Timer1 Capture Handler
+	reti
+
+TIM1_COMPA:	; Timer1 Compare A Handler
+	reti
+
+TIM1_COMPB:	; Timer1 Compare B Handler
+	reti
+
+TIM1_OVF:	; Timer1 Overflow Handler
+	reti
+
+TIM0_OVF:	; Timer0 Overflow Handler
+	reti
+
+SPI_STC:	; SPI Transfer Complete Handler
+	reti
+
+USART_RXC:	; USART RX Complete Handler
+	reti
+
+USART_UDRE:	; UDR Empty Handler
+	reti
+
+USART_TXC:	; USART TX Complete Handler
+	reti
+
+ADCC:		; ADC Conversion Complete Handler
+	reti
+
+EE_RDY:		; EEPROM Ready Handler
+	reti
+
+ANA_COMP:	; Analog Comparator Handler
+	reti
+
+TWSI:		; Two-wire Serial Interface Handler
+	reti
+
+EXT_INT2:	; IRQ2 Handler
+	reti
+
+TIM0_COMP:	; Timer0 Compare Handler
+	reti
+
+SPM_RDY:	; Store Program Memory Ready Handler
+	reti
+
+.exit

+ 152 - 0
avr/templates/ATmega8A.asm

@@ -0,0 +1,152 @@
+; Автор:	shilow@ukr.net
+; Дата:
+; Название:
+; Версия:
+; Имя файла:
+; Для AVR:	ATmega8
+; Тактовая частота:
+; Выполняемые функции:
+;
+;
+
+.listmac	; развернём макросы
+; инклуды
+.nolist
+.include "m8adef.inc"
+.list
+
+; опредления
+.def temp = r16		; рабочая переменная
+
+; константы
+.equ a = 0		; sample
+
+;******************************
+; ячейки в СОЗУ
+.DSEG
+;.ORG	SRAM_START
+Sample:	.byte	30
+
+; константы в EEPROM
+.ESEG
+smpl1:	.DW	0x0000	; sample 1
+smpl2:	.DB	0x05	; sample 2
+
+; память программ
+.CSEG
+.ORG 0
+; Таблица векторов прерываний
+	rjmp	RESET		; Reset Handler
+	rjmp	EXT_INT0	; IRQ0 Handler
+	rjmp	EXT_INT1	; IRQ1 Handler
+	rjmp	TIM2_COMP	; Timer2 Compare Handler
+	rjmp	TIM2_OVF	; Timer2 Overflow Handler
+	rjmp	TIM1_CAPT	; Timer1 Capture Handler
+	rjmp	TIM1_COMPA	; Timer1 CompareA Handler
+	rjmp	TIM1_COMPB	; Timer1 CompareB Handler
+	rjmp	TIM1_OVF	; Timer1 Overflow Handler
+	rjmp	TIM0_OVF	; Timer0 Overflow Handler
+	rjmp	SPI_STC		; SPI Transfer Complete Handler
+	rjmp	USART_RXC	; USART RX Complete Handler
+	rjmp	USART_UDRE	; UDR Empty Handler
+	rjmp	USART_TXC	; USART TX Complete Handler
+	rjmp	ADCC		; ADC Conversion Complete Handler
+	rjmp	EE_RDY		; EEPROM Ready Handler
+	rjmp	ANA_COMP	; Analog Comparator Handler
+	rjmp	TWSI		; Two-wire Serial Interface Handler
+	rjmp	SPM_RDY		; Store Program Memory Ready Handler
+
+;
+RESET:
+;;;;; Первичная инициализация
+; Set Stack Pointer to top of RAM
+	ldi	temp,high(RAMEND)
+	out	SPH,temp
+	ldi	temp,low(RAMEND)
+	out	SPL,temp
+; выкл. аналог. компаратор
+	ldi	temp,1<<ACD
+	out	ACSR,temp
+; Enable interrupts
+	sei
+BEGIN:
+;;;;; Основная программа
+	rjmp	BEGIN
+
+;;;;; Подпрограммы
+
+;;;;; Обработчики прерываний
+
+; IRQ0 Handler
+EXT_INT0:
+	reti
+
+; IRQ1 Handler
+EXT_INT1:
+	reti
+
+; Timer2 Compare Handler
+TIM2_COMP:
+	reti
+
+; Timer2 Overflow Handler
+TIM2_OVF:
+	reti
+
+; Timer1 Capture Handler
+TIM1_CAPT:
+	reti
+
+; Timer1 CompareA Handler
+TIM1_COMPA:
+	reti
+
+; Timer1 CompareB Handler
+TIM1_COMPB:
+	reti
+
+; Timer1 Overflow Handler
+TIM1_OVF:
+	reti
+
+; Timer0 Overflow Handler
+TIM0_OVF:
+	reti
+
+; SPI Transfer Complete Handler
+SPI_STC:
+	reti
+
+; USART RX Complete Handler
+USART_RXC:
+	reti
+
+; UDR Empty Handler
+USART_UDRE:
+	reti
+
+; USART TX Complete Handler
+USART_TXC:
+	reti
+
+; ADC Conversion Complete Handler
+ADCC:
+	reti
+
+; EEPROM Ready Handler
+EE_RDY:
+	reti
+
+; Analog Comparator Handler
+ANA_COMP:
+	reti
+
+; Two-wire Serial Interface Handler
+TWSI:
+	reti
+
+; Store Program Memory Ready Handler
+SPM_RDY:
+	reti
+
+.exit

+ 105 - 0
avr/templates/ATtiny13A.asm

@@ -0,0 +1,105 @@
+; Автор:	shilow@ukr.net
+; Дата:
+; Название:
+; Версия:
+; Имя файла:
+; Для AVR:	ATTiny13A
+; Тактовая частота: 9.6/8 МГц, внутренняя
+; Выполняемые функции:
+;
+
+.listmac	; развернём макросы
+;******************************
+; инклуды
+.nolist
+.include "tn13Adef.inc"
+.list
+
+;******************************
+; опредления
+.def temp = r16		; рабочая переменная
+
+.equ a = 0		; sample
+
+;******************************
+; ячейки в СОЗУ
+.DSEG
+;.ORG	SRAM_START
+Sample:	.byte	30
+
+;******************************
+; константы в EEPROM
+.ESEG
+smpl1:	.DW	0x0000	; sample 1
+smpl2:	.DB	0x05	; sample 2
+
+;******************************
+; память программ
+.CSEG
+.ORG 0
+
+;******************************
+; Таблица векторов прерываний
+	rjmp	RESET		; Reset Handler
+	rjmp	EXT_INT0	; IRQ0 Handler
+	rjmp	PCINT		; PCINT0 Handler
+	rjmp	TIM0_OVF	; Timer0 Overflow Handler
+	rjmp	EE_RDY		; EEPROM Ready Handler
+	rjmp	ANA_COMP	; Analog Comparator Handler
+	rjmp	TIM0_COMPA	; Timer0 CompareA Handler
+	rjmp	TIM0_COMPB	; Timer0 CompareB Handler
+	rjmp	WATCHDOG	; Watchdog Interrupt Handler
+	rjmp	ADCC		; ADC Conversion Handler
+
+;******************************
+;;;;; Первичная инициализация
+RESET:	; Set Stack Pointer to top of RAM
+	ldi	temp,low(RAMEND)
+	out	SPL,temp
+; выкл. аналог, компаратор
+	ldi	temp,1<<ACD
+	out	ACSR,temp
+; Enable interrupts
+	sei
+;******************************
+;;;;; Основная программа
+BEGIN:
+;;;;
+	rjmp	BEGIN
+
+;******************************
+;;;;; Подпрограммы
+
+
+;******************************
+;;;;; Обработчики прерываний
+
+; IRQ0 Handler
+EXT_INT0:
+	reti
+; PCINT0 Handler
+PCINT:
+	reti
+; Timer0 Overflow Handler
+TIM0_OVF:
+	reti
+; EEPROM Ready Handler
+EE_RDY:
+	reti
+; Analog Comparator Handler
+ANA_COMP:
+	reti
+; Timer0 CompareA Handler
+TIM0_COMPA:
+	reti
+; Timer0 CompareB Handler
+TIM0_COMPB:
+	reti
+; Watchdog Interrupt Handler
+WATCHDOG:
+	reti
+; ADC Conversion Handler
+ADCC:
+	reti
+
+.exit

+ 106 - 0
avr/templates/ATtiny2313A.asm

@@ -0,0 +1,106 @@
+; Автор:	shilow@ukr.net
+; Дата:
+; Название:
+; Версия:
+; Имя файла:
+; Для AVR:	ATTiny2313
+; Тактовая частота: 8 МГц
+; Выполняемые функции:
+; Шаблон для ATtiny2313
+;
+
+.listmac	; развернём макросы
+.nolist
+.include "tn2313adef.inc"
+.list
+
+;******************************
+; ячейки в СОЗУ
+.DSEG
+;.ORG	SRAM_START
+Sample:	.byte	30
+
+;
+	rjmp RESET		; Reset Handler
+	rjmp INT0		; External Interrupt0 Handler
+	rjmp INT1		; External Interrupt1 Handler
+	rjmp TIM1_CAPT		; Timer1 Capture Handler
+	rjmp TIM1_COMPA		; Timer1 CompareA Handler
+	rjmp TIM1_OVF		; Timer1 Overflow Handler
+	rjmp TIM0_OVF		; Timer0 Overflow Handler
+	rjmp USART0_RXC		; USART0 RX Complete Handler
+	rjmp USART0_DRE		; USART0,UDR Empty Handler
+	rjmp USART0_TXC		; USART0 TX Complete Handler
+	rjmp ANA_COMP		; Analog Comparator Handler
+	rjmp PCINT		; Pin Change Interrupt
+	rjmp TIMER1_COMPB	; Timer1 Compare B Handler
+	rjmp TIMER0_COMPA	; Timer0 Compare A Handler
+	rjmp TIMER0_COMPB	; Timer0 Compare B Handler
+	rjmp USI_START		; USI Start Handler
+	rjmp USI_OVERFLOW	; USI Overflow Handler
+	rjmp EE_READY		; EEPROM Ready Handler
+	rjmp WDT_OVERFLOW	; Watchdog Overflow Handler
+
+;
+RESET:	ldi	r16,low(RAMEND)	; Main program start
+	out	SPL,r16		; Set Stack Pointer to top of RAM
+	sei			; Enable interrupts
+BEGIN:
+;;;;
+	rjmp	BEGIN
+
+;
+; External Interrupt0 Handler
+INT0:
+	reti
+; External Interrupt1 Handler
+INT1:
+	reti
+; Timer1 Capture Handler
+TIM1_CAPT:
+	reti
+; Timer1 CompareA Handler
+TIM1_COMPA:
+	reti
+; Timer1 Overflow Handler
+TIM1_OVF:
+	reti
+; Timer0 Overflow Handler
+TIM0_OVF:
+	reti
+; USART0 RX Complete Handler
+USART0_RXC:
+	reti
+; USART0,UDR Empty Handler
+USART0_DRE:
+	reti
+; USART0 TX Complete Handler
+USART0_TXC:
+	reti
+; Analog Comparator Handler
+ANA_COMP:
+	reti
+; Pin Change Interrupt
+PCINT:
+	reti
+; Timer1 Compare B Handler
+TIMER1_COMPB:
+	reti
+; Timer0 Compare A Handler
+TIMER0_COMPA:
+	reti
+; Timer0 Compare B Handler
+TIMER0_COMPB:
+	reti
+; USI Start Handler
+USI_START:
+	reti
+; USI Overflow Handler
+USI_OVERFLOW:
+	reti
+; EEPROM Ready Handler
+EE_READY:
+	reti
+; Watchdog Overflow Handler
+WDT_OVERFLOW:
+	reti

+ 136 - 0
avr/templates/ATtiny24a.asm

@@ -0,0 +1,136 @@
+; Автор:	shilow@ukr.net
+; Дата:
+; Название:
+; Версия:
+; Имя файла:
+; Для AVR:	ATtiny24A
+; Тактовая частота:
+; Выполняемые функции:
+;
+; Шаблон для ATtiny24A
+;
+
+.listmac	; развернём макросы
+;******************************
+; инклуды
+.nolist
+.include "tn24Adef.inc"
+.list
+
+;******************************
+; опредления
+.def temp	= r16	; рабочая переменная
+
+;******************************
+; константы
+.equ a		= 0	; sample
+
+;******************************
+; ячейки в СОЗУ
+.DSEG
+;.ORG	SRAM_START
+Sample:		.byte	30
+
+;******************************
+; константы в EEPROM
+.ESEG
+smpl1:		.DW	0x0000	; sample 1
+smpl2:		.DB	0x05	; sample 2
+
+;******************************
+; память программ
+.CSEG
+.ORG 0
+;******************************
+; Таблица векторов прерываний
+	rjmp	RESET		; Reset Handler
+	rjmp	INT0		; IRQ0 Handler
+	rjmp	PCINT0		; PCINT0 Handler
+	rjmp	PCINT1		; PCINT1 Handler
+	rjmp	WDT		; Watchdog Interrupt Handler
+	rjmp	TIM1_CAPT	; Timer1 Capture Handler
+	rjmp	TIM1_COMPA	; Timer1 Compare A Handler
+	rjmp	TIM1_COMPB	; Timer1 Compare B Handler
+	rjmp	TIM1_OVF	; Timer1 Overflow Handler
+	rjmp	TIM0_COMPA	; Timer0 Compare A Handler
+	rjmp	TIM0_COMPB	; Timer0 Compare B Handler
+	rjmp	TIM0_OVF	; Timer0 Overflow Handler
+	rjmp	ANA_COMP	; Analog Comparator Handler
+	rjmp	ADCC		; ADC Conversion Handler
+	rjmp	EE_RDY		; EEPROM Ready Handler
+	rjmp	USI_STR		; USI STart Handler
+	rjmp	USI_OVF		; USI Overflow Handler
+
+;******************************
+;;;;; Первичная инициализация
+RESET:	ldi	r16,high(RAMEND); Main program start
+	out	SPH,r16		; Set Stack Pointer to top of RAM
+	ldi	r16,low(RAMEND)
+	out	SPL,r16
+; выкл. аналог, компаратор
+	ldi	temp,1<<ACD
+	out	ACSR,temp
+; Enable interrupts
+	sei
+;******************************
+;;;;; Основная программа
+BEGIN:
+;;;;
+	rjmp	BEGIN
+
+;******************************
+;;;;; Подпрограммы
+
+;******************************
+;;;;; Обработчики прерываний
+
+INT0:		; IRQ0 Handler
+	reti
+
+PCINT0:		; PCINT0 Handler
+	reti
+
+PCINT1:		; PCINT1 Handler
+	reti
+
+WDT:		; Watchdog Interrupt Handler
+	reti
+
+TIM1_CAPT:	; Timer1 Capture Handler
+	reti
+
+TIM1_COMPA:	; Timer1 Compare A Handler
+	reti
+
+TIM1_COMPB:	; Timer1 Compare B Handler
+	reti
+
+TIM1_OVF:	; Timer1 Overflow Handler
+	reti
+
+TIM0_COMPA:	; Timer0 Compare A Handler
+	reti
+
+TIM0_COMPB:	; Timer0 Compare B Handler
+	reti
+
+TIM0_OVF:	; Timer0 Overflow Handler
+	reti
+
+ANA_COMP:	; Analog Comparator Handler
+	reti
+
+ADCC:		; ADC Conversion Handler
+	reti
+
+EE_RDY:		; EEPROM Ready Handler
+	reti
+
+USI_STR:	; USI STart Handler
+	reti
+
+USI_OVF:	; USI Overflow Handler
+	reti
+
+;
+.exit

+ 79 - 0
avr/templates/ATtiny26.asm

@@ -0,0 +1,79 @@
+; Автор:	shilow@ukr.net
+; Дата:
+; Название:
+; Версия:
+; Имя файла:
+; Для AVR:	ATTiny26
+; Тактовая частота:
+; Выполняемые функции:
+;
+; Шаблон для ATTiny26
+;
+
+.listmac	; развернём макросы
+.nolist
+.include "tn26def.inc"
+.list
+
+	rjmp	RESET		; Reset handler
+	rjmp	EXT_INT0	; IRQ0 handler
+	rjmp	PIN_CHANGE	; Pin change handler
+	rjmp	TIM1_CMP1A	; Timer1 compare match 1A
+	rjmp	TIM1_CMP1B	; Timer1 compare match 1B
+	rjmp	TIM1_OVF	; Timer1 overflow handler
+	rjmp	TIM0_OVF	; Timer0 overflow handler
+	rjmp	USI_STRT	; USI Start handler
+	rjmp	USI_OVF		; USI Overflow handler
+	rjmp	EE_RDY		; EEPROM Ready handler
+	rjmp	ANA_COMP	; Analog Comparator handler
+	rjmp	ADCC		; ADC Conversion Handler
+
+;******************************
+; ячейки в СОЗУ
+.DSEG
+;.ORG	SRAM_START
+Sample:	.byte	30
+
+;
+
+RESET:	ldi	r16, RAMEND	; Main program start
+	out	SP, r16
+	sei			; Enable interrupts
+BEGIN:
+;;;;
+	rjmp	BEGIN
+
+;
+EXT_INT0:
+	reti
+;
+PIN_CHANGE:
+	reti
+;
+TIM1_CMP1A:
+	reti
+;
+TIM1_CMP1B:
+	reti
+;
+TIM1_OVF:
+	reti
+;
+TIM0_OVF:
+	reti
+;
+USI_STRT:
+	reti
+;
+USI_OVF:
+	reti
+;
+EE_RDY:
+	reti
+;
+ANA_COMP:
+	reti
+;
+ADCC:
+	reti
+;

+ 10 - 0
avr/timer.txt

@@ -0,0 +1,10 @@
+Инициализация таймера:
+
+; настроим таймер0 и прескалер. нам нужны 10Гц интервалы, прескалер на 1024
+; таймер0 на $62 это даст 9.965Гц -- нам достаточно
+	ldi	temp,(1<<CS02)|(1<<CS00)
+	out	TCCR0,temp
+	ldi	temp,(1<<TOIE0)
+	out	TIMSK,temp	; разр. прерывания от Timer0 по переполнению
+	ldi	temp,Kdiv
+	out	TCNT0,temp	; зарядили таймер

+ 84 - 0
avr/usart.txt

@@ -0,0 +1,84 @@
+; инитим USART
+; при тактовой 1МГц и скорости 9600 бод мин погрешность 0.2% при U2X=1 и
+; UBRR=12 (мануал стр.161-164). установим бодрейт:
+	outi	UBRRH,0
+	outi	UBRRL,12
+	outi	UCSRA,1<<U2X
+; установим формат кадра: 8data, 1stop bit
+	outi	UCSRC,(1<<URSEL)|(0<<USBS)|(3<<UCSZ0)
+
+; включим приёмник и передатчик
+	outi	UCSRB,(1<<RXEN)|(1<<TXEN)
+
+вероятно, включать передатчик стоит только на то время, пока передаём данные
+
+нужно нарисовать универсальные процедуры на прерываниях для приёма-передачи
+передавать или один символ в регистре
+или адрес строки в озу/еепром/пзу
+
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+http://easyelectronics.ru/avr-uchebnyj-kurs-peredacha-dannyx-cherez-uart.html
+
+UCSRA
+биты RXC и TXC это флаги завершения приема и передачи, соответственно
+Биты UDRE сигнализирует о том, что регистр UDR приемника пуст и в него можно
+пихать новый байт
+U2X - это бит удвоения скорости при работе в ассинхронном режиме
+
+
+UCSRB
+биты RXEN и TXEN — разрешение приема и передачи. Стоит их сбросить как выводы UART
+тут же становятся обычными ножками I/O.
+Биты RXCIE, TXCIE, UDRIE разрешают прерывания по завершению приема, передачи
+и опустошении буфера передачи UDR
+
+UCSRC
+Самый прикол тут — это бит селектора URSEL дело в том, что по неизвестной
+причине создаетели решили сэкономить байт адреса и разместили регистры UCSRC
+и UBRRH в одной адресном пространстве. А как же определять куда записать? А
+по старшему биту! Поясню на примере. Если мы записываем число у которого
+седьмой бит равен 1, то оно попадет в UCSRC, а если 0 то UBRRH. Причем этот
+бит есть не во всех AVR в новых моделях его нет, а регистры имеют разные
+адреса. Так что надо смотреть в даташите этот момент — есть там бит URSEL или
+нет.
+Остальные биты задают число стопов, наличие и тип контроля четности. Если
+оставить все по дефолту то будет стандартный режим. Надо только выставить
+формат посылки. Делается это битами UCSZ0, UCSZ1 и UCSZ2 (этот бит тусуется в
+регистре UCSRB). Для стандартной 8ми битной посылки туда надо записать две
+единички.
+
+
+Скорость обмена.
+Тут все зависит от пары UBBRx
+Вычисляется требуемое значение по формуле:
+	UBBR=XTAL/(16*baudrate)-1 для U2X=0
+	UBBR=XTAL/(8*baudrate)-1 для U2X=1
+Где:
+XTAL - рабочая тактовая частота контроллера.
+baudrate - требуемая скорость, чем медленней тем надежней,
+	9600 в большинстве случаев хватает
+
+
+вариант обработчика на приём:
+-----------------------------------------------------------------------------
+RX_OK:	PUSHF			; Макрос, пихающий в стек SREG и R16
+
+	IN	R16,UDR		; Тут главное забрать байт из UDR иначе
+				; флаг прерывания не снимется
+				; Дальше, если время позволяет, можно и обработать
+
+	CPI	R16,Value	; Например, разобрать по байтам и выполнить действие
+	BRNE	NXT		; Обычным CASE оператором.
+	Action1			; Делаем что нибудь ценное. Главное не забыть в стеке
+				; Регистры попрятать. А то будет тебе упячка.
+	; здесь можно обрабатывать команды
+
+NXT:	CPI	R16,Value2
+	BRNE	RX_Exit
+	Action2			; Делаем что нибудь ценное2
+	; а здесь, если не команда, сохранять байты в буффер
+
+Rx_Exit:
+	POPF			; Достаем SREG и R16
+	RETI
+-----------------------------------------------------------------------------

+ 34 - 0
bits_macros.h

@@ -0,0 +1,34 @@
+#ifndef BITS_MACROS_
+#define BITS_MACROS_
+/***********************************************************
+//BITS MACROS
+//PASHGAN 2009
+//CHIPENABLE.RU
+//
+//reg : имя переменной, регистра
+//bit : позиция бита
+//val : 0 или 1
+************************************************************/
+#define Bit(bit)  (1<<(bit))
+
+#define ClearBit(reg, bit)       reg &= (~(1<<(bit)))
+//пример: ClearBit(PORTB, 1); //сбросить 1-й бит PORTB
+
+#define SetBit(reg, bit)          reg |= (1<<(bit))
+//пример: SetBit(PORTB, 3); //установить 3-й бит PORTB
+
+#define SetBitVal(reg, bit, val) do{if ((val&1)==0) reg &= (~(1<<(bit)));\
+                                  else reg |= (1<<(bit));}while(0)
+//пример: SetBitVal(PORTB, 3, 1); //установить 3-й бит PORTB
+//	  SetBitVal(PORTB, 2, 0); //сбросить 2-й бит PORTB
+
+#define BitIsClear(reg, bit)    ((reg & (1<<(bit))) == 0)
+//пример: if (BitIsClear(PORTB,1)) {...} //если бит очищен
+
+#define BitIsSet(reg, bit)       ((reg & (1<<(bit))) != 0)
+//пример: if(BitIsSet(PORTB,2)) {...} //если бит установлен
+
+#define InvBit(reg, bit)	  reg ^= (1<<(bit))
+//пример: InvBit(PORTB, 1); //инвертировать 1-й бит PORTB
+
+#endif//BITS_MACROS_

+ 114 - 0
pin_macros.h

@@ -0,0 +1,114 @@
+/*----------------------------------------------------------------------------------------------
+ *  pin_macros.h  (AVR/avr-gcc)
+ *----------------------------------------------------------------------------------------------
+ *
+ * Author:  Oleksandr Redchuk aka ReAl (real@real.kiev.ua)
+ *
+ * Description: port bits access macros for AVR uC family (avr-gcc compiler)
+ *
+ * Based on macros by Ascold Volkov, Andy Mozzevilov, Aleksey Musin
+ *----------------------------------------------------------------------------------------------
+ */
+
+/*
+examples
+
+#define Pin1 A,2,H
+#define Pin2 B,3,L
+             ^ ^ ^
+          port | |
+             bit \active level
+
+void main(void)
+{
+    DRIVER(Pin1,OUT);   //as output
+    DRIVER(Pin2,IN);        //as input
+    DRIVER(Pin2,PULLUP);    // with pullup
+    ON(Pin1);
+    if (ACTIVE(Pin2)) OFF(Pin1);
+    if (LATCH(Pin1)) { //if active level presents on Pin1 for drive something
+        //do something
+    }
+}
+*/
+
+#ifndef PIN_MACROS_H
+#define PIN_MACROS_H
+
+// assume chip has PORT_TOGGLE_BY_PIN_WRITE feature by default (all new AVR chips)
+// check only old-style chips
+
+#if defined(__AVR_AT94K__) \
+    || defined(__AVR_AT43USB320__) || defined(__AVR_AT43USB355__) \
+    || defined(__AVR_AT76C711__) || defined(__AVR_AT86RF401__) \
+    || defined(__AVR_AT90C8534__) || defined(__AVR_AT90S4434__) \
+    || defined(__AVR_AT90S1200__) || defined(__AVR_AT90S2343__) \
+    || defined(__AVR_AT90S2333__) || defined(__AVR_AT90S2323__) \
+    || defined(__AVR_AT90S2313__) || defined(__AVR_AT90S4433__) \
+    || defined(__AVR_AT90S4414__) \
+    || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \
+    || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \
+    || defined(__AVR_ATmega103__) \
+    || defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) \
+    || defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) \
+    || defined(__AVR_ATmega32__) \
+    || defined(__AVR_ATtiny11__) || defined(__AVR_ATtiny12__) \
+    || defined(__AVR_ATtiny15__) || defined(__AVR_ATtiny28__) \
+    || defined(__AVR_ATtiny22__) || defined(__AVR_ATtiny26__) \
+    || defined(__AVR_ATmega161__) || defined(__AVR_ATmega162__) \
+    || defined(__AVR_ATmega163__) || defined(__AVR_ATmega323__) \
+    || defined(__AVR_ATmega8HVA__) || defined(__AVR_ATmega16HVA__)
+#  define PORT_TOGGLE_BY_PIN_WRITE 0
+#else
+#  define PORT_TOGGLE_BY_PIN_WRITE 1
+#endif
+
+#define PM_BITNUM(port,bit,val) (bit)
+#define BITNUM(x) PM_BITNUM(x)
+#define BITMASK(x) (1<<PM_BITNUM(x))
+
+#define PM_SETOUT(port,bit) (DDR##port |= (1<<(bit)))
+#define PM_SETIN(port,bit) (DDR##port &= ~(1<<(bit)))
+#define PM_SETPULLUP(port,bit) (PORT##port |= (1<<(bit)))
+#define PM_SETHIZ(port,bit) (PORT##port &= ~(1<<(bit)))
+#define PM_DRIVER(port,bit,val,mode) PM_SET##mode(port,bit)
+/* dmode = OUT or IN, PULLUP or HIZ */
+#define DRIVER(x,mode) PM_DRIVER(x,mode)
+
+#define PM_SETL(port,bit,dummy) (PORT##port &= ~(1<<(bit)))
+#define PM_SETH(port,bit,dummy) (PORT##port |= (1<<(bit)))
+#define PM_SET(port,bit,val) PM_SET##val(port,bit,dummy)
+#define ON(x) PM_SET(x)
+#define SET(x) PM_SETH(x)
+#define CLR(x) PM_SETL(x)
+
+#define PM_CLRL(port,bit,dummy) PM_SETH(port,bit,dummy)
+#define PM_CLRH(port,bit,dummy) PM_SETL(port,bit,dummy)
+#define PM_CLR(port,bit,val) PM_CLR##val(port,bit,dummy)
+#define OFF(x) PM_CLR(x)
+
+#define PM_PINH(port,bit,dummy) (PIN##port & (1<<(bit)))
+#define PM_PINL(port,bit,dummy) !PM_PINH(port,bit,dummy)
+#define PM_PIN(port,bit,val) PM_PIN##val(port,bit,dummy)
+#define ACTIVE(x) PM_PIN(x)
+#define PIN_H(x) PM_PINH(x)
+#define PIN_L(x) PM_PINL(x)
+
+#define PM_LATCHH(port,bit,dummy) (PORT##port & (1<<(bit)))
+#define PM_LATCHL(port,bit,dummy) !PM_LATCHH(port,bit,dummy)
+#define PM_LATCH(port,bit,val) PM_LATCH##val(port,bit,dummy)
+#define LATCH(x) PM_LATCH(x)
+#define LATCH_H(x) PM_LATCHH(x)
+#define LATCH_L(x) PM_LATCHL(x)
+
+
+#if PORT_TOGGLE_BY_PIN_WRITE
+#  define PM_CPL(port,bit,val)      (PIN##port |= (1 << (bit)))
+#else
+#  define PM_CPL(port,bit,val)      (PORT##port ^= (1 << (bit)))
+#endif
+
+#define CPL(x) PM_CPL(x)
+#define TOGGLE(x) PM_CPL(x)
+
+#endif  // PIN_MACROS_H

+ 120 - 0
stm8/mcu_usart.c

@@ -0,0 +1,120 @@
+/*
+ *  File:   mcu_usart.c
+ *  Date:   26.05.2011
+ *  Denis Zheleznjakov @ ZiBlog.ru
+ */
+
+#include "main.h"
+
+struct
+{
+	volatile uint8_t rx_buffer[USART_RX_BUFFER_SIZE];
+	volatile uint8_t rx_buffer_head;
+	volatile uint8_t rx_buffer_tail;
+	volatile uint8_t tx_buffer[USART_TX_BUFFER_SIZE];
+	volatile uint8_t tx_buffer_head;
+	volatile uint8_t tx_buffer_tail;
+} usart_fifo;
+
+void mcu_usart_init(uint32_t baud_rate)
+{
+	usart_fifo.rx_buffer_head = 0;
+	usart_fifo.rx_buffer_tail = 0;
+	usart_fifo.tx_buffer_head = 0;
+	usart_fifo.tx_buffer_tail = 0;
+
+	CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE);
+
+	USART_DeInit(USART1);
+
+	USART_Init(USART1, baud_rate, USART_WordLength_8b, USART_StopBits_2, USART_Parity_No, (USART_Mode_TypeDef) (USART_Mode_Tx | USART_Mode_Rx));
+
+	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
+
+	USART_Cmd(USART1, ENABLE);
+}
+
+_Bool mcu_usart_fifo_receive(uint8_t * data)
+{
+	uint8_t rx_head;
+	uint8_t rx_tail;
+
+	rx_head = usart_fifo.rx_buffer_head;
+
+	if (rx_head == usart_fifo.rx_buffer_tail)
+		return FALSE;
+
+	rx_tail = (uint8_t) ((usart_fifo.rx_buffer_tail + 1) & (uint8_t) (USART_RX_BUFFER_SIZE - 1));
+
+	usart_fifo.rx_buffer_tail = rx_tail;
+
+	*data = usart_fifo.rx_buffer[rx_tail];
+
+	return TRUE;
+}
+
+void mcu_usart_fifo_transmit(uint8_t data)
+{
+	uint8_t tx_head;
+
+	tx_head = (uint8_t) ((usart_fifo.tx_buffer_head + 1) & (uint8_t) (USART_TX_BUFFER_SIZE - 1));
+
+	while (tx_head == usart_fifo.tx_buffer_tail)
+	{
+	}
+
+	usart_fifo.tx_buffer[tx_head] = data;
+	usart_fifo.tx_buffer_head = tx_head;
+
+	USART1->CR2 |= USART_CR2_TIEN;
+	//USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
+}
+
+void mcu_usart_fifo_tx_handler(void)
+{
+	uint8_t status;
+	uint8_t tx_tail;
+	uint8_t tx_head;
+
+	status = USART1->SR;
+
+	if (status & USART_SR_TC)
+	{
+		USART1->SR &= (uint8_t) (~USART_SR_TC);
+	}
+
+	if (status & USART_SR_TXE)
+	{
+		tx_head = usart_fifo.tx_buffer_head;
+		tx_tail = usart_fifo.tx_buffer_tail;
+
+		if (tx_head != tx_tail++)
+		{
+			tx_tail &= USART_TX_BUFFER_SIZE - 1;
+
+			usart_fifo.tx_buffer_tail = tx_tail;
+			USART1->DR = usart_fifo.tx_buffer[tx_tail];
+		}
+		else
+		{
+			USART1->CR2 &= (uint8_t) (~USART_CR2_TIEN);
+		}
+	}
+}
+
+void mcu_usart_fifo_rx_handler(void)
+{
+	uint8_t rx_data;
+	uint8_t rx_head;
+
+	(void) USART1->SR;
+	rx_data = USART1->DR;
+
+	rx_head = (uint8_t) ((usart_fifo.rx_buffer_head + 1) & (uint8_t) (USART_RX_BUFFER_SIZE - 1));
+
+	if (rx_head != usart_fifo.rx_buffer_tail)
+	{
+		usart_fifo.rx_buffer_head = rx_head;
+		usart_fifo.rx_buffer[rx_head] = rx_data;
+	}
+}

+ 19 - 0
stm8/mcu_usart.h

@@ -0,0 +1,19 @@
+/*
+ *  File:   mcu_usart.h
+ *  Date:   26.05.2011
+ *  Denis Zheleznjakov @ ZiBlog.ru
+ */
+
+#ifndef MCU_USART_H_
+#define MCU_USART_H_
+
+#define USART_TX_BUFFER_SIZE    64 // кратен двум
+#define USART_RX_BUFFER_SIZE    64 // кратен двум
+
+void mcu_usart_init(uint32_t baud_rate);
+void mcu_usart_fifo_tx_handler(void);
+void mcu_usart_fifo_rx_handler(void);
+void mcu_usart_fifo_transmit(uint8_t data);
+_Bool mcu_usart_fifo_receive(uint8_t * data);
+
+#endif /* MCU_USART_H_ */

+ 177 - 0
subroutine.c

@@ -0,0 +1,177 @@
+/*
+*
+*	Ïîäïðîãðàìêè, êîòîðûå ÿ óñïåë íàâàÿòü íà C
+*
+*/
+
+
+//============================================================================
+// ïðîãðàììíûé SPI. Âûâîäèò áàéò íà÷èíàÿ ñî ñòàðøåãî áèòà
+// âûõîäíûå ïèíû -- SCK, MOSI, ïîðò -- SPI_PORT. ñòðîá -- èç 0 â 1
+void spi_SendByte (uint8_t DataByte) {
+	uint8_t i;					// ñ÷åò÷èê áèò
+	for (i=8; i>0; i--) {
+		SPI_PORT &= (~(1<<PIN_SCK));		// âûäàëè ñòðîá
+		if (bit_is_set(DataByte,7)) {		// åñëè áèò 7 == 1
+			SPI_PORT |= (1<<PIN_MOSI);	// MOSI = 1
+		} else {					// åñëè áèò 7 == 0
+			SPI_PORT &= (~(1<<PIN_MOSI));	// MOSI = 0
+		}
+		SPI_PORT |= (1<<PIN_SCK);		// çàù¸ëêíóëè ñòðîá
+		DataByte <<= 1;				// ñäâèã âëåâî íà 1 áèò
+	}
+}
+
+
+//============================================================================
+// bcd2ascii
+// ïðèäóìàë ñàì, åù¸ íå ïðîâåðÿë
+typdef struct {uint8_t msb, uint8_t lsb} x2_ascii;
+
+x2_ascii BCD_to_ASCII(unit8_t bcd) {
+	x2_ascii ascii;
+
+	ascii.msb = bcd;
+	ascii.lsb = bcd;
+
+	ascii.msb >>= 4;
+	ascii.msb |= 0x0F;
+	ascii.lsb |= 0x0F;
+
+	ascii.msb += 0x30;
+	ascii.lsb += 0x30;
+
+	return ascii;
+}
+// êàê-òî òàê...
+
+//============================================================================
+/*
+  http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=66337
+  Post subject: RE: 16bit Binary to BCD conversion
+   The cheap way, leveraging on the C libraries ascii conversion routines. 
+
+Code:
+*/
+
+char (*a)[10];	// Óêàçàòåëü íà ìàññèâ èç äåñÿòè ñèìâîëîâ
+
+ // returns number of digits converted 
+ // result array must be large enough to hold 
+ // the number of digits converted. 
+
+ int itobcd(unsigned int val, char *result) 
+ { 
+   char BCD_text[6]; // max 5 digits in a 16 bit uint 
+   int i; 
+
+   itoa(val, BCD_text, 10); 
+   i=0; 
+   while(BCD_text[i]) 
+   { 
+     result[i] = BCD_text[i]-'0'; 
+     i++; 
+   } 
+   return i; 
+ }
+
+
+//============================================================================
+// http://www.strudel.org.uk/itoa/
+// char* version 0.1
+char* itoa(int val, int base){
+	static char buf[32] = {0};
+	int i = 30;
+	for(; val && i ; --i, val /= base){
+		buf[i] = "0123456789abcdef"[val % base];
+	}
+	return &buf[i+1];
+}
+
+// char* version 0.4
+/*
+ * C++ version 0.4 char* style "itoa":
+ * Written by Lukas Chmela
+ * Released under GPLv3.
+*/
+
+char* itoa(int value, char* result, int base) {
+	// check that the base if valid
+	if (base < 2 || base > 36) { *result = '\0'; return result; }
+
+	char* ptr = result, *ptr1 = result, tmp_char;
+	int tmp_value;
+
+	do {
+		tmp_value = value;
+		value /= base;
+		*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
+	} while ( value );
+
+	// Apply negative sign
+	if (tmp_value < 0) *ptr++ = '-';
+	*ptr-- = '\0';
+	while(ptr1 < ptr) {
+		tmp_char = *ptr;
+		*ptr--= *ptr1;
+		*ptr1++ = tmp_char;
+	}
+	return result;
+}
+
+
+//============================================================================
+/*
+Ðåàëèçàöèÿ îò Êåðíèãàíà è Ðèò÷è
+Ôóíêöèÿ itoa ïîÿâèëàñü â ïåðâîì èçäàíèè êíèãè Áðàéàíà Êåðíèãàíà è Äåíèñà
+Ðèò÷è ßçûê ïðîãðàììèðîâàíèÿ Ñè, íà ñòðàíèöå 60. Âòîðîå èçäàíèå ßçûê
+ïðîãðàììèðîâàíèÿ Ñè («K&R2») íà ñòð. 64 ñîäåðæàëî íèæåñëåäóþùóþ ðåàëèçàöèþ
+itoa.  êíèãå îòìå÷åíî íåñêîëüêî âîïðîñîâ, ñâÿçàííûõ ñ ýòîé ðåàëèçàöèåé,
+âêëþ÷àÿ òîò ôàêò, ÷òî îíà íå â ñîñòîÿíèè êîððåêòíî îáðàáîòàòü ñàìîå
+ìàëåíüêîå îòðèöàòåëüíîå ÷èñëî -2äëèíà ìàøèííîãî ñëîâà â áèòàõ-1.[1]
+*/
+ /* itoa:  êîíâåðòèðóåì n â ñèìâîëû â s */
+ void itoa(int n, char s[])
+ {
+     int i, sign;
+ 
+     if ((sign = n) < 0)  /* çàïèñûâàåì çíàê */
+         n = -n;          /* äåëàåì n ïîëîæèòåëüíûì ÷èñëîì */
+     i = 0;
+     do {       /* ãåíåðèðóåì öèôðû â îáðàòíîì ïîðÿäêå */
+         s[i++] = n % 10 + '0';   /* áåðåì ñëåäóþùóþ öèôðó */
+     } while ((n /= 10) > 0);     /* óäàëÿåì */
+     if (sign < 0)
+         s[i++] = '-';
+     s[i] = '\0';
+     reverse(s);
+ }
+
+/*
+Ôóíêöèÿ reverse ðåàëèçîâàíà äâóìÿ ñòðàíèöàìè ðàíåå:
+*/
+#include <string.h>
+
+/* reverse:  ïåðåâîðà÷èâàåì ñòðîêó s íà ìåñòå */
+void reverse(char s[])
+{
+    int i, j;
+    char c;
+
+    for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
+        c = s[i];
+        s[i] = s[j];
+        s[j] = c;
+    }
+}
+
+//============================================================================
+// çàäåðæêà íà ïðåðûâàíèÿõ
+void delay_ms (word ms) {
+	ADCSRA &= (~(1<<ADEN)); // âûêëþ÷èì ÀÖÏ
+	do { // äâà áàéòà ýêîíîìèè
+		set_sleep_mode(SLEEP_MODE_IDLE);
+		sleep_mode();
+	} while (ms > 0);
+	ADCSRA |= (1<<ADEN); // âêëþ÷èì ÀÖÏ
+}