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

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

Сообщение alexan9er »

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

Сообщение akl »

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

Сообщение 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?
Друг Кота
Аватара пользователя
Сообщения: 20093
Зарегистрирован: Чт сен 18, 2008 12:27:21
Откуда: Столица Мира Санкт-Петербург

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

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

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

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

Сообщение alexan9er »

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

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

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

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

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

Сообщение alexan9er »

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

Сообщение 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
Друг Кота
Сообщения: 4450
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Сообщение 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
Открыл глаза
Аватара пользователя
Сообщения: 54
Зарегистрирован: Пт окт 03, 2014 14:41:16

Сообщение alexan9er »

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

Сообщение akl »

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

Сообщение alexan9er »

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

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

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

Сообщение akl »

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

Сообщение alexan9er »

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

Сообщение c2n »

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

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

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

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

Сообщение ARV »

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

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

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

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

Сообщение 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
Родился
Сообщения: 3
Зарегистрирован: Пн янв 26, 2015 20:15:32

Сообщение 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;
Опытный кот
Аватара пользователя
Сообщения: 721
Зарегистрирован: Ср июн 11, 2014 09:43:13
Откуда: США

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

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

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