Справочник по программировани BASCOM-8051 (М.Л. Кулиш, 2001). Справочник по программированию bascom8051 Краснодар 2001
Скачать 6.61 Mb.
|
===================================== Справочник по программированию «Bascom-8051» == числа, особенно в операциях с плавающей точкой, и еще в большей степени при операции деления. Разница в ре- зультате при использовании знаков деления “/” и “\” не замечена. Ниже дается пример быстрой ассемблерной программы беззнакового умножения 16-разрядных чисел, дающей 32-разрядный результат. ;---------------------------------------------- ;УМНОЖЕНИЕ ДВУХБАЙТНОГО ЧИСЛА НА ДВУХБАЙТНОЕ ЧИСЛО. ;ВРЕМЯ ИСПОЛНЕНИЯ 52 ТАКТА. ;ИСХОДНЫЕ ЧИСЛА: В R3-СТ.,R2-МЛ. И R1-СТ.,R0-МЛ. РЕЗУЛЬТАТ В R7-СТ.,R6,R5,R4 ;---------- MUL2B: ;УМНОЖЕНИЕ МЛАДШИХ ЦИФР ПЕРВОГО И ВТОРОГО ЧИСЛА MOV A,R2 MOV B,R0 MUL AB MOV R4,A MOV R5,B ;УМНОЖЕНИЕ МЛАДШЕЙ ЦИФРЫ ПЕРВОГО ЧИСЛА НА СТАРШУЮ ВТОРОГО ЧИСЛА MOV A,R2 MOV B,R1 MUL AB ;СЛОЖИТЬ С ПРЕДЫДУЩИМ РЕЗУЛЬТАТОМ ADD A,R5 MOV R5,A CLR A ADDC A,B MOV R6,A ;УМНОЖЕНИЕ МЛАДШЕЙ ЦИФРЫ ВТОРОГО ЧИСЛА НА СТАРШУЮ ПЕРВОГО ЧИСЛА MOV A,R3 MOV B,R0 MUL AB ;СЛОЖИТЬ С ПРЕДЫДУЩИМ РЕЗУЛЬТАТОМ ADD A,R5 MOV R5,A MOV A,R6 ADDC A,B MOV R6,A CLR A RLC A MOV R7,A ;УМНОЖЕНИЕ СТАРШИХ ЦИФР ПЕРВОГО И ВТОРОГО ЧИСЛА MOV A,R3 MOV B,R1 MUL AB ;СЛОЖИТЬ С ПРЕДЫДУЩИМ РЕЗУЛЬТАТОМ ADD A,R6 MOV R6,A MOV A,R7 ADDC A,B MOV R7,A ;---------------------------------------------------- Bascom позволяет производить очень сложные вычисления, благодаря краткой форме записи производи- мых действий. Компилятор при этом создает очень компактный код, содержащий только установку исходных зна- чений и вызов библиотечных подпрограмм. При реализации сложных формул необходимо раскладывать ее на ряд последовательно выполняемых операций, каждая из которых должна содержать только одно действие. Чтобы уменьшить число переменных, используемых при вычислениях, необходимо анализировать порядок их использо- вания, занимая для хранения промежуточных результатов регистры с уже ненужными данными. Ниже, в качестве примера, приведена простая подпрограмма для вычисления квадратного корня. У данной программы есть одна неприятность – неопределенность результата при нулевом значении аргумента. Чтобы избавится от этого недос- татка, к исходному числу добавляется любое незначительное число. '---------------------------------------------------- ' тестирование программы вычисления квадратного корня Dim X As Single , Y As Single , Z As Single 'временные значения ============================================================================= 23-4 ===================================== Справочник по программированию «Bascom-8051» == Do Input "x=" , X X = X + 0.00001 'чтобы никогда не было нулевого значения, которое 'вызывает переполнение при вычислении квадратного корня Gosub Sqr 'теперь вычислим квадратный корень (время вычисления 50 мс) Print Y 'посмотрим результат Loop '----------------------------- 'подпрограмма вычисления квадратного корня по формуле Ньютона 'вычисление производится методом последовательных приближений: ' Yi+1 = (X / Yi + Yi) * .5 'начальное (исходное) значение вычисляется по формуле: ' Y0 = X / 200 + 2 Sqr: 'вычислим начальное значение, с которого начнем иттерацию Y = X * 0.005 : Y = Y + 2 Do 'вычислим очередное значение корня Y = (X / Y + Y) * .5 Z = Y : Y = X / Y : Y = Y + Z : Y = Y * 0.5 'проверим IF ABS(Y1 - Y) > Y / 1000 GOTO srq_1 'в Bascom функция ABS не работает с числами в формате с плавающей точкой Z = Z - Y : Z = Z / Y 'вычисляем отношение между посл. и предпосл. значение $asm Anl {z + 3} , #&H7f ; делаем абсолютное значение стиранием знака $end Asm Loop Until Z < 0.001 'если необходимая точность достигнута (0.1 %) Return 'выходим '---------------------------------------------------- Далее приведены еще несколько подпрограмм для вычисления функций методом разложения в степенной ряд. В этих программах для сокращения размера кода применена упаковка повторяющихся операций в подпро- граммы, что значительно сокращает размер кода (2 – 3 раза). '-------------------------------------------------------------------------- 'вычисление десятичного логарифма. Log(x) функция в Ua от аргумента Ua '-------------------------------------------------------------------------- Log: 'выделим порядок (двоичный исходного числа), а остаток сделаем 'числом в диапазоне от 1 до 2 $asm Mov R0 , #{ua + 2} Mov A , @R0 Mov C , Acc.7 Clr Acc.7 Mov @R0, A Inc R0 Mov A , @r0 Rlc A Mov {tmpb} , A Mov @R0 , #&H40 $end Asm 'Числа для справки: 'ln(2)= 0,69314718, 1/ln(2)=1.442695, ln(10)=2.3025851, 1/ln(10)=0.4342945 Gosub Ln 'вычислим натуральный логарифм остатка Ua = Ua * 1.442695 'преобразуем в двоичный логарифм остатка Ub = Tmpb : Ub = Ub - 128 : Ua = Ua + Ub 'объединим порядок и логарифм остатка 'и получим двоичный логарифм числа Ua = Ua * 0.30103001 'преобразуем в десятичный логарифм Return '-------------------------------------------------------------------------- 'вычисление натурального логарифма. Ln(x) функция в Ua от аргумента Ua 'очень хорошая точность только от x = 1 до x = 3 (около 0.003 %) ============================================================================= 23-5 ===================================== Справочник по программированию «Bascom-8051» == 'при x = 5 погрешность около 0.02 %, а при x = 10 - 0.7 % ' ' 3 5 7 9 11 13 n ' p p p p p p p x-1 ' ln(x)=2*[p + - + - + - + - + -- + -- ...+-] где p = ----- ' 3 5 7 9 11 13 n x+1 ' '-------------------------------------------------------------------------- Ln: Ub = Ua - 1 : Ua = Ua + 1 Ua = Ub / Ua Ub = Ua * Ua : Uc = Ub * Ua : Ud = Uc * 0.3333333 : Gosub Add_aad Gosub Mul_cbc : Ud = Uc * 0.2 : Gosub Add_aad Gosub Mul_cbc : Ud = Uc * 0.14285714 : Gosub Add_aad Gosub Mul_cbc : Ud = Uc * 0.1111111111 : Gosub Add_aad Gosub Mul_cbc : Ud = Uc * 0.09090909 : Gosub Add_aad Gosub Mul_cbc : Ud = Uc * 0.07692308 : Gosub Add_aad 'точность 0.003 % ' Gosub Mul_cbc : Ud = Uc * 0.06666667 : Gosub Add_aad ' Gosub Mul_cbc : Ud = Uc * 0.05882353 : Gosub Add_aad ' Gosub Mul_cbc : Ud = Uc * 0.05263158 : Gosub Add_aad Ua = Ua + Ua : Return '--------------------- 'для сокращения размера кода повторяющиеся программы выделим Mul_cbc: Uc = Ub * Uc : Return '--------------------- Add_aad: Ua = Ua + Ud : Return '--------------------- '-------------------------------------------------------------------------- 'синусная функция в Ua от аргумента Ua в радианах 'хорошая точность только до 90 град (около 0.0002 %) 'при 180 град погрешность достигает 4 %!!! Sin: Ub = Ua : Ua = Ua * Ua Uc = Ua Ua = Ua * 0.013888889 ' 1/72 Gosub Sub_aa1 Gosub Mul_aac Ua = Ua * 0.0238095243 '1/42 Gosub Add_aa1 Gosub Mul_aac Ua = Ua * .05 '1/20 Gosub Sub_aa1 Gosub Mul_aac Ua = Ua * 0.16666667 '1/6 Gosub Add_aa1 Gosub Mul_aab Return '--------------------- Add_aa1: Ua = Ua + 1 Return '--------------------- Sub_aa1: Ua = Ua - 1 Return '--------------------- Mul_aac: Ua = Ua * Uc Return '--------------------- ============================================================================= 23-6 ===================================== Справочник по программированию «Bascom-8051» == Mul_aab: Ua = Ua * Ub Return '-------------------------------------------------------------------------- 'косинусная функция в Ua от аргумента Ua в радианах 'хорошая точность только до 90 град (около 0.003 % от максимального значения) 'при 180 град погрешность достигает 3 %!!! Cos: Ua = Ua * Ua 'angle squared Ub = Ua 'save Ua = Ua * 0.017857144 '1/56 Gosub Sub_aa1 Gosub Mul_aab Ua = Ua * 0.033333333 '1/30 Gosub Add_aa1 Gosub Mul_aab Ua = Ua * 0.083333333 '1/12 Gosub Sub_aa1 Gosub Mul_aab Ua = Ua * 0.5 '1/2 Gosub Add_aa1 Return '-------------------------------------------------------------------------- 'показательная функция e^x в Ua от аргумента Ua в радианах 'хорошая точность только до x = 3 (около 0.002 %) 'точность при x = 4 (около 0.07 %), а при x = 10 - 4 % Exp: Ub = Ua + 1 '1+x/1! Gosub Mul_cac : Ud = Uc * 0.5 : Gosub Add_bbd '+x^2/2! Gosub Mul_cac : Ud = Uc * 0.16666667 : Gosub Add_bbd '+x^3/3! Gosub Mul_cac : Ud = Uc * 0.041666667 : Gosub Add_bbd '+x^4/4! Gosub Mul_cac : Ud = Uc * 0.008333333 : Gosub Add_bbd '+x^5/5! Gosub Mul_cac : Ud = Uc * 0.0013888889 : Gosub Add_bbd '+x^6/6! Gosub Mul_cac : Ud = Uc * 0.0001984127 : Gosub Add_bbd '+x^7/7! Gosub Mul_cac : Ud = Uc * 0.000024801587 : Gosub Add_bbd '+x^8/8! Gosub Mul_cac : Ud = Uc * 0.000002755732 : Gosub Add_bbd '+x^9/9! Gosub Mul_cac : Ud = Uc * 0.0000002755732 : Gosub Add_bbd '+x^10/10! Return '--------------------- Add_bbd: Ub = Ub + Ud : Return '--------------------- Mul_cac: Uc = Uc * Ua : Return '--------------------- Add_cad: Ua = Ua + Ud : Return '-------------------------------------------------------------------------- Возможность применения тех или иных вычислительных программ частот обусловлена производительно- стью микроконтроллера. Далее приведена программа цифрового фильтра нижних частот третьего порядка. Для его реализации с указанной частотной характеристикой требуется очень высокая производительность микрокон- троллера – в десять раз выше стандартной (эквивалентно более 120 МГц). Для этого могут быть использованы только улучшенные модели W77E58, DS89C420). При использовании микроконтроллера с ядром AVR эта и все приведенные выше вычислительные программы работают быстрее в среднем в 50 раз (компилированные BasAVR). '-------------------------------------------------------------------------- ' фильтр с частотой среза около 5-10 Гц при частоте выборок 500 Гц ' (частоте вызова данной программы). Коэффициент передачи фильтра: ' 1 1 ' К = ----------------------- * --------- ' 0.006*p^2 + 0.111*p + 1 0.1*p + 1 ============================================================================= 23-7 ===================================== Справочник по программированию «Bascom-8051» == 'а это коэффициенты цифрового фильтра Const _a = 0.013869625 Const _b = -0.83217753 Const _c = 1.8183079 Const _d = 0.09090909 Const _e = 0.9090909 '--------------------- Dim Ux As Single 'входное значение Dim Uy As Single 'выходное значение первого звена Dim Uy1 As Single 'предыдущее выходное значение первого звена Dim Uy2 As Single 'предпредыдущее выходное значение первого звена Dim Uz As Single 'выходное значение второго звена Dim Uz1 As Single 'предыдущее выходное значение второго звена '------------------------ ' программа цифрового фильтра третьего порядка содержащего два звена ' 2-го и 1-го порядка: ' Uy = Ux * a + Uy2 * b + Uy1 * c - формула звена второго порядка ' Uz = Uy * d + Uz1 * e - формула фильтра звена первого порядка '----- Filtr_3p: Uy = Ux * _a : Uz = Uy2 * _b : Uy = Uy + Uz 'программа фильтра второго порядка Uz = Uy1 * _c : Uy = Uy + Uz Uy2 = Uy1 : Uy1 = Uy '----- Uz = Uy * _d : Uy = Uz1 * _e : Uz = Uy + Uz 'программа фильтра первого порядка Uz1 = Uz : Return '------------------------------------------ Bascom версий 2.хх расширил диапазон возможных действий с битовыми переменными. Теперь стала возможным операция с индексированными битами. Причем в качестве индекса может выступать другая перемен- ная, и конечно только байтовая. Например: Dim X As Byte , Y As Byte X.3 = Y.2 : P2.1 = Y.4 'передача значений между битами байтовых переменных For X = 0 To 7 'индексирование бита Set P3.X Next If P2.X=1 Then 'проверка индексированного бита P2.X = 0 End If ============================================================================= 23-8 ===================================== Справочник по программированию «Bascom-8051» == 24. Преобразование строковых переменных Строковые переменные могут преобразовываться в другие строковые переменные – длинные разбираться на части и, наоборот, из коротких строк могут складываться длинные. Bascom обеспечивает преобразование цифр, записанных в строковых переменных, в числа и преобразование чисел в строковые переменные. Причем числа могут быть записаны в виде десятичных или шестнадцатеричных цифр (символов). В следующей таблице показано расположение байтов строковой переменной в памяти после ее очистки (нулями). В первом случае в переменную длиной N записано символами число «1234». Во втором случае на его место записано сообщение «AF» Расположение в памяти строковой переменной, определенной как: Dim S As String * N Adr Adr+1 Adr+2 Adr+3 Adr+4 … Adr+N Adr+N+1 30H 31H 32H 33H 00H 00H 00H 00H 41H 46H 00H 33H 00H 00H 00H 00H Преобразование строк может выполняться в явном и неявном виде. Примеры явного преобразования: а) разделение строк с помощью операторов MID(), LEFT(), RIGHT(); б) слияние суммированием строк ( “.. ” + “..”); в) монтаж строк с помощью оператора MID(); г) преобразование строки в число с помощью функций VAL(), HEXVAL(); д) преобразование числа в строку с помощью функций STR(), HEX(), CHR(). Неявное преобразование строковых переменных происходит при вводе (оператором типа INPUT) и выводе (оператором PRINT) цифровых переменных. Ниже дана демонстрационная программа, показывающая основные способы преобразования строковых переменных. Подобные примеры имеются и в других программах, приведенных выше. '------------------------------- Dim R_rd As Integer 'код для ЦАП Dim R_frq As Single 'частота для синтезатора Dim R_lin As String * 6 'введенная строка Dim R_tmp As String * 20 'временная строка Mc: Input "Input six characters" , R_lin 'в R_lin принятая строка: “+XXXXX”, “-XXXXX”, “HXXXXX” или “R” R_tmp = Left(r_lin , 1) 'выделим первый символ для анализа If R_tmp = "+" Then 'положительная полярность? R_tmp = Mid(r_lin , 2 , 5) 'выделим только числовое значение R_rd = Val(r_tmp) 'преобразовать в целое число Goto Mc 'строка обработана - в главный цикл End If If R_tmp = "-" Then 'отрицательная полярность? R_rd = Val(r_lin) 'преобразуем строку с полярностью Goto Mc 'строка обработана - в главный цикл End If If R_tmp = "H" Then 'частота в Герцах? R_tmp = Mid(r_lin , 2 , 5) 'выделим числовое значение R_frq = Val(r_tmp) 'преобразовать в число с плав. точкой R_frq = R_frq * 0.001 'преобразовать в килогерцы Goto Mc 'строка обработана - в главный цикл End If If R_tmp = "R" Then 'вернуть значения Print "H" ; R_frq ; "D" ; R_rd 'передадим строку состояния 'или иначе R_tmp = "H" + Str(r_frq) + "D" + Str(r_rd) 'сформируем строку состояния Print R_tmp 'передадим готовую строку Goto Mc 'строка обработана - в главный цикл End If Goto Mc 'в главный цикл '------------------------------- В новой версии добавлено два новых оператора LCASE и UCASE, осуществляющих преобразование букв строковых переменных. Первый оператор уменьшает размер букв (делает все буквы строчными), а второй наоборот, делает все буквы большими (прописными). Замечательно, что эти операторы не просто добавляют или ============================================================================= 24-1 ===================================== Справочник по программированию «Bascom-8051» == вычитают из кода символа число 20h, а выбирают символы, являющиеся латинскими буквами. Таким образом цифры и другие служебные символы не преобразуются и остаются неизменными. Еще одним важным добавление в версии 1.20 является функция INSTR(), с помощью которой стало возможным производить поиск значения одной строки в составе другой строки. В результате работы этой функции возвращается номер позиции, указывающий на начало искомого фрагмента. Если фрагмент не найден, то возвращается нулевое значение. Практическая ценность этой функции заключается в возможности применения сложных строк в протоколах обмена между процессорами, т.е. стало возможным применять команды переменного состава или производит накопление нескольких команд без обработки. Ниже дается пример применения новых функций. '---------------------------------------------- ' демонстрация декодирования сложных команд '---------------------------------------------- ' программа запрашивает строку (командой "r", которая ' может содержать одну или несколько команд: ' Axx - установить параметр с двухзначным числом ' Bxxxx - установить параметр с четырехзначным числом ' Cxxxxxxxx - установить параметр с восьмизначным числом ' Например: "A12B1234C00123456", "A30", "c00004055" или "a05b0010" Dim P_a As Byte , P_b As Word , P_c As Long Dim Tmp1 As Byte , Tmps As String * 10 Dim In_buf As String * 20 '---------------------------------------------- P_a = 0 : P_b = 0 : P_c = 0 'очистим переменые параметров Do 'цикл установки параметров Input "r" , In_buf : 'приняли строку с командами In_buf = Ucase(in_buf) 'переведем все символы в верхний регистр 'проверим наличие первой команды Tmps = "A" : Tmp1 = Instr(1 , In_buf , Tmps) If Tmp1 <> 0 Then 'если она присутствует, Tmps = Mid(in_buf , Tmp1 , 2) 'выберем числовое значение P_a = Val(tmps) 'и преобразуем в число End If 'проверим наличие второй команды Tmps = "B" : Tmp1 = Instr(1 , In_buf , Tmps) If Tmp1 <> 0 Then 'если она присутствует, поступим аналогично Tmps = Mid(in_buf , Tmp1 , 4) : P_b = Val(tmps) End If 'аналогично проверим наличие третьей команды Tmps = "C" : Tmp1 = Instr(1 , In_buf , Tmps) If Tmp1 <> 0 Then Tmps = Mid(in_buf , Tmp1 , 8) : P_c = Val(tmps) End If Wait 1 'немного подождем и повторим Loop ============================================================================= 24-2 |