Два семисегментных индикатора и таймер
Два семисегментных индикатора и таймер
Здравствуйте, пишу программу на ATmega16, хотел чтобы отображалось на двух семисегментных индикаторах значения от 00 до 99, после чего он обнулялся и всё начиналось с начала. Но возникла проблема, программа выводит не так как надо, а именно 00, 11, 22 и т.д. Не могли бы подсказать где я накосячил..
Мой код:
.Macro outi
LDI R16, @1
out @0, R16
.ENDM
.CSEG
.ORG $000 ; reset
RJMP Reset
.ORG $002
Reti
.ORG $004
Reti
.ORG $008
Rjmp Timer2_OVF ;
.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
.ORG INT_vectors_SIZE ; Конец таблицы прерываний
; **********************
; Инициализация
; **********************
Reset: //________________
.DEF Led=R17
.DEF MASK=R18
.DEF Ch1=R19 ;десятки
.DEF Ch10=R20 ;еденицы
.def Temp=r16
.def Temp1=r21
OUTI SPL, Low(ramend) ; инициализация стека
OUTI SPH, High(ramend)
//_________________
OUTI DDRA, 255
OUTI DDRB, 255
//________________
OUTI TCCR2, (1<<CS20)|(1<<CS22)
OUTI TIMSK , 1<<TOIE2
OUTI ASSR , 1<<AS2
//_________________
LDI led, 1<<7
LDI MASK, 1<<7
LDI Ch1, 0
LDI Ch10, 0
SEI
; ****************************
Main:
rcall Decoder
Out portA, Led
OUTI portB, 0b00000001
rcall Loop
OUTI portB, 0b00000010
rcall Loop
rjmp Main
; *****************************
Loop:
ldi Temp, 100
ldi Temp1, 20
Loop1:
dec Temp
brne Loop1
dec Temp1
brne Loop1
ret
; *****************************
Timer2_OVF:
INC Ch10
CPI Ch10, 10
BREQ Tool1
RETI
Tool1:
ldi Ch10, 0
INC Ch1
CPI Ch1, 10
BREQ END
RETI
END:
LDI Ch1, 0
LDI Ch10, 0
RETI
; *****************************************
decoder:
LDI ZL, LOW(DIGITS_TABLE*2) ; Инициализация массива
LDI ZH, HIGH(DIGITS_TABLE*2)
CLR R16
ADD ZL, Ch10 ; Смещение на десяток цифр
ADC ZH, R16
LPM ; Загрузка сегмента для десятков
MOV Led, R0 ; Сохраняем сегмент для десятков
CLR R16
ADD ZL, Ch1 ; Смещение на единицу цифр
ADC ZH, R16
LPM ; Загрузка сегмента для единиц
MOV Led, R0 ; Объединение сегментов (десятков и единиц)
RET
; ************************************
Digits_Table:
.db 0b00111111 , 0b10000110 ; 0,1
.db 0b01011011 , 0b11001111 ; 2,3
.db 0b01100110 , 0b11101101 ; 4,5
.db 0b01111101 , 0b10000111 ; 6,7
.db 0b11111111 , 0b11101111 ; 8,9
Мой код:
.Macro outi
LDI R16, @1
out @0, R16
.ENDM
.CSEG
.ORG $000 ; reset
RJMP Reset
.ORG $002
Reti
.ORG $004
Reti
.ORG $008
Rjmp Timer2_OVF ;
.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
.ORG INT_vectors_SIZE ; Конец таблицы прерываний
; **********************
; Инициализация
; **********************
Reset: //________________
.DEF Led=R17
.DEF MASK=R18
.DEF Ch1=R19 ;десятки
.DEF Ch10=R20 ;еденицы
.def Temp=r16
.def Temp1=r21
OUTI SPL, Low(ramend) ; инициализация стека
OUTI SPH, High(ramend)
//_________________
OUTI DDRA, 255
OUTI DDRB, 255
//________________
OUTI TCCR2, (1<<CS20)|(1<<CS22)
OUTI TIMSK , 1<<TOIE2
OUTI ASSR , 1<<AS2
//_________________
LDI led, 1<<7
LDI MASK, 1<<7
LDI Ch1, 0
LDI Ch10, 0
SEI
; ****************************
Main:
rcall Decoder
Out portA, Led
OUTI portB, 0b00000001
rcall Loop
OUTI portB, 0b00000010
rcall Loop
rjmp Main
; *****************************
Loop:
ldi Temp, 100
ldi Temp1, 20
Loop1:
dec Temp
brne Loop1
dec Temp1
brne Loop1
ret
; *****************************
Timer2_OVF:
INC Ch10
CPI Ch10, 10
BREQ Tool1
RETI
Tool1:
ldi Ch10, 0
INC Ch1
CPI Ch1, 10
BREQ END
RETI
END:
LDI Ch1, 0
LDI Ch10, 0
RETI
; *****************************************
decoder:
LDI ZL, LOW(DIGITS_TABLE*2) ; Инициализация массива
LDI ZH, HIGH(DIGITS_TABLE*2)
CLR R16
ADD ZL, Ch10 ; Смещение на десяток цифр
ADC ZH, R16
LPM ; Загрузка сегмента для десятков
MOV Led, R0 ; Сохраняем сегмент для десятков
CLR R16
ADD ZL, Ch1 ; Смещение на единицу цифр
ADC ZH, R16
LPM ; Загрузка сегмента для единиц
MOV Led, R0 ; Объединение сегментов (десятков и единиц)
RET
; ************************************
Digits_Table:
.db 0b00111111 , 0b10000110 ; 0,1
.db 0b01011011 , 0b11001111 ; 2,3
.db 0b01100110 , 0b11101101 ; 4,5
.db 0b01111101 , 0b10000111 ; 6,7
.db 0b11111111 , 0b11101111 ; 8,9
- Вложения
-
- Схема.png
- (154.66 КБ) 90 скачиваний
- Реклама
Re: Два семисегментных индикатора и таймер
[uquote="DenisLoga",url="/forum/viewtopic.php?p=4701089#p4701089"][/uquote]
Почему одна запись в portA? Половину времени светить сегменты десятков, другую половину времени - сегменты единиц. Если быстро переключать, глаз не будет видеть мерцания будет казаться что светятся два знака одновременно. Так работает "динамическая индикация". Вы один раз записываете сегменты, конечно в двух знаках увидите одинаковые значения.
Ну и что за индикатор? Какой-то "синтетический" (только для моделирования)?
[uquote="DenisLoga",url="/forum/viewtopic.php?p=4701089#p4701089"][/uquote]
Перед этой командой регистровая пара Z указывает не на начало массива.
[uquote="DenisLoga",url="/forum/viewtopic.php?p=4701089#p4701089"][/uquote]
Какое же это "объединение"? По мне так переписывание регистра с "полезными" данными.
Код: Выделить всё
Out portA, Led
OUTI portB, 0b00000001
rcall Loop
OUTI portB, 0b00000010
rcall Loop
Почему одна запись в portA? Половину времени светить сегменты десятков, другую половину времени - сегменты единиц. Если быстро переключать, глаз не будет видеть мерцания будет казаться что светятся два знака одновременно. Так работает "динамическая индикация". Вы один раз записываете сегменты, конечно в двух знаках увидите одинаковые значения.
Ну и что за индикатор? Какой-то "синтетический" (только для моделирования)?
[uquote="DenisLoga",url="/forum/viewtopic.php?p=4701089#p4701089"]
Код: Выделить всё
ADD ZL, Ch1 ; Смещение на единицу цифрПеред этой командой регистровая пара Z указывает не на начало массива.
[uquote="DenisLoga",url="/forum/viewtopic.php?p=4701089#p4701089"]
Код: Выделить всё
MOV Led, R0 ; Объединение сегментов (десятков и единиц)Какое же это "объединение"? По мне так переписывание регистра с "полезными" данными.
Re: Два семисегментных индикатора и таймер
А как нужно написать, чтобы объединять данные десятков и единиц?
Последний раз редактировалось DenisLoga Пт апр 04, 2025 05:25:08, всего редактировалось 1 раз.
Re: Два семисегментных индикатора и таймер
По мне ничего объединять не надо. Как вариант.
Код: Выделить всё
.include "m16def.inc"
.DEF Led1=R17
.DEF Led10=R18
.DEF Ch1=R19 ;десятки
.DEF Ch10=R20 ;еденицы
.def DC=R21
.Macro outi
LDI R16, @1
out @0, R16
.ENDM
.CSEG
.ORG $000 ; reset
RJMP START ;Reset
.ORG $008
Timer2_OVF:
LDI ZL,17 ; загрузить в ZH,ZL адрес LED1
ADD ZL,DC
LD R0,Z ; содержимое текущего регистра
OUT PORTA,R0
OUT PORTB,R22 ; вывод на индикацию
IND:
; подготовиться к индикации следующего знака
DEC XL
MOV DC,XL
ANDI DC,0b00000001
LDI ZL, LOW(TB_DC*2) ; Инициализация массива
ADD ZL,DC
LPM R22,Z
TST XL
BRNE IND_OUT
RET ; интервал 1 секунда
IND_OUT:
RETI
;*************************************************
TB_DC:
.DB 1,2
;*************************************************
Digits_Table:
.db 0b00111111 , 0b10000110 ; 0,1
.db 0b01011011 , 0b11001111 ; 2,3
.db 0b01100110 , 0b11101101 ; 4,5
.db 0b01111101 , 0b10000111 ; 6,7
.db 0b11111111 , 0b11101111 ; 8,9
; **********************
; Инициализация
; **********************
START:
CLR ZH
OUTI SPL, Low(ramend) ; инициализация стека
OUTI SPH, High(ramend)
//_____
OUTI DDRA, 255
OUTI DDRB, 255
//_____
OUTI TCCR2,1<<CS20
; OUTI TCCR2, (1<<CS20)|(1<<CS22)
OUTI TIMSK , 1<<TOIE2
OUTI ASSR , 1<<AS2
LDI R16,1<<SE
OUT MCUCR,R16
LDI XL,128
CLR DC
LDI R22,1
RJMP TIME_0
GO:
SEI
SLEEP
WAIT_1SEC:
BRIE WAIT_1SEC
LDI XL,128
Main:
INC Ch10
CPI Ch10, 10
BRLO DIG_OUT
LDI Ch10, 0
INC Ch1
CPI Ch1, 10
BRLO DIG_OUT
TIME_0:
LDI Ch1, 0
LDI Ch10, 0
DIG_OUT:
decoder:
LDI ZL, LOW(DIGITS_TABLE*2) ; Инициализация массива
;LDI ZH, HIGH(DIGITS_TABLE*2)
ADD ZL, Ch10 ; Смещение для цифры десятов
LPM Led10,Z ; Загрузка сегмента для десятков
LDI ZL, LOW(DIGITS_TABLE*2) ; Инициализация массива
ADD ZL, Ch1 ; Смещение цифры единиц
LPM Led1,Z ; Загрузка сегмента для единиц
rjmp GO
; ************************************
.EXITRe: Два семисегментных индикатора и таймер
Может попробовать для начала разделить обработку дисплея (вывод и динамическая развертка) и счетчик (инкремент и перекодировка данных для сегментов индикатора)?

- Реклама
Re: Два семисегментных индикатора и таймер
Спасибо, буду пробовать!
Re: Два семисегментных индикатора и таймер
Спойлер
Код: Выделить всё
.Macro outi
LDI R16, @1
out @0, R16
.ENDM
.CSEG
.ORG $000 ; reset
RJMP Reset
.ORG $002
Reti
.ORG $004
Reti
.ORG $008
Rjmp Timer2_OVF ;
.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
.ORG INT_vectors_SIZE ; Конец таблицы прерываний
Reset:
.DEF Led=R17
.DEF MASK=R18
.DEF Ch1=R19 ; единицы
.DEF Ch10=R20 ; десятки
.def Temp=r16
.def Temp1=r21
.def Digit=r22 ; текущий разряд
OUTI SPL, Low(ramend)
OUTI SPH, High(ramend)
OUTI DDRA, 255
OUTI DDRB, 255
OUTI TCCR2, (1<<CS20)|(1<<CS22)
OUTI TIMSK, 1<<TOIE2
OUTI ASSR, 1<<AS2
LDI Led, 0
LDI Ch1, 0
LDI Ch10, 0
LDI Digit, 0 ; 0 - единицы, 1 - десятки
SEI
Main:
rcall Decoder
rcall Display
rjmp Main
Display:
; Отображаем текущий разряд
CPI Digit, 0
BREQ ShowUnits
; Показываем десятки
OUTI PORTB, 0b00000010 ; Включить разряд десятков
rjmp EndDisplay
ShowUnits:
; Показываем единицы
OUTI PORTB, 0b00000001 ; Включить разряд единиц
EndDisplay:
OUT PORTA, Led ; Вывести текущую цифру
; Переключаем разряд для следующей итерации
LDI Temp, 1
EOR Digit, Temp
rcall Delay
ret
Delay:
ldi Temp, 50
Delay1:
dec Temp
brne Delay1
ret
Timer2_OVF:
INC Ch1
CPI Ch1, 10
BRNE EndTimer
LDI Ch1, 0
INC Ch10
CPI Ch10, 10
BRNE EndTimer
LDI Ch10, 0 ; Сброс на 00 после 99
EndTimer:
RETI
decoder:
CPI Digit, 1
BREQ DecodeTens
; Декодируем единицы
MOV Temp, Ch1
rjmp LoadDigit
DecodeTens:
; Декодируем десятки
MOV Temp, Ch10
LoadDigit:
LDI ZL, LOW(DIGITS_TABLE*2)
LDI ZH, HIGH(DIGITS_TABLE*2)
CLR R16
ADD ZL, Temp
ADC ZH, R16
LPM
MOV Led, R0
RET
Digits_Table:
.db 0b00111111, 0b00000110 ; 0, 1
.db 0b01011011, 0b01001111 ; 2, 3
.db 0b01100110, 0b01101101 ; 4, 5
.db 0b01111101, 0b00000111 ; 6, 7
.db 0b01111111, 0b01101111 ; 8, 9
Последний раз редактировалось Уош Пт апр 04, 2025 17:53:59, всего редактировалось 1 раз.
Re: Два семисегментных индикатора и таймер
Уош Любовь давать бестолковые имена регистрам и, затем, путаться в них
Код: Выделить всё
decoder:
CPI Digit, 1
BREQ DecodeTens
; Декодируем единицы
MOV R1, Ch1
; MOV Temp, Ch1
rjmp LoadDigit
DecodeTens:
; Декодируем десятки
MOV R1, Ch10
; MOV Temp, Ch10
LoadDigit:
LDI ZL, LOW(DIGITS_TABLE*2)
LDI ZH, HIGH(DIGITS_TABLE*2)
CLR R16
ADD ZL,R1
; ADD ZL, Temp ;это ошибка!!!!!!!!!!!!!!
ADC ZH, R16
LPM
MOV Led, R0
RETRe: Два семисегментных индикатора и таймер
Разбираться в чужом да весьма неудобном задании...
Но таки и сие можно попробовать подправить...
Дабы не сильно портить исходное от
DenisLoga вот такой вариант (в студии не проверял!) вроде должен быть:
может с соответствием позиций "промахнулся" - тогда меняем соответственно...

Коты!
Имейте совесть (насчет спойлера)...

Но таки и сие можно попробовать подправить...
Дабы не сильно портить исходное от
DenisLoga вот такой вариант (в студии не проверял!) вроде должен быть:
Спойлер
Код: Выделить всё
.DEF Led=R17
.DEF MASK=R18
.DEF Ch1=R19 ;десятки
.DEF Ch10=R20 ;еденицы
.def Temp=r16
.def Temp1=r21
.Macro outi
LDI R16, @1
out @0, R16
.ENDM
.nolist
.include "m16def.inc"
.list
;---------------------------------------------------------------------------------------
.CSEG
.ORG $000 ; reset
RJMP Reset
.ORG $008
Rjmp Timer2_OVF ;
.ORG INT_vectors_SIZE ; Конец таблицы прерываний
; **********************
; Инициализация
; **********************
Reset: //_____
OUTI SPL, Low(ramend) ; инициализация стека
OUTI SPH, High(ramend)
//_____
OUTI DDRA, 255
OUTI DDRB, 255
//_____
OUTI TCCR2, (1<<CS20)|(1<<CS22)
OUTI TIMSK , 1<<TOIE2
OUTI ASSR , 1<<AS2
//_____
LDI led, 1<<7
LDI MASK, 1<<7
LDI Ch1, 0
LDI Ch10, 0
OUTI portB, 0b00000001 ; страховка (*добавлено*)
; но начальный статус таки будет с "с мусорком"
SEI
; ****************************
Main:
rcall Decoder ; вывод десятков
Out portA, Led
OUTI portB, 0b00000001
rcall Loop
rcall Decoder ; вывод единиц (*добавлено*)
OUTI portB, 0b00000010
rcall Loop
rjmp Main
; *****************************
Loop:
ldi Temp, 100
ldi Temp1, 20
Loop1:
dec Temp
brne Loop1
dec Temp1
brne Loop1
ret
; *****************************
Timer2_OVF:
INC Ch10
CPI Ch10, 10
BREQ Tool1
RETI
Tool1:
ldi Ch10, 0
INC Ch1
CPI Ch1, 10
BREQ END
RETI
END:
LDI Ch1, 0
LDI Ch10, 0
RETI
; *****************************************
decoder:
LDI ZL, LOW(DIGITS_TABLE*2) ; Инициализация массива
LDI ZH, HIGH(DIGITS_TABLE*2)
; if pb в десятках
SBIS portB,0 ; (*добавлено*)
rjmp eddat ; (*добавлено*)
CLR R16
ADD ZL, Ch10 ; Смещение на десяток цифр
ADC ZH, R16
LPM ; Загрузка сегмента для десятков
MOV Led, R0 ; Сохраняем сегмент для десятков
ret ; (*добавлено*)
; if pb в единицах
eddat: ; (*добавлено*)
CLR R16
ADD ZL, Ch1 ; Смещение на единицу цифр
ADC ZH, R16
LPM ; Загрузка сегмента для единиц
MOV Led, R0 ; Объединение сегментов (десятков и единиц)
RET
; ************************************
; таблица сегментов под активный уровень = 1
; тогда активный уровень позиционого ключа должен быть равен 0,
; но вывод меги держать 70-80 мА это уже садизм
; (для симулятора вроде сойдет - не ведаю)
; правки приведены из предположения,
; что активный уровень позиционных ключей равен 0
Digits_Table:
.db 0b00111111 , 0b10000110 ; 0,1
.db 0b01011011 , 0b11001111 ; 2,3
.db 0b01100110 , 0b11101101 ; 4,5
.db 0b01111101 , 0b10000111 ; 6,7
.db 0b11111111 , 0b11101111 ; 8,9
Коты!
Имейте совесть (насчет спойлера)...
Re: Два семисегментных индикатора и таймер
Всем огромное спасибо!) Я уже нашёл проблему в своём коде, благодаря вашим вариантам. Всё оказалось куда проще))


