Управление семисегментным индикатором. Сбивается программа.

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 2
Зарегистрирован: Сб ноя 09, 2013 13:49:16

Сообщение Radio Killer »

Здравствуйте.
Для МК AVR ATmega32 с тактовой частотой 4МГц написана программа, которая считает количество нажатий на кнопки SB1 и SB2. И выводит на семисегментный индикатор А1 с общим анодом определенное число: 0..9. Кнопка SB1 инкрементирует данный счетчик, кнопка SB2 декрементирует счетчик. Кнопки управляют МК активным нулем. Кнопки подтянуты к питанию резисторами R9 и R10 на 6 кОм. Симуляция программы в Протеусе проходит без проблем. Устройство уже даже собрано в железе, подключение точно такое же, как на картинке.

Изображение

Вот проект в Протеусе:
Lesson 5 Counter with Debounce.rar
(17.47 КБ) 226 скачиваний
Проблема такая, происходит так, что в реальном устройстве МК выводит на дисплей не числа, а что-то не понятное, подсвечивает определенные сегменты, но не ясные числа. При нажатии на кнопки, символы меняются, причем определенные комбинации соответствуют определенным позициям чисел. Т.е. "У" на индикаторе - соответствует числу "1", "h" на индикаторе - соответствует числу "2" и т.д. Программная отладка и симулиция не показывает эту проблему, что в AVR Studio, что в Протеусе - все работает как надо.

Программу проверял, коды для изображения чисел на индикаторе соответствуют правильным. Подключен индикатор правильно, все соответствует, иначе бы вообще не работало, но она же начинает нормально работать после некоторых манипуляций. Прогонял эти коды в реальном устройстве отдельно, даже с нажатиями кнопок, все выводится нормально. А как прошью полной программой - так и появляется эта проблема. Вот программа, написана в AVR Studio 5.0:
Upgrade Lesson 5 Counter with Debounce.rar
(18.81 КБ) 214 скачиваний
Так происходит не постоянно, такое чувство, будто нормально работать программе мешают какие-то наводки, статика или помехи. Т.е. при включении и первой прошивке это начинается, полежит включенное какое-то время или после нескольких включений/выключений устройства все становится нормальным, то ли наводки исчезают, то ли статика снимается, в общем, все начинает работать нормально, отображаются нормальные числа. Или если пальцем провести по ножкам МК, где кварц припаян, тоже, моргнет и нормально становится, но от этого не всегда. Не могу пока понять, в чем дело.

Такое именно с индикаторами и с этой программой. В Протеусе и в AVR Studio нет такой проблемы. Да и другие программы работают с этим МК нормально.

Вот эта программа:
Спойлер

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

 ; Автор: Владимир Николаевич
 ; Дата: 03.11.13
 ; Версия: 0.01
 ; Имя файла: Lesson 3 Counter
 ; Для AVR: ATmega32A
 ; Тактовая частота: 4 МГц

 ; Выполняемые функции: Управление семисегментным индикатором и подсчет нажатий на кнопку

 .device ATmega32
 .nolist
 .include "C:\Program Files\Atmel\AVR Studio 5.0\avrassembler\include\m32def.inc"
 .list

 ; ============
 ; Объявления
 .def temp    = r16
 .def Counter = r17
 .def Delay2  = r18
 .def Delay3  = r19

 ; ============
 ; Начало программы
 rjmp Init

 ; Подпрограммы
Debounce:               ; подпрограмма задержки для подавления дребезга
 ldi temp, 0x80         ; младшие разряды числа 0х013880 (400'000/5=80'000)
 ldi Delay2, 0x38       ; средние разряды числа 0х013880 (400'000/5=80'000)
 ldi Delay3, 0x01       ; старшие разряды числа 0х013880 (400'000/5=80'000)

Loop:
 subi temp, 1           ; вычитаем 1 из Delay1 (temp)
 sbci Delay2, 0         ; вычитаем 1 из Delay2, если флаг С = 1
 sbci Delay3, 0         ; вычитаем 1 из Delay3, если флаг С = 1
 brcc Loop              ; возвращаемся к метке, если флаг С = 0
 ret                    ; выход из подпрограммы

 ; ============

Init:
 ldi temp, LOW(RAMEND)  ; указатель стека установлен
 out SPL, temp          ; на последний адрес ОЗУ
 ldi temp, HIGH (RAMEND)
 out SPH, temp

 ldi r20, 0b10000001    ; код для цифры 0
 ldi r21, 0b11001111    ; код для цифры 1
 ldi r22, 0b10010010    ; код для цифры 2
 ldi r23, 0b10000110    ; код для цифры 3
 ldi r24, 0b11001100    ; код для цифры 4
 ldi r25, 0b10100100    ; код для цифры 5
 ldi r26, 0b10100000    ; код для цифры 6
 ldi r27, 0b10001111    ; код для цифры 7
 ldi r28, 0b10000000    ; код для цифры 8
 ldi r29, 0b10000100    ; код для цифры 9

 ser temp
 out DDRB, temp         ; порт В: биты 0..7 - выходы
 ldi temp, 0b11111100
 out DDRD, temp         ; порт D: биты 0,1 - входы, биты 2..7 - выходы (не исп.)

 ldi temp, 0b10000001
 out PortB, temp        ; портВ: начальное состояние - цифра "0"
 ldi temp, 0b00000011
 out PortD, temp        ; порт D: биты 0,1 - включить поддяжку, биты 2..7 - начальное состояние "0"

 clr counter            ; сбросить счетчик

 ; ============
 ; Основная программа
Start:
 sbic PinD, 0            ; проверить состояние кнопки и пропустить команду, если бит сброшен (кнопка нажата)
 rjmp DownCounting
 inc Counter             ; инкрементировать счетчик на единицу
 
 cpi Counter, 10         ; сравнить значение счетчика с числом 10
 brne PC+2               ; пропустить одну команду, если флаг нуля сброшен (т.е. счетчик не был равен "10")
 clr Counter             ; сбросить счетчик

 ldi ZL, 20              ; загрузить в регистр ZL адрес регистра R20.
 add ZL, Counter         ; прибавить к содержимому ZL (адрес регистра с кодом цифры) значение счетчика
 ld temp, Z              ; считываем адрес регистра Rx в temp
 out PortB, temp         ; вывести цифру (содержимое регистра) на идикатор
 
 rcall Debounce          ; вызвать подпрограмму задержки от дребезга
ReleaseWait1: 
 sbis PinD, 0            ; проверить состояние кнопки и пропустить команду, если бит установлен (кнопка не нажата)
 rjmp ReleaseWait1
 rcall Debounce          ; вызвать подпрограмму задержки от дребезга
 
 rjmp Start

DownCounting:            ; счет в обратную сторону
 sbic PinD, 1            ; проверить состояние кнопки и пропустить команду, если бит сброшен (кнопка нажата)
 rjmp Start 
 dec Counter             ; декрементировать счетчик на единицу

 brne PC+2               ; пропустить одну команду, если флаг нуля сброшен (т.е. счетчик не был равен "0")
 ldi Counter, 9          ; сбросить счетчик

 ldi ZL, 20              ; загрузить в регистр ZL адрес регистра R20.
 add ZL, Counter         ; прибавить к содержимому ZL (адрес регистра с кодом цифры) значение счетчика
 ld temp, Z              ; считываем адрес регистра Rx в temp
 out PortB, temp         ; вывести цифру (содержимое регистра) на идикатор

 rcall Debounce          ; вызвать подпрограмму задержки от дребезга
ReleaseWait2:
 sbis PinD, 1            ; проверить состояние кнопки и пропустить команду, если бит установлен (кнопка не нажата)
 rjmp ReleaseWait2
 rcall Debounce          ; вызвать подпрограмму задержки от дребезга

 rjmp Start

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

Сообщение akl »

А так?
Спойлер

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

; Автор: Владимир Николаевич
 ; Дата: 03.11.13
 ; Версия: 0.01
 ; Имя файла: Lesson 3 Counter
 ; Для AVR: ATmega32A
 ; Тактовая частота: 4 МГц

 ; Выполняемые функции: Управление семисегментным индикатором и подсчет нажатий на кнопку

 .device ATmega32
 .nolist
 .include "m32def.inc"
 .list

 ; ============
 ; Объявления
 .def temp    = r16
 .def Counter = r17
 .def Delay2  = r18
 .def Delay3  = r19

 ; ============
 ; Начало программы
 rjmp Init

 ; Подпрограммы
Debounce:               ; подпрограмма задержки для подавления дребезга
 ldi temp, 0x80         ; младшие разряды числа 0х013880 (400'000/5=80'000)
 ldi Delay2, 0x12
; ldi Delay2, 0x38       ; средние разряды числа 0х013880 (400'000/5=80'000)
; ldi Delay3, 0x01       ; старшие разряды числа 0х013880 (400'000/5=80'000)

Loop:
 subi temp, 1           ; вычитаем 1 из Delay1 (temp)
 sbci Delay2, 0         ; вычитаем 1 из Delay2, если флаг С = 1
; sbci Delay3, 0         ; вычитаем 1 из Delay3, если флаг С = 1
 brcc Loop              ; возвращаемся к метке, если флаг С = 0
 ret                    ; выход из подпрограммы

 ; ============

Init:
 ldi temp, LOW(RAMEND)  ; указатель стека установлен
 out SPL, temp          ; на последний адрес ОЗУ
 ldi temp, HIGH (RAMEND)
 out SPH, temp

 ldi r20, 0b10000001    ; код для цифры 0
 ldi r21, 0b11001111    ; код для цифры 1
 ldi r22, 0b10010010    ; код для цифры 2
 ldi r23, 0b10000110    ; код для цифры 3
 ldi r24, 0b11001100    ; код для цифры 4
 ldi r25, 0b10100100    ; код для цифры 5
 ldi r26, 0b10100000    ; код для цифры 6
 ldi r27, 0b10001111    ; код для цифры 7
 ldi r28, 0b10000000    ; код для цифры 8
 ldi r29, 0b10000100    ; код для цифры 9

 	CLR	ZH

 ser temp
 out DDRB, temp         ; порт В: биты 0..7 - выходы
	OUT	DDRD,R16
	OUT	PORTD,R16
 ldi temp, 0b11111100
 out DDRD, temp         ; порт D: биты 0,1 - входы, биты 2..7 - выходы (не исп.)
 ldi temp, 0b10000001
 out PortB, temp        ; портВ: начальное состояние - цифра "0"
 ldi temp, 0b00000011
 out PortD, temp        ; порт D: биты 0,1 - включить поддяжку, биты 2..7 - начальное состояние "0"

 clr counter            ; сбросить счетчик

 ; ============
 ; Основная программа
Start:
 sbic PinD, 0            ; проверить состояние кнопки и пропустить команду, если бит сброшен (кнопка нажата)
 rjmp DownCounting
 inc Counter             ; инкрементировать счетчик на единицу
 
 cpi Counter, 10         ; сравнить значение счетчика с числом 10
	BRLO	PC+2               ; пропустить одну команду, если флаг нуля сброшен (т.е. счетчик не был равен "10")
; brne PC+2               ; пропустить одну команду, если флаг нуля сброшен (т.е. счетчик не был равен "10")
 clr Counter             ; сбросить счетчик

 ldi ZL, 20              ; загрузить в регистр ZL адрес регистра R20.
 add ZL, Counter         ; прибавить к содержимому ZL (адрес регистра с кодом цифры) значение счетчика
 ld temp, Z              ; считываем адрес регистра Rx в temp
 out PortB, temp         ; вывести цифру (содержимое регистра) на идикатор
 
 rcall Debounce          ; вызвать подпрограмму задержки от дребезга
ReleaseWait1:
 sbis PinD, 0            ; проверить состояние кнопки и пропустить команду, если бит установлен (кнопка не нажата)
 rjmp ReleaseWait1
 rcall Debounce          ; вызвать подпрограмму задержки от дребезга
 
 rjmp Start

DownCounting:            ; счет в обратную сторону
 sbic PinD, 1            ; проверить состояние кнопки и пропустить команду, если бит сброшен (кнопка нажата)
 rjmp Start
 dec Counter             ; декрементировать счетчик на единицу

	BRGE PC+2               ; пропустить одну команду, если флаг нуля сброшен (т.е. счетчик не был равен "0")
; brne PC+2               ; пропустить одну команду, если флаг нуля сброшен (т.е. счетчик не был равен "0")
 ldi Counter, 9          ; сбросить счетчик

 ldi ZL, 20              ; загрузить в регистр ZL адрес регистра R20.
 add ZL, Counter         ; прибавить к содержимому ZL (адрес регистра с кодом цифры) значение счетчика
 ld temp, Z              ; считываем адрес регистра Rx в temp
 out PortB, temp         ; вывести цифру (содержимое регистра) на идикатор

 rcall Debounce          ; вызвать подпрограмму задержки от дребезга
ReleaseWait2:
 sbis PinD, 1            ; проверить состояние кнопки и пропустить команду, если бит установлен (кнопка не нажата)
 rjmp ReleaseWait2
 rcall Debounce          ; вызвать подпрограмму задержки от дребезга

 rjmp Start

 ; ============
-когда идёт работа с памятью с использованием регистровых пар - адрес памяти в регистровой паре должен быть объявлен полностью. У Вас был задан ZL, а ZH? Совсем не факт, что он по умолчанию равен 0.
-ограничение счётчика в диапазоне 0...9 сделано неправильно.
Реклама
Родился
Сообщения: 2
Зарегистрирован: Сб ноя 09, 2013 13:49:16

Сообщение Radio Killer »

akl писал(а): -когда идёт работа с памятью с использованием регистровых пар - адрес памяти в регистровой паре должен быть объявлен полностью. У Вас был задан ZL, а ZH? Совсем не факт, что он по умолчанию равен 0.
Точно! Как же я мог не заметить, что регистр то не инициализированный! Спасибо Вам большое!
akl писал(а): А так?

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

...
  CLR	 ZH
...
Я внес только вот это, предложенное Вами изменение в свою программу - и всё вроде бы заработало!
akl писал(а): -ограничение счётчика в диапазоне 0...9 сделано неправильно.
Да, это Вы правы. При инкрементировании - всё ограничивается нормально, а вот при декрементировании - нет, если данную операцию начинать, когда на индикаторе горит "0" (т.е. выведено содержимое регистра R20), операция сбивается, адреса регистров уходят ниже R20. Я это знаю. Но это мелочь, я сам устраню.

Спасибо большое!
Ответить

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