Библиотечная пустая функция putchar() нужна как затычка. Пустая функция __low_level_init() у Вас вопросы не вызывает?
При отсутствии Вашей функции putchar() вызывается она.
Ведь вывод можно делать и на индикатор (графический, семисигментный, символьный и т.д.), и последовательный порт, и даже в какую нибудь eeprom-ку.
Кроме Вас никто не знает, куда будет выводить Ваш putchar() и к каким ногам/портам он подключен.
Так вот Ваша функция putchar() должна обеспечивать низкоуровневый вывод символа на Ваше устройство.
Код
/* --- putchar() ------------------------------------------------------------ **
* Вывод байта в терминал
* -------------------------------------------------------------------------- */
int putchar( int c )
{
if ( !c )
return( 0 );
return( uart0_tx( c ));
}
// или что-то такое, немного кастрировано
/* --- putchar() ------------------------------------------------------------ **
* Вывод байта на символьный индикатор или принтер
* Универсальный, для ЖКИ любого размера.
* Используется перекодировка из таблицы win1251 в таблицу, применяемую в ЖКИ.
* \a (\007) - Звуковой сигнал 50 ms, окончания звука не ожидает, пищит в фоне.
* \b (\010) - Возврат на шаг (забой), из начала первой строки перейдет в конец последней
* \t (\011) - Табуляция горизонтальная (сдвиг по ...). С конца последней строки переходит на начало первой!
* \n (\012) - Перевод строки (новая строка), с последней строки индикатора осуществляется переход на первую.
* \v (\013) - Переход в начало экрана (gotoxy(0,0))
* \f (\014) - Очистка экрана + Переход в начало экрана (gotoxy( 0, 0 ))
* \r (\015) - Возврат каретки (на начало строки)
* \0 (\000) - Ничего не делает, просто возвращает 0, и все.
* \016 - символ '\000' дополнительного знакогенератора
* \017 - символ '\007' дополнительного знакогенератора
* \033 - ESC-команда см. esc_cmd.h
* lcd_pos указывает на позицию курсора, т.е. после выполнения функции указывает на место, в которое будет
* выводиться при следующем вызове функции. Позиции STROKA * STOLB и 0 эквивалентны!
* -------------------------------------------------------------------------- */
int putchar( int c )
{
static const char perecod[] = // перекодировка русских букв из таблицы win1251 в таблицу, применяемую в ЖКИ
{ 'A' , 0xa0, 'B' , 0xa1, 0xe0, 'E' , 0xa3, 0xa4, 0xa5, 0xa6, 'K' , 0xa7, 'M' , 'H' , 'O' , 0xa8, // 0xc0..0xcf
'P' , 'C' , 'T' , 0xa9, 0xaa, 'X' , 0xe1, 0xab, 0xac, 0xe2, 0xad, 0xae, 'b' , 0xaf, 0xb0, 0xb1, // 0xd0..0xdf
'a' , 0xb2, 0xb3, 0xb4, 0xe3, 'e' , 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 'o' , 0xbe, // 0xe0..0xef
'p' , 'c' , 0xbf, 'y' , 0xe4, 'x' , 0xe5, 0xc0, 0xc1, 0xe6, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 // 0xf0..0xff
};
static int previos; // 10.05.04г. добавил для корректной работы последовательностей "\f\n", "\v\n" и "\n\n"
int c_old = 0;
// if ( c )
// { if ( c >= 'А' ) // А - по русски это 0xc0 в win1251
// c = perecod[c - 'А']; // русские буквы в кодировке win1251
// else if ( c >= 0x80 ) // спецсимволы, расположенные в знакогенераторе lcd
// c += 0x40; // мы их немного перенесли (символы с кодом 0xc0..0xff перенесены в область 0x80..0xc0
int a; // пришлось ввести переменную и вынести ее расчет из perecod[c - 'А'], ато "крутой" оптимизатор от ИАР МСП v3.30а заоптимизировывает...
if ( c )
{ if ( flag.redirect == ON ) // перенаправление putchar() на принтер
return( prn_byte( c ));
c_old = c;
a = c - 'А'; // А - по русски это 0xc0 в win1251
if ( a >= 0 )
c = perecod[a]; // А - по русски это 0xc0 в win1251
else if ( c >= 0x80 ) // спецсимволы, расположенные в знакогенераторе lcd
{ if ( c == 0xa8 ) // буква "Ё"
c = 0xa2;
else if ( c == 0xb8 ) // буква "ё"
c = 0xb5;
else
c += 0x40; // мы их немного перенесли (символы с кодом 0xc0..0xff перенесены в область 0x80..0xc0
}
switch ( c )
{ case '\a': // Звуковой сигнал
beep( 50 );
break;
case '\b': // возврат на один символ (забой)
if ( !lcd_pos )
lcd_pos = STROKA * STOLB;
if (( lcd_pos-- % STROKA ) == 0 ) // последний символ в конце строки
goto_pos();
else
lcd_send_com( LCD_CURS_MOV_LEFT );
lcd_send_dat( ' ' );
lcd_send_com( LCD_CURS_MOV_LEFT );
break;
case '\t': // табуляция. С конца последней строки переходит на начало первой!
if (( lcd_pos += TAB_SIZE ) <= STROKA * STOLB )
lcd_pos = ( lcd_pos / TAB_SIZE ) * TAB_SIZE;
else
lcd_pos = 0;
goto_pos();
break;
case '\n': // на новую строку
if ( previos == '\n' || previos == '\f' || previos == '\v' || ( lcd_pos % STROKA ) != 0 ) // игнорируем, если позиция кратна строке (уже сделан \n)
{ lcd_pos /= STROKA;
if ( ++lcd_pos == STOLB )
lcd_pos = 0;
else
lcd_pos *= STROKA;
goto_pos();
}
break;
case '\v': // в начало экрана (gotoxy(0,0))
if ( flag.cls_ind != ON ) // если установлен флаг - надо делать '\f'
{ lcd_send_com( LCD_HOME ); // lcd_gotoxy( 0, 0 );
lcd_pos = 0;
break;
}
case '\f': // очистка экрана + gotoxy(0,0)
lcd_send_com( LCD_CLS_HOME );
flag.cls_ind = OFF;
lcd_pos = 0;
break;
case '\r': // возврат на начало строки без очистки экрана
if ( lcd_pos == STROKA * STOLB ) // Если находимся в самой последней позиции
lcd_pos--; // подумаем, что она предпоследняя
lcd_pos -= lcd_pos % STROKA;
goto_pos();
break;
case '\033': // Обработка ESC-команд
esc_cmd();
break;
case '\016': // код '\000'
c = 0;
default: // собственно выводим символ на индикатор
if (( lcd_pos % STROKA ) == 0 ) // переходить ли на следующую строку?
goto_pos();
lcd_send_dat( c );
if ( lcd_pos++ == STROKA * STOLB ) // Позиции STROKA * STOLB и 0 эквивалентны!
lcd_pos = 1;
break;
}
previos = c_old;
}
else
flag.redirect = OFF;
return( c_old );
}