23 августа 2012 г.

Подсчет нажатий с 8-сегментным индикатором

Я доработал программу, которая считает количество нажатий кнопки. Теперь количество отображается с помощью 8-сегментного светодиодного индикатора. Для простоты я использовал один индикатор, соответственно отобразить можно только одну цифру. Поэтому программа считает до 9, а при следующем нажатии сбрасывает счетчик.


В схеме используется индикатор RL-S3910. Это индикатор с общим катодом (минусом). Схема выводов на рис. 1.
Рис. 1. Схема выводов  RL-S3910
Светодиоды, насколько я понял из даташита, рассчитаны на ток 20 мА. Прямое напряжение на светодиоде я принял за 2 В. К каждому нужно подключить резистор R = (6В - 2В)/0,02А = 200Ом.

Восьмиразрядные двоичные числа, каждое из которых представляет десятичную цифру, отображаемую индикатором, я записываю в SRAM (процедура SAVE_TEST_DATA, листинг 1). Каждый бит числа соответствует одному сегменту индикатора. Лучше было бы записать их в EEPROM, но пока пусть будет так.

Двоичные числа, представляющие десятичные цифры на индикаторе я записываю подряд, начиная с адреса, помеченного меткой "Numbers". Место для них резервируется с помощью директивы .BYTE. Получение адреса необходимого числа производится сложением адреса "Numbers" со значением счетчика нажатий. Таким образом мы получили подобие одномерного массива.

Обработчик прерывания инкрементирует счетчик нажатий. Потом с помощью команды cpi я сравниваю значение счетчика с константой 10. Фактически эта команда производит вычитание константы из регистра без изменения содержимого последнего. Если счетчик насчитал меньше 10, результат вычитания отрицательный, и в регистре SREG устанавливается флаг отрицательного значения Z. В этом случае мы пропускаем сброс счетчика и переходим к отображению числа нажатий. В противном случае - сбрасываем счетчик и начинаем считать с нуля.

Листинг 1.
.device ATiny26
.include "tn26def.inc"

.equ Numbers_count = 10

.def temp = r16
.def Counter = r17

.dseg
Numbers: .BYTE Numbers_count

.cseg
.org 0
rjmp RESET ; Reset handler
rjmp EXT_INT0 ; IRQ0 handler
reti; rjmp PIN_CHANGE ; Pin change handler
reti; rjmp TIM1_CMP1A ; Timer1 compare match 1A
reti; rjmp TIM1_CMP1B ; Timer1 compare match 1B
reti; rjmp TIM1_OVF ; Timer1 overflow handler
reti; rjmp TIM0_OVF ; Timer0 overflow handler
reti; rjmp USI_STRT ; USI Start handler
reti; rjmp USI_OVF ; USI Overflow handler
reti; rjmp EE_RDY ; EEPROM Ready handler
reti; rjmp ANA_COMP ; Analog Comparator handler
reti; rjmp ADC ; ADC Conversion Handler
;

EXT_INT0:
    inc Counter
    cpi Counter, 0b00001010
    brbs 2, SKIP_RESET
    clr Counter
    
    SKIP_RESET:

    rcall LOAD_DATA
    out PORTA, r0
    reti


LOAD_DATA:
    ldi ZH, High(Numbers)
    ldi ZL, Low(Numbers)
    
    clr temp
    add ZL, Counter
    adc ZH, temp

    ld r0, Z

    ret;


SAVE_TEST_DATA:
    ldi YH, High(Numbers)
    ldi YL, Low(Numbers)

    ;DP, C, B, A, D, E, F, G
    ;0
    ldi temp, 0b01111110
    st Y+, temp

    ;1
    ldi temp, 0b01100000
    st Y+, temp

    ;2
    ldi temp, 0b00111101
    st Y+, temp

    ;3
    ldi temp, 0b01111001
    st Y+, temp

    ;4
    ldi temp, 0b01100011
    st Y+, temp

    ;5
    ldi temp, 0b01011011
    st Y+, temp

    ;6
    ldi temp, 0b01011111
    st Y+, temp

    ;7
    ldi temp, 0b01110000
    st Y+, temp

    ;8
    ldi temp, 0b01111111
    st Y+, temp

    ;9
    ldi temp, 0b01111011
    st Y+, temp

    ret;


RESET:
    ldi r16, RAMEND ; Main program start
    out SP, r16

    ;set all A port contacts to OUT mode
    ldi temp, 0b11111111
    out DDRA, temp

    ;turn off Analog Comparator
    ldi temp, (1<<ACD)
    out ACSR, temp

    ;pull-up resistor
    ldi temp, 0b00000010
    out PORTB, temp

    /*
    ISC01 ISC00 Description
      0        0    The low level of INT0 generates an interrupt request.
      0        1    Any change on INT0 generates an interrupt request.
      1        0    The falling edge of INT0 generates an interrupt request.
      1        1    The rising edge of INT0 generates an interrupt request.

      When changing the ISC10/ISC00 bits, INT0 must be disabled by clearing
      its Interrupt Enable bit in the GIMSK Register. 
      Otherwise an interrupt can occur when the bits are changed.
    */
    ldi temp, (1<<ISC00)
    out MCUCR, temp

    ldi temp, (1<<ISC01)
    out MCUCR, temp

    ;allow external interrupt interrupt INT0
    ldi temp, (1<<INT0)
    out GIMSK, temp
    sei
    
    rcall SAVE_TEST_DATA

    rcall LOAD_DATA
    out PORTA, r0

MAIN_CYCLE:
rjmp MAIN_CYCLE

Вот как это всё выглядит:

А вот как это работает:

Комментариев нет:

Отправить комментарий