Главная страница

Справочник по программированию «Bascom-AVR» (М.Л. Кулиш). Справочник по программированию Bascomavr Создание микропроцессорной системы Теория


Скачать 1.18 Mb.
НазваниеСправочник по программированию Bascomavr Создание микропроцессорной системы Теория
АнкорСправочник по программированию «Bascom-AVR» (М.Л. Кулиш).pdf
Дата21.03.2017
Размер1.18 Mb.
Формат файлаpdf
Имя файлаСправочник по программированию «Bascom-AVR» (М.Л. Кулиш).pdf
ТипСправочник
#4054
КатегорияПромышленность. Энергетика
страница6 из 8
1   2   3   4   5   6   7   8
'---------------------
' ......
'установка индексного регистра Z для считывания байтовых данных
Ldi R30 , Low(Tab_phs * 2) 'записать адрес метки Tab_phs в индексный регистр Z
Ldi R31 , High(Tab_phs * 2) 'младший и старший байты
' ......
'установка специального индексного регистра компилятора
Restore Tab_phs 'запись указателя на метку в регистры R8 и R9
' ......
Tab_phs:
Data 55 , 55 , 55 , 56 'поля данных
' ......
M12:
Read Tmpb 'считывание данных
=============================================================================
24

===================================== Справочник по программированию «Bascom-AVR» ==
Индексы, получаемые в приведенном выше примере, предполагают побайтную адресацию (соответствуют нумерации байт). Имеется еще одна форма загрузки адреса метки, предполагающая получение адреса перехода для его загрузки в программный счетчик.
' ......
'установка индексного регистра Z для операции перехода
Ldi R30 , Low(M12 * 1) 'записать адрес метки M12 в индексный регистр Z
Ldi R31 , High(M12 * 1) 'младший и старший байты как адрес перехода
Ijmp Z 'переход по считанному адресу
' ......
- следует упомянуть об аналогичных операторах, недопустимых в программах прерывания. Вот они
'---------------------
Dim W As Word
'---------------------
' ......
W = Varptr(fldb) 'запись в переменную W указателя на переменную fldb
W = Loadlabel(Tab_phs) 'запись в переменную W указателя на метку
' ......
Типовые программы прерывания
Далее приведены примеры программ обработки прерываний различного типа.
Пример 1 - Прерывание таймера
'----------------------------------------------------------------------------------
Dim R_tim As Byte 'счетчик временных интервалов, задаваемых в главной программе
' ......
On Timer0 Timer0_int Nosave 'вектор прерывания от таймера 0
' ......
Tccr0 = &B00000101 'режим таймера 0: Fкв/1024 - часы реального времени
Enable Timer0 'разрешить прерывание таймера
Enable Interrupts 'разрешить прерывания
' ......
'----------------------------------------------------------------------------------
'обработка прерывания таймера 0 (8-битный таймер)
'используется как часы реального времени с частотой 10 мс
'для этого организована схема деления 8 МГц/1024/78
Timer0_int:
$asm
Push R31 'сохраним регистры
In R31 , Sreg
Push R31
'-----
Ldi R31 , 178 'переустановим счетчик
Out Tcnt0 , R31
'-----
Lds R31 , {r_tim} 'обработка счетчика переменных временных интервалов
And R31 , R31
Breq Intt0_e
Dec R31
Sts {r_tim} , R31
'-----
Intt0_e:
Pop R31
Out Sreg , R31 'восстановим регистры
Pop R31
$end Asm
Return
'----------------------------------------------------------------------------------
Пример 2 - Прерывание от изменения уровня на линии порта
'----------------------------------------------------------------------------------
Dim Edat As Byte 'признак "Есть новые данные энкодера"
Dim R_cdec As Byte 'СЧЕТЧИК ЩЕЛЧКОВ ВЛЕВО
Dim R_cinc As Byte 'СЧЕТЧИК ЩЕЛЧКОВ ВПРАВО
' ......
On Int0 Int0_int Nosave 'вектор внешнего прерывания 0
' ......
'---------------------
Mcucr = &B10000010 'IDLE - разрешить, INT0 - по спаду
'---------------------
' ......
Enable Int0 'разрешить внешнее прерывание 0
=============================================================================
25

===================================== Справочник по программированию «Bascom-AVR» ==
Enable Interrupts 'разрешить прерывания
' ......
'----------------------------------------------------------------------------------
'ОБРАБОТКА ВНЕШНЕГО ПРЕРЫВАНИЯ 0, ОБСЛУЖИВАЮЩЕГО ДВУХФАЗНЫЙ ЭНКОДЕР
'ПРЕРЫВАНИЕ ПРОИСХОДИТ ПО СПАДУ НА ВХОДЕ P_CHA. ЗАТЕМ ПРОГРАММА ИНТЕГРИРУЕТ
'(ФИЛЬТРУЕТ) ЭТОТ УРОВЕНЬ, ДОЖИДАЯСЬ НАДЕЖНОГО УСТАНОВЛЕНИЯ "0". В МОМЕНТ
'ФИКСАЦИИ "0" НА ЛИНИИ P_cha РЕГИСТРИРУЕТСЯ УРОВЕНЬ P_chb , ПО КОТОРОМУ И
'ОПРЕДЕЛЯЕТСЯ НАПРАВЛЕНИЕ ВРАЩЕНИЯ
'-------------------------------------------
' P_cha Alias PIND.2 'ОПРЕДЕЛЕНИЕ ПОРТОВ ВВОДА КОДА ЦИФРОВОЙ РУЧКИ
' P_chb Alias PIND.3
'-------------------------------------------
Const Con_irt = 30 'КОНСТАНТА ИНТЕГРИРОВАНИЯ УРОВНЯ НА ВХОДЕ
'---------
Int0_0:
Inc R31 'УРОВЕНЬ ВЫСОКИЙ - ОТКАТ СЧЕТЧИКА
Cpi R31 , 45 'это Con_irt*1.5
Brne Int0_1 'ЕСЛИ ЖДЕМ СЛИШКОМ ДОЛГО - ВЫХОД
Rjmp Int0_e
'---------
'ВНЕШНЕЕ ПРЕРЫВАНИЕ ОТ ЦИФРОВОЙ РУЧКИ
Int0_int:
$asm
Push R31 'сохраним регистры
In R31 , Sreg
Push R31
'-----
Ldi R31 , 30 'ПОСТОЯНАЯ ИНТЕГРИРОВАНИЯ
Int0_1:
Sbic Pind , 2
Rjmp Int0_15 'ЕСЛИ НА НОЖКЕ "1"
Dec R31 'ПОКА НЕ ОБНУЛИЛСЯ СЧЕТЧИК ЖДЕМ
Brne Int0_1 'УСТАНОВЛЕНИЯ НИЗКОГО УРОВНЯ
Rjmp Int0_2
'-----
Int0_15:
Inc R31 'УВЕЛИЧИВАЕМ СЧЕТЧИК
Cpi R31 , 60 'ЕСЛИ НА "1" УСТАНОВЛЕНА СЛИШКОМ ДОЛГО
Brne Int0_e 'НА ВЫХОД
Rjmp Int0_1
'---------------------------------------------
'ПРОГРАММА РАСЧИТАНА НА КОДОВЫЙ ПЕРЕКЛЮЧАТЕЛЬ
'С НОРМАЛЬНО РАЗОМКНУТЫМИ КОНТАКТАМИ, ЗАМЫКАЮЩИМИСЯ
'ТОЛЬКО В МОМЕНТ ЩЕЛЧКА. ЭТО ОЧЕНЬ УПРОЩАЕТ ЗАДАЧУ
'---------------------------------------------
' |<----- ВРАЩЕНИЕ ВЛЕВО (ИЛИ НАОБОРОТ, В ЗАВИСИМОСТИ ОТ МОНТАЖА)
'chA--- --------- ------ ОПРЕДЕЛЕНИЕ НАПРАВЛЕНИЯ
' ¦ ¦ chA ¦ ¦ ВРАЩЕНИЯ ЦИФРОВОГО КОДЕРА
' --- --- ОСНОВАНО НА АНАЛИЗЕ СОСТОЯНИЯ
'chB----- | --------- ---- КАНАЛА "B" В МОМЕНТ ЗАМЫКАНИЯ
' | ¦ | ¦ chB ¦ ¦ (ЩЕЛЧКА) В КАНАЛЕ "A"
' | --- ---
' | |<------ ВРАЩЕНИЕ ВПРАВО
'---------------------------------------------
Int0_2:
'ОБРАБОТКА ИЗМЕНЕНИЯ УРОВНЯ
'---------
Sbis Pind , 3 'ОПРЕДЕЛИМ НАПРАВЛЕНИЕ ВРАЩЕНИЯ
Rjmp Int0_3
'---------
'ВРАЩЕНИЯ ВЛЕВО (УМЕНЬШЕНИЕ)
Lds R31 , {r_cdec} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВЛЕВО
Inc R31
Sts {r_cdec} , R31
Rjmp Int0_4
'---------
Int0_3:
'ВРАЩЕНИЯ ВПРАВО (УВЕЛИЧЕНИЕ)
Lds R31 , {r_cinc} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВПРАВО
Inc R31
Sts {r_cinc} , R31
Int0_4:
Ldi R31 , &HFF
Sts {edat} , R31 'поставить признак "НОВЫЕ ДАННЫЕ ЕНКОДЕРА"
'---------
Int0_e:
Pop R31
Out Sreg , R31
Pop R31
=============================================================================
26

===================================== Справочник по программированию «Bascom-AVR» ==
$end Asm
Return
'----------------------------------------------------------------------------------
Пример 3 - Прерывание АЦП при завершении преобразования
'----------------------------------------------------------------------------------
Dim Tmpb As Byte 'временные байтовые данные
Dim B_adc As Byte 'указатель "есть новые данные внутреннего АЦП"
Dim Dadc As Word 'данные АЦП (внутреннего)
Dim Ua As Single 'временное значение
' ......
Mcucr = &B10000000 'IDLE – разрешить
' ......
'------------------------------------------
' измерение с помощью внутреннего АЦП результат Ua, выражен в Вольтах шкалы
Rd_iadc:
Admux = &B00000001 'внешняя опора АЦП со входа AREF, внутренняя выключена
'измерение по входу PA1 (напряжение)
Adcsr = &B10001110 'разрешить АЦП с частотой тактирования F / 64 в режиме
'с естественным положением битов, прерывание разрешено
'-------
For Tmpb = 1 To 16 'произвести 16 измерений
Set Adcsr.6 'запустить АЦП
Rdiadc1:
Idle 'останов
If B_adc = 0 Then 'есть данные внутреннего АЦП?
Goto Rdiadc1 'нет - повторить
End If
Next Tmpb
Adcsr = &B00000110 'запретить АЦП
Dadc = Dadc - 25 'коррекция смещения нуля
Ua = Dadc : Dadc = 0 'в формат с плавающей точкой, а исходный очистить
Ua = Ua * 0.0003052 : Return 'привести к шкале 0...5 В
'------------------------------------------
'обработка прерывания от внутреннего АЦП
Adc_int:
$asm
Push R31 'сохраним регистры
In R31 , Sreg
Push R31
Push R30
Push R29
'-----
'считать данные внутреннего АЦП
lds R29 , {Dadc} 'считать сумму
Lds R30 , {Dadc + 1}
In R31 , Adcl 'считать показани
Add R29 , R31 'добавить к сумме показания АПЦ
In R31 , Adch
Adc R30 , R31
Sts {Dadc} , R29
Sts {Dadc + 1} , R30
'-----
Ldi R31 , 255 'есть данные внутреннего АЦП
Sts {B_adc} , R31
'-----
Adcinte:
Pop R29 'восстановим регистры
Pop R30
Pop R31
Out Sreg , R31
Pop R31
Reti
$end Asm
Return
'----------------------------------------------------------------------------------
Пример 4 - Прерывание приемника и передатчика UART
'----------------------------------------------------------------------------------
Dim Rdat As Byte 'признак "Есть новые данные из RS"
Dim Cnt_rc As Byte 'счетчик принимаемых из RS символов
Dim R_cch As Word 'указатель буфера принимаемых символов
Dim Bufrr As String * 20 'принятой строки из RS
Dim Bufr As String * 20 'обрабатываемой строки из RS
Dim T_cch As Word 'указатель буфера передаваемых символов
Dim Buft As String * 20 'передаваемая строка
=============================================================================
27

===================================== Справочник по программированию «Bascom-AVR» ==
' ......
'---------------------
' UART:
$baud = 9600 'скорость 9.6 кБ
$crystal = 8000000 'при кварце 8 МГц
'---------------------
' назначение векторов прерывания
On Urxc Rxd_int Nosave 'вектор прерывания от приемника UART
On Utxc Txd_int Nosave 'вектор прерывания от приемника UART
'---------------------
Gosub Clr_bufrr 'очистить переменные приемного буфера
Enable Urxc 'разрешить прерывание приемника UART
Enable Utxc 'разрешить прерывание передатчика UART
Enable Interrupts 'разрешить прерывания
'---------------------
' ......
Buft = "TRANSFERED DATA" 'передаваемая строка
Gosub Print_tb 'передать буфер
' ......
'----------------------------------------------
' обработка прерывания приемника UART
Rxd_int:
$asm
Push R31 'сохраним регистры
In R31 , Sreg
Push R31
Push R30
Push R27
Push R26
'---------
'принимаем данные интерфейса
Lds R26, {R_cch} 'значение текущей позиции буфера
Lds R27, {R_cch + 1}
In R31 , Udr 'считать принятый символ
'преобразование строчного символа в прописной
Andi R31 , &h7f 'ограничение диапазона символов
Cpi R31 , &h61 'ниже кода символа 'a'? (нижняя граница)
Brcs Rxdc_0 'да - переход
Cpi R31 , &h7b 'выше кода символа 'z'? (верхняя граница)
Brcc Rxdc_0 'да - переход
Andi R31 , &h5f 'между ними - наложить маску
'-----
Rxdc_0:
Cpi R31 , &H0A 'CR?
Breq Rxdc_e 'игнорировать
Cpi R31 , &H0D 'LF?
Breq Rxdc_2 'это конец строки
St X+ , R31 'остальное записывать в буфер
Lds R30, {Cnt_rc}
Inc R30
Cpi R30 , 20 'число 20 – длина буфера
Breq Rxdc_e 'если не последняя позиция
Rxdc_1:
Sts {r_cch} , R26 'записать измененный указатель буфера
Sts {r_cch + 1} , R27
Sts {cnt_rc} , R30 'и новое значение счетчика символов
Rxdc_e:
Pop R26
Pop R27
Pop R30
Pop R31
Out Sreg , R31
Pop R31
Reti
'---------
'принят конец строки – нужно переписать принятые данные в промежуточный буфер
Rxdc_2:
Ldi R31 , &HFF
Sts {rdat} , R31 'поставить признак наличия принятой строки в буфере Bufr
'---------
'займем еще регистры (Y) для копирования из Bufrr в Bufr
Push R29 'сохраним их
Push R28
$end Asm
Loadadr Bufr , X 'указатель буфера Bufr в Y на начало
$asm
Mov R28 , R26 'применим такой извратный способ, чтобы компилятор
Mov R29 , R27 'не увидел явного использования программного стека
$end Asm
=============================================================================
28

===================================== Справочник по программированию «Bascom-AVR» ==
Loadadr Bufrr , X 'указатель буфера Bufrr в X на начало
$asm
Lds R30, {Cnt_rc} 'считать число принятых символов
Rxdc_c:
Ld R31 , X+ 'считать из Bufrr
St Y+ , R31 'записать в буфер Bufr
Dec R30
Brne Rxdc_c
St Y , R30 'записать в буфер Bufr конец строки
Pop R28 'восстановим указатель программного стека
Pop R29
'---------
$end Asm
Loadadr Bufrr , X 'указатель буфера Bufrr в X снова на начало
$asm
Rjmp Rxdc_1 'и сбросить значение счетчика символов
$end Asm
Return 'пустая команда, на место которой компилятор
'поставит обязательную команду RETI
'----------------------------------------------
' обработка прерывания передатчика UART
Txd_int:
Push R31 'сохраним регистры
In R31 , Sreg
Push R31
Push R27
Push R26
'-----
Lds R26 , {t_cch} 'значение текущей позиции буфера
Lds R27 , {t_cch + 1}
Ld R31 , Y+
And R31 , R31 'проверить на нуль
Breq Txdint1 'если он равен 0 - переход
!Out Udr , R31 'записать передаваемый символ
Sts {t_cch} , R26 'записать измененный указатель буфера
Sts {t_cch + 1} , R27
'-----
Txdint1:
Pop R27 'восстановим регистры
Pop R26
Pop R31
!Out Sreg , R31
Pop R31
Reti
$end Asm
Return
'----------------------------------------------
' ......
'----------------------------------------------
'передача буфера
Print_tb:
Buft = Buft + Chr(13) + Chr(10) 'добавить к содержимому буфера команды конца строки
T_cch = Varptr(buft) 'установить указатель на начало буфера
Udr = Peek(t_cch) 'инициализировать начало передачи, загрузив
'первый символ в передатчик это можно было бы не делать,
'если бы можно установить бит TXC (Ucsra , 6),
'а использовать бит UDRE (Ucsra , 5) нельзя
Incr T_cch 'установить указатель на следующий символ
Return
'----------------------------------------------
'очистить переменные приемного буфера
Clr_bufrr:
Bufrr = "" 'сам буфер (записать нуль в начало)
Rdat = 0 'признак наполнения
Cnt_rc = 0 'счетчик принятых символов
R_cch = Varptr(bufrr) 'указатель буфера на начало
Return
'----------------------------------------------------------------------------------
Разумеется, что при отсутствии необходимости экономить ресурсы микроконтроллера программа прерыва- ния может быть выполнена без ассемблерных вставок. Ниже приведен пример программы, содержащей такой об- работчик прерываний. Сохранение регистров общего назначения выполняется компилятором самостоятельно (оп- ция NOSAVE не применена) и все операции обработки данных производятся с использованием операторов Bas- com-AVR.
=============================================================================
29

===================================== Справочник по программированию «Bascom-AVR» ==
Пример 5 - Прерывание от изменения уровня на линиях порта
'----------------------------------------------------------------------------------
$regfile = "m644def.dat" 'для чипа ATMega644
' ......
Dim Num_port As Byte 'номер порта с изменившимся уровнем
Dim Dub_pa As Byte 'дублер порта A
Dim Dub_pb As Byte 'дублер порта B
Dim Dub_pc As Byte 'дублер порта C
Dim Dub_pd As Byte 'дублер порта D
1   2   3   4   5   6   7   8


написать администратору сайта