Здесь будут собраны варианты написания кода с помощью компилятора Bascom и его аналог на ASM AVR (ассемблере).
Не жадничайте, делитесь информацией!
Отредактировано sasha_1973 (2013-10-21 09:51:47)
Программирование ATMEL в BASCOM. |
Привет, Гость! Войдите или зарегистрируйтесь.
Вы здесь » Программирование ATMEL в BASCOM. » Применение Assembler в среде Bascom(-8051) » Варианты интерпретации Bascom на ASM AVR (ассемблер)
Здесь будут собраны варианты написания кода с помощью компилятора Bascom и его аналог на ASM AVR (ассемблере).
Не жадничайте, делитесь информацией!
Отредактировано sasha_1973 (2013-10-21 09:51:47)
Ограниченный константой повторяющийся счетчик, сбрасывается в 1.
Const Количество_подсчетов = 8
Dim Счетчик As Byte
Incr Счетчик
If Счетчик > Количество_подсчетов Then
Счетчик = 1
End If
или такIncr Счетчик : If Счетчик > Количество_подсчетов Then Счетчик = 1
LDI R26,0x00
LDI R27,0x01
LD R24 , X
SUBI R24,0xFF
ST X , R24
LDS R16,0x0100
CPI R16,0x08
BRCS PC + 0x03
BREQ PC+0x02
RJMP PC + 0x0002
RJMP PC+0x0004
LDI R24 , 0x01
STS 0x0100 , R24
$asm
lds R31 , {Счетчик} ' Прямая загрузка из переменной в регистр время выполнения 2 такта
cpi R31 , Количество_подсчетов ' Сравнить регистр и константу "Количество_подсчетов" 1 такт
BRCS Счетчик_плюс ' Перейти если меньше чем "Количество_подсчетов + 1 " если переход на метку тогда 2 такта иначе 1 такт
clr R31 ' Очистить регистр 1 такт
Счетчик_плюс:
inc R31 ' Инкрементировать содержимое регистра 1 такт
sts {Счетчик} , R31 ' Прямая загрузка из регистра в переменную 2 такта
$end Asm
Отредактировано sasha_1973 (2013-10-21 12:35:11)
Секундные прерывания TIMER2 с выводом секундных импульсов на OC2A
'=================================================
' Подпрограмма обработки прерывания TIMER2, происходит 1 или 2 раза в секунду, в зависимости от настроек TIMER2
'=================================================
Обработка_прерывания_timer2:
'-------------------------------------------------------------------------------------------
Incr Счетчик_прерываний_timer2
If Счетчик_прерываний_timer2 < Const_количество_прерыв_timer2 Then Goto Выход_прерывание_timer2Incr Счетчик_секунд
Счетчик_прерываний_timer2 = 0
Флаг_было_прерывание_timer2 = 1
Флаг_данные_для_передачи_usart = 1
'-----------------------------------
Выход_прерывание_timer2:
'-------------------------------------------------------------------------------------------
Return
'=================================================
'=================================================
' Подпрограмма обработки прерывания TIMER2, происходит 1 или 2 раза в секунду, в зависимости от настроек TIMER2
'=================================================
Обработка_прерывания_timer2:
'-------------------------------------------------------------------------------------------
$asm
'--- Сохраняем регистры, которые используем в обработке прерывания ---
Push R31 ' Сохраняем регистры, которые используем в обработке прерывания
In R31 , Sreg
Push R31
'------------------ Считаем количество прерываний TIMER2 --------------------
Lds R31 , {счетчик_прерываний_timer2} ' Считываем значение переменной "Счетчик_прерываний_timer2" в регистр "R31", для последующих операций
Inc R31 ' Инкриминируем значение переменной в регистре "R31"
sts {счетчик_прерываний_timer2} , R31 ' Заносим значение из регистра "R31" в переменную "Счетчик_прерываний_timer2" и идем дальше
Andi R31 , Const_количество_прерыв_timer2 ' Сравниваем полученное значение с значением "Const_количество_прерыв_timer2"
'---------------- Делаем, что надо, по результату сравнения ------------------
Breq Выход_прерывание_timer2 ' Перейти если меньше чем "Количество_переменных + 1 " если переход на метку тогда 2 такта иначе 1 такт
clr R31 ' Если полученное значение равно значениию "Const_количество_прерыв_timer2", пишем "0" в регистр "R31
sts {счетчик_прерываний_timer2} , R31 ' Заносим значение из регистра "R31" в переменную "Счетчик_прерываний_timer2" и идем дальше
'-------------------------------------------------------------------------------------------
' Подпрограммы и флаги обрабатываемые по значению константы "Const_количество_прерыв_timer2"
'--------------------------- Считаем секунды ----------------------------------------
lds R31 , {Счетчик_секунд} ' Считываем значение переменной "Счетчик_секунд" в регистр "R31", для последующих операций
Inc R31 ' Инкриминируем значение переменной в регистре "R31"
sts {Счетчик_секунд} , R31 ' Заносим значение из регистра "R31" в переменную "Счетчик_секунд" и идем дальше
'----------------- Пишем числовое значение поднятых флагов -----------------
Ldi R31 , 1 ' Пишем числовое значение (любое байтовое значение (1-255)) в регистр "R31", для последующих операций с флагами
'---------------------- Подымаем нужные флажки ---------------------------------
' sts {Флаг_обновить_данные_времени} , R31 ' Пишем значение из регистра "R31" в переменную "Флаг_обновить_данные_времени"
' sts {Флаг_обновить_индикатор} , R31 ' (STS) Прямое сохранение , Пишем значение из регистра "R31" в переменную "Флаг_обновить_индикатор"
sts {Флаг_данные_для_передачи_usart} , R31 ' Пишем значение из регистра "R31" в переменную "Флаг_данные_для_передачи_usart"
'------------- Подымаем флажок, что было прерывание TIMER2 ---------------
sts {Флаг_было_прерывание_timer2} , R31 ' Заносим значение из регистра "R31" в переменную "Счетчик_прерываний_timer2" и идем дальше
'-------------------------------------------------------------------------------------------
Выход_прерывание_timer2:
' Восстанавливаем ранее сохраненные регистры и выходим из прерывания
Pop R31
Out Sreg , R31 ' Восстанавливаем регистры
Pop R31
$end Asm
'-------------------------------------------------------------------------------------------
Return
'=================================================
$regfile = "m88def.dat" ' Используемый контроллер
$crystal = 1000000 ' 1 МГц
$framesize = 32
$hwstack = 40
$swstack = 16
$baud = 4800 '4800 '9600 '19200 '38400'------------- Настройка прерывания TIMER2, для работы часов (раскомментировать нужное) -----------------
Config Timer2 = Timer , Async = On , Prescale = 64 , Compare A = Toggle ' Делитель 32768 / 64 / 256 = 0,5 сек (прерывание TIMER2 = 2 раза в секунду)
Const Const_количество_прерыв_timer2 = 2
'---------------------------------------------------------------
' Config Timer2 = Timer , Async = On , Prescale = 128 ' Делитель 32768 / 128 / 256 = 1 сек (прерывание TIMER2 = 1 раз в секунду)
' Const Const_количество_прерыв_timer2 = 1 ' Значение константы используется в подпрограмме "Обработка_прерывания_timer2"
'---------------------------------------------------------------
' Ссылка на подпрограмму обработчика прерывания TIMER2, для работы часов
On Timer2 Обработка_прерывания_timer2 Nosave ' Ссылка на подпрограмму обработчика прерывания TIMER2
'--------------- Настройка пониженного энергопотребления МК ---------------
' Assr.3 = 1 : Waitms 100 ' Включить НЧ-генератор AS2 и подождать стабилизации амплитуды генератора
' При включении бита AS2 (3) в регистре ASSR (ASSR.3), становится возможным применение режима "Powersave" - разновидность спящего режима. Пробуждение МК от TIMER2
' Mcucr = &B10000000 ' Разрешаем режим пониженного энергопотребления Power Idle
' Mcucr = &B10110000 ' Разрешаем режим пониженного энергопотребления Power Save
'-------------------------------------------------------------------------------------------
Dim Счетчик_секунд As Byte
Dim Счетчик_прерываний_timer2 As Byte
Dim Флаг_было_прерывание_timer2 As Byte
Dim Флаг_данные_для_передачи_usart As Byte
'-------------------- Разрешаем работу нужных прерываний --------------------
Enable Timer2
'-------------------- Разрешаем работу всех прерываний ------------------------
Enable Interrupts
'=================================================Do
If Флаг_данные_для_передачи_usart = 1 Then
Print Счетчик_секунд
Флаг_данные_для_передачи_usart = 0
End If'-----------------------
Спящий_режим:
' Power Idle
Power Powersave
' Powerdown
'-----------------------
Loop
End
'=================================================' И С П О Л Ь З У Е М Ы Е П О Д П Р О Г Р А М М Ы
'=================================================
'=================================================
' Подпрограмма обработки прерывания TIMER2, происходит 1 или 2 раза в секунду, в зависимости от настроек TIMER2
'=================================================
Обработка_прерывания_timer2:
'-------------------------------------------------------------------------------------------
$asm
'--- Сохраняем регистры, которые используем в обработке прерывания ---
Push R31 ' Сохраняем регистры, которые используем в обработке прерывания
In R31 , Sreg
Push R31
'------------------ Считаем количество прерываний TIMER2 --------------------
Lds R31 , {счетчик_прерываний_timer2} ' Считываем значение переменной "Счетчик_прерываний_timer2" в регистр "R31", для последующих операций
Inc R31 ' Инкриминируем значение переменной в регистре "R31"
sts {счетчик_прерываний_timer2} , R31 ' Заносим значение из регистра "R31" в переменную "Счетчик_прерываний_timer2" и идем дальше
Andi R31 , Const_количество_прерыв_timer2 ' Сравниваем полученное значение с значением "Const_количество_прерыв_timer2"
'---------------- Делаем, что надо, по результату сравнения ------------------
Breq Выход_прерывание_timer2 ' Перейти если меньше чем "Количество_переменных + 1 " если переход на метку тогда 2 такта иначе 1 такт
clr R31 ' Если полученное значение равно значениию "Const_количество_прерыв_timer2", пишем "0" в регистр "R31
sts {счетчик_прерываний_timer2} , R31 ' Заносим значение из регистра "R31" в переменную "Счетчик_прерываний_timer2" и идем дальше
'-------------------------------------------------------------------------------------------
' Подпрограммы и флаги обрабатываемые по значению константы "Const_количество_прерыв_timer2"
'--------------------------- Считаем секунды ----------------------------------------
lds R31 , {Счетчик_секунд} ' Считываем значение переменной "Счетчик_секунд" в регистр "R31", для последующих операций
Inc R31 ' Инкриминируем значение переменной в регистре "R31"
sts {Счетчик_секунд} , R31 ' Заносим значение из регистра "R31" в переменную "Счетчик_секунд" и идем дальше
'----------------- Пишем числовое значение поднятых флагов -----------------
Ldi R31 , 1 ' Пишем числовое значение (любое байтовое значение (1-255)) в регистр "R31", для последующих операций с флагами
'---------------------- Подымаем нужные флажки ---------------------------------
' sts {Флаг_обновить_данные_времени} , R31 ' Пишем значение из регистра "R31" в переменную "Флаг_обновить_данные_времени"
' sts {Флаг_обновить_индикатор} , R31 ' (STS) Прямое сохранение , Пишем значение из регистра "R31" в переменную "Флаг_обновить_индикатор"
sts {Флаг_данные_для_передачи_usart} , R31 ' Пишем значение из регистра "R31" в переменную "Флаг_данные_для_передачи_usart"
'------------- Подымаем флажок, что было прерывание TIMER2 ---------------
sts {Флаг_было_прерывание_timer2} , R31 ' Заносим значение из регистра "R31" в переменную "Счетчик_прерываний_timer2" и идем дальше
'-------------------------------------------------------------------------------------------
Выход_прерывание_timer2:
' Восстанавливаем ранее сохраненные регистры и выходим из прерывания
Pop R31
Out Sreg , R31 ' Восстанавливаем регистры
Pop R31
$end Asm
'-------------------------------------------------------------------------------------------
Return
'=================================================
Отредактировано sasha_1973 (2013-10-21 09:46:26)
Подпрограмма расчета часов, минут, секунд
'=================================================
'----------- Подпрограмма расчета времени: часов, минут и секунд ---------
'=================================================
Обновить_данные_времени:
'-------------------------------------------------------------------------------------------
Incr Секунды ' Плюс секундаIf Секунды > 59 Then ' При необходимости
Секунды = 0 : Goto Обновить_минуты ' корректируем счетчик секунд и обновляем счетчик минут
End IfGoto Обновить_индикатор
'----------------------------------------------------
Обновить_минуты:
'----------------------------------------------------
Incr Минуты ' Плюс минутаIf Минуты > 59 Then ' При необходимости
Минуты = 0 : Goto Обновить_часы ' корректируем счетчик минут и обновляем счетчик часов
End IfGoto Обновить_индикатор
'----------------------------------------------------
Обновить_часы:
'----------------------------------------------------
Incr Часы ' Плюс часIf Часы > 23 Then ' При необходимости
Часы = 0 ' корректируем счетчик часов
End If
'----------------------------------------------------
Обновить_индикатор:
'----------------------------------------------------
' Флаг_данные_для_передачи_usart = 1
' Флаг_обновить_данные_времени = 0
' Флаг_обновить_индикатор = 1 ' Ставим флаг, что надо обновить индикацию
'-------------------------------------------------------------------------------------------
Выход_обновить_данные_времени:
'-------------------------------------------------------------------------------------------
Return
'=================================================
'=================================================
'----------- Подпрограмма расчета времени: часов, минут и секунд ---------
'=================================================
Обновить_данные_времени:
'-------------------------------------------------------------------------------------------
$asmLds R31 , {секунды} ' Считываем значение переменной "Счетчик_прерываний_timer2" в регистр "R31", для последующих операций
Inc R31 ' Инкриминируем значение переменной в регистре "R31"
Cpi R31 , 60 ' (CPI) Сравнить с константой
BRSH Обновить_минуты ' (BREQ) Если равно перейти на метку
sts {секунды} , R31 ' Пишем значение из регистра "R31" в переменную "Счетчик_прерываний_timer2"
Rjmp Выход_обновить_данные_времениОбновить_минуты:
clr R31
sts {секунды} , R31 ' Пишем значение из регистра "R31" в переменную "Счетчик_прерываний_timer2"Lds R31 , {минуты} ' Считываем значение переменной "Счетчик_прерываний_timer2" в регистр "R31", для последующих операций
Inc R31 ' Инкриминируем значение переменной в регистре "R31"
Cpi R31 , 60 ' (CPI) Сравнить с константой
BRSH Обновить_часы ' (BREQ) Если равно перейти на метку
sts {минуты} , R31 ' Пишем значение из регистра "R31" в переменную "Счетчик_прерываний_timer2"
Rjmp Выход_обновить_данные_времениОбновить_часы:
clr R31
sts {минуты} , R31 ' Пишем значение из регистра "R31" в переменную "Счетчик_прерываний_timer2"Lds R31 , {часы} ' Считываем значение переменной "Счетчик_прерываний_timer2" в регистр "R31", для последующих операций
Inc R31 ' Инкриминируем значение переменной в регистре "R31"
Cpi R31 , 24 ' (CPI) Сравнить с константой
BRLO Выход_обновить_данные_времени ' Перейти если меньше
Ldi R31 , 0
sts {часы} , R31 ' Пишем значение из регистра "R31" в переменную "Счетчик_прерываний_timer2"Выход_обновить_данные_времени:
' Ldi R31 , 0
' sts {Флаг_обновить_данные_времени} , R31
' sts {Флаг_данные_для_передачи_usart} , R31' Обязательная строчка, возврат из подпрограммы в обрабатываемое прерывание
Ret ' Возврат из подпрограммы$end Asm
'=================================================
Отредактировано sasha_1973 (2013-10-21 10:41:35)
Нужно быстро очистить массив.
Dim Picsel(128) As Byte
For I = 1 To 128
Picsel(i) = 0
Next IНо так в конкретной ситуации медленно...
Как это написать на АСМе?
$asm
LDI R24 , 0 '0
Loadadr Picsel , X 'указатель на начало массива в Z
'записать 128 раз
St Z+ , R24 'записать 1
St Z+ , R24 'записать 2
... 'повторять 3...126
St,Z+ , R24 'записать 127
St,Z+ , R24 'записать 128
$end Asm
$asm
LDI R24 , 0 '0
LDI R25 , 128 '128
Loadadr Picsel , X 'указатель на начало массива в
Clar:
St Z+ , R24 'записать 128 раз
Dec R25
Brne Clar
$end Asm
Здесь есть алгоритм получения случайного числа на асме.
Как это всё приспособить к Баскому? Ибо RND работает очень медленно, особенно если нужно получить много итераций подряд.
$regfile = "m168def.dAT" '
Dim Value As Byte
Dim Cnt As Byte
Dim Tmpw As Word
Dim Tmpb As Byte
Dim Rnd_a As Byte
Dim Rnd_b As Byte
Dim Rnd_c As Byte 'выходное случайное число
Dim Rnd_d As Byte
Dim Stat_rnd(256) As Byte 'ПОЛЕ СТАТИСТИКИ
Dim Bufs As String * 80
Dim Bufz As String * 10
'-----------------------------------------
Rnd_a = 123 : Rnd_b = 23 : Rnd_c = 1 : Rnd_d = 20 'Начальные Значения. Любые, Кроме 0
Do
Gosub Clr_cnt
For Tmpw = 0 To 2047 'сделать 2048 проходов
Gosub Rnd_byte 'тестируемая программа
Gosub Add_stat 'добавить статистику
Next Tmpw
Gosub Strlin 'распечатать результат
Print "---------------------------- * = >9"
Loop
'-----------------------------------------
'программа генерации случайного байта
'статистически работает правильно, хотя в спектре доминирует
'какая-то составляющая с периодом 7-12 проходов
'это выглядит приблизительно так,
' - - - - -
' - - -- - - - - - - - - -
' - - - - - - - - - - -
' - - - - - - - - - -
' - - - - - - -
'
'что для обработки аналоговых сигналов не очень хорошо. С этой проблемой я уже
'сталкивался - появляются "пораженные" частоты
Rnd_byte:
$asm
Lds R16 , {Rnd_a} 'загрузка
Lds R17 , {Rnd_b}
Lds R18 , {Rnd_c}
Mov R16 , R17 'A=B
Mov R17 , R18 'B=C
Lsl R17 'B<<1
Brcc _Null
Sbr R17 , 1 'добавляем "1" в D1 если 7 бит до сдвига был "1"
_null:
Mov R18 , R16 'С=B+A
Add R18 , R17 '-||-
Sts {Rnd_a} , R16 'выгрузка
Sts {Rnd_b} , R17
Sts {Rnd_c} , R18
$end Asm
' исходник
' Mov Rnd_a , Rnd_b 'A=B
' Mov Rnd_b , Rnd_c 'B=C
' Lsl Rnd_b 'B<<1
' Brcc Null
' Sbr Rnd_b , 1 'добавляем 1 если 7 бит был 1
'Null:
' Mov Rnd_c , Rnd_a 'С=B+A
' Add Rnd_c , Rnd_b '-||-
Return
'-----------------------------------------
'очистка поля статистики
Clr_cnt:
For Tmpb = 1 To 255
Stat_rnd(tmpb) = 0
Next Tmpb
Return
'-----------------------------------------
'добавить в поле статистики +1 в ячейку с номером полученного случайного значения
Add_stat:
Tmpb = Rnd_c + 1
If Tmpb = 0 Then
Value = Stat_rnd(256) : Incr Value : Stat_rnd(256) = Value
Else
Value = Stat_rnd(tmpb) : Incr Value : Stat_rnd(tmpb) = Value
End If
Return
'-----------------------------------------
'сформировать строковое значение одной ячейки
Str_stat:
Tmpb = Cnt + 1
If Tmpb = 0 Then
Value = Stat_rnd(256)
Else
Value = Stat_rnd(tmpb)
End If
'-----
If Value > 9 Then
Bufz = "+ "
Else
Bufz = Str(value) + " "
End If
Return
'-----------------------------------------
'сформировать и распечатать восемь строк значений поля статистики
Strlin:
Bufs = "000-031: "
For Cnt = 0 To 31
Gosub Str_stat : Bufs = Bufs + Bufz
Next Cnt
Print Bufs
'-----
Bufs = "032-063: "
For Cnt = 32 To 63
Gosub Str_stat : Bufs = Bufs + Bufz
Next Cnt
Print Bufs
'-----
Bufs = "064-095: "
For Cnt = 64 To 95
Gosub Str_stat : Bufs = Bufs + Bufz
Next Cnt
Print Bufs
'-----
Bufs = "096-127: "
For Cnt = 96 To 127
Gosub Str_stat : Bufs = Bufs + Bufz
Next Cnt
Print Bufs
'-----
Bufs = "128-159: "
For Cnt = 128 To 159
Gosub Str_stat : Bufs = Bufs + Bufz
Next Cnt
Print Bufs
'-----
Bufs = "160-191: "
For Cnt = 160 To 191
Gosub Str_stat : Bufs = Bufs + Bufz
Next Cnt
Print Bufs
'-----
Bufs = "192-223: "
For Cnt = 192 To 223
Gosub Str_stat : Bufs = Bufs + Bufz
Next Cnt
Print Bufs
'-----
Bufs = "224-255: "
For Cnt = 224 To 255
Gosub Str_stat : Bufs = Bufs + Bufz
Next Cnt
Print Bufs
'-----
Return
'-----------------------------------------
RADAN - Попробовал. Доволен.
Нужно изменить диапазон случайного числа от 0 до 127.
Для обнуления старшего бита:
cbr r18, $80
а еще проще так:
lsr r18
Компилятор: BASCOM-AVR 2.0.7.1
Для оптимального отображения псевдографики используйте шрифт в Bascom: Consolas; размер = 14
Кому надо симуляцию в Протеусе, пишите мыло, закину.
'===============================================================================
$map ' Получаем карту распределения памяти
$regfile = "m328Pdef.dat" ' Используемый контроллер
' $crystal = 1000000
$crystal = 7372800 ' 7,3728 МГц, кварц для стабильной работы USART во всём диапазоне скоростей передачи и приёма
$framesize = 32 'размер области используемой и необходимой для преобразований
$hwstack = 40 ' Размер аппаратного стека
$swstack = 16 ' Размер программного стека
$baud = 38400 '1200 '2400 '4800 '9600 '19200 '38400 '57600 '115000 '230400' Ucsr0a.1 = 1 ' Двойная скорость работы USART, скорость трансляции = $baud * 2
'==============================================================================='---------- Конфигурация АЦП, измерения проходят в фоновом режиме ------------
' Config Adc = Free , Prescaler = 2 , Reference = Off
' значение регистра при включении МК, ADMUX = &B00000000
Admux = &B00000000
' ||||||||
' |||||||+--- 0 - MUX0 - выбор входа АЦП для измерения
' ||||||+---- 1 - MUX1 - выбор входа АЦП для измерения
' |||||+----- 2 - MUX2 - выбор входа АЦП для измерения
' ||||+------ 3 - MUX3 - выбор входа АЦП для измерения
' |||+------- 4 - резерв
' ||+-------- 5 - ADLAR - выравнивание результата измерения по левому краю
' |+--------- 6 - REFS0 - выбор источника опорного напряжения
' +---------- 7 - REFS1 - выбор источника опорного напряжения'--------------------------------------------------------------------------------------------------------+
'| REFS1 | REFS0 | Источник опорного напряжения дла работы АЦП |
'|-------|-------|---------------------------------------------------------------------------------------|
'| 0 | 0 | Внешний источник опорного напряжения на вывод AREF |
'| 0 | 1 | Источник опорного напряжения с вывода AVCC |
'| 1 | 0 | Резерв |
'| 1 | 1 | Внутренний источник опорного напряжения 1.1V, вывод AREF через конденсатор на землю |
'--------------------------------------------------------------------------------------------------------+'------------------------------------------------------------------------
'| MUX3 | MUX2 | MUX1 | MUX0 | Источник измеряемого сигнала |
'|------|------|------|------|------------------------------------------|
'| 0 | 0 | 0 | 0 | ADC0, 23 вывод МК, для корпуса DIP-28 |
'| 0 | 0 | 0 | 1 | ADC1, 24 вывод МК, для корпуса DIP-28 |
'| 0 | 0 | 1 | 0 | ADC2, 25 вывод МК, для корпуса DIP-28 |
'| 0 | 0 | 1 | 1 | ADC3, 26 вывод МК, для корпуса DIP-28 |
'| 0 | 1 | 0 | 0 | ADC4, 27 вывод МК, для корпуса DIP-28 |
'| 0 | 1 | 0 | 1 | ADC5, 28 вывод МК, для корпуса DIP-28 |
'| 0 | 1 | 1 | 0 | ADC6 |
'| 0 | 1 | 1 | 1 | ADC7 |
'| 1 | 0 | 0 | 0 | ADC8, внутренний датчик температуры МК |
'| 1 | 0 | 0 | 1 | резерв |
'| 1 | 0 | 1 | 0 | резерв |
'| 1 | 0 | 1 | 1 | резерв |
'| 1 | 1 | 0 | 0 | резерв |
'| 1 | 1 | 0 | 1 | резерв |
'| 1 | 1 | 1 | 0 | 1,1V |
'| 1 | 1 | 1 | 1 | 0V (Gnd) |
'------------------------------------------------------------------------' значение регистра при включении МК, ADCSRA = &B00000000
Adcsra = &B11001000
' ||||||||
' |||||||+--- 0 - ADPS0 - выбор делителя частоты АЦП
' ||||||+---- 1 - ADPS1 - выбор делителя частоты АЦП
' |||||+----- 2 - ADPS2 - выбор частоты делителя АЦП
' ||||+------ 3 - ADIE - разрешение прерывания по окончании прелбразования
' |||+------- 4 - ADIF - флаг окончание преобразования
' ||+-------- 5 - ADATE - АЦП Auto Trigger Включить
' |+--------- 6 - ADSC - АЦП старт преобразования
' +---------- 7 - ADEN - включение АЦП'--------------------------------------
'| ADPS2 | ADPS1 | ADPS0 | Делитель |
'|-------|-------|-------|------------|
'| 0 | 0 | 0 | 2 |
'| 0 | 0 | 1 | 2 |
'| 0 | 1 | 0 | 4 |
'| 0 | 1 | 1 | 8 |
'| 1 | 0 | 0 | 16 |
'| 1 | 0 | 1 | 32 |
'| 1 | 1 | 0 | 64 |
'| 1 | 1 | 1 | 128 |
'--------------------------------------' значение регистра при включении МК, ADCSRB = &B00000000
Adcsrb = &B00000000
' ||||||||
' |||||||+--- 0 - ADTS0 - выбор источника-инициатора начала измерения
' ||||||+---- 1 - ADTS1 - выбор источника-инициатора начала измерения
' |||||+----- 2 - ADTS2 - выбор источника-инициатора начала измерения
' ||||+------ 3 - резерв
' |||+------- 4 - резерв
' ||+-------- 5 - резерв
' |+--------- 6 - ACME
' +---------- 7 - резерв'----------------------------------------------------------+
'| ADTS2 | ADTS1 | ADTS0 | источника-инициатора |
'|-------|-------|-------|---------------------------------|
'| 0 | 0 | 0 | Free Running mode |
'| 0 | 0 | 1 | Analog Comparator |
'| 0 | 1 | 0 | External Interrupt Request 0 |
'| 0 | 1 | 1 | Timer/Counter0 Compare Match A |
'| 1 | 0 | 0 | Timer/Counter0 Overflow |
'| 1 | 0 | 1 | Timer/Counter1 Compare Match B |
'| 1 | 1 | 0 | Timer/Counter1 Overflow |
'| 1 | 1 | 1 | Timer/Counter1 Capture Event |
'----------------------------------------------------------+' значение регистра при включении МК, DIDR0 = &B00000000
Didr0 = &B00000000 ' Вкл/Откл цифровых входов МК
' ||||||||
' |||||||+--- 0 - ADC0D
' ||||||+---- 1 - ADC1D
' |||||+----- 2 - ADC2D
' ||||+------ 3 - ADC3D
' |||+------- 4 - ADC4D
' ||+-------- 5 - ADC5D
' |+--------- 6 - резерв
' +---------- 7 - резерв'------------ Переход к подпрограмме обработки прерывания АЦП ----------------
On Adc Обработка_прерывания_ацп Nosave
'------------------- Используемые переменные ---------------------------------
Dim Цикл_print As Byte
'------------- Для 6-ти каналов АЦП ------------------------------------------
Dim Данные_ацп(6) As Word ' At $200 ' Привязываем переменную к конкретному адресу в оперативке МК
Dim Temp_данные_ацп As Word
Dim Сырые_данные_ацп(2) As Byte At Temp_данные_ацп Overlay'------------ Разрешаем работу всех включенных прерываний --------------------
Enable Interrupts
'Ждём первого измерения АЦП, последующие измерения происходят в фоновом режиме
Power Adcnoise
'===============================================================================
' Г Л А В Н Ы Й Ц И К Л
'===============================================================================
Главный_цикл:nop
For Цикл_print = 1 To 6
Print "Тест АЦП " ; Цикл_print ; ": " ; Данные_ацп(цикл_print)
Next Цикл_printWaitms 50
Idle
Goto Главный_цикл
End
'===============================================================================' П О Д П Р О Г Р А М М Ы
'===============================================================================
'===============================================================================
Обработка_прерывания_ацп:
'-------------------------------------------------------------------------------
nop
'------ Сохраняем используемые регистры и SREG -------!push R24
!in R24 , sreg
!push r24!push R25
!push R26
!push R27'---- Выключаем прерывание от АЦП ----
!in R25 , adcsra ' Читаем значение, время выполнения инструкции - 1 такт
!CBR R25 , &B00001000 ' Сбросить бит в регистре, время выполнения инструкции - 1 такт
!out Adcsra , R25 ' Пишем значение, время выполнения инструкции - 1 такт'---- Забираем данные из регистров АЦП ----
!in R26 , adcl
!sts {Сырые_данные_ацп(1)} , R26!in R26 , adch
!sts {Сырые_данные_ацп(2)} , R26'------ Готовим следующий канал АЦП -------
!in R26 , ADMUX ' Читаем ADMUX
!ANDI R26 , &H07 ' Маской отрезаем лишние биты. Получаем номер канала
!inc R26
!ANDI R26 , &H07 ' Обрезаем лишние биты, чтобы не было переполнения!cpi R26 , 6
!BRLO Выбор_входа_ацп ' Перейти если меньше
!ldi R26 , 0Выбор_входа_ацп:
!IN R27 , ADMUX ' Читаем ADMUX
!ANDI R27 , &HF8 ' Маской отрезаем биты номера канала, получаем настройку АЦП
!OR R27 , R26 ' Сложили настройки АЦП c новым значением номера канала, т.е., сделали MUX = MUX + 1
!OUT ADMUX , R27 ' Закидываем полученное значение в регистр АЦП'------ Забираем готовые данные АЦП в массив -------
!cpi R26 , 0
!BREQ Ацп_0 ' (BREQ) Если равно перейти на метку, время выполнения 2 такта, если не равно 1 такт!cpi R26 , 1
!BREQ Ацп_1 ' (BREQ) Если равно перейти на метку, время выполнения 2 такта, если не равно 1 такт!cpi R26 , 2
!BREQ Ацп_2 ' (BREQ) Если равно перейти на метку, время выполнения 2 такта, если не равно 1 такт!cpi R26 , 3
!BREQ Ацп_3 ' (BREQ) Если равно перейти на метку, время выполнения 2 такта, если не равно 1 такт!cpi R26 , 4
!BREQ Ацп_4 ' (BREQ) Если равно перейти на метку, время выполнения 2 такта, если не равно 1 такт!cpi R26 , 5
!BREQ Ацп_5 ' (BREQ) Если равно перейти на метку, время выполнения 2 такта, если не равно 1 тактАцп_0:
Данные_ацп(6) = Temp_данные_ацп
!rjmp Запуск_ацпАцп_1:
Данные_ацп(1) = Temp_данные_ацп
!rjmp Запуск_ацпАцп_2:
Данные_ацп(2) = Temp_данные_ацп
!rjmp Запуск_ацпАцп_3:
Данные_ацп(3) = Temp_данные_ацп
!rjmp Запуск_ацпАцп_4:
Данные_ацп(4) = Temp_данные_ацп
!rjmp Запуск_ацпАцп_5:
Данные_ацп(5) = Temp_данные_ацп
!rjmp Запуск_ацп'---- Включаем прерывание от АЦП ----
Запуск_ацп:!in R25 , adcsra ' Читаем значение, время выполнения инструкции - 1 такт
!SBR R25 , &B01001000 ' Установить бит в регистре, время выполнения инструкции - 1 такт
!out Adcsra , R25 ' Пишем значение, время выполнения инструкции - 1 такт'------ Восстанавливаем ранее сохранённые регистры и SREG -------
!pop R27
!pop R26
!pop R25!pop R24
!Out Sreg , R24
!pop R24'------ Выходим из прерывания -------
nop
!reti'-------------------------------------------------------------------------------
Return
'===============================================================================
Отредактировано sasha_1973 (2014-01-18 06:27:49)
Ого! А эти функции в самом компиляторе заложены или в библиотеке?
Спасиб!
Call _mul8
Call _mul16
Call _mul32
Call _div8
Call _div16
Call _div32
Bascom пишет "нема метки" ?
Это у Вас спецверсия компилятора?
Отредактировано sasha_1973 (2014-11-27 20:35:25)
Mrshilov, компилятор ругается на вызов функции, что такой функции нет либо не объявлена.
$lib "mcs.lbx" Call _div8
Какие тут есть подводные камни? или от версии баскома зависит?
Отредактировано MACTEPok (2014-11-27 20:34:32)
Надо подключать не библиотеку, а именно нужные подпрограммы. Можно сразу несколько через запятую. Пример:
--"Семён Семёныч", СПАСИБО!
Что-то всё равно криво работает, написали-бы пример рабочий?
$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 32
$framesize = 32
$baud = 19200$external _div8 , _div16
Dim A As Word , B As Word , C As Word , Text As String * 16
Dim Результат As Word , Остаток As WordA = 54321
B = 10Do
'---------- Двухбайтное деление --------------
';R17/R16 - числитель
';R21/R20 - знаменатель
' Call _div16
';R21/R20 - результат
';R17/R16 - остаток!lds r16 , {A}
!lds r17 , {A + 1}!lds r20 , {B}
!lds r21 , {B + 1}!Call _div16
!sts {Результат} , r20
!sts {Результат + 1} , r21!sts {Остаток} , r16
!sts {Остаток + 1} , r17' For A = 0 To 32
' Loadadr A , X
' !ld R16 , X ; Числитель
' !ldi R20 , 8 ; Знаменатель = 8
' !Call _div8
' !mov _temp2 , R16 ; Результат R16 => R25
' B = _temp2
' C = _temp1
' Print A ; "/8=" ; B ; " reminder=" ; C
' Next A'Wait 2
LoopEnd
Отредактировано sasha_1973 (2014-11-28 07:47:41)
Капец, вот это подробности!
$regfile = "m8def.dat"
$crystal = 1000000
$hwstack = 32
$swstack = 32
$framesize = 32
' $baud = 19200Dim Переменная_word As Word , Результат_word As Word , Остаток As Byte
Переменная_word = 54321
!lds R16 , {Переменная_word}
!lds R17 , {Переменная_word + 1}!rcall Деление_на_10
!sts {Результат_word} , R0
!sts {Результат_word + 1} , R1!sts {Остаток} , R4
Do
!lds R16 , {Результат_word}
!lds R17 , {Результат_word + 1}!rcall Деление_на_10
!sts {Результат_word} , R0
!sts {Результат_word + 1} , R1!sts {Остаток} , R4
Loop
End'===============================================================================
Деление_на_10:
'-------------------------------------------------------------------------------
!movw R4 , R16
!lsr R17
!ror R16
!movw R0 , R16
!lsr R2
!ror R1
!ror R0
!add R16 , R0
!adc R17 , R1
!movw R0 , R16
!lsr R17
!ror R16
!lsr R17
!ror R16
!lsr R17
!ror R16
!lsr R17
!ror R16
!add R16 , R0
!adc R17 , R1
!movw R0 , R16
!clr R0
!add R16 , R1
!adc R17 , R2
!movw R0 , R16
!clr R0
!add R16 , R2
!adc R17 , R3
!movw R0 , R16
!lsr R1
!ror R0
!lsr R1
!ror R0
!andi R16 , 248
!add R16 , R0
!adc R17 , R1
!cbr R16 , 1
!Sub R4 , R16
!sbc R5 , R17
!lsr R1
!ror R0
!ldi R16 , 9
!cp R16 , R4
!brsh Выход_из_деления
!ldi R16 , 10
!sub R4 , R16
!ldi R16 , 1
!add R0 , R16
!ldi R16 , 0
!adc R1 , R16
!adc R2 , R16
!adc R3 , R16
Выход_из_деления:
'Можно забрать промежуточный результат
'-------------------------------------------------------------------------------
Return
'===============================================================================
Отредактировано sasha_1973 (2014-11-28 08:30:42)
_div16 работает с "Integer", поэтому все правильно:
Если я правильно понял, _div16 работает только с "Integer", а если мне надо делить числа >32768, использовать _div32 ?
Расчет четности байта
Dim A As Byte ' Байт с данными Dim Parity As Byte ' Флаг четности 0 - чет, 1 - нечет
Для 8 бит:
A = &B1111_1000
!lds R16, {A} ' Переменная с данными
!mov R17, R16 ' Копируем переменную в другой регистр
!SWAP R17 ' Меняем местами старшие и младшие биты
!EOR R17, R16 ' XOR с исходной переменной
!mov R16,R17
!LSR R17 ' Сдвиг вправо
!EOR R17, R16 ' XOR с исходной переменной
!SBRC R17,2 ' В R17 результат проверки. Биты 2 и 0. Если бит 2=0, то бит четности = биту 0
!inc R17 ' Иначе бит четности в 0 бите, но его нужно инвертировать, прибавив +1
' Здесь бит 0 содержит бит четности
ANDI R17, &B00000001 ' Очищаем незначащие биты
sts {Parity}, R17 ' Запись результата в переменнуюДля 4 бит:
A = &B0000_1000
!lds R16, {A} ' Переменная с данными
!mov R17, R16 ' Копируем переменную в другой регистр
!LSR R17 ' Сдвиг вправо
!EOR R17, R16 ' XOR с исходной переменной
!SBRC R17,2 ' В R17 результат проверки. Биты 2 и 0. Если бит 2=0, то бит четности = биту 0
!inc R17 ' Иначе бит четности в 0 бите, но его нужно инвертировать, прибавив +1
' Здесь бит 0 содержит бит четности
!ANDI R17, &B00000001 ' Очищаем незначащие биты
!sts {Parity}, R17 ' Запись результата в переменнуюВы здесь » Программирование ATMEL в BASCOM. » Применение Assembler в среде Bascom(-8051) » Варианты интерпретации Bascom на ASM AVR (ассемблер)