КОНТР-&-БАСИК

     
 

Контроллер поворотного устройства

    Эта программа была написана в ответ на пожелание радиолюбителя UA6EM участвовать в создании простого GS232 совместимого устройства на базе Бейсик-контроллера. Программа была написана с применением препроцессора, отлажена на имитаторе сигналов обратной связи и передана на тестирование UA6EM

' **********************************************************
' ПОВОРОТНОЕ УСТРОЙСТВО
' УПРАВЛЯЮЩАЯ ПРОГРАММА ДЛЯ БЕЙСИК КОНТРОЛЛЕРА
' версия 2.0A
' 2006, 17, November TBC Group
' **********************************************************
' **********************************************************
' Десятичные коды символов
' **********************************************************
' таблица получена при помощи программы
' print
' for i=32 to 47
' print "$";i,i,"$";i+16,i+16,"$";i+32,i+32,"$";i+48,i+48
' next
' **********************************************************
' 32 0 48 @ 64 P 80
' ! 33 1 49 A 65 Q 81
' " 34 2 50 B 66 R 82
' # 35 3 51 C 67 S 83
' $ 36 4 52 D 68 T 84
' % 37 5 53 E 69 U 85
' & 38 6 54 F 70 V 86
' ' 39 7 55 G 71 W 87
' ( 40 8 56 H 72 X 88
' ) 41 9 57 I 73 Y 89
' * 42 : 58 J 74 Z 90
' + 43 ; 59 K 75 [ 91
' , 44 < 60 L 76 \ 92
' - 45 = 61 M 77 ] 93
' . 46 > 62 N 78 ^ 94
' / 47 ? 63 O 79 _ 95
' **********************************************************
' -------------------------------------------------------
' свободные переменные
' * * C D * * G * * J * * * * * * Q * * * * * W * * *
'
' ---------------- ПЕРЕМЕННЫЕ ---------------------------
' M - флаг подъёма/опускания
' 0 - стоим
' 1 - крутим руками вверх
' 2 - крутим руками вниз
' 3 - автоматика вверх
' 4 - автоматика вниз
' S - минимальный предел АЦП подъёма
' E - максимальный предел АЦП подъёма
' Y - текущее значение АЦП подъёма
' L - масштабирующий коэффициент для шкалы подъёма
' U - смещение по углу места
' V - задача по углу места
' -------------------------------------------------------
' F - флаг поворота
' 0 - стоим
' 1 - крутим руками вверх
' 2 - крутим руками вниз
' 3 - автоматика вверх
' 4 - автоматика вниз
' T - минимальный предел АЦП поворота
' N - максимальный предел АЦП поворота
' X - текущее значение АЦП поворота
' K - масштабирующий коэффициент для шкалы поворота
' O - смещение по азимуту
' H - задача по азимуту
' -------------------------------------------------------
' Z - ошибка ввода
' P - флаг вывода служебной информации
' -------------------------------------------------------
' Дискретный вывод 1 - подъём
' 2 - опускание
' 3 - поворот по часовой стрелке
' 4 - поворот против часовой стрелки
' Аналоговый ввод 1 - подъём / опускание
' 2 - поворот в горизонтальной плоскости
' -------------------------------------------------------
' ----------------КОМАНДЫ--------------------------------
'
' U (85) - Подъём
' D (68) - Опускание
' E (69) - Останов UP/DN вращения
' R (82) - Вращение по часовой стрелке (CW)
' L (76) - Вращение против часовой стрелки (CCW)
' A (65) - Останов CW/CCW вращения
' S (83) - Останов UP/DN и CW/CCW вращения
' M (77) - Установка горизонтального направления
' в формате MXXX, где XXX - горизонтальный угол
' W (87) - Установка направления в формате WXXX YYY
' где XXX - горизонтальный угол
' YYY - вертикальный угол
' B (66) - показать текущий угол места в формате +Onnn
' C (67) - показать текущий азимут в формате +Onnn
' C2 (67,50) - показать текущий азимут в формате +Oaaa+Oeee
' Z (90) - включение/выключение служебного вывода
'
'
' ----------------- СООТНОШЕНИЕ ШКАЛ -----------------------
' географические градусы------------0 (смещение в перем. O)
' физические градусы--------0       |                 360
' сооружения                |       |                  |
' единицы АЦП----------0    T       |                  N    1023
'                      XXXXXX__________________________XXXXXX
' XXXXX - концевые секторы
'
' -----------------------------------------------------------------
' МЕТОДИКА КАЛИБРОВКИ
' -----------------------------------------------------------------
' 1. установить в программе значения переменных как показано ниже
'
' S=0
' E=1023
' T=0
' N=1023
' O=0
' U=0
'
' 2. Загрузить программу, запустить и включить служебный вывод,
' пользуясь командами ручного перемещения роторов, определить
' показания ацп для крайних физических положений,
' то есть, для нуля физического и для полной шкалы физической
' 3. Изменить значения переменных, как показано ниже
'
' S=показания Y при положении ротора UP/DN в физическом нуле
' E=показания Y при положении ротора UP/DN на конечной точке шкалы
'
' T=показания X при положении ротора CW/CCW на физическом нуле
' E=показания X при положении ротора CW/CCW на конечной точке шкалы
'
'
' 4. Загрузить программу, запустить и включить служебный вывод,
' пользуясь командами ручного перемещения роторов, привести их
' в точку физического нуля и считать показания угла места и азимута
'
' 5. Изменить значения переменных, как показано ниже
'
' O=показания азимута в точке физического нуля
' U=показания угла места в точке физического нуля
'
'
'
' ====================================================================
' ПРОГРАММА

define KEY_U = 85 ' Подъём
define KEY_D = 68 ' Опускание
define KEY_E = 69 ' Останов UP/DN вращения
define KEY_R = 82 ' Вращение по часовой стрелке (CW)
define KEY_L = 76 ' Вращение против часовой стрелки (CCW)
define KEY_A = 65 ' Останов CW/CCW вращения
define KEY_S = 83 ' Останов UP/DN и CW/CCW вращения
define KEY_M = 77 ' Установка горизонтального направления
' в формате MXXX, где XXX - горизонтальный угол
define KEY_W = 87 ' Установка направления в формате WXXX YYY
' где XXX - горизонтальный угол
' YYY - вертикальный угол
define KEY_B = 66 ' показать текущий угол места в формате +Onnn
define KEY_C = 67 ' показать текущий азимут в формате +Onnn
define KEY_Z = 90 ' включение/выключение служебного вывода

define ElevScaleCoeff = L ' масштабирующий коэффициент для шкалы подъёма
define RotScaleCoeff = K ' масштабирующий коэффициент для шкалы поворота
define StartAdcElev = S ' минимальный предел АЦП подъёма
define EndAdcElev = E ' максимальный предел АЦП подъёма
define StartAdcRot = T ' минимальный предел АЦП поворота
define EndAdcRot = N ' максимальный предел АЦП поворота
define AzimuthOffset = O ' смещение по азимуту
define VertAngleOffset = U ' смещение по углу места
define CurAdcAzimuth = X ' текущее значение АЦП поворота
define CurAdcVertangle = y ' текущее значение АЦП подъёма
define VertRef = V ' задача по углу места
define HorizRef = H ' задача по азимуту
define ElevState = M ' флаг подъёма/опускания
define RotState = F ' флагповорота


define Main = 10
define W_Command = 187
define Up_Command = 185
define Down_Command = 168
define Turn_CW_Command = 282
define M_Command = 277
define Turn_CCW_Command = 276
define All_Stop = 283
define ShowElevAngle = 566
define ShowAzimuth = 567
define On_Off_service_output = 190
define stop_elevation = 200
define stop_rotation = 300
define input_angle = 900
define print_angle = 600

print "ROTOR V2.0A"
' перед расчётом укладочные коэффициенты заполняются
' конечными точками шкалы
ElevScaleCoeff=180
RotScaleCoeff=360

' рабочие границы для полных шкал
' (здесь даны значения для примера)
StartAdcElev=100
EndAdcElev=899
StartAdcRot=100
EndAdcRot=899
' смещение по углу места
VertAngleOffset=0
' смещение по азимуту
AzimuthOffset=0

' ---------------------------------------------
' расчёт коэффициентов укладки полной шкалы
' ---------------------------------------------
SCALE ElevScaleCoeff,10000,(EndAdcElev-StartAdcElev)
SCALE RotScaleCoeff,10000,(EndAdcRot-StartAdcRot)

' ****************************
' * Главный цикл *
' ****************************
' считать канал азимута в переменную Х
Main
adc CurAdcAzimuth
' переключить коммутатор на канал угла места
setb 128
' если флаг вывода служебной информации ноль,
' обходим процедуру вывода
if P=0 then goto 12
b=CurAdcAzimuth-StartAdcRot
SCALE b,RotScaleCoeff,1000
print "X=";CurAdcAzimuth;" A=";b;" dX=";(CurAdcAzimuth-HorizRef);" F=";RotState,
' считать канал угла места в переменную CurAdcVertangle
12 adc CurAdcVertangle
' переключить коммутатор на канал азимута
clrb 128
' если флаг вывода служебной информации ноль,
' обходим процедуру вывода
if P=0 then goto 14
b=CurAdcVertangle-StartAdcElev
SCALE b,ElevScaleCoeff,1000
print "Y=";CurAdcVertangle;" A=";b;" dY=";(CurAdcVertangle-VertRef);" M=";ElevState
' ----------------------------------------------
' если текущий режим автоматического
' подъёма-опускания, переход на процедуру режима
' ----------------------------------------------
14 if ElevState>2 then gosub 210
' ----------------------------------------------------
' проверки на попадание значения ацп
' в "концевые" секторы потенциометра подъёма-опускания
' -----------------------------------------------------
if ElevState=2 then if CurAdcVertangle<StartAdcElev then gosub stop_elevation
if ElevState=1 then if CurAdcVertangle>EndAdcElev then gosub stop_elevation
' ----------------------------------------------
' если текущий режим автоматического
' подъёма-опускания, переход на процедуру режима
' ----------------------------------------------
if RotState>2 then gosub 310
' ----------------------------------------------------
' проверки на попадание значения ацп
' в "концевые" секторы потенциометра поворота в гориз.
' плоскости
' -----------------------------------------------------
if RotState=2 then if CurAdcAzimuth<StartAdcRot then gosub stop_rotation
if RotState=1 then if CurAdcAzimuth>EndAdcRot then gosub stop_rotation
' -----------------------------------------------------
' проверка прихода символа от управляющего устройства
' -----------------------------------------------------
tstb b,126
if b=0 then goto Main
' есть символ в буфере, вычитать
input "$",b
' установить признак ошибки в ноль
Z=0
' вызвать процедуру анализа команд
gosub 50
' -----------------------------------------------------
' если команда распознана и выполнена, отвечаем
' управляющему устройству символом возврата каретки
' -----------------------------------------------------
if Z=0 then print "$";13;
' -----------------------------------------------------
' иначе выводим ?>, согласно протоколу GS-232
' -----------------------------------------------------
if Z=1 then print "?>"
goto Main

' *******************************************
' * Анализатор команд *
' *******************************************
50
'
if b=KEY_W then goto W_Command ' Установка направления в формате WXXX YYY,
' где XXX - горизонтальный угол
' YYY - вертикальный угол
if b=KEY_U then goto Up_Command ' Подъём
if b=KEY_D then goto Down_Command ' Опускание
if b=KEY_E then goto Stop_Elevation ' Останов UP/DN вращения
if b=KEY_M then goto M_Command ' Установка горизонтального
' направления
if b=KEY_R then goto Turn_CW_Command ' Вращениепочасовойстрелке (CW)
if b=KEY_L then goto Turn_CCW_Command ' Вращениепротивчасовойстрелки (CCW)
if b=KEY_S then goto All_Stop ' Останов UP/DN и CW/CCW вращения
if b=KEY_A then goto stop_rotation ' Останов CW/CCW вращения
if b=KEY_B then goto ShowElevAngle ' показатьтекущийуголместа
' вформате +Onnn
'
if b=KEY_C then goto ShowAzimuth 'C - показатьтекущийазимут
' в формате +Onnn (первая версия команды)
' C2 - показать текущий азимут и угол места в
' формате +Oaaa+Oeee
' Есть 500 миллисекунд, чтобы ввести символ 2 и,
' чтобы команда была воспринята во воторой версии
if b=KEY_Z then goto On_Off_service_output ' включение/выключение служебного вывода
' если дошли до этого места, значит проверили все команды
' и не нашли что делать, устанавливаем признак ошибки
Z=1
return
' **************************
' * Опускание *
' **************************
Down_Command
if ElevState>0 then return
if CurAdcVertangle<StartAdcElev then return
' clrb 1
' delay 1000
setb 2
ElevState=2
return

' **************************
' * Подъём *
' **************************
Up_Command
if ElevState>0 then return
if CurAdcVertangle>EndAdcElev then return
' clrb 2
' delay 1000
setb 1
ElevState=1
return

' *************************************
' * Установка направления в формате *
' * WXXX YYY *
' *************************************
W_Command
' если флаги режимов ElevState и RotState не нули, происходит вращение,
' отказываемся от выполнения
if ElevState>0 then goto 188
if RotState>0 then goto 188
gosub input_angle ' вычитать угол горизонтального направления
HorizRef=I+AzimuthOffset
IF HorizRef>359 THEN HorizRef=HorizRef-360
gosub input_angle ' вычитать угол вертикального направления
VertRef=I+VertAngleOffset
IF VertRef>179 THEN VertRef=VertRef-180
gosub 278
SCALE VertRef,10000,ElevScaleCoeff
VertRef=VertRef+StartAdcElev
B=CurAdcVertangle-VertRef
if B<0 then B=-B
if B<10 then return
if CurAdcVertangle>VertRef then gosub Down_Command
if CurAdcVertangle<VertRef then gosub Up_Command
ElevState=ElevState+2
return
' холостое вычитывание параметров
' и установка признака ошибки
188 gosub input_angle
189 gosub input_angle
z=1
return
On_Off_service_output
P=(P+1)&1
return

' *************************************
' * Останов вертикального перемещения *
' *************************************
stop_elevation
clrb 1
clrb 2
ElevState=0
delay 1000
return

' ************************************************
' * Проверка на попадание в сектор заданного *
' направления (во время вращения) *
' Дело в том, что останов двигателя и торможение *
' должно быть сделано несколько раньше, чем *
' станет равным нулю рассогласование. Величина *
' сектора заданного направления определяется *
' экспериментально *
' ************************************************
210
' определение величины рассогласования
B=CurAdcVertangle-VertRef
' взять рассогласование по модулю
if B<0 then B=-B
' если рассогласование меньше некоторого
' значения (10), остановить вращение
if B<10 then goto 200
return
' ***********************************************
' * Вращение против часовой стрелки (CCW) *
' * в ручном режиме *
' ***********************************************
Turn_CCW_Command
' если флаг режима не ноль (вращение), ничего не делаем
if RotState>0 then return
' если уже находимся в начальном секторе, ничего не делаем
if CurAdcAzimuth<StartAdcRot then return
setb 4
RotState=2
return
' ********************************************
' * Установить горизонтальное направление *
' ********************************************
M_Command ' считать направление в градусах
gosub input_angle
' если уже происходит вращение, то выходим,
' делаемвсёчерезстоп
if RotState>0 then return
' начинаем преобразование угла в единицы АЦП
HorizRef=I+AzimuthOffset
IF HorizRef>359 THEN HorizRef=HorizRef-360
278 SCALE HorizRef,10000,RotScaleCoeff
' учитываем смещение из-за наличия начального сектора
HorizRef=HorizRef+StartAdcRot
' определяем величину рассогласования
B=CurAdcAzimuth-HorizRef
' берём величину по модулю
if B<0 then B=-B
' если мы уже в секторе заданного направления,
' то ничего не делаем
if B<10 then return
' вызов процедур начала вращения
' в зависимости от знака рассогласования
if CurAdcAzimuth>HorizRef then gosub Turn_CCW_Command
if CurAdcAzimuth<HorizRef then gosub Turn_CW_Command
' процедуры начала вращения устанавливают
' флаг режима в значение направления вращения,
' а мы ещё добавим признак работы в автоматическом режиме
RotState=RotState+2
return
' ******************************************
' * Вращение по часовой стрелке (CW) *
' * в ручном режиме *
' ******************************************
Turn_CW_Command
if RotState>0 then return
if CurAdcAzimuth>EndAdcRot then return
setb 3
RotState=1
return
' ***************************************
' * Останов горизонтального и *
' * вертикального вращения *
' ***************************************
All_Stop
clrb 1
clrb 2
ElevState=0
' ***************************************
' * Останов горизонтального перемещения *
' ***************************************
stop_rotation
clrb 3
clrb 4
RotState=0
delay 1000
return
' ********************************************
' * Проверка на попадание в сектор заданного *
' * направления (во время авт. вращения) *
' * Величина сектора заданного направления *
' * определяется экспериментально *
' ********************************************
310
' определение величины рассогласования
B=CurAdcAzimuth-HorizRef
' взять рассогласование по модулю
if B<0 then B=-B
' если рассогласование меньше некоторого
' значения (10, не градусы! единицы АЦП), остановить вращение
if B<10 then goto stop_rotation
return
' *********************************************
' * Процедура вывода текущего угла места *
' * в формате +Onnn *
' *********************************************
ShowElevAngle
' взять в промежуточную переменную положение ротора
' подъёма/опускания в единицах АЦП,
' с учётом размера начального сектора
R=CurAdcVertangle-StartAdcElev
' взять в промежуточную переменную значение
' коэффициента укладки шкалы
B=ElevScaleCoeff
' войти в процедуру вычисления и отображения
I=VertAngleOffset
A=180
goto 590

' *******************************************************
' * Процедура вывода текущего азимута *
' * (команда С) или азимута и угла места (команда С2) *
' *******************************************************
ShowAzimuth
' выждать время, возможно придёт следующий символ "2"
delay 500
' проверить наличие второго символа в буфере
tstb b,126
' если символа нет, это версия вывода только азимута
if b=0 then goto 580
' символ есть, вычитываем
input "$",b
' если этот смивол "2", это вторая версия команды,
' вывод азимута и угла места
if b=50 then goto 570
' иначе, устанавливаем флаг ошибки и возвращаемся
Z=1
return
' вывод по второй версии команды
570 R=CurAdcAzimuth-StartAdcRot
B=RotScaleCoeff
I=AzimuthOffset
A=360
' сначала вычисляем и выводим азимут
gosub print_angle
' переход на отображение угла места
goto ShowElevAngle
580 ' вывод только азимута (первая версия команды)
R=CurAdcAzimuth-StartAdcRot
B=RotScaleCoeff
I=AzimuthOffset
A=360
' просто продолжение вывода, что выводится,
' определяется содержимым R и B
590 gosub print_angle
print
return
' ***********************************************
' * Процедура вывода угла в формате +0NNN *
' * стандартный print смог бы вывести только *
' * в формате N,NN,..NNNNN,-N,-NN,-NNN,..-NNNNN *
' * п/программа принимает значения в переменных *
' * R - текущее положение ротора в единицах АЦП*
' * без величины начального сектора *
' * B - коэффициент укладки шкалы *
' ***********************************************
print_angle
SCALE R,B,10000
R=R-I
IF R<0 THEN R=A-R
if R>-1 then print "+";
if R<0 then print "-";
if R<0 then R=-R
I=R/100
R=R%100
print "0";I;
I=R/10
R=R%10
print I;R;
return

' ********************************************
' * Процедура посимвольного ввода угла *
' * в формате NNN 0NN 00N, после ввода *
' * третьей цифры, ожидается CR или пробел *
' * на самом деле любой символ завершит ввод. *
' * П/программа возвращает значение угла в *
' * переменной I *
' ********************************************
input_angle
input "$",b
I=(B-48)*100
input "$",b
I=I+(B-48)*10
input "$",b
I=I+B-48
input "$",b
return

 
Обновлён: 11.01.2007