Таймеры/счётчики в AVR

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

Re: Таймеры/счётчики в AVR

Сообщение alexan9er »

akl, спасибо!
Насколько я понял, вы советуете этот подход для энергосбережения?
У меня вопрос с потреблением пока не стоит, питается от сети. Я хочу просто поработать с внешним кварцем.
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

Нет, у меня на первом месте стоит точность. Конечно, очень хорошо, когда удается совместить и точность и потребление. В качестве примера формирование интервала 100'000мкс для малоподходящей частоты кварца. Работа в SLEEP'е привлекательна не только малым потреблением, а тем, что ядро стоит, т.е. конвейер, в отличие от опроса флагов в цикле, не работает.
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

Re: Таймеры/счётчики в AVR

Сообщение alexan9er »

Ага, спасибо за идею! Я её попробую позже, когда дойду до спящего режима.

Вчерашние эксперименты показали что дело в этом опросе флагов, прерывания по таймерам его сильно замедляют и получаются пропуски отсчёта. Для эксперимента перенёс подсчёт времени в обработчик прерывания часового таймера, в итоге отставание получилось около секунды на 15 минут.

Вопрос 1. Я правильно понимаю, что т.к. прерывание самое приоритетное да ещё и тактируется от собственного кварца остальные прерывания и т.п. НЕ могут его замедлить и это уже погрешность самого кварца?

Вопрос 2. Нигде в даташите не указана паразитная ёмкость ножек XTAL1 и XTAL2, где её взять? В интернетах нашёл что её берут 3 пФ, но откуда это значение не сказано, кроме того сказано что оно может быть другое - " If you suspect your stray capacitance is higher, add the additional stray capacitance ..."

Вопрос 3. Если для тактирования МК используется внутрненний осцилятор 8 МГц (CKSEL 0010), подключаются ли внутренние конденсаторы на 18 и 8 пФ к ножкам XTAL1 и XTAL2? Или они подключаются только если вырать фьюзами Low Frequency Crystal Oscillator?
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Re: Таймеры/счётчики в AVR

Сообщение Gudd-Head »

alexan9er писал(а):т.к. прерывание самое приоритетное да ещё и тактируется от собственного кварца остальные прерывания и т.п. НЕ могут его замедлить и это уже погрешность самого кварца?
Эээ... Чего? Если помимо этого прерывания есть и другие, то могут запросто.

2. Да какая разница? Они сами предлагают брать кондёры в диапазоне 12...22 пФ.

3. Только фьюзами для низкочастотного кварца.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

Re: Таймеры/счётчики в AVR

Сообщение alexan9er »

1. Этот момент я не понимаю. Допустим прерывание 1 с высшим приоритетом, 2 с более низким. В какой ситуации обработчик прерывания 1 будет ждать выполнения прерывания 2? К тому же у меня прерывание 1 тактируется от собственного часового кварца, я читал что в этом случае все команды также выполняются по его тактам и основной генератор тут вообще не задействован. Как же на него может повлиять другое прерывание?

2. Я читал что влияет, и на практике у меня получается что влияет и довольно сильно. Хотя также читал мнение что кварц довольно устойчив к вариациям нагрузочных кондёров :)

3. Спасибо
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Re: Таймеры/счётчики в AVR

Сообщение Gudd-Head »

alexan9er писал(а):1. Этот момент я не понимаю. Допустим прерывание 1 с высшим приоритетом, 2 с более низким...
Вы для начала даташит или другую литературу прочитайте про прерывания у АВР.
alexan9er писал(а):2. Я читал что влияет
В небольшом диапазоне подстроить можно.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

Re: Таймеры/счётчики в AVR

Сообщение alexan9er »

ОК, спасибо.
Про прерывания прочитал, теперь ясно. Получается что если мне нужен точный отсчёт времени то другие прерывания использовать нельзя... Как же это обходят на практике? Очень уж хочется использовать прерывания и от часового кварца, и от внутрненнего.
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

Re: Таймеры/счётчики в AVR

Сообщение alexan9er »

Убрал все прерывания кроме часового.
Всё равно отстаёт на 15 сек в минуту :(
Визуально первые 5 сек считает норм, потом замедляется.
Можете подсказать что-нибудь по коду?
В коде стоит заглушка чтобы минута считалась за секунду - для отладки.
И цифры выводит HEX.

Спойлер

Код: Выделить всё

/*
 * clocks.asm
 *
 * Created: 03.12.2014 1:18:40
 * Author: Alexander
 */

.device     ATMEGA328P
.include    "m328Pdef.inc"

; Пороговые значения обработки кнопок
.equ      CNTBUTTONPUSHED = 30; пороговое значение счётчика для констатации нажатия клавиши
.equ      CNTBUTTONLONGPUSHED = 90; пороговое значение счётчика для констатации длинного нажатия клавиши

.dseg
bD1:            .byte   1      ; байт первой цифры
bD2:            .byte   1      ; байт второй цифры
bDD:            .byte   1      ; байт символа точки
bD3:            .byte   1      ; байт третьей цифры
bD4:            .byte   1      ; байт четвёртой цифры
bIdx:            .byte   1      ; позиция отображаемого разряда
bHrs:            .byte   1      ; байт часов
bMin:            .byte   1      ; байт минут
bSec:            .byte   1      ; байт секунд
bDot:            .byte   1      ; байт состояния точки
bIsEven:         .byte   1      ; флаг чётного срабатывания часового кварца
bIsRenew:         .byte   1      ; флаг установки цифр индикатора
bCntBtnScanDelay:   .byte   1      ; счётчик паузы сканирования кнопок
bIsIncHrs:         .byte   1      ; флаг инкремента часов
bIsIncMin:         .byte   1      ; флаг инкремента минут
bCntBtnHrs:         .byte   1      ; счётчик периодов нажатого состояния кнопки установки часов
bCntBtnMin:         .byte   1      ; счётчик периодов нажатого состояния кнопки установки минут

.cseg
.org 0

; векторы прерываний
.org 0x000  rjmp    RESET           ; Reset Handler
.org 0x002  reti               ; IRQ0 Handler
.org 0x004  reti                    ; IRQ1 Handler
.org 0x006  reti                    ; PCINT0 Handler
.org 0x008  reti                    ; PCINT1 Handler
.org 0x00A  reti                    ; PCINT2 Handler
.org 0x00C  reti                    ; Watchdog Timer Handler
.org 0x00E  reti                    ; Timer2 Compare A Handler
.org 0x010  reti                    ; Timer2 Compare B Handler
.org 0x012  rjmp   TIMER2OVF      ; Timer2 Overflow Handler
.org 0x014  reti                    ; Timer1 Capture Handler
.org 0x016  reti               ; Timer1 Compare A Handler
.org 0x018  reti                ; Timer1 Compare B Handler
.org 0x01A  reti                    ; Timer1 Overflow Handler
.org 0x01C  reti               ; Timer0 Compare A Handler
.org 0x01E  reti                    ; Timer0 Compare B Handler
.org 0x020  reti                    ; Timer0 Overflow Handler
.org 0x022  reti                    ; SPI Transfer Complete Handler
.org 0x024  reti                    ; USART, RX Complete Handler
.org 0x026  reti                    ; USART, UDR Empty Handler
.org 0x028  reti                    ; USART, TX Complete Handler
.org 0x02A   reti                    ; ADC Conversion Complete Handler
.org 0x02C   reti                    ; EEPROM Ready Handler
.org 0x02E   reti                    ; Analog Comparator Handler
.org 0x030   reti                    ; 2-wire Serial Interface Handler
.org 0x032   reti                    ; Store Program Memory Ready Handler


; ----------
; Вектор RESET HANDLER
RESET:
            cli

            ; установка указателя стека
            ldi     R16, high(RAMEND)
            out     SPH, R16
            ldi     R16, low(RAMEND)
            out     SPL, R16

            ; отключаем WD
            wdr
            in      R16, MCUSR
            andi    R16, ( 0xff & ( 0 << WDRF ) )
            out     MCUSR, R16
            lds     R16, WDTCSR
            ori     R16, ( 1 << WDCE ) | ( 1 << WDE )
            sts     WDTCSR, R16
            ldi     R16, ( 0 << WDE )
            sts     WDTCSR, R16

            ; начальное состояние порта B
         ; PB0 вход кнопки
         ; PB1 вход кнопки
            ldi     R16, ( 0 << PB1 ) | ( 0 << PB0 )
            out     DDRB, R16
         ldi      R16, ( 1 << PB1 ) | ( 1 << PB0 )
         out      PORTB, R16

            ; начальное состояние порта C
         ; порт C управляет анодами индикаторов
            ldi     R16, 0b11111111
            out     DDRC, R16

            ; начальное состояние порта D
         ; порт D управляет катодами индикаторов
            ldi     R16, 0b11111111
            out     DDRD, R16

         ; выдерживаем паузу для раскачки внешнего часового кварца
         ; ему нужна пауза примерно в 1 сек
         ; счётчик 0x001F40 при частоте 8 МГц даст задержку в ~ 1 сек
         ldi      R16, 0x40
         ldi      R17, 0x1F
         ldi      R18, 0x02
WAITQUARTZ:
         subi   R18, 1
         sbci   R17, 0
         sbci   R16, 0
         brcc   WAITQUARTZ

         ; таймер 2
         ; асинхронный режим
         ; внешний генератор часовой кварц 32768 Гц
         ; делитель частоты 64
         ; прерывание по переполнению - MAX = 255 период 2 Гц
         ldi      R16, ( 0 << OCIE2B ) | ( 0 << OCIE2A ) | ( 0 << TOIE2 )
         sts      TIMSK2, R16
         ldi      R16, ( 0 << EXCLK ) | ( 1 << AS2 )
         sts      ASSR, R16
         ldi      R16, ( 0 << COM2A1 ) | ( 0 << COM2A0 ) | ( 0 << COM2B1 ) | ( 0 << COM2B0 ) | ( 0 << WGM21 ) | ( 0 << WGM20 )
         sts      TCCR2A, R16
         ldi      R16, ( 0 << FOC2A ) | ( 0 << FOC2B ) | ( 0 << WGM22 ) | ( 1 << CS22 ) | ( 0 << CS21 ) | ( 0 << CS20 )
         sts      TCCR2B, R16
WAITASSR:
         lds      R16, ASSR   ; ждём пока кварц инициализируется
         cpi      R16, ( 0 << EXCLK ) | ( 1 << AS2 ) | ( 0 << OCR2AUB ) | ( 0 << OCR2BUB ) | ( 0 << TCR2AUB ) | ( 0 << TCR2BUB )   ; флаги должны быть сброшены
         brne   WAITASSR
         ldi      R16, ( 1 << OCF2B ) | ( 1 << OCF2A ) | ( 1 << TOV2 )
         out      TIFR2, R16
         ldi      R16, ( 0 << OCIE2B ) | ( 0 << OCIE2A ) | ( 1 << TOIE2 )
         sts      TIMSK2, R16
         clr      R16
         sts      TCNT2, R16

         ; задание начальных значений
         ldi      R16, 0
         sts      bD1, R16
         ldi      R16, 0
         sts      bD2, R16
         ldi      R16, 0
         sts      bDD, R16
         ldi      R16, 0
         sts      bD3, R16
         ldi      R16, 0
         sts      bD4, R16
         ldi      R16, 1
         sts      bIdx, R16
         ldi      R16, 0
         sts      bHrs, R16
         ldi      R16, 0
         sts      bMin, R16
         ldi      R16, 0
         sts      bSec, R16
         ldi      R16, 1
         sts      bDot, R16
         ldi      R16, 1
         sts      bIsEven, R16
         ldi      R16, 1
         sts      bIsRenew, R16
         ldi      R16, 0
         sts      bCntBtnScanDelay, R16
         ldi      R16, 0
         sts      bIsIncHrs, R16
         ldi      R16, 0
         sts      bIsIncMin, R16
         ldi      R16, 0
         sts      bCntBtnHrs, R16
         ldi      R16, 0
         sts      bCntBtnMin, R16

            sei
         jmp      BEGIN


; ----------
; Подпрограмма раскодировки цифры для отображения на 7-ми сегментном индикаторе
; in R16 - байт младшие 4 бита цифра
; out R16 - бинарный код цифры
DECODE:
         push   R17

         andi   R16, 0b00001111
         ldi      ZL, low( dbDigits * 2 )
         ldi      ZH, high( dbDigits * 2 )
         ldi      R17, 0
         add      ZL, R16
         adc      ZH, R17
         lpm
         mov      R16, R0

         pop      R17
         ret

; массив байтов с бинарными кодами цифр на 7-ми сегментном индикаторе
dbDigits:
         .db      0b11000000,   0b11111001   ; 0 1
         .db      0b10100100,   0b10110000   ; 2 3
         .db      0b10011001,   0b10010010   ; 4 5
         .db      0b10000010,   0b11111000   ; 6 7
         .db      0b10000000,   0b10010000   ; 8 9
         .db      0b10001000,   0b10000011   ; A B
         .db      0b11000110,   0b10100001   ; C D
         .db      0b10000110,   0b10001110   ; E F


; ----------
; Подпрограмма отображения символов на 4-х символьном 7-ми сегментном индикаторе
; Также отображается состояние точки между 2м и 3м символами
; Динамическая индикация
DISPLAY:
         push   R16
         push   R17

         lds      R17, bIdx
         cpi      R17, 1
         breq   DISPLAY1ST
         cpi      R17, 2
         breq   DISPLAY2ND
         cpi      R17, 3
         breq   DISPLAY3RD
         cpi      R17, 4
         breq   DISPLAY4TH
         cpi      R17, 5
         breq   DISPLAY5TH

         ; 1-ая позиция индикатора
         ; отображаем символ
DISPLAY1ST:
         ldi      R16, 0b00000000
         out      PORTC, R16
         lds      R16, bD1
         call   DECODE
         out      PORTD, R16
         ldi      R16, 0b00000001
         out      PORTC, R16
         rjmp   INCIDX

         ; 2-ая позиция индикатора
         ; отображаем символ
DISPLAY2ND:
         ldi      R16, 0b00000000
         out      PORTC, R16
         lds      R16, bD2
         call   DECODE
         out      PORTD, R16
         ldi      R16, 0b00000010
         out      PORTC, R16
         rjmp   INCIDX

         ; 3-я позиция индикатора
         ; отображаем точку
DISPLAY3RD:
         ldi      R16, 0b00000000
         out      PORTC, R16
         lds      R16, bDD
         swap   R16                  ; состояние точки в 0-м бите
         lsl      R16                  ; точкой на индикаторе управляет PD7
         lsl      R16                  ; поэтому сдвигаем на 7 битов влево
         lsl      R16
         ori      R16, 0b01111111         ; а остальные биты устанавливаем всегда чтобы не засвечивать лишние сегменты
         out      PORTD, R16
         ldi      R16, 0b00000100
         out      PORTC, R16
         rjmp   INCIDX

         ; 4-ая позиция индикатора
         ; отображаем символ
DISPLAY4TH:
         ldi      R16, 0b00000000
         out      PORTC, R16
         lds      R16, bD3
         call   DECODE
         out      PORTD, R16
         ldi      R16, 0b00000100
         out      PORTC, R16
         rjmp   INCIDX

         ; 5-ая позиция индикатора
         ; отображаем символ
DISPLAY5TH:
         ldi      R16, 0b00000000
         out      PORTC, R16
         lds      R16, bD4
         call   DECODE
         out      PORTD, R16
         ldi      R16, 0b00001000
         out      PORTC, R16
         rjmp   INCIDX

INCIDX:
         inc      R17
         cpi      R17, 6               ; если показали последнюю позицию индикатора
         brne   IDXSET               ; устанавливаем указатель обратно на первую
         ldi      R17, 1
IDXSET:
         sts      bIdx, R17

         pop      R17
         pop      R16
         ret


; ----------
; Подпрограмма сканирования кнопок
; Выставляет флаги нажатия
; Распознаёт одиночное нажатие и факт длительного зажатия кнопки
; С защитой от дребезга контактов
SCANBUTTONS:
         push   R16

         ; сканирование осуществляем только каждую 256-ю итерацию
         lds      R16, bCntBtnScanDelay
         inc      R16
         sts      bCntBtnScanDelay, R16
         cpi      R16, 0
         brne   ENDSCANBUTTONS

         ; обрабатываем состояние кнопки часов
         in      R16, PINB
         sbrs   R16, PB1
         rjmp   BTNHPUSHED
         rjmp   BTNHRELEASED
BTNHPUSHED:
         lds      R16, bCntBtnHrs
         inc      R16
         sts      bCntBtnHrs, R16
         cpi      R16, CNTBUTTONLONGPUSHED
         brlo   BTNHANALYZED
         ldi      R16, CNTBUTTONPUSHED
         sts      bCntBtnHrs, R16
         ldi      R16, 1
         sts      bIsIncHrs, R16
         rjmp   BTNHANALYZED
BTNHRELEASED:
         lds      R16, bCntBtnHrs
         cpi      R16, CNTBUTTONPUSHED
         brlo   CLEARCNTBTNH
         ldi      R16, 1
         sts      bIsIncHrs, R16
CLEARCNTBTNH:
         clr      R16
         sts      bCntBtnHrs, R16
BTNHANALYZED:
         nop

         ; обрабатываем состояние кнопки минут
         in      R16, PINB
         sbrs   R16, PB0
         rjmp   BTNMPUSHED
         rjmp   BTNMRELEASED
BTNMPUSHED:
         lds      R16, bCntBtnMin
         inc      R16
         sts      bCntBtnMin, R16
         cpi      R16, CNTBUTTONLONGPUSHED
         brlo   BTNMANALYZED
         ldi      R16, CNTBUTTONPUSHED
         sts      bCntBtnMin, R16
         ldi      R16, 1
         sts      bIsIncMin, R16
         rjmp   BTNMANALYZED
BTNMRELEASED:
         lds      R16, bCntBtnMin
         cpi      R16, CNTBUTTONPUSHED
         brlo   CLEARCNTBTNM
         ldi      R16, 1
         sts      bIsIncMin, R16
CLEARCNTBTNM:
         clr      R16
         sts      bCntBtnMin, R16
BTNMANALYZED:
         nop

ENDSCANBUTTONS:
         pop      R16
         ret


; ----------
; Вектор TIMER2 OVERFLOW HANDLER
; Отсчитывает время
TIMER2OVF:
         push   R16
         in      R16, SREG
         push   R16

         lds      R16, bIsEven         ; инвертируем флаг чётности
         ldi      R17, 0b00000001
         eor      R16, R17
         sts      bIsEven, R16
         sts      bDot, R16            ; точка переключается каждую итерацию
         ldi      R16, 1
         lds      R16, bIsEven         ; если чётная итерация значит отсчитали секунду
         cpi      R16, 1
         brne   EVENANALYZED
         call   COUNTSECOND
EVENANALYZED:
         ldi      R16, 1
         sts      bIsRenew, R16

         pop      R16
         out      SREG, R16
         pop      R16
         reti

         
; ----------
; Подпрограмма отсчёта секунды
COUNTSECOND:
         push   R16
         push   R17
         push   R18

         lds      R16, bSec
         lds      R17, bMin
         lds      R18, bHrs

         ldi      R16, 59               ; ЗАГЛУШКА

         inc      R16
         cpi      R16, 60
         brne   CLOCKED
         clr      R16
         inc      R17
         cpi      R17, 60
         brne   CLOCKED
         clr      R17
         inc      R18
         cpi      R18, 24
         brne   CLOCKED
         clr      R18
CLOCKED:
         sts      bSec, R16
         sts      bMin, R17
         sts      bHrs, R18

         pop      R18
         pop      R17
         pop      R16
         ret


; ----------
; Подпрограмма установки отображаемых символов индикатора
SETDIGITS:
         push   R16

         lds      R16, bIsRenew         ; отрабатываем только если установлен флаг
         cpi      R16, 1
         brne   ENDSETDIGITS
         lds      R16, bMin
         andi   R16, 0b00001111
         sts      bD1, R16
         lds      R16, bMin
         andi   R16, 0b11110000
         swap   R16
         sts      bD2, R16
         lds      R16, bDot
         sts      bDD, R16
         lds      R16, bHrs
         andi   R16, 0b00001111
         sts      bD3, R16
         lds      R16, bHrs
         andi   R16, 0b11110000
         swap   R16
         sts      bD4, R16
         clr      R16
         sts      bIsRenew, R16

ENDSETDIGITS:
         pop      R16
         ret

; ----------
; Основной цикл
BEGIN:
         ; ВНИМАНИЕ
         ; флаги обрабатываются по одному за итерацию
         ; для того чтобы не задерживать цикл
         ; если флагов нет то сканируем кнопки

         ; обрабатываем флаг инкремента часов
         lds      R16, bIsIncHrs
         cpi      R16, 1
         brne   NOINCHRS
         clr      R16
         sts      bIsIncHrs, R16
         lds      R16, bHrs
         inc      R16
         cpi      R16, 24               ; при переполнении начинаем прокручивать сначала
         brne   HRSSET
         clr      R16
HRSSET:
         sts      bHrs, R16
         ldi      R16, 1
         sts      bIsRenew, R16
         jmp      MAINROUTINES
NOINCHRS:
         nop

         ; обрабатываем флаг инкремента минут
         lds      R16, bIsIncMin
         cpi      R16, 1
         brne   NOINCMIN
         clr      R16
         sts      bIsIncMin, R16
         sts      bSec, R16            ; очищаем секунды
         lds      R16, bMin
         inc      R16
         cpi      R16, 60               ; при переполнении начинаем прокручивать сначала
         brne   MINSET
         clr      R16
MINSET:
         sts      bMin, R16
         ldi      R16, 1
         sts      bIsRenew, R16
         jmp      MAINROUTINES
NOINCMIN:
         nop

         call   SCANBUTTONS            ; сканируем кнопки

MAINROUTINES:
         call   SETDIGITS            ; устанавливаем отображаемые символы
         call   DISPLAY               ; отображаем символы на индикаторе

            rjmp    BEGIN
END:

akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

По мне, ну очень тяжёлая для понимания программа. Разбирался 2 часа, не смог. Скидал свою. Работа только от таймера Т2 в режиме CTC. Для проверки в студии подал на вход 32768*64.
Спойлер

Код: Выделить всё

.include    "m328Pdef.inc"

; Пороговые значения обработки кнопок
.equ   Fo=32768*64
;.equ   Fo=8000000


.def DC=R18
.def _FF =R2 ;FF
.def R_SEC=R25
.def R_MIN=R24
.def R_HOUR=R23

.cseg
.org 0

; векторы прерываний
.org 0x000
RESET:
   CLR   ZH
   LDI      R16,0b10000111
   OUT      DDRB,R16
   out      PORTB, R16
   out      DDRB,ZH
   rjmp   START           ; Reset Handler
; массив байтов с бинарными кодами цифр на 7-ми сегментном индикаторе
TB_DIG:
   .db      0b11000000,   0b11111001   ; 0 1
   .db      0b10100100,   0b10110000   ; 2 3
   .db      0b10011001,   0b10010010   ; 4 5
   .db      0b10000010,   0b11111000   ; 6 7
   .db      0b10000000,   0b10010000   ; 8 9
TB_DC:
   ;десятки часов     единицы часов
   .db 0b00001000,    0b00000100
   ;десятки минут     единицы минут
   .db 0b00000010,    0b00000001
.org 0x00E
TIMER2_COMPA:
   OUT   PORTC,ZH   ; принудительное гашение всех сегментов
   OUT   PORTD,_FF   ; обратной полярностью
;*************************************************
   LDI   ZL,LOW(TB_DC*2)
   ADD   ZL,DC
   LPM

   LDI   ZL,5      ; загрузить в ZH,ZL адрес R5
   ADD   ZL,DC
   LD   R16,Z      ; содержимое текущего регистра R5...R10 в R16
POINT:   
   OUT   PORTC,R0
   OUT   PORTD,R16   ; вывод на индикацию
IND:
; подготовиться к индикации следующего знака
   INC   DC
   ANDI   DC,$03
SCAN:
   SBIW   YL,1
   BRMI     SEC_OUT
   RETI
SEC_OUT:
   SET         ; период 1'000'000us окончен
   RET
; ----------
START:
; начальное состояние порта C
; порт C управляет анодами индикаторов
   ldi     R16, 0b11111111
   out     DDRC, R16
; начальное состояние порта D
; порт D управляет катодами индикаторов
   out   DDRD, R16
   OUT   PORTD,R16
;*************************************************
   RJMP   TIME_BEGIN
GO:
   CLR   ZH
   LDI   R16,0b11111111
   MOV   _FF,R16
   
   CLR   DC
   
   LDI   YH,HIGH(4*128-1)
   LDI   YL,LOW(4*128-1)   ;число сравнений компаратора

   LDI   R16,(Fo/64/512-1)
   STS   OCR2A,R16
   LDI   R16,1<<SE
   OUT   SMCR,R16      ; SLEEP IDLE ENABLE
   
   CLT
   
   SBI   DDRB,7
   SBI   PORTB,7      ; конец импульса 1 секунда

   LDI   R16,(1 <<WGM21)
   sts   TCCR2A, R16
   ldi   R16,(1 <<CS22)
   sts   TCCR2B, R16

   ldi      R16,(1<<OCF2A)
   sts      TIMSK2, R16
   out      TIFR2, R16

   SEI          ; разрешение глобальных прерываний
WAIT:
   SLEEP
   BRTC   WAIT
   CLT   
;**********************************************************
   CBI   PORTB,7      ; начало импульса 1 секунда
;EXT_POWER:
;   SBIS   PINB,3
;   RJMP   INC_TIME   ; работа от батареи с блокировкой кнопок
KEY_MIN:
   SBIC   PINB,1
   RJMP   KEY_HOUR   ; проверка нажатия часов MIN
    INC   R_MIN      ; нажата MIN
    CPI   R_MIN,60
    BRLO   MIN_60
    CLR   R_MIN
MIN_60:    
KEY_HOUR:    
   SBIC   PINB,0   ; проверка нажатия часов HOUR
   RJMP   KEY_PAUSE
    INC   R_HOUR
    CPI   R_HOUR,24
    BRLO   KEY_PAUSE
    CLR   R_HOUR
KEY_PAUSE:
   SBIC   PINB,2
   RJMP   INC_TIME
   
   RJMP   GO_TIME_PAUSE      ; нажата кнопка ПАУЗА
INC_TIME:
   INC   R_SEC
INC_TIME1:
   CPI   R_SEC,60
   BRLO   GO_TIME
   CLR   R_SEC
INC_MIN:
   INC   R_MIN
   CPI   R_MIN,60
   BRLO   GO_TIME
   CLR   R_MIN
INC_HOUR:
   INC   R_HOUR
   CPI   R_HOUR,24
   BRLO   GO_TIME
TIME_BEGIN:   
   CLR   R_HOUR
   CLR   R_MIN
GO_TIME_PAUSE:
   CLR   R_SEC
GO_TIME:
   RCALL   DIG_HOUR
   RCALL   DIG_MIN
;   RCALL   DIG_SEC
   RJMP   GO
;**********************************************************
DIG_HOUR:
   MOV   R17,R_HOUR
   RCALL   BIN8_BCD3

   LDI   ZL,LOW(TB_DIG*2)
   ADD   ZL,R27
   LPM   R5,Z
   LDI   ZL,LOW(TB_DIG*2)
   ADD   ZL,R28
   LPM   R6,Z

   RET
;*************************************************
DIG_MIN:
   MOV   R17,R_MIN
   RCALL   BIN8_BCD3

   LDI   ZL,LOW(TB_DIG*2)
   ADD   ZL,R27
   LPM   R7,Z
   LDI   ZL,LOW(TB_DIG*2)
   ADD   ZL,R28
   LPM   R8,Z

   RET
;*************************************************
;DIG_SEC:
;   MOV   R17,R_SEC
;   RCALL   BIN8_BCD3

;   LDI   ZL,LOW(TB_DIG*2)
;   ADD   ZL,R27
;   LPM   R9,Z
;   LDI   ZL,LOW(TB_DIG*2)
;   ADD   ZL,R28
;   LPM   R10,Z

;   RET
;*************************************************
BIN8_BCD3:
   CLR   R27      ; BCD OUT 10,1

   LDI   R28,8
PR:
   subi r27,-0x33   ;add 0x33
   sbrs r27, 3   ;if carry to bit 3
   subi r27, 3   ;subtract 3
   sbrs r27, 7   ;if carry to bit 7
   subi r27, 0x30   ;subtract 0x30

   LSL R17      ;shift input*/
   ROL R27
   
   dec R28      ;\n"
   brne PR      ;repeat for all bits*/
   
   MOV      R28,R27
   ANDI   R28,$0F
   SWAP   R27
   ANDI   R27,$0F

   RET

.EXIT
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

Re: Таймеры/счётчики в AVR

Сообщение alexan9er »

Спасибо, значит буду смотреть вашу :)
У вас МК тактируется от часового кварца?
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

Для проверки в студии задавал тактирование Fo=32768*64 и Т2 в синхронном режиме.
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

Re: Таймеры/счётчики в AVR

Сообщение alexan9er »

Кстати, а почему если ядро стоит а не крутит цикл то это предпочтительнее с т.з. точности прерываний асинхронного таймера? Прерывание же останавливает основной цикл и выполняется, по идее основной цикл его не замедляет ...
Аватара пользователя
Gudd-Head
Друг Кота
Сообщения: 20092
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

Re: Таймеры/счётчики в AVR

Сообщение Gudd-Head »

alexan9er писал(а):Кстати, а почему если ядро стоит а не крутит цикл то это предпочтительнее с т.з. точности прерываний асинхронного таймера?
Кто сказал?
alexan9er писал(а):Прерывание же останавливает основной цикл и выполняется, по идее основной цикл его не замедляет ...
Есть команды которые выполняются больше чем за 1 такт. И пока команда не выполнится, прерывания не произойдёт.
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

Gudd-Head писал(а): Кто сказал?
Я :)
akl писал(а):Работа в SLEEP'е привлекательна не только малым потреблением, а тем, что ядро стоит, т.е. конвейер, в отличие от опроса флагов в цикле, не работает.
Поэтому не накапливается, хоть и небольшая, но погрешность.
Gudd-Head писал(а): Есть команды которые выполняются больше чем за 1 такт. И пока команда не выполнится, прерывания не произойдёт.
Аватара пользователя
alexan9er
Открыл глаза
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

Re: Таймеры/счётчики в AVR

Сообщение alexan9er »

Понятненько, спасибо!
Кстати эксперименты показали что кварц то отстаёт, то догоняет и обгоняет, но в среднем мне удалось выставить порог в режиме CTC таймера чтобы время шло более менее точно.
Засекал отклонение за 5 часов.
Очень интересное поведение :shock:
Аватара пользователя
c2n
Сверлит текстолит когтями
Сообщения: 1193
Зарегистрирован: Ср июл 25, 2012 21:40:09
Откуда: Самара
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение c2n »

Думается мне.... мозги оно конопатит из-за перепадов питания.
Отмониторьте напряжение питания и ток потребления, и сравните с динамикой рахождений.

По идее если используется внешний кварц, то проблем не должно быть.

Попробуйте поменяйте конденсаторы в обвязе....

К стати, если есть хороший осциллоскоп, проверьте, на сколько равномерно происходит тактирование.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение ARV »

люди, которые утверждают, что может накапливаться ошибка счета времени из-за того, что разные команды основного цикла могут иметь разное кол-во тактов, ответьте на вопрос: как ошибка в 1 или 2 такта может накапливать ошибку, а пробуждение из SLEEP-а, которое длится десятки и даже сотни тактов, не накапливает этой ошибки?!

неужели не понятно, что если между прерываниями будет промежуток больше, чем внесенная по любым причинам задержка, никакого искажения хода часов не будет?

вот простой пример: запустим метроном, чтобы стукал 1 раз в минуту - это будет аналог запроса прерывания. а вы будете ядром процессора, и по каждому тику метронома будете обрабатывать прерывание таким образом: встаете со стула, обходите его кругом и снова садитесь. если вам 15 лет, вы среагируете на щелчок мгновенно, и отработаете прерывание за 10 секунд. если вам 70 лет, то среагируете вы на щелчок за 5 секунд, и еще 40 уйдет на обработку, но ведь каждый запрос будет обработан своевременно, ни один пропущен не будет!!! откуда же возьмется погрешность у реального ядра микроконтроллера?!
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
akl
Друг Кота
Сообщения: 4444
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: Таймеры/счётчики в AVR

Сообщение akl »

На аналогию наложено ещё одно условие - отсчёт события проводится когда глаза открыты.
- SLEEP IDLE глаза открыты всегда, т.е. мгновенная реакция на событие
- непрерывно моргаем, находясь в цикле и реакция на событие будет разная, в зависимости от того открыты глаза или моргнули в момент наступления события.
Проверяется простым примером. SLEEP IDLE даёт постоянный отсчет ...201,201,201..., а без слипа в цикле чередующийся интервал ...200-202-200-202...
Спойлер

Код: Выделить всё

.include "tn13def.inc"

.cseg
.org 0

RESET:
   RJMP   GO

.org 6
TIMER0_COMP1A:
   SET
   RET
;***********************************
GO:
   LDI   R22,1<<SE
   OUT   MCUCR,R22   ;SLEEP IDLE

   LDI   R22,1<<WGM01
   OUT   TCCR0A,R22   ; режим CTC T0

   LDI   R22,200
   OUT   OCR0A,R22   ; число сравнения

   LDI   R22,1<<OCIE0A
   OUT   TIMSK0,R22   ; режим прерывания по сравнению
   OUT   TIFR0,R22   ; сброс соответствующего флага

   LDI   R22,1<<CS00
   OUT   TCCR0B,R22

   CLT
   SEI
WAIT:
;   SLEEP
   BRTC   WAIT
   RJMP   GO
.EXIT
u-Art
Родился
Сообщения: 3
Зарегистрирован: Пн янв 26, 2015 20:15:32

Re: Таймеры/счётчики в AVR

Сообщение u-Art »

Приветствую!

Подскажите, есть ли возможность настроить ШИМ в Attiny13 с пониженной разрядностью?

Так, чтобы была возможность 2 такта держать лапку в 1, затем 8 тактов на лапке 0 и возврат к началу счета.
Вроде это режим Fast PWM top=OCR0A...

Но такая настройка от CodeVision не работает:

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 9600,000 kHz
// Mode: Fast PWM top=OCR0A
// OC0A output: Non-Inverted PWM
// OC0B output: Disconnected
TCCR0A=0x83;
TCCR0B=0x09;
TCNT0=0x02;
OCR0A=0x0A;
OCR0B=0x00;
Аватара пользователя
Pink-Pank
Опытный кот
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США
Контактная информация:

Re: Таймеры/счётчики в AVR

Сообщение Pink-Pank »

такое количество тактов можно только программно эмулировать. на ассемблере. При этом ничего другого контроллер делать не сможет. Аппаратно Вы такое не сделаете. Единственный вариант - поднять частоту тактирования. Тогда можно выдать нужную Вам частоту аппаратно.
Fucking static initialization order fiasco
Ответить

Вернуться в «AVR»