1   2   3   4   5
Ім'я файлу: КеруванняЗвукомФедорів.docx
Розширення: docx
Розмір: 339кб.
Дата: 23.06.2020
скачати

ТЕХНІЧНЕ ЗАВДАННЯ


Програми завантажуються в пам'ять для виконання за допомогою функції DOS Exec (Int 21h, функція 4Bh), яка грає роль системного завантажувача. При запуску програми через командний рядок функцію Exec викликає командний процесор COMMAND.COM. Інакше – через оболонку DOS або інший програмний інтерфейс. Програма, завантажена функцією Exec в пам'ять, включає три компоненти: оточення, префікс програмного сегменту (PSP) і власне програму.

У процесі початкового завантаження DOS створює так зване оточення, в якому будуть працювати керуючі програми і, перш за все, командний процесор COMMAND.COM. Оточення представляє собою область пам'яті, в якій у вигляді символьних рядків записані значення змінних, які називаються змінними оточення. Кожен рядок має формат змінна = значення і закінчується нульовим байтом.

Після того, як виконане початкове завантаження DOS, активною програмою стає командний процесор, який фактично нічого не робить, очікуючи введення команди з клавіатури. Отримавши команду оператора на запуск, COMMAND.COM, активізуючи цю програму, передає їй своє оточення. Після завершення програми і повернення управління батьківському процесові оточення дочірньої програми знищується, і батьківський процес продовжує працювати зі своїм власним оточенням.

Друга структура даних, що формується функцією Exec при активізації викликається програми, - PSP - займає обсяг 256 байт і фактично включається до складу завантажується програми. У слово PSP з адресою 2Ch DOS поміщає сегментну адресу оточення програми, а в область, що починається з адреси 80h - хвіст команди. У байті за адресою 80h знаходиться довжина хвоста, а потім розташовуються самі параметри у вигляді символьного рядка. За допомогою хвоста командного рядка програмі часто передаються ключі, керуючі її роботою, а також імена робочих файлів.

У разі, якщо команда не передавалася б інтерпретатору DOS, а виконувалася нами самостійно, то виявилося б: щоб запустити будь-яку програму з-під shell.com, треба б було попередньо переходити в директорію з цією програмою або вводити її з повним шляхом. Справа в тому, що COMMAND.COM при запуску файлу шукає його по черзі в кожній з директорій, зазначених у змінній середовища PATH.DOS створює копію всіх змінних середовища (так зване оточення DOS) для кожного запускається процесу. Сегментний адресу копії оточення для поточного процесу розташовується в PSP за зміщенням 2Сh. У цьому сегменті записані всі змінні поспіль у формі ASCIZ-рядків виду «COMSPEC = C:/WINDOWS/COMMAND.COM», 0. Після закінчення останнього рядка стоїть додатковий нульовий байт, потім слово (зазвичай 1) – кількість додаткових рядків оточення, а потім – додаткові рядки. Перший додатковий рядок – завжди повний шлях та ім'я поточної програми – також у формі ASCIZ-рядків. При запуску нової програми за допомогою функції 4Bh можна створити повністю нове оточення і передати його сегментну адресу програмою або просто вказати 0, дозволивши DOS зібрати оточення поточної програми.

При запуску програми DOS поміщає весь командний рядок (включаючи останній символ 0Dh) в блок PSP запущеної програми з зміщенням 81h та її довжину в байтах 80h (таким чином, довжина командного рядка не може бути більше 7Eh (126) символів). Під Windows 95 і 4DOS, якщо командний рядок перевищує ці розміри, байт PSP: 0080h (довжина) встановлюється в 7Fh, в останній байт PSP (PSP: 00FFh) записується 0Dh, перші 126 байт командного рядка розміщуються в PSP, а весь рядок цілком – у змінній середовища CMDLINE.

3. РОЗРОБКА АЛГОРИТМІВ І ПРОГРАМНОГО КОДУ


3.1 Керування системним таймером та звуком



Програма 1.1 – Програвання мелодії на динаміку ПК

Згідно з завданням було потрібно розробити програму, яка б відтворювала послідовність нот із додатка А, варіант 25 Сі(1/4) Ля(1/4) Соль(1/4) Фа(1/4) Мі(1/4) Ре(1/4) До(1/4) Кожній ноті відповідає певна частота і тривалість її відтворення в тіках системного таймера. Створюємо два масиви типу int. У масив iMel[] запишемо частоти нот заданої мелодії, закінчивши масив нулем. У масив iDel[] - довжину нот в тіках, де 9 приймемо за ½, а 4 - за ¼ ноти, так як системний таймер викликає переривання приблизно 18 разів на секунду. Програємо кожну ноту на динаміці, виконуючи функцію, яка генерує звук з висотою тону і довжиною, незалежно від тактової частоти ЕОМ (у нашому випадку називається tm_sound ()).

Функція затримки (в нашому випадку називається tm_delay ()) формує відрізки часу, що не залежать від частоти процесора IBM-сумісної ЕОМ. У цю функцію передається один параметр - ціле число тіків системного таймера, на яке слід виконати затримку. Заносить в регістр si необхідну затримку в тиках.

Зчитуємо вміст лічильника таймера функцією 00h переривання 1Ah. Результат заноситься в регістр BX і до нього додається число тіків, на які виконується затримка. Далі знову зчитується значення системного таймера в регістр DX і поки воно не буде дорівнювати значенню з регістра BX, буде виконуватися умовний перехід jne і знову переривання 1Ah і порівняння вмісту DX і BX.

В функцію, що генерує звук tm_sound(), передаються 3 параметри – частота ноти, тривалість і октава. Функція звертається до управляючого порту 43h, посилає в цей порт послідовність бітів для вибору каналу таймера, статусу читання/запису, режима операції и форми представлення чисел. Визначає коефіцієнт ділення. Загружає коефіцієнт ділення в регістр лічильника-таймера (висота звука). Вмикає динамік, виконує затримку функцією tm_delay() и вимикає динамік через звертання до його порту.



Рисунок 3.1 – Блок-схема програми, що програє мелодію.


Рисунок 3.2 – Блок-схема функції tm_sound


Рисунок 3.3 – Блок-схема функції tm_delay
Лістинг 3.1- Програма програвання мелодії на динаміку ПК
#include

#include

#include

#include

#include

int i;

int left, top, right, bottom;

void main (void);

void tm_sound (int, int, int);//функція генерації звуку;

void tm_delay (int); //функція для створення затримки;
//Масив частот (еквівалент нот в герцах) другої октави
int iMel[ ] = 493, 440, 392, 349, 329, 293, 261. };
//Масив довжин звуків в тіках
int iDel[ ] = { 4,4,4,2,4,4,4,4,2,

4 };
int iOct; // коефіцієнт октави

void main (void)

{

/*---------------------*/

int gdriver = DETECT, gmode, errorcode;
/* initialize graphics and local variables */

initgraph(&gdriver, &gmode, "");
/* read result of initialization */

errorcode = graphresult();

if (errorcode != grOk) /* an error occurred */

{

printf("Graphics error: %s\n", grapherrormsg(errorcode));

printf("Press any key to halt:");

getch();
}
left = getmaxx() / 2 - 50;

top = getmaxy() / 2 - 50;

right = getmaxx() / 2 + 50;

bottom = getmaxy() / 2 + 50;
for(iOct=2;iOct<3;iOct++)

{

for ( i = 0; iMel[i] != 0; i++ )

tm_sound ( iMel[i], iDel[i], iOct-1);

}

}
/*Функція tm_sound генерує звук з висотою тону й довжиною, незалежною від тактової частоти ЕОМ. Це досягнуто за рахунок того, що за замовчуванням кількість тіків в секунду однакова для всіх IBM-сумісних ЕОМ. Частота тіків - приблизно 18,2 Гц. */

void tm_sound(int iFreq, int iTime, int Oct)

{

int iPer, //Коефіцієнт ділення;

iOct = Oct //Коефіцієнт октави;

; //Додатковий лічильник;
/*Звернутися до керуючого порту 43h. Надіслати до цього порту послідовність бітів (байт) для вибору каналу таймеру, статусу читання/запису, режиму операції та форми представлення чисел і т.і. */

outp(0x43, 0xb6);
// З’ясувати коефіцієнт ділення,

iPer = 1193180L / (pow(2,iOct)*iFreq);//1193180 Гц - частота кварцового генератору;

/*Завантажити коефіцієнт ділення до регістру лічильника таймеру (задати висоту звуку). Завантажити спочатку молодший, а потім старший байт: */

outp(0x42, iPer & 0x00ff);

outp(0x42, ((iPer & 0xff00)>>8));
//Ввімкнути динамік:

outp(0x61, inp(0x61) | 3);
//Виконати затримку:

setcolor(i);

rectangle(left,top,right,bottom);

tm_delay(iTime);
//Вимкнути динамік:

outp(0x61, inp(0x61) & 0xfc);

}
//Функція tm_delay для отримання затримки.
void tm_delay ( int iTicks)

{
_asm {

push si //; завантажити до стеку вміст регістру SI;

mov si,iTicks //;занести до регістру необхідну затримку в тіках;

mov ah,0 //; функція 00h – для зчитування вмісту лічильника таймеру;

int 1ah //; переривання для роботи з таймером; в регістрі DX зчитане молодше слово лічильника таймеру

mov bx,dx //; це слово занести до регістру BX

add bx,si //; й до нього додано число тіків, рівне затримці;

}
delay_loop:
/* З кожним тіком таймеру вміст лічильника за допомогою переривання BIOS INT 8h збільшується на одиницю */

_asm {

int 1ah //;- переривання для роботи з таймером; в регістрі DX зчитане молодше слово лічильника таймеру

cmp dx, bx //; порівняти з вмістом регістру BX;

jne delay_loop //;якщо не рівні – затримка продовжується;

pop si //; - інакше поновлення регістру SI значенням зі стеку
Програма 1.2 – Виконання затримки на ціле число секунд
Програма виконання затримки на ціле число секунд реалізує інтерфейс для введення цілого числа секунд затримки з клавіатури. На початку виконання програми проводиться затримка на 2 секунди – за варіантом курсової роботи, далі знову проводиться затримка на кількість секунд, введену з клавіатури. В обох випадках виконується функція tm_delay (), яка в свою чергу використовує функцію затримки delay () бібліотеки "dos.h", що приймає в якості параметрів кількість мілісекунд. Також до і після виконання tm_delay() використовується функція clock () бібліотеки "time.h", що повертає приблизне процесорний час використане програмою. У кінці програми виводиться час затримки отримане на основі вимірів.


Рисунок 3.4 – Блок-схема програми виконання затримки на ціле число секунд
Лістинг 3.2 – Програма виконання затримки на ціле число секунд

#include

#include

#include

#include

#include

#include

void tm_delay ( int iTicks)

{

_asm {

push si //; завантажити до стеку вміст регістру SI;

mov si,iTicks //;занести до регістру необхідну затримку в тіках;

mov ah,0 //; функція 00h – для зчитування вмісту лічильника таймеру;

int 1ah //; переривання для роботи з таймером; в регістрі DX зчитане молодше слово лічильника таймеру

mov bx,dx //; це слово занести до регістру BX

add bx,si //; й до нього додано число тіків, рівне затримці;

}

delay_loop:

/* З кожним тіком таймеру вміст лічильника за допомогою переривання BIOS INT 8h збільшується на одиницю */

_asm {

int 1ah //;- переривання для роботи з таймером; в регістрі DX зчитане молодше слово лічильника таймеру

cmp dx, bx //; порівняти з вмістом регістру BX;

jne delay_loop //;якщо не рівні – затримка продовжується;

pop si //; - інакше поновлення регістру SI значенням зі стеку

}

};
void main()

{

int i,t;

cout<<"Enter count of second:\n";

cin>>t;

int left, top, right, bottom;

int gdriver = DETECT, gmode, errorcode;
/* initialize graphics and local variables */

initgraph(&gdriver, &gmode, "");

/* read result of initialization */

errorcode = graphresult();

if (errorcode != grOk) /* an error occurred */

{

printf("Graphics error: %s\n", grapherrormsg(errorcode));

printf("Press any key to halt:");

getch();

}

left = getmaxx() / 2 - 50;

top = getmaxy() / 2 - 50;

right = getmaxx() / 2 + 50;

bottom = getmaxy() / 2 + 50;

char msg[10];

cout<<" delay begin...\n";

for(i=0;i
{

left+=5;

top+=5;

right+=5;

bottom+=5;

setcolor(4);

rectangle(left,top,right,bottom);

setcolor(5);

sprintf(msg, "%d sec", i);

outtextxy(left+(right-left)/2-5, top+(bottom-top)/2-5, msg);

tm_delay(18);

setcolor(0);

rectangle(left,top,right,bottom);

outtextxy(left+(right-left)/2-5, top+(bottom-top)/2-5, msg);

}

cout<<"\n "<<" delay last\n Press any key";

getch();

closegraph();

}

Програма 1.3 - Фіксація часу між першим і другим натисканням клавіші

Згідно завдання, потрібно було розробити алгоритм, засікати час між двома натисканнями будь-якої клавіші клавіатури і виводити його на екран. Кінець і початок відліку часу фіксувати на екрані ПК.

Для цієї програми змінна – лічильник тиків системного таймера count ініціалізується нульовим значенням. Після виведення інформаційного напису викликаємо функцію, що зупиняє програму до натискання клавіші getch (), чекаючи першого натискання клавіші. Після натискання клавіші запускається нескінченний цикл while(!kbhit ()) (kbhit () -функція бібліотеки «conio.h», яка приймає ненульове значення у момент натиснення клавіші). У тілі циклу виконуємо затримку на 1 тік за допомогою функції tm_delay (), описаної для програми 1.1 і інкрементуємо значення лічильника тиків count. Після натискання будь-якої клавіші роздруковуємо значення лічильника тиків, обчислюємо минулий час в секундах, розділивши count на 18 і також виводимо його на екран.



Рисунок 3.5 – Блок-схема програми фіксації часу між натисканнями клавіш

Лістинг 3.3 – Програма фіксації часу між натисканнями клавіш.
#include

#include

#include

#include

#include
void main()

{

int n1,n2;

cout<<"press any key\n\n";

getch();

_asm {

mov ah,0 //; функція 00h – для зчитування вмісту лічильника таймеру;

int 1ah //; переривання для роботи з таймером; в регістрі DX зчитане молодше слово лічильника таймеру

mov n1,dx //; це слово занести y n1

}

cout<<"delay on...\npress key to stop\n\n";

getch();

_asm {

mov ah,0 //; функція 00h – для зчитування вмісту лічильника таймеру;

int 1ah //; переривання для роботи з таймером; в регістрі DX зчитане молодше слово лічильника таймеру

mov n2,dx //; це слово занести y n2

}

cout<<"left time="<
getch();

clrscr();

1   2   3   4   5

скачати

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