Как пример для 3-го вопроса:
Код: Выделить всё
.include "tn13def.inc"
.equ PWM1=64
.equ PWM2=32
.macro OUTI
LDI R16,@1
OUT @0,R16
.endm
.cseg
RJMP RESET ;RESET
RETI ;INT0
RETI ;PCINT
RETI ;T0_OV
RETI ;EE_RDY
RETI ;ANA_COMP
RETI ;T0=A
RETI ;T0=B
RETI ;WDT
RETI ;ADC
RESET:
OUTI CLKPR,0x80 ;enable CLKPR change
OUTI CLKPR,0x00 ;Clear DIV8
L1: IN R16,OSCCAL ;load current OSCCAL (9.6MHz)
DEC R16 ;slowly change speed
OUT OSCCAL,R16
CPI R16,0x01 ;to 6.4MHz ?
L2: BRNE PC-3
OUTI SPL,low(Ramend) ;set stack
OUTI PORTB,0x00 ;set port
OUTI DDRB,0x03 ;set direction
OUTI TCCR0A,(1<<COM0A1)|(1<<WGM01)|(1<<WGM00)
OUTI TCCR0B,(1<<CS00);set timer prescaler
OUTI OCR0A,PWM1 ;set 1st PWM
OUTI ADCSRA,(1<<ADEN)|(1<<ADATE)|(1<<ADSC)|(1<<ADPS0);enable ADC
LDI R17,0xFF ;set softPWM counter
LOOOOOP:
SBIS ADCSRA,ADIF ;check ADC flag
RJMP LOOOOOP ;idle loop
SBI ADCSRA,ADIF ;clear ADC flag
INC R17 ;increment softPWM counter
BRNE PC+2 ;branch if <>0
SBI PINB,PB1 ;set pin to 1
CPI R17,PWM2 ;compare with PWM2
BRNE LOOOOOP ;go to idle if <>
SBI PINB,PB1 ;clear pin if =
RJMP LOOOOOP ;go to idle
Для тактовой 9.6. Если использовать 6.4, то строки с L1 по L2 не нужны.
Вместо программного делителя - флаг прерывания АЦП, за счет этого программная ШИМ на ноге PB1 получается как раз в 25 раз медленнее чем аппаратная ШИМ на PB0. Вообще тут использование АЦП не совсем оправдано, но для меньших частот можно использовать прерывание АЦП в качестве второго таймера.