/*-------------------------------------------------------------- Проект: test_sio Название: Последовательный интерфейс RS-232. UART. Файл: test_sio.c Авторы: Быков В., Ванин А., Дидин Е. Описание: Данная программа работает в двух режимах. В первом режиме синхронно опрашивается наличие данных с ПК (цифра), и на ПК отправяляются все числа с считанного до нуля. Во втором режиме производится операция деления двух двузначных чисел. --------------------------------------------------------------*/ #include "aduc812.h" #include "sio.h" #include "led.h" #define NEWLINE 0x0A #define DEFAULT_VAL 0xFF #define MAX_RESULT 0x63 //Global variables for mathematic construction unsigned char mode, result, d1, d2; /**---------------------------------------------------------------------------- moderes() ------------------------------------------------------------------------------- Сброс состояния конечного автомата Вход: нет Выход: нет ----------------------------------------------------------------------------- */ void moderes() { mode = 1; d1 = DEFAULT_VAL; d2 = DEFAULT_VAL; result = DEFAULT_VAL; } /**---------------------------------------------------------------------------- mistake() ------------------------------------------------------------------------------- Ошибка! Вход: нет Выход: нет Описание: Вывод в терминал сообщения об ошибке а также сигнализирование об этом путём зажигания диодов. ----------------------------------------------------------------------------- */ void mistake() { EA = 0; ES = 0; type ( "Mistake has happend\n" ); leds( DEFAULT_VAL ); moderes(); EA = 1; ES = 1; } /**---------------------------------------------------------------------------- SIO_ISR ------------------------------------------------------------------------------- Обработчик прерывания от последовательного канала Вход: нет Выход: нет Результат: В случае приёма цифры или спец. символа формируется математическая операция деления. В случае готовности отправки - последовательно отправляются цифры результата и символ переноса строки. Описание: В случае приёма значения на основе состояний конечного автомата формируется делимое и делитель. Смена состояния автомата происходит при вводе символов '=' и '/'. В случае отправки последовательно отправляются цифра, обозначающая десятки (если есть), цифра, обозначающая единицы и перенос строки. -----------------------------------------------------------------------------*/ void SIO_ISR( void ) __interrupt ( 4 ) { unsigned char r_buf; //Блок прерывания по отправлению данных if( TI ) { //0xFF - значение по умолчанию, следует игнорировать if ( result != DEFAULT_VAL ) { //0x63 - это максимальный возможный результат деления. //Этот блок нужен для отправки \n после числа if ( result > MAX_RESULT ) { SBUF = NEWLINE; moderes(); } //Данный блок отправляет цифру - десятки else if ( result >= 10 ) { SBUF = ( result / 10 ) + 0x30; result = result % 10; } //Данный блок отправялцет цифру - единицы else { SBUF = result + 0x30; result = 0xAA; } TI = 0; } } //Блок прерывания по приёму данных if( RI ) { r_buf = SBUF; leds( r_buf ); //Подсветка считанного символа для debug RI = 0; if ( r_buf >= 0x30 && r_buf <= 0x39 ) { //В зависимости от состояния кон. автомата осуществим приём числа switch ( mode ) { case 1: //Делимое if ( d1 == DEFAULT_VAL ) //Первая считанная цифра d1 = ( r_buf - 0x30 ); else if ( d1 < 10 ) //Вторая считанная цифра { d1 *= 10; d1 += ( r_buf - 0x30 ); } else //Введено не двузначное число mistake(); break; case 2: //Делитель if ( d2 == DEFAULT_VAL ) //Первая считанная цифра d2 = ( r_buf - 0x30 ); else if (d2 < 10) //Вторая считанная цифра { d2 *= 10; d2 += ( r_buf - 0x30 ); } else //Введено не двузначное число mistake(); break; default: mistake(); break; } } else if ( r_buf == '/' ) { mode = 2; } else if ( r_buf == '=' ) { //Проверка что были введены оба числа в нужном диапазоне if ( d1 < 100 && d2 > 0 && d2 < 100 ) { result = d1 / d2; TI = 1; } else mistake(); } else //Введён некорректный символ { mistake(); } } } /**---------------------------------------------------------------------------- SetVectir ------------------------------------------------------------------------------- Установка пользовательского вектора прерывания. Вход: Vector – адрес обработчика прерывания, Address – вектор пользовательской таблицы прерываний. Выход: нет Результат: нет Описание: Функция, устанавливающая вектор прерывания в пользовательской таблие прерываний -----------------------------------------------------------------------------*/ void SetVector(unsigned char __xdata * Address, void * Vector) { unsigned char __xdata * TmpVector; // Первым байтом по указанному адресу записывается // код команды передачи управления ljmp, равный 02h *Address = 0x02; // Далее записывается адрес перехода Vector TmpVector = (unsigned char __xdata *) (Address + 1); *TmpVector = (unsigned char) ((unsigned short)Vector >> 8); ++TmpVector; *TmpVector = (unsigned char) Vector; // Таким образом, по адресу Address теперь // располагается инструкция ljmp Vector } void main( void ) { unsigned char dig, i, dipval; SetVector( 0x2023, (void *)SIO_ISR ); init_sio( S2400 ); moderes(); while( 1 ) { dipval = readdip(); //В положение DIP-переключателя 0xFF будем работать синхронно if ( dipval == DEFAULT_VAL ) { //На момент синхронной работы отключим прерывания EA = 0; ES = 0; if( rsiostat() ) { dig = rsio(); if ( dig >= 0x30 && dig <= 0x39 ) { for ( i = dig; i >= 0x30; i-- ) wsio(i); //В конце выведим перенос строки wsio(NEWLINE); } } } //В остальных режимах DIP-переключателя будем работать по прерыванию else { EA=1; ES=1; } } }