Как-то вот по реализации ШИМ на AVR на ассемблере в гугле нашел только статейку с изиелектроникс, но не особо она мне разъяснила интересующие меня вопросы
Необходимо реализовать 4-х канальный ШИМ, для начала на меге 32
период импульсов 20мс исходя из это предположил что необходимо делать ШИМ на основе СТС (хотя могу и ошибаться)
коэффициент заполнения должен меняться исходя из положения переменных резисторов.
Вторую часть пока можно не разъяснять, планирую сначала вручную вводить его так сказать, сделать что б работало так, а после подключать уже ацп.
В общем как реализовать первую часть?
1. Настроить таймер на прерывания с периодом 20мс/разрядность ШИМ.
2. Завести четыре переменных для хранения коэффициентов заполнения.
3. Завести переменную счётчик с требуемой разрядностью ШИМ.
4. По каждому прерыванию увеличивать показания счётчика на единицу (при переполнении обнулять).
5. Если в текущем прерывании счётчик =0, то включить все четыре ключа.
6. Сравнить счётчик поочерёдно с коэффициентами заполнения и если счётчик>=К, то выключить соответствующий ключ.
Если принять разрядность = 8 бит, то прерывания должны следовать с периодом 20мс/256 = 0,0000781 с.
Если Мега работает на частоте 8 МГц, то один такт длится 0,000000125 с.
Следовательно прерывания должны следовать каждые 0,0000781/0,000000125=625 тактов.
При использовании 16-битного таймера нужно записать в OCRxA значение 625, переключить таймер в режим CTC по сравнению А и включить прерывание по совпадению с А.
Если использовать все 3 таймера, то 4 канала ШИМа найдется.
Но это больше из пушки по воробьям.
На тех частотах, которые надо вам, программный ШИМ именно оно.
считывание данных с ацп, можно будет поместить как раз где-нибудь после каждого периода ШИМ сигнала, правильно понимаю? они не добавят большой задержки?
Прерывание АЦП? Используйте его и будет вам счастье.
Минимальная активность в прерываниях, и проблем с задержками и потерей данных по интерфейсах не будет. Вычитали нужные регистры, установили флаги и покидаем прерывание
Да какие там могут быть опасения и сбои ?
ШИМы - программно на одном таймере.
АЦП спокойненько читаем в основном цикле, со всеми расчётами и преобразованиями. Прочитали, преобразовали в попугаи, обновили задающие скважность переменные.
Не думаю, что ТС'у нужна бешеная скорость чтения АЦП, ибо скважность, зависимая от АЦП, будет меняться максимум через 20 мс.
Задача, обслуживающая ШИМы, в этом случае, боооолее приоритетнее задачи преобразования АЦП.
Андрей СШ писал(а):Прерывания выполняются в порядке - кто первый встал того и тапки, а приоритет имеет значения только если два прерывания возникли одновременно.
Вот два абзаца из даташита:
Спойлер
The lowest addresses in the program memory space are by default defined as the Reset and Interrupt vectors. The complete list of vectors is shown in “Interrupts” on page 59. The list also determines the priority levels of the different interrupts. The lower the address the higher is the priority level. RESET has the highest priority, and next is INT0 – the External Interrupt Request 0.
Similarly, if one or more interrupt conditions occur while the global interrupt enable bit is cleared, the corresponding interrupt flag(s) will be set and remembered until the global interrupt enable bit is set, and will then be executed by order of priority.
Если ждут обработки два прерывания (таймер и АЦП), то первым - по праву более высокого приоритета - выполнится таймер.
А чтобы не было проблем с "гуляньем" ШИМ, не надо долго задерживаться в прерывании от АЦП. Считали результат, флаг взвели и убежали.
Можно, конечно, разрешить прерывания внутри прерывания от АЦП (извините за тавтологию ). Тогда таймер будет его тупо прерывать. Но вложенные прерывания еще то удовольствие, без крайней необходимости, я бы с ними не связывался.
не получается по прерыванию сравнения переходить в обработчик прерывания. наверное не правильно оформляю таблицу прерываний, но тогда не понимаю как правильно, подскажите где лажа
Спойлер
.include "m32def.inc"
.cseg
.org 0
rjmp Reset
rjmp INT_0
rjmp INT_1
rjmp INT_2
rjmp TIMER2_COMP
rjmp TIMER2_OVF
rjmp TIMER1_CAPT
rjmp TIMER1_COMPA
rjmp TIMER1_COMPB
rjmp TIMER1_OVF
rjmp TIMER0_COMP
rjmp TIMER0_OVF
rjmp UART_RX
rjmp UART_UDRE
rjmp UART_TX
rjmp ANA_COMP
.org INT_VECTORS_SIZE
;Reset:
INT_0:
INT_1:
INT_2:
TIMER2_COMP:
TIMER2_OVF:
TIMER1_CAPT:
TIMER1_COMPA:
TIMER1_COMPB:
TIMER1_OVF:
;TIMER0_COMP:
TIMER0_OVF:
UART_RX:
UART_UDRE:
UART_TX:
ANA_COMP:
reti
reset:
ldi r16, low(ramend)
out spl,r16
ldi r16, high(ramend)
out sph,r16
ldi r16, 0b00001001
out tccr0, r16
ldi r16, 10
out ocr0, r16
ldi r16, 0b00000010
out timsk, r16
out tifr, r16
sei
main:
rjmp main
Timer0_comp:
;cod
reti
сейчас пытался добиться, что бы при значении счетчика таймера 0, равном 10, переходило в соответствующий обработчик, последний блок в коде, по итогу переходит на какое-то другое прерывание, только не понимаю на какое
// Таблица прерываний вынесена для удобства.
;=== BEGIN "ivectors.inc" ==============
; Тут располагается "таблица векторов на обработчики прерываний" - важнейшая вещь!
; Если про нее забыть, то можно огрести такие неразрешимые глюки, что просто капец. Так что не забываем...
; (Вынесено из общего кода в отдельный файл - для облегчения портирования программы на другой камень...)
;
; КАК СДЕЛАТЬ:
; Скопировать секцию "INTERRUPT VECTORS" из HAL-файла Микроконтроллера (например, "tn85def.inc"),
; Заменить все ".equ" на ".org"... и дописать ко всем точкам входа команду RETI.
; (Это на тот случай, если Прерывание случайно вылезет - чтобы вернуть управление туда, откуда прервалось.)
; ***** INTERRUPT VECTORS ************************************************
; Используем HAL Микроконтроллера "ATmega88PA"
.org INT0addr ; External Interrupt Request 0
reti
.org INT1addr ; External Interrupt Request 1
reti
.org PCI0addr ; Pin Change Interrupt Request 0
reti
.org PCI1addr ; Pin Change Interrupt Request 1
reti
.org PCI2addr ; Pin Change Interrupt Request 2
reti
.org WDTaddr ; Watchdog Time-out Interrupt
reti
.org OC2Aaddr ; Timer/Counter2 Compare Match A
reti
.org OC2Baddr ; Timer/Counter2 Compare Match B
reti
.org OVF2addr ; Timer/Counter2 Overflow
reti
.org ICP1addr ; Timer/Counter1 Capture Event
reti
.org OC1Aaddr ; Timer/Counter1 Compare Match A
reti
.org OC1Baddr ; Timer/Counter1 Compare Match B
reti
.org OVF1addr ; Timer/Counter1 Overflow
reti
.org OC0Aaddr ; TimerCounter0 Compare Match A
reti
.org OC0Baddr ; TimerCounter0 Compare Match B
reti
.org OVF0addr ; Timer/Couner0 Overflow
reti
.org SPIaddr ; SPI Serial Transfer Complete
reti
.org URXCaddr ; USART Rx Complete
RJMP RX_OK
.org UDREaddr ; USART, Data Register Empty
RJMP UD_OK
.org UTXCaddr ; USART Tx Complete
RJMP TX_OK
.org ADCCaddr ; ADC Conversion Complete
RJMP ADC_OK
.org ERDYaddr ; EEPROM Ready
reti
.org ACIaddr ; Analog Comparator
reti
.org TWIaddr ; Two-wire Serial Interface
reti
.org SPMRaddr ; Store Program Memory Read
reti
.org INT_VECTORS_SIZE ; size in words <<Конец таблицы прерываний>>
;=== END "ivectors.inc" ================