Кстати, можно не подпаиваться к микросхеме чтобы получить доступ к сигналам BitBang - можно взять обычные швейные или канцелярские иголки и наколхозить конструкцию так чтобы они держались с упором на нужные выводы - время жизни такой конструкции = времени на программирование одного контроллера под программатор. Потом конструкцию из иголок и подпорок разбираешь и забываешь как страшный сон.
Теория и практика AVR ассемблера.
Не, че... нормально на безрыбье и рак рыба. Как вспомню веселые времена, когда еще контроллеров небыло а была 537РФ5, 537Ру2 и Z80... при отсутствии программатора и компилятора вполне можно писать программы. Правда любой сбой - набивай программу сначала... А потом принцип матрешки - вручную набиваешь программу которая позволит прошить чистую 537РФ5(для режима прошивки надо только 20 вольт подать) и заносишь туда при помощи 16 кнопок и схемы на логике в 15-ричном виде программу, которая позволит организовать более простой ввод кодов и программирование и пошло поехало... Дошел до подключения ЖК индикатора на 8 строк 20 символов, и уже было пытался подключить винчестер... но там не срослось по электрической части, он даже стартовать не хотел на наколхозенных проводках - слишком высоки пусковые токи. И так все забросилось. Оно даже досихпор работает.
Кстати, можно не подпаиваться к микросхеме чтобы получить доступ к сигналам BitBang - можно взять обычные швейные или канцелярские иголки и наколхозить конструкцию так чтобы они держались с упором на нужные выводы - время жизни такой конструкции = времени на программирование одного контроллера под программатор. Потом конструкцию из иголок и подпорок разбираешь и забываешь как страшный сон.
Кстати, можно не подпаиваться к микросхеме чтобы получить доступ к сигналам BitBang - можно взять обычные швейные или канцелярские иголки и наколхозить конструкцию так чтобы они держались с упором на нужные выводы - время жизни такой конструкции = времени на программирование одного контроллера под программатор. Потом конструкцию из иголок и подпорок разбираешь и забываешь как страшный сон.
- Реклама
Да. 3-рядный разъем -- под монитор.АндрейАвербах писал(а):Слева на право?
Я ж туда флэшки втыкаю4 - не знаю
А, и как заставить аврстудию 6 выполнить действие 50176 раз (нужно для прерывания)?
Jack_A, USB не признали, хоть он и кверху ногами4 - не знаю
Какое такое действие??? Вам цикл что ли нужно 50176 раз выполнить? И причем тут прерывание, поподробнее...АндрейАвербах писал(а):А, и как заставить аврстудию 6 выполнить действие 50176 раз (нужно для прерывания)?
Меня смутили 2 пружинки-защелки, думаю : у USB не может быть 2 контакта! А на бочок своего бука лень было взглянуть. Позор на мою седую лысину ! Только нерезкость фото меня может реблитировать.Engineer_Keen писал(а): Jack_A, USB не признали, хоть он и кверху ногами![]()
?
Итак, это USB.
---------------------
-- Кто сказал вчера, что вода кипит при 100 градусах ?
-- Я.
-- Правильно, Вовочка. А 90 градусов, дети, -- это прямой угол.
- Реклама
Ночью пришла мне в голову идея, заключается она в следующем: контроллер может делать ШИМ, а я слышал, что с помощью ШИМ можно воспроизводить различные звуки, а если можно воспроизводить звуки, значит можно сделать синтезатор речи аля говорящий компьютер.
Как-то так.
Кто-то уже пробовал что-либо подобное? И моя идея вообще осуществима?
Вот короче код
Кто-то уже пробовал что-либо подобное? И моя идея вообще осуществима?
Ну, есть программка, которая должна одновременно мигать светодиодом, и следить за состоянием входа, как только на входе 1, зажечь диод на другой ножке. Главный светодиод мигает независимо от обстановки. Для того, чтобы мигать светодиодом я использую прерывание таймера, 50176, время задержки в микросекундах, тут я малян ошибся. \Какое такое действие??? Вам цикл что ли нужно 50176 раз выполнить? И причем тут прерывание, поподробнее...
Вот короче код
Код: Выделить всё
.org 0x0000 ;вектора прерываний
rjmp Reset
.org 0x0001
rjmp EXT_INT0
.org 0x0002
rjmp PCINT
.org 0x0003
rjmp TIM0_OVF
.org 0x0004
rjmp EE_RDY
.org 0x0005
rjmp ANA_COMP
.org 0x0006
rjmp TIM0_COMPA
.org 0x0007
rjmp TIM0_COMPB
.org 0x0008
rjmp WATCHDOG
.org 0x0009
rjmp ADC_
;Reset:
EXT_INT0:
PCINT:
TIM0_OVF:
EE_RDY:
ANA_COMP:
;TIM0_COMPA:
TIM0_COMPB:
WATCHDOG:
ADC_:
RETI
TIM0_COMPA:
com R19
breq l
ldi R20, 0b000000
mov R21, R20
add R21, R18
out PORTB, R21
rjmp e
l: ldi R20, 0b000001
mov R21, R20
add R21, R18
out PORTB, R21
e: ldi R16, 0 ;обнуление таймера
out TCNT0, R16
reti
Reset: ldi R16, low(ramend)
out SPL, R16
ldi R16, 0b101111
out DDRB, R16
ldi R16, 0x04 ;разрешение прерываний компаратора
out TIMSK0, R16
ldi R16, 0b00000100 ;выбор частоты счетчика
out TCCR0B, R16
ldi R16, 0b11000100 ;число для сравнения
out OCR0A, R16
ldi R16, 0 ;обнуление таймера
out TCNT0, R16
ldi R19, 0b11111111
sei
st1:
in R17, PINB
lsr R17
lsr R17
lsr R17
lsr R17
cpi R17, 0b000001
breq n1
cpi R18, 0b001000
brne n
CLR R18
mov R22, R18
add R22, R20
out PORTB, R22
rjmp n
n1: rcall led
n:
rjmp st1
led: ldi R18, 0b001000
mov R22, R18
add R22, R20
out PORTB, R22
retОййй, ёёёёёё...

А главная программа не глючит?
Ладно, не буду томить.
При входе в обработчик прерывания надо сохранять состояние регистров, а при выходе восстанавливать.
У AVR-ок при входе в прерывание сохраняется только адрес возврата. Остальное надо в коде делать.
Даже если у вас регистры строго распределены между основной программой и прерыванием, то остаётся регистр состояния SREG, который, как правило, надо сохранять и восстанавливать.
Вот пример.Есть, конечно, случаи, когда можно и sreg не сохранять. Но это отдельная тема.
Код действительно короче.АндрейАвербах писал(а):Вот короче код
А главная программа не глючит?
Ладно, не буду томить.
При входе в обработчик прерывания надо сохранять состояние регистров, а при выходе восстанавливать.
У AVR-ок при входе в прерывание сохраняется только адрес возврата. Остальное надо в коде делать.
Даже если у вас регистры строго распределены между основной программой и прерыванием, то остаётся регистр состояния SREG, который, как правило, надо сохранять и восстанавливать.
Вот пример.
Спойлер
Код: Выделить всё
TIM0_COMPA:
push r0 ; сохраняем в стэк r0
in r0,SREG ; загружаем sreg
push r0 ; сохраняем в стэк sreg
push r1 ; сохраняем другие регистры если необходимо
push r2
; основной код обработчика
pop r2 ;восстанавливаем из стэка (в обратном порядке !!!)
pop r1
pop r0
out SREG, r0
pop r0
reti
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Да вроде не глючит, в симуляторе работает как надо, программатор недельки через две придет, проверю в железе.
Есть еще такой вариант.
Есть еще такой вариант.
Код: Выделить всё
ldi R16, 0b101111
out DDRB, R16
ldi R16, low (ramend)
out SPL, R16
clr R23
clr R25
ldi R24, 0b11111111
st1: in R17, PINB
lsr R17
lsr R17
lsr R17
lsr R17
cpi R17, 0b000001
brne m
rcall led
rjmp e
m: clr R18
mov R22, R20
add R22, R18
out PORTB, R22
e: dec R23
brne st1
dec R25
brne st1
rcall stroboskop
rjmp st1
led:
ldi R18, 0b001000
mov R22, R20
add R22, R18
out PORTB, R22
ret
stroboskop:
com R24
cpi R24, 0b00000000
brne s2
ldi R20, 0b000001
mov R22, R18
add R22, R20
out PORTB, R22
rjmp en
s2: ldi R20, 0b000000
mov R22, R18
add R22, R20
out PORTB, R22
en: ret
Если вы не сохраняете состояние регистров используемых в коде, который может быть прерван работой прерывания, то, независимо от "варианта", это потенциальный источник глюков.
Это понятно или пример нужен?
Это понятно или пример нужен?
Последний раз редактировалось Kavka Пт май 31, 2013 07:41:13, всего редактировалось 1 раз.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Синус с частотой F/256/128АндрейАвербах писал(а):Лучше пример.
F - частота контроллера, 256 - разрешение таймера (8 бит), частота квантования получается 8МГц/256=31250 Гц
128 - число семплов, частота синуса получается 31250/128=244Гц
Спойлер
Код: Выделить всё
.include "tn2313def.inc"
.macro OUTI ;просто для сокращения размера кода
LDI R16,@1
OUT @0,R16
.endm
.cseg
.org 0
RJMP START ;RESET
.org OVF0addr
RJMP SND_OUT ;T0 OVERFLOW
//-------------------Program start----------------//
START:
LDI R16,low(ramend);стек
OUT SPL,R16
SBI DDRB,PB2 ;PB2 - выход
OUTI TCCR0A,(1<<COM0A1)|(1<<WGM01)|(1<<WGM00) ;режим FastPWM, PB2 вкл при TCNT=0, выкл в TCNT=OCR0A
OUTI TCCR0B,(1<<CS00) ;делитель=1
OUTI TIMSK,(1<<TOIE0) ;вкл прерывание по переполнению таймера0
LDI ZL,low(sine*2) ;загружаем в ZH:ZL адрес начала таблицы
LDI ZH,high(sine*2)
SEI ;включаем прерывания
LOOP: RJMP LOOP ;ничего не делаем
SND_OUT:LPM R16,Z+ ;в прерывании читаем семпл из флеша
OUT OCR0A,R16 ;выводим в PWM
CBR ZL,0x80; делаем так чтобы адрес был в пределах таблицы: (SINE) ~ (SINE+128)
LDI ZH,high(sine*2)
RETI
.org 0x0100
SINE: ;таблица семплов синуса, 128 штук
.DB 0x80,0x86,0x8c,0x92,0x98,0x9f,0xa5,0xab,0xb0,0xb6,0xbc,0xc1,0xc7,0xcc,0xd1,0xd5
.DB 0xda,0xde,0xe2,0xe6,0xea,0xed,0xf0,0xf3,0xf5,0xf7,0xf9,0xfb,0xfc,0xfd,0xfe,0xfe
.DB 0xfe,0xfe,0xfe,0xfd,0xfc,0xfa,0xf8,0xf6,0xf4,0xf1,0xef,0xeb,0xe8,0xe4,0xe0,0xdc
.DB 0xd8,0xd3,0xce,0xc9,0xc4,0xbf,0xb9,0xb3,0xae,0xa8,0xa2,0x9c,0x95,0x8f,0x89,0x83
.DB 0x7c,0x76,0x70,0x6a,0x63,0x5d,0x57,0x51,0x4c,0x46,0x40,0x3b,0x36,0x31,0x2c,0x27
.DB 0x23,0x1f,0x1b,0x17,0x14,0x10,0x0e,0x0b,0x09,0x07,0x05,0x03,0x02,0x01,0x01,0x01
.DB 0x01,0x01,0x02,0x03,0x04,0x06,0x08,0x0a,0x0c,0x0f,0x12,0x15,0x19,0x1d,0x21,0x25
.DB 0x2a,0x2e,0x33,0x38,0x3e,0x43,0x49,0x4f,0x54,0x5a,0x60,0x67,0x6d,0x73,0x79,0x80
1) воспроизведение сигнала по таблице или какой-либо формуле - тогда много памяти не нужно, так работают простые синтезаторы, генераторы, музыкальные шкатулки, звонки и прочее.
2) воспроизведение ранее записанного сигнала из файла - тут нужна память размером с длину файла, так работают WAV-плееры, диктофоны, в т.ч. и для синтезатора речи придется скорее всего использовать этот способ
Т.е. МР3 не существует в природе ? Можно хранить в формате МР3, но для раскодировки МР3 нужен быстрый процессор. Зато памяти нужно меньше.
Лучше показать на примере.Kavka писал(а):Если вы не сохраняете состояние регистров используемых в коде, который может быть прерван работой прерывания, то, независимо от "варианта", это потенциальный источник глюков.
Это понятно или пример нужен?
Вроде исправил.
Код: Выделить всё
ldi R16, 0b101111
out DDRB, R16
ldi R16, low (ramend)
out SPL, R16
clr R23
clr R25
ldi R24, 0b11111111
st1: in R17, PINB
lsr R17
lsr R17
lsr R17
lsr R17
cpi R17, 0b000001
brne m
rcall led
rjmp e
m: clr R18
mov R22, R20
add R22, R18
out PORTB, R22
e: dec R23
brne st1
dec R25
brne st1
rcall stroboskop
rjmp st1
led:
ldi R18, 0b001000
mov R22, R20
add R22, R18
out PORTB, R22
ret
stroboskop:
in R26, SREG
push R26
com R24
cpi R24, 0b00000000
brne s2
ldi R20, 0b000001
mov R22, R18
add R22, R20
out PORTB, R22
rjmp en
s2: ldi R20, 0b000000
mov R22, R18
add R22, R20
out PORTB, R22
pop R26
out SREG, R26
en: ret
Последний раз редактировалось АндрейАвербах Пт май 31, 2013 11:02:46, всего редактировалось 1 раз.
MP3 тоже относится к 2му типу, только помимо памяти нужно еще и кодек подключать, речь-то про AVR, а его для раскодировки не хватит. То же самое касается и OGG и остальных форматов, не перечислять же их все...
Допустим внезапно между строками ROR R16-ROR R17 случилось прерывание, когда ROR R16 дало 0 в R16 и 1 в C:
Если в результате прерывания С сбросится, то все огни потухнут, так как ROR R17 даст 0
Обратная ситуация, прерывание между ROR-ROR возникло при С=0 и в результате С стало 1 - будут бегать лишние огни.
Представим простейший бегущий огонь на 16 ног (код дан отрывками):АндрейАвербах писал(а): Лучше показать на примере.
Код: Выделить всё
SEI
LDI R16,0x80 ;горит крайний левый диод
LDI R17,0x00
OUT PORTA,R16 ;выводим в порты
OUT PORTB,R17
LOOP:
ROR R16 ;сдвигаем бит вправо через флаг C
ROR R17
OUT PORTA,R16 ;выводим в порты
OUT PORTB,R17
RCALL DELAY ;ждем допустим 1 сек
RJMP LOOP
Код: Выделить всё
INT0_IRQ:
CP R1,R2 ;сравниваем какие-то регистры
BRNE LESS ;все, теперь флаг С зависит от результата операции CP
NOP
LESS:
NOP
RETI
Обратная ситуация, прерывание между ROR-ROR возникло при С=0 и в результате С стало 1 - будут бегать лишние огни.
Последний раз редактировалось Engineer_Keen Пт май 31, 2013 11:13:38, всего редактировалось 1 раз.
Пример.
Самый простой. Допустим в основной программе задействованы абсолютно все регистры. Что будете делать в прерывании?
Ещё один.
Обработчик прерывания регистры не сохраняет и не восстанавливает.
И пусть в конце работы он оставляет установленным флаг С.
Главная программа.
Например вы складываете два 4х байтных числа:
Оба равны 1.
add r0,r4 ; 1+1=2, С=0
adc r1,r5 ; 0+0+C=0, С=0
adc r2,r6 ; 0+0+C=0, С=0
adc r3,r7 ; 0+0+C=0, С=0
Результат 0x00000002 - правильно.
А теперь всё тоже самое, но происходит прерывание между любыми из этих инструкций на выходе которого установлен флаг С.
add r0,r4 ; 1+1=2, С=0
adc r1,r5 ; 0+0+C=0, С=0
; прерывание после которого C=1
adc r2,r6 ; 0+0+C=1, С=0
adc r3,r7 ; 0+0+C=0, С=0
Результат 0x00010002 = 6553810
Самый простой. Допустим в основной программе задействованы абсолютно все регистры. Что будете делать в прерывании?
Ещё один.
Обработчик прерывания регистры не сохраняет и не восстанавливает.
И пусть в конце работы он оставляет установленным флаг С.
Главная программа.
Например вы складываете два 4х байтных числа:
Оба равны 1.
add r0,r4 ; 1+1=2, С=0
adc r1,r5 ; 0+0+C=0, С=0
adc r2,r6 ; 0+0+C=0, С=0
adc r3,r7 ; 0+0+C=0, С=0
Результат 0x00000002 - правильно.
А теперь всё тоже самое, но происходит прерывание между любыми из этих инструкций на выходе которого установлен флаг С.
add r0,r4 ; 1+1=2, С=0
adc r1,r5 ; 0+0+C=0, С=0
; прерывание после которого C=1
adc r2,r6 ; 0+0+C=1, С=0
adc r3,r7 ; 0+0+C=0, С=0
Результат 0x00010002 = 6553810
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Для проверки в начале каждой подпрограммы, в т.ч. прерывании нужно камент написать, какие ресурсы используются, и какие при этом "портятся", а потом пройтись по всей программе и проверить, чтобы ресурсы не пересекались (если конечно это не предусмотрено целью программы).
пример:
Совет: беречь регистры начиная с R26, так как они используются для 16-битной адресации (X, Y, Z), например в коде выше можно R26 заменить на R22, а R22 на один из младших регистров R0-R15
Совет2: после com сравнивать с 0 не обязательно, com сам ставит флаг Z если надо (команда BRNE проверяет именно флаг Z), таким образом с R24 снимается ограничение на использование только старшей половины регистров (команда cpi работает только с ними) и вместо него можно взять более дешевые R0-R15
совет3: если есть лишний регистр, который вообще нигде в программе не используется, можно использовать для сохранения SREG его во всех подпрограммах, тогда не нужно его каждый раз PUSH-POP-ить (каждый PUSH или POP - это 2 такта и отъединение одного байта от ОЗУ)
пример:
Код: Выделить всё
led: ;используется: R20, ломается: R18,R22,SREG
ldi R18, 0b001000
mov R22, R20
add R22, R18
out PORTB, R22
ret
stroboskop: Используется:R18, SREG, ломается:R20,R22,R24,R26
in R26, SREG
push R26
com R24
cpi R24, 0b00000000
brne s2
ldi R20, 0b000001
mov R22, R18
add R22, R20
out PORTB, R22
rjmp en
s2: ldi R20, 0b000000
mov R22, R18
add R22, R20
out PORTB, R22
pop R26
out SREG, R26
en: ret
Совет2: после com сравнивать с 0 не обязательно, com сам ставит флаг Z если надо (команда BRNE проверяет именно флаг Z), таким образом с R24 снимается ограничение на использование только старшей половины регистров (команда cpi работает только с ними) и вместо него можно взять более дешевые R0-R15
совет3: если есть лишний регистр, который вообще нигде в программе не используется, можно использовать для сохранения SREG его во всех подпрограммах, тогда не нужно его каждый раз PUSH-POP-ить (каждый PUSH или POP - это 2 такта и отъединение одного байта от ОЗУ)
Ну упрощенно мою прогу можно представить так:
загрузка
\/
Прочесть состояние входа.
Равно X? Нет ->-
Да |
\/ |
Зажечь светодиод |
Прыгнуть в конец |
Основного цикла |
Погасить светодиод <---
Конец основного цикла: Уменьшить значение регистра-
счетчика
Счетчик равен нулю? Нет--------------
\/ |
Да |
Зажечь(погасить) стробоскоп |
В начало цикла <--------------------
загрузка
\/
Прочесть состояние входа.
Равно X? Нет ->-
Да |
\/ |
Зажечь светодиод |
Прыгнуть в конец |
Основного цикла |
Погасить светодиод <---
Конец основного цикла: Уменьшить значение регистра-
счетчика
Счетчик равен нулю? Нет--------------
\/ |
Да |
Зажечь(погасить) стробоскоп |
В начало цикла <--------------------


