Texto en ruso en la pantalla con controlador HD44780 y generador de caracteres japoneses

Una forma no est谩ndar de controlar la pantalla en el controlador HD44780 para renderizar fuentes rusas con cualquier tabla de c贸digos de pantalla propia.


La idea misma de tal control naci贸 de la tarea de rusificaci贸n de un dispositivo con una pantalla personalizada basada en el controlador HD44780. Habiendo considerado la opci贸n de reemplazar los caracteres rusos con caracteres latinos similares, decid铆 no meterme con esto, porque parece no comercializable y el dispositivo es comercial.

A diferencia de las pantallas OLED basadas en el controlador Winstar WS0010, las pantallas en los controladores HD44780 o sus equivalentes no tienen un modo de funcionamiento gr谩fico. Pero tienen la llamada memoria CGRAM, en la que puede escribir hasta 8 caracteres en una representaci贸n gr谩fica.

El algoritmo en s铆 es bastante simple:
  1. Iniciamos el temporizador de renderizado a una frecuencia de interrupci贸n aceptable para la carga del procesador.
  2. En temporizador de interrupci贸n:
    • borrar (completar con espacios) todo lo que estaba en la pantalla;
    • cargar la informaci贸n gr谩fica requerida en los primeros 8 familiaridad de la memoria CGRAM del controlador;
    • mostramos estos caracteres en la pantalla en un desplazamiento determinado y salimos de la interrupci贸n.



El c贸digo se parece a esto:
// Cham map 0x80 - 0xFF, with filler uint8_t cmap[] = { 0x04, 0x0a, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x00, // russian A 0x1f, 0x10, 0x10, 0x1e, 0x11, 0x11, 0x1e, 0x00, // russian Be 0x1e, 0x11, 0x11, 0x1e, 0x11, 0x11, 0x1e, 0x0, // russian Ve 0x1f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, // russian Ge 0x0e, 0x0a, 0x0a, 0x0a, 0x0a, 0x1f, 0x11, 0x00, // russian De 0x1f, 0x10, 0x10, 0x1e, 0x10, 0x10, 0x1f, 0x00, // russian E 0x15, 0x15, 0x15, 0x0e, 0x15, 0x15, 0x15, 0x00, // russian Zhe 0x0e, 0x11, 0x01, 0x06, 0x01, 0x11, 0x0e, 0x00, // russian Ze 0x11, 0x11, 0x11, 0x13, 0x15, 0x19, 0x11, 0x00, // russian I 0x0e, 0x00, 0x11, 0x13, 0x15, 0x19, 0x11, 0x00, // russian Ij 0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11, 0x00, // russian Ka 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x11, 0x00, // russian L 0x11, 0x11, 0x1b, 0x15, 0x15, 0x11, 0x11, 0x00, // russian M 0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11, 0x00, // russian N 0x0e, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0e, 0x00, // russian O 0x1f, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, // russian Pe 0x1e, 0x11, 0x11, 0x11, 0x1e, 0x10, 0x10, 0x00, // russian Re 0x0e, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0e, 0x00, // russian Se 0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, // russian Te 0x11, 0x11, 0x11, 0x0f, 0x01, 0x11, 0x0e, 0x00, // russian U 0x0e, 0x15, 0x15, 0x15, 0x0e, 0x04, 0x04, 0x00, // russian Fe 0x11, 0x0a, 0x04, 0x04, 0x0a, 0x0a, 0x11, 0x00, // russian He 0x12, 0x12, 0x12, 0x12, 0x12, 0x1f, 0x01, 0x00, // russian Ce 0x11, 0x11, 0x11, 0x0f, 0x01, 0x01, 0x01, 0x00, // russian Che 0x11, 0x15, 0x15, 0x15, 0x15, 0x15, 0x1f, 0x00, // russian She 0x11, 0x15, 0x15, 0x15, 0x15, 0x1f, 0x01, 0x00, // russian Sche 0x18, 0x08, 0x08, 0x0e, 0x09, 0x09, 0x0e, 0x00, // russian Tverduy znak 0x11, 0x11, 0x19, 0x15, 0x15, 0x15, 0x19, 0x00, // russian bI 0x10, 0x10, 0x1e, 0x11, 0x11, 0x11, 0x1e, 0x00, // russian Myagkiy znak 0x1e, 0x01, 0x01, 0x0f, 0x01, 0x01, 0x1e, 0x00, // russian Ee 0x17, 0x15, 0x15, 0x1d, 0x15, 0x15, 0x17, 0x00, // russian You 0x0f, 0x11, 0x11, 0x0f, 0x05, 0x09, 0x11, 0x00, // russian Ya // 0x00, 0x00, 0x0e, 0x01, 0x0f, 0x11, 0x0f, 0x00, // russian small A 0x01, 0x0e, 0x10, 0x1e, 0x11, 0x11, 0x0e, 0x00, 0x00, 0x00, 0x1e, 0x11, 0x1e, 0x11, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x0a, 0x0a, 0x1f, 0x11, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x1e, 0x10, 0x0e, 0x00, 0x00, 0x00, 0x15, 0x15, 0x0e, 0x15, 0x15, 0x00, 0x00, 0x00, 0x1e, 0x01, 0x0e, 0x01, 0x1e, 0x00, 0x00, 0x00, 0x11, 0x13, 0x15, 0x19, 0x11, 0x00, 0x0e, 0x00, 0x11, 0x13, 0x15, 0x19, 0x11, 0x00, 0x00, 0x00, 0x09, 0x0a, 0x0c, 0x0a, 0x09, 0x00, 0x00, 0x00, 0x07, 0x09, 0x09, 0x09, 0x11, 0x00, 0x00, 0x00, 0x11, 0x1b, 0x15, 0x11, 0x11, 0x00, 0x00, 0x00, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x11, 0x11, 0x0e, 0x00, 0x00, 0x00, 0x1f, 0x11, 0x11, 0x11, 0x11, 0x00, // russian small Pe // 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler // 0x00, 0x00, 0x1e, 0x11, 0x11, 0x1e, 0x10, 0x00, // russian small Re 0x00, 0x00, 0x0e, 0x11, 0x10, 0x11, 0x0e, 0x00, 0x00, 0x00, 0x1f, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x11, 0x11, 0x0f, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x1f, 0x15, 0x15, 0x1f, 0x04, 0x00, 0x00, 0x00, 0x11, 0x0a, 0x04, 0x0a, 0x11, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x0f, 0x01, 0x01, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15, 0x15, 0x1f, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x18, 0x0e, 0x09, 0x09, 0x0e, 0x00, 0x00, 0x00, 0x11, 0x11, 0x1d, 0x15, 0x1d, 0x00, 0x00, 0x00, 0x10, 0x1e, 0x11, 0x11, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x01, 0x0f, 0x01, 0x1e, 0x00, 0x00, 0x00, 0x17, 0x15, 0x1d, 0x15, 0x17, 0x00, 0x00, 0x00, 0x0d, 0x13, 0x0f, 0x05, 0x09, 0x00, // russian small Ya 0x0a, 0x00, 0x1f, 0x10, 0x1e, 0x10, 0x1f, 0x00, // russian Yo 0x0a, 0x00, 0x0e, 0x11, 0x1e, 0x10, 0x0f, 0x00, // russian small Yo // 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00, // filler 0x00, 0x04, 0x0a, 0x15, 0x0a, 0x04, 0x00, 0x00 // filler }; static uint8_t lcd_draw_part = 0; static uint8_t lcd_ch; static uint8_t lcd_draw_string[16] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }; void TIM4_IRQHandler() { if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM4, TIM_IT_Update); //     , part = 0 - 0..7, part = 1 - 8..15 LCD_gotoxy(0, (lcd_draw_part ? 0 : 8)); LCD_write_data(0x20); LCD_write_data(0x20); LCD_write_data(0x20); LCD_write_data(0x20); LCD_write_data(0x20); LCD_write_data(0x20); LCD_write_data(0x20); LCD_write_data(0x20); //   CGRAM  8  for(uint8_t i = 0; i < 8; i++) { lcd_ch = lcd_draw_string[i + (lcd_draw_part ? 8 : 0)]; if(lcd_ch > 127) LCD_load_symbol(i, cmap + 8 * (lcd_ch & 0x7f) ); } //  LCD_gotoxy(0, (lcd_draw_part ? 8 : 0)); for(uint8_t i = 0; i < 8; i++) { lcd_ch = lcd_draw_string[i + (lcd_draw_part ? 8 : 0)]; if(lcd_ch < 128) LCD_write_data(lcd_ch); else LCD_write_data(i); } lcd_draw_part ^= 0x01; } } void LCD_start_fps() { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); TIM_TimeBaseInitTypeDef timerInitStructure; timerInitStructure.TIM_Prescaler = 48-1; timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up; timerInitStructure.TIM_Period = 20000; // 20ms/isr timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; timerInitStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM4, &timerInitStructure); TIM_Cmd(TIM4, ENABLE); TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); NVIC_InitTypeDef nvicStructure; nvicStructure.NVIC_IRQChannel = TIM4_IRQn; nvicStructure.NVIC_IRQChannelPreemptionPriority = 0; nvicStructure.NVIC_IRQChannelSubPriority = 2; nvicStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvicStructure); } 



En este caso, es muy importante configurar adecuadamente el control de la pantalla y usar tiempos de intercambio cercanos al m铆nimo, as铆 como, si es posible, una interfaz de 8 bits para la pantalla (aunque seg煤n las pruebas, 4 bits no carga demasiado el controlador). Tambi茅n es necesario usar la lectura de la se帽al BUSY en la l铆nea D7 desde la pantalla para reducir el tiempo de espera para su respuesta.

C贸mo se ve en una pantalla real se puede ver en el siguiente video:



La l铆nea superior se controla mediante el m茅todo de redibujo r谩pido y muestra informaci贸n de CGRAM. La l铆nea contiene caracteres dibujados gr谩ficamente de la tabla de c贸digos CP866 con c贸digos 0x80-0xFF, los pseudogr谩ficos son reemplazados por rombos de ajedrez. En la l铆nea inferior se encuentran los s铆mbolos del generador de caracteres incorporado de la pantalla y al lado de sus c贸digos.

Las desventajas del m茅todo:
A una frecuencia de actualizaci贸n inferior a 25Hz, el parpadeo se nota en la pantalla cuando se ve en 谩ngulo, y cuando se mira directamente, no es visible verticalmente.
Adem谩s, el contraste de la imagen de la pantalla cae ligeramente, pero esto casi no se nota.

Source: https://habr.com/ru/post/es403831/


All Articles