Насколько я понял, вы советуете этот подход для энергосбережения?
У меня вопрос с потреблением пока не стоит, питается от сети. Я хочу просто поработать с внешним кварцем.
Эээ... Чего? Если помимо этого прерывания есть и другие, то могут запросто.alexan9er писал(а):т.к. прерывание самое приоритетное да ещё и тактируется от собственного кварца остальные прерывания и т.п. НЕ могут его замедлить и это уже погрешность самого кварца?
Вы для начала даташит или другую литературу прочитайте про прерывания у АВР.alexan9er писал(а):1. Этот момент я не понимаю. Допустим прерывание 1 с высшим приоритетом, 2 с более низким...
В небольшом диапазоне подстроить можно.alexan9er писал(а):2. Я читал что влияет
Код: Выделить всё
/*
* 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:
Код: Выделить всё
.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 писал(а):Кстати, а почему если ядро стоит а не крутит цикл то это предпочтительнее с т.з. точности прерываний асинхронного таймера?
Есть команды которые выполняются больше чем за 1 такт. И пока команда не выполнится, прерывания не произойдёт.alexan9er писал(а):Прерывание же останавливает основной цикл и выполняется, по идее основной цикл его не замедляет ...
ЯGudd-Head писал(а): Кто сказал?
Поэтому не накапливается, хоть и небольшая, но погрешность.akl писал(а):Работа в SLEEP'е привлекательна не только малым потреблением, а тем, что ядро стоит, т.е. конвейер, в отличие от опроса флагов в цикле, не работает.
Gudd-Head писал(а): Есть команды которые выполняются больше чем за 1 такт. И пока команда не выполнится, прерывания не произойдёт.
Код: Выделить всё
.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