_________________ Просто не учи физику в школе, и вся твоя жизнь будет наполнена чудесами и волшебством Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Даже не знаю в какую тему писать но по смыслу сюда. Ни у кого не бывало, что прерывание срабатывает не как положено, например на atmega8 16 битный таймер настроен на срабатывание по переполнению раз в 10 сек, все прекрасно работает. меняешь кварц, соответственно меняешь настройки частоты камня, I2C, UART. И прерывание работает но не так. TCCR1B|=((1<<CS12)|(1<<CS10)); TCNT1=29535; кварц 3,6864МГц, но срабатывает не раз в 10 сек, а в 18, то есть полный перебор с 0. Сделано в атмел студио. Может кто помочь объяснить что не так? Кстати, 8 битный таймер также начал филонить аналогично. TCCR0|=((1<<CS02)|(1<<CS00)); //предделитель 1024, срабатывает раз в (1/3686400)*1024*255=0,0708(3) секунды, для 0,02с нужно записать tcnt0=183 раз в 0,02с ровно; TIMSK |= (1<<TOIE0); // разрешить прерывание по переполнению таймера счетчика 0; TCNT0=183; //начало счета от 183;
Всем спасибо кто ответил. Походу камешек сдох - прописал так: TCNT1 =29535; USART_Transmit(contr); USART_Transmit(TCNT1H); USART_Transmit(TCNT1L); так он переменную правильно передает - а значение регистра равно 0. То есть он просто напросто его не записывает. перезапись, стирание, сброс настроек - не работает. придется попаять. PS 1.Z_h_e - раньше работало и не сбивалось, было все четко. 2.dgrett - СТС - не мое. 3.АСУ - насчет 255 - это относится к таймеру 8 битному, на нем тоже самое.
Потому что тайме будет считать до 65535 и затем обнулится и начнет считать с начала, с нуля, а не с 29535.
Прошу прощенья, вы были правы. Надо вводить при каждом прерывании. Но он, зараза так хорошо работал. Нашел на одном сайте, что TCNT1 =29535; надо вводить в самом начале прерывания, первой строчкой. Теперь все отрабатывает
Всем привет. Я тут пытаюсь разобраться с Timer/Counter1 (ATmega16), режим CTC, вывод OC1A устанавливается в "1", когда TCNT достигнет заданного значения в OCR1A. Пользуюсь AVRStudio 4.06, в железе пока не проверял.
Запускаю счетчик так:
Код:
in temp,TCCR1A sbr temp,0b11000000 ;При совпадении (CTC) вывод OC1A устанавливается в "1" out TCCR1A,temp
ldi temp,$01 out OCR1AH,temp ldi temp,$FF out OCR1AL,temp
in temp,TCCR1B sbr temp,0b00001001 ;Режим CTC. Тактовая частота CK/1 out TCCR1B,temp
Когда счетчик TCNT досчитывает до заданного значения, вывод OC1A устанавливается в "1".
После срабатывания счетчика, запрещаю его работу:
Код:
in temp,TCCR1B cbr temp,0b00001001 ;Обнулить биты out TCCR1B,temp
clr temp out TCNT1H,temp ;Очистить счетчик out TCNT1L,temp
in temp,TIFR sbr temp,0b00010000 ;Сбросить флаг OCF1A out TIFR,temp
Подскажите, как правильно сбрасывать пин PD5 (OC1A)?
cbi PortD,5 - результата не дает. cbi PinD,5 - пин порта сбрасывается. По крайней мере, в AVRStudio...
Следующий код сбрасывает вывод PD5 в ноль:
Код:
in temp,TCCR1A cbr temp,0b11000000 ;Обнулить биты COM1A1 и COM1A0 out TCCR1A,temp
Еще можно принудительно изменить состояние вывода OC1A путем записи "1" в FOC1A регистра TCCR1A, но тогда надо перенастраивать этот TCCR1A... Что-то у меня с этим ничего не получилось. Перенастраивал по-всякому, пин PD5 не сбрасывается.
Вам кодом был показан вариант сброса PD5/OC1A ATmega16. Старые камни или новые не суть. Главное, чтобы была объявлена возможность
Цитата:
Toggling the Pin Writing a '1' to PINxn toggles the value of PORTxn, independent on the value of DDRxn. The SBI instruction can be used to toggle one single bit in a port.
.ORG $0000 RESET: RJMP START ; On Reset .ORG $000C T1_COMP_A: RETI ;************************************************* ;************************************************* ;************************************************* START: LDI ZH,0 LDI ZL,-1 OUT SPH,ZH OUT SPL,ZL
SBI ACSR,ACD ; выключить аналоговый компаратор
SBI DDRD,5
LDI R16,1<<SE OUT MCUCR,R16 ; режим SLEEP IDLE
ldi temp,$01 out OCR1AH,temp ldi temp,$FF out OCR1AL,temp OUT TCCR1A,ZH ;длительность 1 на PD5 30 тактов
LDI R17,1<<COM1A1|1<<COM1A0 OUT TCCR1A,R17
LDI R16,1<<OCIE1A ; прерывания OUT TIMSK,R16 OUT TIFR,R16
LDI R16,1<<WGM12|1<<CS10 ; Fo/1, CTC OUT TCCR1B,R16
WAIT: SEI SLEEP
; OUT TCCR1A,ZH ;длительность 1 на PD5 14 тактов NOP RJMP START .EXIT
Как я понял, пин PD5 вы очищаете так же, как и я - обнулением TCCR1A (+очистка OCF1A), что и требовалось подтвердить. Правда, зачем-то вы используете для этого ZH. У вас в нем всегда 0 что ли?
Код:
ldi temp,$01 out OCR1AH,temp ldi temp,$FF out OCR1AL,temp OUT TCCR1A,ZH ;длительность 1 на PD5 30 тактов
Здесь нет явной записи ZH, т.е. в нем может быть все, что угодно. И что означает "длительность 1 на PD5 30 тактов"? А, наверное, длительность лог. единицы на пине PD5 30 тактов...
Код:
WAIT: SEI SLEEP
; OUT TCCR1A,ZH ;длительность 1 на PD5 14 тактов NOP RJMP START .EXIT
А тут что означает "длительность 1 на PD5 14 тактов"? Ок, тут тоже тогда понятно.
И много лишнего в этом коде - запрещение аналогового компаратора, режим сна, прерывания. Спасибо, конечно, но я всего этого не просил. Я стараюсь более понятно писать, чтобы можно было понять свою же программу спустя годы. И уж тем более, если придется кому-то свой код показать. Я вот МК не занимался более 10 лет и сейчас, просматривая свои программы начала 2000-х, очень самому себе благодарен за понятные комментарии, оставленные тогда к разным участкам кода. У каждого своя манера писать код, и легче написать свой, чем разобраться в чужом.
А стек я вот так назначаю (в конце SRAM):
Код:
ldi temp,high(RAMEND) ;назначить стек out SPH,temp ldi temp,low(RAMEND) out SPL,temp
;Временная задержка (1.011491 сек) на 4 МГц Tim_dl: ldi r20,$15 ldi r21,$A9 ldi r22,$18 D_r_1x: dec r22 brne D_r_1x ldi r22,$FF dec r21 brne D_r_1x ldi r21,$FF dec r20 brne D_r_1x
;*********************************** ;Запретить и обнулить Timer/Counter1
ldi r16,(0<<WGM12)|(0<<CS12)|(0<<CS10) out TCCR1B,r16
ldi r16,(0<<COM1A1)|(0<<COM1A0) out TCCR1A,r16
clr r16 out TCNT1H,r16 out TCNT1L,r16
ldi r16,1<<OCF1A out TIFR,r16 ;***********************************
rjmp Cycle
Здесь у меня бесконечный цикл. В начале T/C1 настраивается и запускается. 0.5 секунды он считает; после окончания счета выставляет "1" на 5 пине порта D. После проходит еще ~0.5 сек., T/C1 останавливается и обнуляется ("0" на 5 пине порта D). И по-новой. 0.5 сек - "0", 0.5 сек - "1". Но, почему-то, с момента, когда устанавливается TCCR1B и счетчик начинает считать, и до момента окончания счета, когда выставляется флаг OCF1A проходит разное время. 500195.00 мкс, 500156.50 мкс, 500030.50 мкс и т.д. (кварц на 4 МГц) А если предделитель не использовать, то считает одинаково.
Немножко не то, что мне нужно. Я буду "вручную" обнулять счетчик, а в "1" он должен перебрасываться сам, по счету. То, что я выложил, это я временно так организовал код - для проверки. Мне непонятно, почему счетчик после обнуления и нового запуска отмеряет разные интервалы времени до установки OC1A в "1". После выполнения команды "clr r16" (в конце, перед "out TCNT1H,r16") OC1A сбрасывается в "0" и в этот момент я засекаю время (обнуляю Stop Watch). Потом ловлю момент установки OC1A в "1" (долго и муторно) и это время каждый раз разное. А почему - мне непонятно... Формулы, типа "(5*Fo/10/64-1)" я редко когда использовал, уже и забыл, что так можно. Спасибо за подсказку.
Добавлено after 51 minute 13 seconds: Мне посоветовали добавить в начале сброс предделителей (PSR10 в SFIOR), но ничего не изменилось:
Добавлено after 1 hour 52 minutes 20 seconds: Я переписал временнУю задержку, чтоб удобнее было отслеживать появление "1" на 5 пине порта D. Сначала нужно обнулить Stop Watch в AVRStudio в момент, когда 5 пин очищается - после записи (0<<COM1A1)|(0<<COM1A0) в TCCR1A. Теперь достаточно поставить курсор на оператор "nop" и нажать Ctrl+F10. Stop Watch в AVRStudio показывает разное прошедшее время. Спойлер
D_r_1x: sbic PIND,5 nop dec r22 brne D_r_1x ldi r22,$FF dec r21 brne D_r_1x ldi r21,$FF dec r20 brne D_r_1x
Добавлено after 1 hour 37 minutes 18 seconds: Заметил, что время, через которое срабатывает счетчик не гуляет бессистемно, а все время увеличивается от прогона к прогону. Сначала счетчик срабатывает через 499990.00 мкс, на следующем прогоне через 500012.50 мкс, потом через 500035.00 мкс и т.д. Дошло до 500214.50 мкс и следующая задержка уже была 499981.25 мкс и опять начала увеличиваться (500003.75 мкс ...). Все время увеличиваясь на одну и ту же величину - 22.5 мкс (90 тактов на 4 МГц). Тогда я добавил в цикл 90 пустых команд "nop", и счетчик стал срабатывать через одинаковое время - 500223.25 мкс. Но это же никуда не годится... Что это за 22.5 мкс такие?
Вот полная моя программа: Спойлер
Код:
.include "m16def.inc"
.CSEG
;***** Определения портов В/В ***** ;Port D:
.equ DIRD =0b00100000 .equ PUPD =0b00000000
;***** Векторы Прерываний *****
.CSEG .org $000 rjmp RESET ;Сброс вектор
.org $002 reti .org $004 reti .org $006 reti .org $008 reti .org $00A reti .org $00C reti .org $00E reti .org $010 reti .org $012 reti .org $014 reti .org $016 reti .org $018 reti .org $01A reti .org $01C reti .org $01E reti .org $020 reti .org $022 reti .org $024 reti .org $026 reti .org $028 reti
;***** Программное выполнение начинается здесь *****
RESET: ldi r16,high(RAMEND) ;назначить стек out SPH,r16 ldi r16,low(RAMEND) out SPL,r16
;********************* ;Установка портов В/В:
ldi r16,DIRD out DDRD,r16 ;установка направления PORTD ldi r16,PUPD out PORTD,r16 ;инициализация PORTD
START: ldi r16,$07 ;$07A1 = 0.5 секунды out OCR1AH,r16 ldi r16,$A1 out OCR1AL,r16
Cycle: in r16,SFIOR sbr r16,00000001 ; ldi r16,1<<PSR10 out SFIOR,r16
Запустил программу на своей студии 4,19. Вместо 1 секунды отсчитывается 1,6832. Думаю из-за магических чисел в программе задержки. Спойлер Переделал. Спойлер
.org $002 reti .org $004 reti .org $006 reti .org $008 reti .org $00A reti .org $00C reti .org $00E reti .org $010 reti .org $012 reti .org $014 reti .org $016 reti .org $018 reti .org $01A reti .org $01C reti .org $01E reti .org $020 reti .org $022 reti .org $024 reti .org $026 reti .org $028 reti
;***** Программное выполнение начинается здесь *****
RESET: ldi r16,high(RAMEND) ;назначить стек out SPH,r16 ldi r16,low(RAMEND) out SPL,r16
;********************* ;Установка портов В/В:
ldi r16,DIRD out DDRD,r16 ;установка направления PORTD ldi r16,PUPD out PORTD,r16 ;инициализация PORTD START: LDI R16,HIGH(5*Fo/10/64-1) ; (5*Fo/10/64-1)= 0.5 секунды OUT OCR1AH,R16 LDI R16,LOW(5*Fo/10/64-1) OUT OCR1AL,R16
; ldi r16,$07 ;$07A1 = 0.5 секунды ; out OCR1AH,r16 ; ldi r16,$A1 ; out OCR1AL,r16 ;Равно 500000/256=1953,125+1=1954*256=500224мкс CLR ZERO
Cycle: ldi r16,(1<<COM1A1)|(1<<COM1A0) out TCCR1A,r16
Да задержка это такое, на глаз, особой роли точность не играет. Просто я пытаюсь понять, как работает этот T/C1. В студии 4,06 у меня вывод PD5 половину времени в "0", половину в "1" - типа меандр. А в железе это нифига не работает - на этом PD5 практически постоянно "1" и на очень короткое время появляется "0". Я светодиод повесил и видно, как он еле-еле блымкает пару раз в секунду. Пробовал свою программку в Atmel Studio 7.0 - она подтверждает, что на выходе практически постоянно "1". И появляется она в начале цикла, после команды:
Код:
ldi r16,(1<<COM1A1)|(1<<COM1A0) out TCCR1A,r16
Потом идет задержка. После нее, после команды:
Код:
ldi r16,(0<<COM1A1)|(0<<COM1A0) ;Обнулить вывод 5 порта D out TCCR1A,r16
PD5 переходит в "0". Потом идет переход в начало цикла и опять, после установки (1<<COM1A1)|(1<<COM1A0) в TCCR1A он переходит в "1". Т.е. "0" появляется всего на несколько микросекунд, как и в железе я это вижу. А у вас в студии 4,19 как работает? 2-3 прогона цикла сделать надо, потому что в Atmel Studio 7.0 в первом проходе "0" держится все время задержки, а потом появляется "1". Я тут пробовал AVR Studio 5.1, Atmel Studio 6.2 и 7.0. Какие же они тяжелые в работе и неудобные... У меня есть AVR Studio v4.16.628, попробую еще в ней.
Сейчас этот форум просматривают: Google [Bot] и гости: 4
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения