| Таджикистан, Душанбе, ОАО "Точиксодиротбонк", Главный специалист |
Программирование приложений в 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.