Таджикистан, Душанбе, Таджикский Технический Университет (ТТУ), 2013 |
Программирование приложений в 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.