1   2   3   4   5   6   7
Ім'я файлу: Арх_комп_КСД12_Гайдук_КР.pdf
Розширення: pdf
Розмір: 997кб.
Дата: 13.02.2022
скачати
Пов'язані файли:
пояснительная_записка.doc

12.19 Расчет часового угла Расчет часового угла как разности звездного времени и прямого восхождения.
;*******************************************************************************
; Расчет часового угла.
;*******************************************************************************
GetTmAng: rcall LoadRisgSunToA rcall MovAToB rcall LoadStarTimeToA rcall SubF rcall LoadAToTmAng ret
Послная последовательность операций, требуемая для вычисления часового угла, описана в файле tmang.asm, и представлена ниже
;*******************************************************************************
;
; Расчет часового угла (в радианах) на заданное время.
;
;*******************************************************************************
HourAngGivenTime:
; Определение звездного времени в радианах. rcall GetHHhh ; Время в формате HH,hh. rcall GetDDdd ; Сутки и доли суток. rcall CorrectYear ; Коррекция представления года 15 -> 2015. rcall GetJD ; Расчет юлианской даты (со смещением. rcall GetStdTime ; Получаем поясное время (in JD). rcall StdTimeToUT ; Поясное время во всемирное. rcall JulianCent ; Расчет юлианских столетий со смещением -36524/36525. rcall StarryTime0 ; Звездное время по Гринвичу. rcall StdTime ; Поясное время (часы и доли часа. rcall LongToDeg ; Долготу в градусы и доли градуса.

62 rcall DegToHour ; Долгота как время. rcall LoadAToLongitude rcall StarTime ; Звездное время. rcall HourToRad ; Звездное время в радианах. rcall LoadAToStarTime
; Подготовка входных данных. rcall LatitToDeg ; Широту в градусы и доли градуса. rcall DegToRad ; Широту в радианы. rcall LoadAToLatit rcall DeclinToDeg ; Склонение в градусы и доли градуса. rcall DegToRad ; Склонение в радианы. rcall LoadAToDecl rcall RisgSunToHour ; Прямое восхождение в часы и доли часа. rcall HourToRad ; Прямое восхождение в радианах. rcall LoadAToRisgSun rcall GetTmAng ; Расчет часового угла.
; Пр. восх., склонение, широта и часовой угол готовы. ret
13. Расчет горизонтальнвых координат Для вычисления горизонтальных координат необходимо прежде рассчитать несколько вспомогательных величин (2.2, 2.3, 2.4), с помощью которых потом, на основании формул 2.5 и 2.6 рассчитываются горизонтальные координаты. Подпрограмма расчета вспомогательных величин описана в файле xyz.asm, а собственно расчет координат выполняется в подпрограмме, описанной в файле coord.asm.
13.1 Расчет вспомогательных величин x, y, z Подпрограмма расчета вспомогательных величин
;*******************************************************************************
;
; Расчет вспомогательных величин x, y, z.
;
;*******************************************************************************
GetXYZ:
; Расчет X. rcall LoadDeclToA ; Склонение d в регистр А. rcall CosF ; A <- cos(d). ldi temp, 0x80 eor pA, temp ; A <- -A = -cosd
PushA ; -cosd to stack rcall LoadTmAngToA ; Часовой угол t в регистр А. rcall SinF ; A <- sint
PopB ; B <- -cosd rcall MulF ; A = -cosd*sint = x rcall AToX ; X в память.
; Расчет Y. rcall LoadDeclToA ; Склонение d в регистр А. rcall SinF ; A <- sin(d).

63
PushA ; sind to stack rcall LoadLatitToA ; Широта в А. rcall CosF ; A = cos(fi)
PopB ; B = sind rcall MulF ; cos(fi)*sind
PushA ; cos(fi)*sind to stack rcall LoadDeclToA ; Склонение d в регистр А. rcall CosF ; cosd
PushA ; cosd to stack rcall LoadTmAngToA ; t rcall CosF ; cost
PushA ; cost to stack rcall LoadLatitToA ; fi rcall SinF ; sin(fi)
PopB ; B = cost rcall MulF ; A = cost*sin(fi)
PopB ; B = cosd rcall MulF ; A = cosd*cost*sin(fi) rcall swapAB ; B = cosd*cost*sin(fi)
PopA ; A = cos(fi)*sind rcall SubF ; y = cos(fi)*sind-cosd*cost*sin(fi) rcall AToY ; y в память.
; Расчет Z. rcall LoadDeclToA ; Склонение d в регистр А. rcall SinF ; A <- sin(d).
PushA ; sind to stack rcall LoadLatitToA ; Широта в А. rcall SinF ; A = sin(fi)
PopB ; B = sind rcall MulF ; sin(fi)*sind
PushA ; sin(fi)*sind to stack rcall LoadDeclToA ; Склонение d в регистр А. rcall CosF ; cosd
PushA ; cosd to stack rcall LoadTmAngToA ; t rcall CosF ; cost
PushA ; cost to stack rcall LoadLatitToA ; fi rcall CosF ; cos(fi)
PopB ; B = cost rcall MulF ; A = cost*cos(fi)
PopB ; B = cosd rcall MulF ; A = cosd*cost*cos(fi) rcall swapAB ; B = cosd*cost*cos(fi)
PopA ; A = sin(fi)*sind rcall AddF ; y = sin(fi)*sind+cosd*cost*cos(fi) rcall AToZ ; z в память. ret
13.2 Расчет азимута и высоты Подпрограмма расчета горизонтальных координат
;*******************************************************************************
;
; Расчет азимута и высоты.
;
;*******************************************************************************

64
GetAandH:
; Определение азимута. rcall XToA ; A = x rcall MovAToB ; B = x rcall YToA ; A = y rcall swapAB ; A = x, B = y rcall DivF ; tgA = x/y rcall ArctgF ; A = arctg(x/y) rcall AToAzimuth ; arctg(x/y) to mem rcall XToA ; A = x ori pA, 0x00 brpl GetAandH1 rcall AzimuthToA ldi pb, 0x40 ; pi 40490fdb 40490fdb ldi mbH, 0x49 ldi mbM, 0x0f ldi mbL, 0xdb rcall AddF ; A = arctg(x/y)+pi/2 rcall AToAzimuth
GetAandH1:
; Определение высоты. rcall XToA ; A = x rcall MovAToB ; B = x rcall MulF ; A = x^2
PushA rcall YToA ; A = y rcall MovAToB ; B = y rcall MulF ; A = y^2
PopB rcall AddF ; x^2 + y^2 rcall SqrtF ; sqrt(x^2 + y^2) rcall MovAToB rcall ZToA rcall DivF rcall ArctgF rcall AToHeight ; Height to mem ret Пример Вычислим азимут и высоту солнца в Киеве на момент 20 июня 2015 года 02:15:35 местного времени. Географическая долгота Киева , широта . Прямое восхождение Солнца 05 h 52 m 57 s, склонение . Входные данные указываем в файле input.asm. Программа для ОМК выдает такие значения азимут 0x3f0cbbfb = 0.54974335 рад = 31,45 высота 0xbe368da2 = -0.17827466 рад = -10,21 Корректность полученного результата проверим с помощью авторской программы Смыкова
В.П. Солнечный калькулятор (рис. 13.1). Программа выдает такие значения

65 азимут 31,493 высота -10,216 Рис. 13.1 – Проверка корректности расчет азимута и высоты Солнца на заданное время в заданном месте.
14. Определение количества шагов каждого из двигателей Последняя задача вычислительного ядра МПС – определение количества шагов, на которые должен повернуться ротор каждого двигателя двигателя навигации в горизонтальной плоскости, и двигателя навигации в вертикальной плоскости. Предполагается, что полный оборот каждый двигатель выполняет за 200 шагов. То, количество требуемых шагов определяется исходя из того, что рад – это 100 шагов. Количество шагов может быть как положительным, таки отрицательным – от -100 до +100, в зависимости оттого, в какую сторону нужно выполнять вращение. Количество шагов двигателя навигации в горизонтальной плоскости заносится в память по адресу 0xd1, а количество шагов двигателя навигации в вертикальной плоскости заносится в память по адресу 0xd2. Подпрограмма расчет количества шагов описана в файле drive.asm, и представлена ниже
;*******************************************************************************
;
; Работа с шаговыми двигателями.
;
;*******************************************************************************
GetCountSteps:
; Количество шагов двигателя навигации в гор. плоскости. rcall AzimuthToA ; A <- azimuth
; Проверяем, не больше ли азимут, чем 180 гр. rcall AToBuf ldi pb, 0x40 ; 3.14 0x40490fdb ldi mbH, 0x49 ldi mbM, 0x0f ldi mbL, 0xdb rcall SubF ori pA, 0x00 brpl GetCountSteps1

66 rjmp GetCountSteps2
GetCountSteps1: rcall BufToA ldi pb, 0x40 ; 40c90fdb 2*pi ldi mbH, 0xc9 ldi mbM, 0x0f ldi mbL, 0xdb rcall SubF ; fi-2*pi
GetCountSteps2:
PushA ldi mAL, 100 rcall IntToFloat ; 100 as float
PopB rcall MulF ; fi*100 ldi pb, 0x40 ; 3.14 0x40490fdb ldi mbH, 0x49 ldi mbM, 0x0f ldi mbL, 0xdb rcall DivF rcall FloatToInt sts h_drive, mAL
; Количество шагов двигателя навигации в верт. плоскости. rcall HeightToA ; A <- Height
PushA ldi mAL, 100 rcall IntToFloat ; 100 as float
PopB rcall MulF ; fi*100 ldi pb, 0x40 ; 3.14 0x40490fdb ldi mbH, 0x49 ldi mbM, 0x0f ldi mbL, 0xdb rcall DivF rcall FloatToInt sts v_drive, mAL ret Пример Вычислим, на какое количество шагов нужно повернуть ротор каждого из двигателей, если труба телескопа находится в начальном положении (параллельна горизонту, ориентирована на юг, дабы наблюдать Луну, экваториальные координаты которой на момент наблюдений составляют склонение , прямое восхождение 09 h 09 m 05 s. Наблюдение проводится в Киеве 20 июня
2015 года 15:15:35 местного времени. Географическая долгота Киева , широта . Программа для ОМК выдает такие значения горизонтальных координат азимут 0x404b0948 = 3,1724415 рад = 181,77 высота 0x3f67df6c = 0,9057529 рад = 51,90 Проверку корректности выполненных расчетов выполним с помощью авторской программы
Смыкова В.П. Лунный калькулятор (рис. 13.2). Программа выдает такие значения

67 азимут 180,9 высота 51,9 Рис. 13.2 – Проверка корректности расчет азимута и высоты Луны на заданное время в заданном месте. Как видим, ошибка имеется только в азимуте, и то, всего 0,8 , что для любительских наблюдений на столь принципиально (тем более, можно вручную подрегулировать. Итак, из полученных результатов видно, что двигатель навигации в горизонтальной плоскости должен выполнить поворот на -178,23 = -99 шагов, а двигатель навигации в вертикальной плоскости должен выполнить поворот на 51,9 = +29 шагов. Результаты, выданные программой для ОМК: количество поворотов двигателя навигации в горизонтальной плоскости – 9D = -99 количество поворотов двигателя навигации в вертикальной плоскости – 1C = 28 Ошибка имеется только в определении количества поворотов двигателя навигации в вертикальной плоскости, но всего лишь на единицу.
15. Индикация количества шагов двигателей Для отображения количества шагов ротора каждого из двигателей использованы два двухразрядных семисегментных индикатора с общим анодом (рис. 15.1).

68 Рис. 15.1 – Схема для отображения количества шагов двигателей. Подпрограмма индикации результатов описана в файле indicate.asm, а ее код приведен ниже. Код несколько трудночитаем, что связано стем, что регистры были определены для мат. вычислений, ив данной подпрограмме их названия не совсем логичны.
IndicCntSteps: rcall init_ports ; Настройка портов. rcall init_timer ; Инициализация таймера. lds acc, 0xd1 ; Количество шагов двигателя навигации
; в гор. плоскости. lds mBM, 0xd2 ; Количество шагов двигателя навигации
; в верт. плоскости. ldi sgn, 0 ; Первым отображается ст. разряд. rcall decode1 ; Получаем семисегментные коды. rcall decode2 ; sei ; Разрешение внешних прерываний. ret init_ports: ; Настройка портов. ldi temp, 0xFF out ddrb, temp ; PB на выход. out ddrc, temp ; PC на выход. out ddra, temp ; PA на выход. ret init_timer : ; Инициализация таймера. ldi temp, 0b00000010 ; Прерывание компаратора out TIMSK, temp ; TC0 вкл.

69 ldi temp, 0b00000100 ; Деление частоты на 256. out TCCR0, temp ; 0-255 за 0,065536 s. ldi temp, 0x82 ; "Потолок" счетчика. out OCR0, temp ; 130 тиков -

1/30 сек. ldi temp, 0 ; Обнуляем счетчик. out TCNT0, temp ret
; Количество шагов двигателя навигации в верт. плоскости - декодирование. decode1: ; Декодирование числа. ldi mCM, Low(DcMatrix*2) ; Адрес начала массива в регистр Z. ldi mCL, High(DcMatrix*2) ; mov temp, mBM ; temp <- mBM andi temp, 0x0F ; Выделение мл. х бит. push mCM ; Сохраняем начало массива. push mCL add mCM, temp ; Добавляем смещение. ldi temp, 0x00 adc mCL, temp ; На случай, если был перенос. lpm ; r0 <- M(Z). mov _pC, r0 ; Мл. шестн. разряд. mov temp, mBM ; Выделение ст. х бит. swap temp andi temp, 0x0F pop mCL ; Восстановление начала массива. pop mCM add mCM, temp ; Добавляем смещение. ldi temp, 0x00 adc mCL, temp ; На случай, если был перенос. lpm ; r0 <- M(Z). mov mCH, r0 ; Ст. шестн. разряд. ret
; Количество шагов двигателя навигации в гор. плоскости - декодирование. decode2: ; Декодирование числа. ldi mCM, Low(DcMatrix*2) ; Адрес начала массива в регистр Z. ldi mCL, High(DcMatrix*2) ; mov temp, acc ; temp <- acc andi temp, 0x0F ; Выделение мл. х бит. push mCM ; Сохраняем начало массива. push mCL add mCM, temp ; Добавляем смещение. ldi temp, 0x00 adc mCL, temp ; На случай, если был перенос. lpm ; r0 <- M(Z). mov pB, r0 ; Мл. шестн. разряд. mov temp, acc ; Выделение ст. х бит. swap temp andi temp, 0x0F pop mCL ; Восстановление начала массива. pop mCM add mCM, temp ; Добавляем смещение. ldi temp, 0x00 adc mCL, temp ; На случай, если был перенос. lpm ; r0 <- M(Z). mov pA, r0 ; Ст. шестн. разряд. ret int_comp0: ; Совпадение в компараторе TC0. ldi temp, 0 ; Обнуляем счетчик. out TCNT0, temp

70 cpi sgn, 0x01 breq disp2 ; Это мл. разряд. ldi temp, 0x05 out portb, temp ; Иначе, показываем ст. разряд. out portc, pA ; out porta, mCH rjmp exit disp2: ldi temp, 0x0a out portb, temp ; Отображение мл. разряда. out portc, pB ; out porta, _PC ; exit: ldi temp, 0x01 eor sgn, temp ; Меняем разряд. reti
DcMatrix: ; Семисегментные коды.
.db 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8
.db 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E На рис. 15.2 показана работа схемы на ранее рассмотренном наборе входных данных наведение телескопа на Луну, рассмотренное в разделе 14). Рис. 15.2 – Отображение количества шагов ротора каждого из двигателей.
16. Основная программа Основная программа содержится в файле telescope.asm. Код программы представлен ниже.

71
.include "m8535def.inc" ; Файл описания.
.include "def_reg.inc" ; Определение регистров.
.include "def_const.inc" ; Определение констант.
.cseg
.org 0x00 rjmp reset ; Вектор прерывания сброса.
.org 0x13 rjmp int_comp0 ; Обработчик компаратора TC0.
.org 0x15 ; Код после таблицы векторов.
.include "def_macro.asm" ; Подключение макросов и подпрограмм пересылок.
; Начало программы. reset:
; Инициализация стека.
InitStack
; Задание входных данных. rcall InitInputData
; Расчет часового угла (в радианах) на заданное время. rcall HourAngGivenTime
; Расчет вспомогательных величин. rcall GetXYZ
; Расчет азимута и высоты. rcall GetAandH
; Расчет количества шагов каждого двигателя. rcall GetCountSteps
; Индикация результатов. rcall IndicCntSteps
; Рабочий цикл программы. main: rjmp main
.include "input.asm" ; Инициализация входных данных.
.include "math.asm" ; Математические функции и арифметические операции.
.include "astro.asm" ; Модуль астрономических расчетов.
; На выходе дает высоту и азимут светила.
.include "drive.asm" ; Работа с шаговыми двигателями.
.include "indicate.asm" ; Идникация результатов. Заключение Итогом проведенной работы стало написание вычислительного ядра для наведения телескопа. На основании вектора входных данных программа вычисляет количество шагов ротора каждого из двух двигателей двигателя навигации в горизонтальной плоскости и двигателя навигации в вертикальной плоскости. С использованием этого ядра нетрудно реализовать и программу суточного ведения – достаточно лишь инкрементировать через определенные интервалы времени значение часового угла, заново пересчитывать значение горизонтальных координата, по ним, уже и колишество шагов роторов двигателей. Все это уже "дело техники" как говорится. Наиболее сложная и муторная часть работы выполнена. Далее же, с использованием написанных подпрограмм можно

72 реализовать полноценную МПС для навигации и суточного ведения телескопа, подключив все необходимые периферийные устройства. Стоит отметить, что данное ядро подходит лишь для использования в любительских наблюдениях, ибо вычисления с одинарной точностью слишком грубы, если говорить о вычислении юлианских столетий, на основании который вычисляется значение часового угла Многие функции написаны не самым оптимальным образом – многие вещи можно сделать быстрее и короче, но при выполнении работы достижение максимальной оптимальности и не преследовалось. Практика показывает, что работать с вещественными числами на 8-миразрядном микроконтроллере не так ужи страшно, если реализованы все необходимые вспомогательные подпрограммы. Литература

1. В.Я. Хартов "Микроконтроллеры AVR. Практикум для начинающих, Москва, 2007.
2. Ж. Мес "Астрономические формулы для калькуляторов, Москва, 1988.
3. Короткий астрономічний календар, 1984. Приложение 1. Программа преобразования десятичных чисел в машинный код

#include "stdafx.h"
#include "iostream"
#include "math.h"
#include "windows.h"
// Преобразование целого числа в массив битов. void int_to_bin (int x, int d, bool* mas)
{ if (d == 0) return; mas[d-1] = bool(x & 1); int_to_bin(x >> 1,--d,mas);
}
// max = 65535 min = 0 void int_to_bin16 (int x, bool* mas)
{ int_to_bin(x,16,mas);
}
// Преобразование дробной части числа в массив битов. void fract_to_bin (float x, int d, bool* mas, int cap)
{ if (d == 0) return; mas[cap-d] = bool(int(x*2)); fract_to_bin(x*2-int(x*2),--d,mas,cap);
}
// 16+23. Разряды дробной части вычисляем с запасом. void fract_to_bin39 (float x, bool* mas)
{ fract_to_bin(x,39,mas,39);
}

73
// Представление числа по стандарту IEEE-754. void format (float x, bool* out, DWORD* res)
{ bool cel[16], drobn[39]; bool dw[55];
DWORD tmp;
*res = 0;
// Если ноль, то результат выдаем сразу. if (x == 0)
{ printf("HEX = %08x",0); for(int i=0;i<32;i++) out[i] = 0; return;
}
// Получение целой и дробной части модуля. int c = int(abs(x)); float d = abs(x)-int(abs(x));
// Переводим их в двоичную систему. int_to_bin16(c,cel); fract_to_bin39(d,drobn);
// Загоняем в рабочий массив. for(int i=0;i<16;i++) dw[i] = cel[i]; for(int i=0;i<39;i++) dw[i+16] = drobn[i];
// Определяем порядок. int p = 0; for(int i=0;i<32;i++) if (dw[i] == 1)

1   2   3   4   5   6   7

скачати

© Усі права захищені
написати до нас