при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Многие просто не представляют, как происходит процесс компиляции. Как сначала .c/.S файлы, обработанные предварительно препроцессором, превращаются в объектные, как потом линкер собирает их в один исполняемый. Как страшно при этом выглядят консольные команды, вызывающие компиляцию/линковку, из-за чего, собственно, и придуманы системы сборки вроде make.ptr128 писал(а):Как то с трудом мне удается представить себе программиста, уверенно пишущего на ассемблере, но который не в состоянии написать простейший makefile
Тогда этот человек должен осозновать, что он не знает, что именно загружает потом в МК и почему у него получился именно такой бинарный файл, а не тот, который он хотел бы получить. Для примера, на уровне LD на платформах, поддерживающих и short и long CALL, можно получить очень своеобразные глюки, не управляя порядком следования функций/подпрограмм. А если жить только в IDE, то вынуждены будете отказаться от short CALL полностью, если памяти больше, чем доступно при short CALL.WiseLord писал(а): Человек просто привязывается к конкретной IDE, жмёт кнопку "Build" в ней, не понимая, что при этом происходит.
Тогда смело пользуйтесь make. В данной ситуации, Вам потребуется 1-2% возможностей GNU make и изучить их можно за 15 минут.trofim2 писал(а):Процесс я представляю
Я не о Вас говорю, а вообще о ситуации. Не только о программистах под МК, но и вообще ситуации программировании. Крик души такой, что ли...trofim2 писал(а):Процесс я представляю
ptr128 писал(а):Для примера, на уровне LD на платформах, поддерживающих и short и long CALL, можно получить очень своеобразные глюки, не управляя порядком следования функций/подпрограмм. А если жить только в IDE, то вынуждены будете отказаться от short CALL полностью, если памяти больше, чем доступно при short CALL.
вы, уважаемые господа, обратите внимание, в какой теме находитесь! все понятно - и платформы разные, и IDE и прочее, но к чему это все в конкретном случае AVR?WiseLord писал(а):Крик души такой
Код: Выделить всё
d:\GCCAVR\bin\avr-gcc -mmcu=atmega48 -I. -Wa,-gstabs -Wall -o test.elf test.S
d:\GCCAVR\bin\avr-objcopy -j .text -j .data -O ihex test.elf test.hex
Код: Выделить всё
define PORTB 0x05
#define data r16
#define loopone r17
#define looptwo r18
#define loopthr r19
.global main
main:
ldi data,0xFF
out PORTB,data
loop:
ldi data,0x00
out PORTB,data
rcall delay
ldi data,0xFF
out PORTB,data
rcall delay
rjmp loop
delay:
ldi loopone,0x0F
waitlooptwo:
ldi looptwo,0xFF
waitloopthr:
ldi loopthr,0xFF
waitloop:
subi loopthr,0x01
brne waitloop
subi looptwo,0x01
brne waitloopthr
subi loopone,0x01
brne waitlooptwo
retВот сейчас на AVR делаю работу со шрифтами, хранящимися на SD. Идея в том, что при выводе строки, на основании заголовка шрифта мы получаем базу для рассчета позиций каждого символа. По мере считывания шрифта сразу формируем на TFT очередной считываемый символ во всех местах, где он есть или пропускаем его, если его нет в строке. Особенно для крупных шрифтов экономия памяти огромная, а в производительности теряем только время, необходимое для последовательного считывания шрифта с SD.ARV писал(а): но к чему это все в конкретном случае AVR?
Ага, и каждый раз перекомпилировать все исходники. Особенно круто это будет выглядеть для реального проекта, кода *.s файлов на несколько килобайт, а включаемых файлов, суммарно для всех *.s файлов - несколько сот килобайт.oleg110592 писал(а):командная строка для GCC asm:
и что? сколько еще таких виртуозов, как вы? насколько ценным будет совет применять частность, как обобщающий принцип?ptr128 писал(а):Вот сейчас на AVR делаю работу со шрифтами
Вы мне льстите. Я, до сентября этого года, последний раз программировал для МК в 1989 году. А последние 10 лет даже на C почти не приходилось писать (разве что, когда дочке с дипломом помогал). Обходился Perl, а остальное - на T-SQL или PL/SQL, ну и в довесок MDX с дотнетовскими сборками на C#.ARV писал(а):и что? сколько еще таких виртуозов, как вы?
Так я ровно про это речь и веду. Сборка только под одну платформу из одного или нескольких файлов исходного кода - частность. Сборка под любое количество платформ из любого объема исходных текстов и разделяемых библиотек - общий принцип.ARV писал(а): насколько ценным будет совет применять частность, как обобщающий принцип?
Код: Выделить всё
* Author: st
*/
.def XXX=R20;// Команда для переименования регистров.
.def timeprod=R21;
.def zero=R22;
.list; // Отоброжения листинга исполнения команды.
.cseg; работаем с програмной памятью а не озу или eeprom
.org 0; устанавливаем начальную позицию строки
rjmp START; Reset Handler
rjmp obrobotkaINT0; IRQ0 Handler
rjmp START; PCINT0Z Handler
rjmp START; Timer0 Overflow Handler
rjmp START; EEPROM Ready Handler
rjmp START; Analog Comparator Handler
rjmp obrobotkaTIM0_COMPA; TIM0_COMPA CompareA Handler
rjmp START; Timer0 CompareB Handler
rjmp START; Watchdog Interrupt Handler
rjmp START; ADC Conversion Handler
//броботка прерывания порта INT0, по высокому сигналу.
obrobotkaINT0:
//Отключаем работу на срабатывания прерывания
ldi R16, (0<<INT0);
out GIMSK, R16;
//скидываем фдлаг если имеется
ldi R16, (1<<INTF0); /скидываем флаги прерывания
out GIFR, R16;
//Подключаем нужный нам порт.
ldi R16, (1<<PB4)|(1<<PB1);
out PORTB, R16;
//RCALL TIMER; //Относительный вызов подпрограммы TIMER.
RCALL TIMER;
nop;
reti; //команда выхода из оброботчика прерывания.
//Прерывания при совапдении таймера
obrobotkaTIM0_COMPA:
inc XXX;
reti;
/*Код установки таймера счетчика*/
TIMER:
/*
http://avrprog.blogspot.com/2013/03/t0-8.html
TIFR0 - регистр индикации флагов прерывания
TOV0 - флаг индикации по переполнению таймера
OCF0A,OCF0B - флаг индикации по совпадению.
OCR0A,OCR0B - регистр установки значения для совпадения.
TCCR0A - регистр управления A;
TCCR0B - регистр управления B;
*TIMSK0 - Регистр выбора режима срабатывания прерывания
TOIE0 - по переполнению, OCIE0A - по совпадению со значанием в регистре А,
OCIE0B - по совпадению со значанием в регистре B.
*/
ldi R16, 0x00;// Сбрасываем все флаги таймера
out TIFR0, R16;
ldi R16, (1<<OCIE0A);Установка режима по совпадению с А;
out TIMSK0, R16;
ldi R16, 0xFF; Устанавливаем значение при совпадении с А
out OCR0A, R16;
/*Скорость работы микроконтролера*/
ldi R16, (1<<CS02)|(0<<CS01)|(1<<CS00);
out TCCR0B, R16;
//Присваем значение переменной 0, для упрощения дальнейшего применения
ret; //возврат из подпрограммы TIMER:
//Определяем начальные параметры микроконтролера.
START:
CLI; команда запрещает глобальные прерывания.
//инициализация стэка.(установка максимально размера ОЗУ);
ldi R17, RAMEND;
out SPL, R17;
ldi zero, 0x00; //Присваеваем значение 0 переменной zero
//Установка предделителя частоты тактового сигнала Устанавляваем деление на 2 что бы не перегревать процесор.
//При прошивки во fuches надо учитывать что мы здесь выставили. В данном случаи этот параметр можно и не трогать.
ldi R16, (1<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)|(0<<CLKPS0);
out CLKPR, R16;
ldi R16, (0<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(1<<CLKPS1)|(0<<CLKPS0);
out CLKPR, R16;
//Отключаем аналогово-цифровой преобразователь
CBI ADCSRA, ADEN;
//Отключение компаратора
//запрещает прерывание от компаратора;
//Команда сбрасывает значение в 0 регистра ACSR ячейки ACIE.
CBI ACSR, ACIE;
////Команда устанавливает значение в 1 регистра ACSR ячейки ASD что выключает компаратор;
SBI ACSR, ACD;
//инициализация портов ввода вывод
//уствнввливаем работу на срабатывания прерывания
ldi R16, (1<<INT0);
out GIMSK, R16;
//порт на высокий уровень сигнала
ldi R16, (1<<ISC01)|(1<<ISC00);
out MCUCR, R16;
//Устанавливаем работу партов на вход и выход.
//Если порт DDB установлен в 1 то данный порт является выходам,
//а если в 0 то входам.
ldi R16,(0<<DDB5)|(1<<DDB4)|(0<<DDB3)|(0<<DDB2)|(0<<DDB1)|(0<<DDB0);
out DDRB, R16;
//Включаем подтягивающий резистор
ldi R16, (1<<PB1);
out PORTB, R16;
/*Конфигурация портов */
sei;//Разрешаем глобальные прерывания
rjmp START1;
START1:
clz; //Очистить флаг в 0 в регистре SREG;
cpi XXX, 254; сравнение чисел если равны то Z флаг установиться;
BREQ prodTime; Условный переход если Z=0;
nop;
rjmp START1;
prodTime:
mov xxx, zero;
inc timeprod; //переменная для увелечения работы времени таймера.
//сравниваем не останавливать ли таймер
clz; //Очистить флаг в 0 в регистре SREG;
cpi timeprod, 10;
BREQ timeoute;
/*Переходим в программу для остановки
таймера и отключения порта питания */
rjmp start1;
timeoute:
/*Отключаем работу таймера*/
ldi R16, (0<<OCIE0A);Установка по совпадению с А отключаем.;
out TIMSK0, R16;
/*Отключаем порт выхода сигнала,
на транзистор прикуривателя*/
ldi R16,(0<<PB4)|(1<<PB1);
out PORTB, R16;
/*Очищаем переменную timeprod*/
mov timeprod, zero;
/*Подключаем прерывания от ножки микроконтролера int0*/
ldi R16, (1<<INTF0); /скидываем флаги прерывания
out GIFR, R16;
ldi R16, (1<<INT0);
out GIMSK, R16;
//Включаем глобальное прерывания
sei;
rjmp start1;
Код: Выделить всё
SBI DDRB,1
SBI PORTB,1
CBI DDRB,1
//инициализация портов ввода вывод
//уствнввливаем работу на срабатывания прерывания
; ldi R16, (1<<ISC01);|(1<<ISC00);
; out MCUCR, R16;
ldi R16, (1<<INT0);
out GIMSK, R16;
OUT GIFR,R16
; ldi R16, (1<<PB1);
; out PORTB, R16;
/*Конфигурация портов */
Код: Выделить всё
.include "tn13Adef.inc"
.def XXX=R20;// Команда для переименования регистров.
.def timeprod=R21;
.def zero=R22;
;.list; // Отоброжения листинга исполнения команды.
.cseg; работаем с програмной памятью а не озу или eeprom
.org 0; устанавливаем начальную позицию строки
rjmp START; Reset Handler
rjmp obrobotkaINT0; IRQ0 Handler
rjmp START; PCINT0Z Handler
rjmp START; Timer0 Overflow Handler
rjmp START; EEPROM Ready Handler
rjmp START; Analog Comparator Handler
rjmp obrobotkaTIM0_COMPA; TIM0_COMPA CompareA Handler
rjmp START; Timer0 CompareB Handler
rjmp START; Watchdog Interrupt Handler
rjmp START; ADC Conversion Handler
//броботка прерывания порта INT0, по высокому сигналу.
obrobotkaINT0:
//Отключаем работу на срабатывания прерывания
; ldi R16, (0<<INT0);
out GIMSK,ZERO;
//скидываем фдлаг если имеется
;ldi R16, (1<<INTF0); /скидываем флаги прерывания
;out GIFR, R16;
//Подключаем нужный нам порт.
ldi R16, (1<<PB4)|(1<<PB1);
out PORTB, R16;
//RCALL TIMER; //Относительный вызов подпрограммы TIMER.
RCALL TIMER;
nop;
reti; //команда выхода из оброботчика прерывания.
//Прерывания при совапдении таймера
obrobotkaTIM0_COMPA:
inc XXX;
reti;
/*Код установки таймера счетчика*/
TIMER:
/*
http://avrprog.blogspot.com/2013/03/t0-8.html
TIFR0 - регистр индикации флагов прерывания
TOV0 - флаг индикации по переполнению таймера
OCF0A,OCF0B - флаг индикации по совпадению.
OCR0A,OCR0B - регистр установки значения для совпадения.
TCCR0A - регистр управления A;
TCCR0B - регистр управления B;
*TIMSK0 - Регистр выбора режима срабатывания прерывания
TOIE0 - по переполнению, OCIE0A - по совпадению со значанием в регистре А,
OCIE0B - по совпадению со значанием в регистре B.
*/
; ldi R16, 0x00;// Сбрасываем все флаги таймера
; out TIFR0, R16;
ldi R16, 0xFF; Устанавливаем значение при совпадении с А
out OCR0A, R16;
ldi R16, (1<<OCIE0A);Установка режима по совпадению с А;
out TIMSK0, R16;
out TIFR0, R16
/*Скорость работы микроконтролера*/
ldi R16,(1<<CS00);
; ldi R16, (1<<CS02)|(0<<CS01)|(1<<CS00);
out TCCR0B, R16;
//Присваем значение переменной 0, для упрощения дальнейшего применения
ret; //возврат из подпрограммы TIMER:
//Определяем начальные параметры микроконтролера.
START:
; CLI; команда запрещает глобальные прерывания.
//инициализация стэка.(установка максимально размера ОЗУ);
; ldi R17, RAMEND;
; out SPL, R17;
ldi zero, 0x00; //Присваеваем значение 0 переменной zero
//Установка предделителя частоты тактового сигнала Устанавляваем деление на 2 что бы не перегревать процесор.
//При прошивки во fuches надо учитывать что мы здесь выставили. В данном случаи этот параметр можно и не трогать.
; ldi R16, (1<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(0<<CLKPS1)|(0<<CLKPS0);
; out CLKPR, R16;
; ldi R16, (0<<CLKPCE)|(0<<CLKPS3)|(0<<CLKPS2)|(1<<CLKPS1)|(0<<CLKPS0);
; out CLKPR, R16;
//Отключаем аналогово-цифровой преобразователь
;CBI ADCSRA, ADEN;
//Отключение компаратора
//запрещает прерывание от компаратора;
//Команда сбрасывает значение в 0 регистра ACSR ячейки ACIE.
;CBI ACSR, ACIE;
////Команда устанавливает значение в 1 регистра ACSR ячейки ASD что выключает компаратор;
SBI ACSR, ACD;
//порт на высокий уровень сигнала
; ldi R16, (1<<ISC01)|(1<<ISC00);
; out MCUCR, R16;
//Устанавливаем работу партов на вход и выход.
//Если порт DDB установлен в 1 то данный порт является выходам,
//а если в 0 то входам.
SBI DDRB,4
; ldi R16,(1<<DDB4)
; out DDRB, R16;
//Включаем подтягивающий резистор
;
SBI DDRB,1
SBI PORTB,1
CBI DDRB,1
//инициализация портов ввода вывод
//уствнввливаем работу на срабатывания прерывания
; ldi R16, (1<<ISC01);|(1<<ISC00);
; out MCUCR, R16;
ldi R16, (1<<INT0);
out GIMSK, R16;
OUT GIFR,R16
; ldi R16, (1<<PB1);
; out PORTB, R16;
/*Конфигурация портов */
sei;//Разрешаем глобальные прерывания
; rjmp START1;
START1:
; clz; //Очистить флаг в 0 в регистре SREG;
cpi XXX, 254; сравнение чисел если равны то Z флаг установиться;
BRNE START1
; BREQ prodTime; Условный переход если Z=0;
; nop;
; rjmp START1;
prodTime:
mov xxx, zero;
inc timeprod; //переменная для увелечения работы времени таймера.
//сравниваем не останавливать ли таймер
;clz; //Очистить флаг в 0 в регистре SREG;
cpi timeprod, 10;
BRNE start1
; BREQ timeoute;
/*Переходим в программу для остановки
таймера и отключения порта питания */
; rjmp start1;
timeoute:
/*Отключаем работу таймера*/
ldi R16, (0<<OCIE0A);Установка по совпадению с А отключаем.;
out TIMSK0, R16;
/*Отключаем порт выхода сигнала,
на транзистор прикуривателя*/
ldi R16,(0<<PB4)|(1<<PB1);
out PORTB, R16;
/*Очищаем переменную timeprod*/
mov timeprod, zero;
/*Подключаем прерывания от ножки микроконтролера int0*/
; ldi R16, (1<<INTF0); /скидываем флаги прерывания
;out GIFR, R16;
ldi R16, (1<<INT0);
out GIMSK, R16;
out GIFR, R16;
//Включаем глобальное прерывания
;sei;
rjmp start1;
.EXIT
Код: Выделить всё
.MACRO TEST
.if @0 != R20
...
.ENDM
;Запуск
TEST R16