- •Лабораторна робота №3
- •Текст програми
- •Interrupt movwf w_copy ;Сохраняем контекст
- •Incf number,f ;Подготавливаемся к воспроизведению следующей мелодии
- •Incf counter,f ;Инкрементируем счетчик номера ноты
- •Incf number,f ;Подготавливаемся к воспроизведению следующей мелодии
- •Xorwf temp3,w ;Последний светодиод был?
- •Приводимо текст нех файла:
- •Використані команди:
- •Висновки:
Interrupt movwf w_copy ;Сохраняем контекст
mov ST_copy,STATUS
movlw B'10000000' ;Коррекция TMR0,
movwf TMR0 ;чтоб прерывания почаще происходили
movf ADDRESS,W ;Адрес ячейки с требуемыми на данном шаге данными
movwf FSR ;заносим в FSR (косвенная адресация)
comf INDF,W ;Переносим данные из ячейки с указанным адресом в W
;с инверсией, т.к. светодиоды подключены к "плюсу"
movwf PORTB ;И выдаем результат на выводы PORTB
movlw BYTE1F ;Заносим адрес ячейки BYTE1F в W
xorwf ADDRESS,W ;Если адреса совпадают, то пора вернутся к BYTE00
btfss STATUS,Z ;Адреса совпали, Z=1, пропускаем переход
goto Int_label ;Адреса не совпали, переход
movlw BYTE00 ;Снова заносим адрес ячейки Byte0
movwf ADDRESS ;в ячейку ADDRESS - начался следующий цикл
Int_label incf ADDRESS,F ;В следующем прерывании будем выводить следующий байт
movf LONGTIMER,W ;Заданное число циклов прошло?
jz PlaybackN ;Да - переход на воспроизведение текущей мелодии
PlaybackN clrf COUNTER ;Обнуляем счетчик номера ноты
movf NUMBER,W
sublw D'11' ;Проверка - если NUMBER не больше 11
btfss STATUS,C ;то переход к воспроизведению
goto Finish ;Иначе переход на Finish
sublw D'11' ;Восстанавливаем исходное значение
clrf PCLATH
addwf PCL,F ;Переход на исполнение мелодии под номером NUMBER
goto Melody11
Finish movf LONGTIMER,W ;Мелодия воспроизведена по причине истечения интервала?
jnz Demand_label ;Нет - переход
Incf number,f ;Подготавливаемся к воспроизведению следующей мелодии
movf NUMBER,W
sublw SONGS-1 ;(SONGS-1-W) --> W
btfss STATUS,C ;Мелодия была последняя по номеру ?
clrf NUMBER ;Да - возврат к начальной мелодии
mvi LONGTIMER,CYCLES ;Исходное значение - начинаем отсчет циклов по новой
Demand_label call Led_all_100
movlw D'200'
call Pause
End_int bcf INTCON,T0IF ;Сбрасываем флаг запроса на прерывание от таймера
mov STATUS,ST_copy ;Восстанавливаем контекст
swapf W_copy,F ;Тут приходится хитрить, чтобы сохранить бит Z в STATUS
swapf W_copy,W ;(MOVF его может изменить, а SWAPF - нет)
retfie ;Возврат из обработчика с установкой бита GIE
;--------------------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------------------
; --- ПОДПРОГРАММЫ ---
;--------------------------------------------------------------------------------------------------
;Подпрограммы табличной конвертации
;--------------------------------------------------------------------------------------------------
;Подпрограмма декодирования длительности
Dec_dur clrf PCLATH
addwf PCL,F
retlw D'8' ;"HHHHH000" = 1/8
retlw D'16' ;"HHHHH001" = 1/4
retlw D'32' ;"HHHHH010" = 1/2
retlw D'48' ;"HHHHH011" = 3/4
retlw D'64' ;"HHHHH100" = 1
retlw D'96' ;"HHHHH101" = 3/2
retlw D'128' ;"HHHHH110" = 2
retlw D'255' ;"HHHHH111" = 4
;Подпрограмма декодирования ноты
Dc_tone sublw D'24' ;Проверка - если число не больше 24
btfss STATUS,C ;то переход на дешифрацию
retlw 00h ;Иначе возвращаем 0 (тишина)
clrf PCLATH
sublw D'24' ;Восстанавливаем исходное значение
addwf PCL,F
retlw D'252' ;"00000DDD" = "си" 1-й октавы (494 Гц)
retlw D'238' ;"00001DDD" = "до" 2-й октавы (524 Гц)
retlw D'224' ;и так далее...
retlw D'212'
retlw D'202'
retlw D'190'
retlw D'178'
retlw D'168'
retlw D'158'
retlw D'150'
retlw D'142'
retlw D'134'
retlw D'126' ;"си" 2-й октавы (988 Гц)
retlw D'119' ;"до" 3-й октавы (1048 Гц)
retlw D'112'
retlw D'106'
retlw D'101'
retlw D'95'
retlw D'89'
retlw D'84'
retlw D'79'
retlw D'75'
retlw D'71'
retlw D'67'
retlw D'63' ;"си" 3-й октавы (1976 Гц)
;Подпрограмма дешифрации номера воспроизводимой ноты для отображения на светодиодах
Dcd8 andlw B'00000111' ;Нас интересуют младшие 3 бита (т.к. 8 светодиодов)
clrf PCLATH
addwf PCL,F
retlw B'11111110'
retlw B'11111100'
retlw B'11111000'
retlw B'11110000'
retlw B'11100000'
retlw B'11000000'
retlw B'10000000'
retlw B'00000000'
;--------------------------------------------------------------------------------------------------
;Сервисные подпрограммы
;--------------------------------------------------------------------------------------------------
;Подпрограмма паузы (используется ячейка TEMP1)
Pause movwf TEMP1 ;Длительность паузы задается числом в W (примерно в мс)
movf TEMP1,F ;Проверка на 0
btfsc STATUS,Z ;Если длительность не равна 0, то Z=0 и пропускаем return
return ;Если же длительность равна 0, то сразу возврат
clrw ;Очищаем W
P_label addlw 01h ;Внутренний цикл по W
btfss STATUS,Z ;
goto P_label ;
decfsz TEMP1,F ;Внешний цикл по TEMP1
goto P_label ;
return ;Конец подпрограммы паузы
;Подпрограмма вспышки всех светодиодов с паузой 100 мс
Led_all_100 clrf PORTB
movlw D'100'
call Pause
mvi PORTB,0FFh
return
;--------------------------------------------------------------------------------------------------
;Музыкальные подпрограммы
;--------------------------------------------------------------------------------------------------
;Подпрограмма выдачи звукового сигнала
Sound
movwf TONE ;Временно сохраняем исходные данные (байт был в W)
andlw B'00000111' ;Маска
call Dec_dur ;Вызов подпрограммы табличной конвертации
movwf DURATION ;Получили результат - байт, задающий длительность ноты
rrf TONE,F
rrf TONE,F
rrf TONE,W ;Сдвигаем...
andlw B'00011111' ;Маска
call Dc_tone ;Вызов подпрограммы табличной конвертации
movwf TONE ;Получили результат - байт, задающий высоту тона
movf COUNTER,W
call Dcd8 ;Вызываем дешифратор, результат в W
movwf PORTB ;И выдаем результат на выводы PORTB
