Russischer Text auf dem Display mit HD44780-Controller und japanischem Zeichengenerator

Eine nicht standardmäßige Methode zur Steuerung der Anzeige auf dem HD44780-Controller zum Rendern russischer Schriftarten mit einer eigenen Anzeigecodetabelle.


Die Idee einer solchen Steuerung entstand aus der Aufgabe der Russifizierung eines Geräts mit einem benutzerdefinierten Display, das auf dem HD44780-Controller basiert. Nachdem ich über die Möglichkeit nachgedacht hatte, russische Zeichen durch ähnliche lateinische Zeichen zu ersetzen, entschied ich mich, mich nicht damit zu beschäftigen, da es nicht vermarktbar aussieht und das Gerät kommerziell ist.

Im Gegensatz zu OLED-Displays, die auf dem Winstar WS0010-Treiber basieren, verfügen Displays auf den HD44780-Treibern oder deren Entsprechungen nicht über einen grafischen Betriebsmodus. Sie verfügen jedoch über den sogenannten CGRAM-Speicher, in den Sie bis zu 8 Zeichen in einer grafischen Darstellung schreiben können.

Der Algorithmus selbst ist recht einfach:
  1. Wir starten den Rendering-Timer mit einer akzeptablen Interrupt-Frequenz für die Prozessorlast.
  2. Im Timer-Interrupt:
    • alles, was auf dem Display angezeigt wurde, löschen (mit Leerzeichen ausfüllen);
    • Laden Sie die erforderlichen Grafikinformationen in die ersten 8 Vertrautheiten des CGRAM-Speichers der Steuerung.
    • Wir zeigen diese Zeichen mit einem bestimmten Versatz auf dem Display an und verlassen den Interrupt.



Der Code sieht ungefähr so ​​aus:
// 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); } 



In diesem Fall ist es sehr wichtig, die Anzeigesteuerung ordnungsgemäß zu konfigurieren und nahezu minimale Austauschzeiten sowie, wenn möglich, eine 8-Bit-Schnittstelle zur Anzeige zu verwenden (obwohl 4-Bit den Controller laut Tests nicht zu stark belastet). Es ist auch erforderlich, das BUSY-Signal auf der D7-Leitung vom Display zu lesen, um die Wartezeit für seine Antwort zu verkürzen.

Wie es auf einem realen Display aussieht, sehen Sie im folgenden Video:



Die oberste Zeile wird durch die schnelle Neuzeichnungsmethode gesteuert und zeigt Informationen aus dem CGRAM an. Die Zeile enthält grafisch gezeichnete Zeichen aus der CP866-Codetabelle mit den Codes 0x80-0xFF. Pseudografien werden durch Schach-Rauten ersetzt. In der unteren Zeile befinden sich die Symbole des eingebauten Zeichengenerators der Anzeige und neben deren Codes.

Die Nachteile der Methode:
Bei einer Bildwiederholfrequenz unter 25 Hz ist ein Flackern auf dem Bildschirm erkennbar, wenn es in einem Winkel betrachtet wird, und wenn es direkt betrachtet wird, ist es vertikal nicht sichtbar.
Auch der Kontrast des Bildes vom Display nimmt leicht ab, was jedoch fast nicht spürbar ist.

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


All Articles