Опубликован: 24.04.2009 | Доступ: свободный | Студентов: 1180 / 358 | Оценка: 4.39 / 4.28 | Длительность: 18:45:00
Специальности: Программист
Лекция 8:

Программирование приложений в CE

Пример программы ILASMIO, использующей включаемый код ассемблера X86

Этот пример программы идентичен предыдущему примеру с последовательным портом, за исключением того только, что не использует библиотеку CEDDK для функций чтения и записи порта В/В. Две функции самого нижнего уровня, Read_Port и Write_Port, находящиеся в конце кода примера реализованы с помощью включаемого языка ассемблера X86. Эта программа C++ читает данные последовательного входа из COM2:, выводит каждый символ в консольном окне eBox, и посылает его назад как выход на COM2:.

Использование языка ассемблера требует больше времени для разработки, делает код менее переносимым, и должно избегаться насколько возможно. Тем не менее существует несколько редких ситуаций, когда низкоуровневая процедура (т.е., процедуры OAL из CE) во встроенном устройстве должны быть реализованы на языке ассемблера, и это можно сделать прямо в исходном коде программы C\C++, используя включаемый ассемблер.

Если внимательно исследовать файлы исходного кода библиотеки CEDDK, поставляемые вместе с CE, вы обнаружите, что низкоуровневые процедуры фактически также используют включаемый язык ассемблера для коммуникации с портом В/В. Однако CEDDK будет автоматически изменять код ассемблера для различных процессоров.

Этот код также не предназначен в качестве замены драйвера производственного качества последовательного устройства управляемого прерываниями с буферизацией В/В и задержками, такого как поставляется с CE, который использовался в первом примере программы последовательного порта. Он служит только для демонстрации, как использовать включаемый язык ассемблера для прямой коммуникации с оборудованием в программе C/C++.

Как и раньше, для просмотра данных последовательный null-модемный кабель соединяет COM2: на eBox с неиспользуемым портом COM на настольном ПК системы разработки. Запустите HyperTerminal или другую программу эмулятора терминала, соединенную с портом COMx: на скорости 9600 бод, 8 битами данных, без контроля четности, 1стоп битом, и без управления потоком. Проверьте, что не выполняется другое приложение, которое использует тот же самый порт COM на любой машине!

Когда выполняется программа, она печатает заголовок, а затем каждый символ, введенный на клавиатуре ПК посылается в eBox, устройство считывает символы, выводит их в консольном окне, и посылает символы назад. Так как они посылаются назад, то они выводятся также в эмуляторе терминала. Ввод Ctrl-C в эмуляторе терминала заставляет eBox выйти из программы.

// ILASMIO.cpp : Определяет точку входа для консольного приложения.
//
// Учебный пример, предназначенный для демонстрации использования 
// включаемого языка ассемблера X86 
// и иллюстрации, как работает программируемый В/В,
// используя оборудование последовательного порта В/В на целевой системе 
// (используйте ассемблер, только когда вы вынуждены это делать!)
//
// Настройка для X86 PC  (CEPC)
// используя оборудование последовательного порта, совместимое с 16550 UART 
// 
// Не предназначено для замены хорошего драйвера последовательного порта!
// Не использует прерывания, не имеет задержек, и не предоставляет поддержку 
// для всех свойств последовательного порта 
// Обычно будет использовать для этих операций вызовы API ОС!
//
// Для примера: Соедините Ebox COM2: с ПК с помощью null-модемного кабеля
// Запустите HyperTerminal на скорости 9600 бод, с 8 битами данных, 
// 1 стоп  битом, без контроля четности и без контроля потока 
#include "stdafx.h"
void Setup_UART (short int Data_Port_Address);
void Write_Serial_Character (short int Data_Port_Address, UCHAR Serial_Data);
void Write_Port (short int Data_Port_Address, UCHAR Data);
UCHAR Read_Port (short int Data_Port_Address);
UCHAR Read_Serial_Character (short int Data_Port_Address);

int _tmain(int argc, TCHAR *argv[], TCHAR *envp[])
{
	short int Data_Port_Address;
	UCHAR  Serial_Input_Data = 0;
	char  Title[]= "\f\n    Hello Serial World!\n\rType something and watch it echo back\n\rCtrl C to exit\n\r";
	unsigned int i;
// Выводим консоль 
	printf("I/O Port X86 ASM READ/WRITE Demo Program - Echos data on COM2:\n\r  Type Ctrl C on other device to exit\n\r");
// Адрес порта данных для COM2:
	Data_Port_Address = 0x2F8;
// Настройка UART для 9600 бод & без прерываний с 8D NP 1S
	Setup_UART(Data_Port_Address);
// Печать заголовка в последовательный порт
	for (i=0; i<strlen(Title); i++)
		Write_Serial_Character(Data_Port_Address, (UCHAR)Title[i]);
// Начало цикла Echo - Цикл, пока не будет нажато Ctrl C 
	while (Serial_Input_Data != 0x03){
			// Чтение данных 
	    Serial_Input_Data = Read_Serial_Character(Data_Port_Address);
			// Copy Data to Console
	    printf("%c", Serial_Input_Data);
			// Запись данных назад (Echo)
	    Write_Serial_Character(Data_Port_Address, Serial_Input_Data);
	}
	return 0;
}


UCHAR Read_Serial_Character (short int Data_Port_Address)
{
// Чтение символа из последовательного порта 
	UCHAR Serial_Data, Status;
		// Ожидаем RX бит готовности входа =1
		// Адрес статуса порта В/В будет Адрес порта данных В/В + 5
	do{
		Status = Read_Port(Data_Port_Address + 5); 	// Если не готов, послать напоминание о кванте времени 
if ((Status & 0x01) == 0) Sleep(0);
	} while ((Status & 0x01) == 0);
		// Считать новые последовательные данные 
	Serial_Data = Read_Port(Data_Port_Address);
	return Serial_Data;
}
void Setup_UART (short int Data_Port_Address)
{
	UCHAR Temp;
// Чтобы полностью понять это потребуется хороший Справочник 
// по оборудованию ПК и/или спецификация 16550 UART!
// Отключение прерываний COMx: (использовать программируемый В/В)
	Write_Port(Data_Port_Address + 1, 0);
// Задание скорости в бодах как 9600 с настройками делителя генератора 
// Включение задания режима делителя 
	Temp = Read_Port(Data_Port_Address + 3);			
	Write_Port(Data_Port_Address + 3, Temp | 0x83);
// Задание LSB делителя (примечание: 12 = 115200/9600)
	Write_Port(Data_Port_Address , 12);
// Задание MSB делителя 
	Write_Port(Data_Port_Address + 1, 0);
// Возврат в нормальный операционный режим (и задание 8D NP 1S)
	Temp = Read_Port(Data_Port_Address + 3);			
	Write_Port(Data_Port_Address + 3, Temp & 0x03);
	return;
}
void Write_Port (short int Data_Port_Address, UCHAR Data)
{
// включаемый язык ассемблера X86 
// использовать только когда требуется!
	_asm {
		mov dx,Data_Port_Address
		mov al,Data
		out dx,al
	}
return;
}
UCHAR Read_Port (short int Data_Port_Address)
{
UCHAR Data;
// включаемый язвк ассемблера X86 
// использовать только когда требуется!
	_asm {
		mov dx,Data_Port_Address
		in  al,dx
		mov Data,al
	}
return Data;
}
8.4.