Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Применение Assembler в среде Bascom(-8051) » Варианты интерпретации Bascom на ASM AVR (ассемблер)


Варианты интерпретации Bascom на ASM AVR (ассемблер)

Сообщений 1 страница 18 из 18

1

Здесь будут собраны варианты написания кода с помощью компилятора Bascom и его аналог на ASM AVR (ассемблере).

Не жадничайте, делитесь информацией!

Отредактировано sasha_1973 (2013-10-21 09:51:47)

+1

2

Ограниченный константой повторяющийся счетчик, сбрасывается в 1.

  Const Количество_подсчетов = 8
  Dim Счетчик As Byte

Bascom, время выполнения 14 тактов, когда "Счетчик > Количество_подсчетов", тогда 17 тактов

Incr Счетчик

  If Счетчик > Количество_подсчетов Then
      Счетчик = 1
  End If

  или так

  Incr Счетчик : If Счетчик > Количество_подсчетов Then Счетчик = 1

Дизассемблирование того, что сгенерировал Bascom

  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 AVR, время выполнения 8 тактов

$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)

+1

3

Секундные прерывания TIMER2 с выводом секундных импульсов на OC2A

Bascom, время выполнения 120 тактов, когда "Счетчик_прерываний_timer2 => Const_количество_прерыв_timer2", тогда 135 тактов

'=================================================
' Подпрограмма обработки прерывания TIMER2, происходит 1 или 2 раза в секунду, в зависимости от настроек TIMER2
'=================================================
  Обработка_прерывания_timer2:
'-------------------------------------------------------------------------------------------
    Incr Счетчик_прерываний_timer2
    If Счетчик_прерываний_timer2 < Const_количество_прерыв_timer2 Then Goto Выход_прерывание_timer2

    Incr Счетчик_секунд
    Счетчик_прерываний_timer2 = 0
    Флаг_было_прерывание_timer2 = 1
    Флаг_данные_для_передачи_usart = 1
'-----------------------------------
  Выход_прерывание_timer2:
'-------------------------------------------------------------------------------------------
  Return
'=================================================

Прерывание реализовано на ASM AVR, время выполнения 18 тактов, когда "Счетчик_прерываний_timer2 => Const_количество_прерыв_timer2", тогда 30 тактов

'=================================================
' Подпрограмма обработки прерывания 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
'=================================================

Весь исходник, не забывайте следить за инструкцией "Nosave"

$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 Счетчик_секунд
          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)

0

4

Подпрограмма расчета часов, минут, секунд

Bascom, время выполнения 24 такта, раз в минуту и раз в час, время выполнения увеличивается

'=================================================
'-----------  Подпрограмма расчета времени: часов, минут и секунд  ---------
'=================================================
  Обновить_данные_времени:
'-------------------------------------------------------------------------------------------
    Incr Секунды       ' Плюс секунда

    If Секунды > 59 Then       ' При необходимости
        Секунды = 0 : Goto Обновить_минуты       ' корректируем счетчик секунд и обновляем счетчик минут
    End If

    Goto Обновить_индикатор
'----------------------------------------------------
   Обновить_минуты:
'----------------------------------------------------
    Incr Минуты       ' Плюс минута

    If Минуты > 59 Then       ' При необходимости
        Минуты = 0 : Goto Обновить_часы       ' корректируем счетчик минут и обновляем счетчик часов
    End If

      Goto Обновить_индикатор
'----------------------------------------------------
    Обновить_часы:
'----------------------------------------------------
      Incr Часы       ' Плюс час

      If Часы > 23 Then       ' При необходимости
          Часы = 0       ' корректируем счетчик часов
      End If
'----------------------------------------------------
    Обновить_индикатор:
'----------------------------------------------------
'      Флаг_данные_для_передачи_usart = 1
'      Флаг_обновить_данные_времени = 0
'      Флаг_обновить_индикатор = 1       ' Ставим флаг, что надо обновить индикацию
'-------------------------------------------------------------------------------------------
   Выход_обновить_данные_времени:
'-------------------------------------------------------------------------------------------
  Return
'=================================================

ASM AVR, время выполнения 17 тактов, раз в минуту и раз в час, время выполнения увеличивается

'=================================================
'-----------  Подпрограмма расчета времени: часов, минут и секунд  ---------
'=================================================
  Обновить_данные_времени:
'-------------------------------------------------------------------------------------------
    $asm

        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 , 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)

0

5

Нужно быстро очистить массив.

Код:
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

+1

6

Здесь есть алгоритм получения случайного числа на асме.
Как это всё приспособить к Баскому? Ибо RND работает очень медленно, особенно если нужно получить много итераций подряд.

DMM - ЗАДАЧА ПОКАЗАЛАСЬ ИНТЕРЕСНОЙ. НАПИСАЛ ПРОГРАММУ ТЕСТИРОВАНИЯ. МОЖНО ПРОБОВАТЬ (ЗАПУСКАЛ В СИМУЛЯТОРЕ)

$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

+1

7

Компилятор: BASCOM-AVR 2.0.7.1

Для оптимального отображения псевдографики используйте шрифт в Bascom: Consolas; размер = 14

Кому надо симуляцию в Протеусе, пишите мыло, закину.

Опрос 6 каналов АЦП в фоновом режиме

'===============================================================================
  $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 Цикл_print

    Print

    Waitms 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)

0

8

Ого! А эти функции в самом компиляторе заложены или в библиотеке?

0

9

Спасиб!

0

10

Call _mul8
Call _mul16
Call _mul32

Call _div8
Call _div16
Call _div32

Bascom пишет "нема метки" ?

Это у Вас спецверсия компилятора?

Отредактировано sasha_1973 (2014-11-27 20:35:25)

0

11

Mrshilov,  компилятор ругается на вызов функции, что такой функции нет либо не объявлена.

Код:
$lib "mcs.lbx"

 Call _div8

Какие тут есть подводные камни? или от версии баскома зависит?

Отредактировано MACTEPok (2014-11-27 20:34:32)

0

12

Mrshilov написал(а):

Надо подключать не библиотеку, а именно нужные подпрограммы. Можно сразу несколько через запятую. Пример:

--"Семён Семёныч", СПАСИБО!

0

13

Что-то всё равно криво работает, написали-бы пример рабочий?

0

14

Не работает?

$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 Word

A = 54321
B = 10

Do

'----------  Двухбайтное деление --------------
';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
Loop

End

http://sa.uploads.ru/t/wm7Yg.jpg

Отредактировано sasha_1973 (2014-11-28 07:47:41)

0

15

Капец, вот это подробности!

0

16

Если оно работает, то оно работает (время выполнения подпрограммы - 45 тактов)

$regfile = "m8def.dat"
  $crystal = 1000000
  $hwstack = 32
  $swstack = 32
  $framesize = 32
'  $baud = 19200

  Dim Переменная_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
'===============================================================================

http://sa.uploads.ru/t/GFPws.jpg

Отредактировано sasha_1973 (2014-11-28 08:30:42)

0

17

Mrshilov написал(а):

_div16 работает с "Integer", поэтому все правильно:

Если я правильно понял, _div16 работает только с "Integer", а если мне надо делить числа >32768, использовать _div32 ?

0

18

Расчет четности байта

Код:
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                                                               ' Запись результата в переменную

+1


Вы здесь » Программирование ATMEL в BASCOM. » Применение Assembler в среде Bascom(-8051) » Варианты интерпретации Bascom на ASM AVR (ассемблер)