Edzelf / ESP32-Radio

Internet radio based on ESP32, VS1053 and a TFT screen.
GNU General Public License v3.0
973 stars 229 forks source link

Русский язык на 1602 #360

Open avulyanichev opened 4 years ago

avulyanichev commented 4 years ago

Hello Ed. 1602 screen with Cyrillic support. Successfully embedded in 1602.h Russian language. I can upload a file for your testing. The main code russifications was made by github pilnikov IMG_20200719_120230

https://drive.google.com/file/d/1sWclx-egmGxnYmpjScZuPHxMw2XI1GYm/view?usp=sharing]

// // LCD1602.h -- Driver for LCD 1602 display with I2C backpack. // // The backpack communicates with the I2C bus and converts the serial data to parallel for the // 1602 board. In the serial data, the 8 bits are assigned as follows: // Bit Destination Description // --- ----------- ------------------------------------ // 0 RS H=data, L=command // 1 RW H=read, L=write. Only write is used. // 2 E Enable // 3 BL Backlight, H=on, L=off. Always on. // 4 D4 Data bit 4 // 5 D5 Data bit 5 // 6 D6 Data bit 6 // 7 D7 Data bit 7 //*** // // Note that the display function are limited due to the minimal available space. //

include <driver/i2c.h>

define I2C_ADDRESS 0x27 // Adjust for your display.

                                                         // В конфиг файле прописать pin_tft_scl = 13, pin_tft_sda = 14

define ACKENA true // Enable ACK for I2C communication

// Color definitions for the TFT screen (if used)

define BLACK 0

define BLUE 1

define RED 1

define GREEN 0

define CYAN GREEN | BLUE

define MAGENTA RED | BLUE

define YELLOW RED | GREEN

define WHITE RED | GREEN | BLUE

define DELAY_ENABLE_PULSE_SETTLE 50 // Command requires > 37us to settle

define FLAG_BACKLIGHT_ON 0b00001000 // Bit 3, backlight enabled (disabled if clear)

define FLAG_ENABLE 0b00000100 // Bit 2, Enable

define FLAG_RS_DATA 0b00000001 // Bit 0, RS=data (command if clear)

define FLAG_RS_COMMAND 0b00000000 // Command

define COMMAND_CLEAR_DISPLAY 0x01

define COMMAND_RETURN_HOME 0x02

define COMMAND_ENTRY_MODE_SET 0x04

define COMMAND_DISPLAY_CONTROL 0x08

define COMMAND_FUNCTION_SET 0x20

define COMMAND_SET_DDRAM_ADDR 0x80

//

define FLAG_DISPLAY_CONTROL_DISPLAY_ON 0x04

define FLAG_DISPLAY_CONTROL_CURSOR_ON 0x02

//

define FLAG_FUNCTION_SET_MODE_4BIT 0x00

define FLAG_FUNCTION_SET_LINES_2 0x08

define FLAG_FUNCTION_SET_DOTS_5X8 0x00

//

define FLAG_ENTRY_MODE_SET_ENTRY_INCREMENT 0x02

define FLAG_ENTRY_MODE_SET_ENTRY_SHIFT_ON 0x01

// // Various macro's to mimic the ST7735 version of display functions

define dsp_setRotation() // Use standard landscape format

define dsp_print(a) // Print a string

define dsp_println(a) // Print string plus newline

define dsp_fillRect(a,b,c,d,e) // Fill a rectange

define dsp_setTextSize(a) // Set the text size

define dsp_setTextColor(a)

define dsp_setCursor(a,b) // Position the cursor

define dsp_erase() tft->sclear() // Clear the screen

define dsp_getwidth() 16 // Get width of screen

define dsp_getheight() 2 // Get height of screen

define dsp_usesSPI() false // Does not use SPI

define TFTSECS 4 // 4 sections, only 2 used

scrseg_struct tftdata[TFTSECS] = // Screen divided in 4 segments { { false, WHITE, 0, 0, "" }, // 1 top line (dummy) { false, WHITE, 0, 0, "" }, // 8 lines in the middle { false, WHITE, 0, 0, "" }, // 4 lines at the bottom { false, WHITE, 0, 0, "" } // 4 lines at the bottom for rotary encoder } ; //*** // L C D 1 6 0 2 rus * //***
// Русификация 1602 с встроенной кириллицей //github Pilnikov// * //*** const byte utf_recode[] PROGMEM = { 0x41, 0xa0, 0x42, 0xa1, 0xe0, 0x45, 0xa3, 0xa4, 0xa5, 0xa6, 0x4b, 0xa7, 0x4d, 0x48, 0x4f, 0xa8, 0x50, 0x43, 0x54, 0xa9, 0xaa, 0x58, 0xe1, 0xab, 0xac, 0xe2, 0xad, 0xae, 0x62, 0xaf, 0xb0, 0xb1, 0x61, 0xb2, 0xb3, 0xb4, 0xe3, 0x65, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0x6f, 0xbe, 0x70, 0x63, 0xbf, 0x79, 0xe4, 0x78, 0xe5, 0xc0, 0xc1, 0xe6, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7 };

String lcd_rus(String source) { String target;

uint16_t i = 0; uint16_t k = source.length();

unsigned char n = 0x0; char m;

while (i < k) { n = source[i]; i++;

if (n == 0xD0 || n == 0xD1)   // UTF-8 handling

{ switch (n) { // Позиция символа в массиве utf_recode вычисляется по формуле pos = код символа - 0х90 для символов от А до п, с кодами от 0x90 по 0xBF, // с позициями с нулевой по сорок седьмую (0x2F в HEX) // Для символов от р до я, с кодами от 0x80 по 0x8F, с позициями с сорок восьмой (0x30 в HEX) по шестьдесят третью (0x3F в HEX) // - формула pos = (код символа - 0х80) + 0x30 = код символа - 0х50 // ё и Ё стоят особняком (выбиваются из общего строя) поэтому для них отдельные строки.

    case 0xD0: 
        n = source[i]; i++;
        if (n == 0x81) m = 0xA2; // Ё
  else if (n >= 0x90 && n <= 0xBF) m = pgm_read_byte_near(utf_recode + n - 0x90); // от А до п
        break;
    case 0xD1: 
        n = source[i]; i++;
        if (n == 0x91) m = 0xB5; // ё
        else if (n >= 0x80 && n <= 0x8F) m = pgm_read_byte_near(utf_recode + n - 0x50); // от р до я
        break;
  }
}
else m = n;

target += m; } return target; }

class LCD1602 { public: LCD1602 ( uint8_t sda, uint8_t scl ) ; // Constructor void print ( char c ) ; // Send 1 char void reset() ; // Perform reset void sclear() ; // Clear the screen void shome() ; // Go to home position void scursor ( uint8_t col, uint8_t row ) ; // Position the cursor void scroll ( bool son ) ; // Set scroll on/off private: i2c_config_t i2c_config ; // I2C configuration i2c_cmd_handle_t hnd ; // Handle for driver void scommand ( uint8_t cmd ) ; void strobe ( uint8_t cmd ) ; void swrite ( uint8_t val, uint8_t rs ) ; void write_cmd ( uint8_t val ) ; void write_data ( uint8_t val ) ; uint8_t bl = FLAG_BACKLIGHT_ON ; // Backlight in every command uint8_t xchar = 0 ; // Current cursor position (text) uint8_t ychar = 0 ; // Current cursor position (text) } ;

LCD1602* tft = NULL ;

bool dsp_begin() { dbgprint ( "Init LCD1602, I2C pins %d,%d", ini_block.tft_sda_pin, ini_block.tft_scl_pin ) ; if ( ( ini_block.tft_sda_pin >= 0 ) && ( ini_block.tft_scl_pin >= 0 ) ) { tft = new LCD1602 ( ini_block.tft_sda_pin, ini_block.tft_scl_pin ) ; // Create an instance for TFT } else { dbgprint ( "Init LCD1602 failed!" ) ; } return ( tft != NULL ) ; }

//*** // L C D 1 6 0 2 write functions * //*** // Write functins for command, data and general. * //*** void LCD1602::swrite ( uint8_t val, uint8_t rs ) // General write, 8 bits data { strobe ( ( val & 0xf0 ) | rs ) ; // Send 4 LSB bits strobe ( ( val << 4 ) | rs ) ; // Send 4 MSB bits }

void LCD1602::write_data ( uint8_t val ) { swrite ( val, FLAG_RS_DATA ) ; // Send data (RS = HIGH) }

void LCD1602::write_cmd ( uint8_t val ) { swrite ( val, FLAG_RS_COMMAND ) ; // Send command (RS = LOW) }

//*** // L C D 1 6 0 2 :: S T R O B E * //*** // Send data followed by strobe to clock data to LCD. * //*** void LCD1602::strobe ( uint8_t cmd ) { scommand ( cmd | FLAG_ENABLE ) ; // Send command with E high scommand ( cmd ) ; // Same command with E low delayMicroseconds ( DELAY_ENABLE_PULSE_SETTLE ) ; // Wait a short time }

// // L C D 1 6 0 2 :: S C O M M A N D //*** // Send a command to the LCD. // Actual I/O. Open a channel to the I2C interface and write one byte. //* void LCD1602::scommand ( uint8_t cmd ) { hnd = i2c_cmd_link_create() ; // Create a link if ( i2c_master_start ( hnd ) | i2c_master_write_byte ( hnd, (I2C_ADDRESS << 1) | // Add I2C address to output buffer I2C_MASTER_WRITE, ACKENA ) | i2c_master_write_byte ( hnd, cmd | bl, // Add command including BL state ACKENA ) | i2c_master_stop ( hnd ) | // End of data for I2C i2c_master_cmd_begin ( I2C_NUM_0, hnd, // Send bufferd data to LCD 10 / portTICK_PERIOD_MS ) ) { dbgprint ( "LCD1602 communication error!" ) ; // Something went wrong (not connected) } i2c_cmd_link_delete ( hnd ) ; // Link not needed anymore }

//*** // L C D 1 6 0 2 :: P R I N T * //*** // Put a character in the buffer. * //*** void LCD1602::print ( char c ) { write_data ( c ) ; }

//*** // L C D 1 6 0 2 :: S C U R S O R * //*** // Place the cursor at the requested position. * //*** void LCD1602::scursor ( uint8_t col, uint8_t row ) { const int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 } ;

write_cmd ( COMMAND_SET_DDRAM_ADDR | ( col + row_offsets[row] ) ) ; }

//*** // L C D 1 6 0 2 :: S C L E A R * //*** // Clear the LCD. * //*** void LCD1602::sclear() { write_cmd ( COMMAND_CLEAR_DISPLAY ) ; }

//*** // L C D 1 6 0 2 :: S C R O L L * //*** // Set scrolling on/off. * //*** void LCD1602::scroll ( bool son ) { uint8_t ecmd = COMMAND_ENTRY_MODE_SET | // Assume no scroll FLAG_ENTRY_MODE_SET_ENTRY_INCREMENT ;

if ( son ) // Scroll on? { ecmd |= FLAG_ENTRY_MODE_SET_ENTRY_SHIFT_ON ; // Yes, change function } write_cmd ( ecmd ) ; // Perform command }

//*** // L C D 1 6 0 2 :: S H O M E * //*** // Go to home position. * //*** void LCD1602::shome() { write_cmd ( COMMAND_RETURN_HOME ) ; }

//*** // L C D 1 6 0 2 :: R E S E T * //*** // Reset the LCD. * //*** void LCD1602::reset() { scommand ( 0 ) ; // Put expander to known state delayMicroseconds ( 1000 ) ; for ( int i = 0 ; i < 3 ; i++ ) // Repeat 3 times { strobe ( 0x03 << 4 ) ; // Select 4-bit mode delayMicroseconds ( 4500 ) ; } strobe ( 0x02 << 4 ) ; // 4-bit delayMicroseconds ( 4500 ) ; write_cmd ( COMMAND_FUNCTION_SET | FLAG_FUNCTION_SET_MODE_4BIT | FLAG_FUNCTION_SET_LINES_2 | FLAG_FUNCTION_SET_DOTS_5X8 ) ; write_cmd ( COMMAND_DISPLAY_CONTROL | FLAG_DISPLAY_CONTROL_DISPLAY_ON ) ; sclear() ; write_cmd ( COMMAND_ENTRY_MODE_SET | FLAG_ENTRY_MODE_SET_ENTRY_INCREMENT ) ; shome() ; for ( char a = 'a' ; a < 'q' ; a++ ) { print ( a ) ; } }

//*** // L C D 1 6 0 2 * //*** // Constructor for the display. * //*** LCD1602::LCD1602 ( uint8_t sda, uint8_t scl ) { esp_err_t espRc ;

i2c_config.mode = I2C_MODE_MASTER, i2c_config.sda_io_num = (gpio_num_t)sda ; i2c_config.sda_pullup_en = GPIO_PULLUP_DISABLE ; i2c_config.scl_io_num = (gpio_num_t)scl ; i2c_config.scl_pullup_en = GPIO_PULLUP_DISABLE ; i2c_config.master.clk_speed = 100000 ; if ( i2c_param_config ( I2C_NUM_0, &i2c_config ) != ESP_OK ) { dbgprint ( "param_config error!" ) ; } else if ( i2c_driver_install ( I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0 ) != ESP_OK ) { dbgprint ( "driver_install error!" ) ; } reset() ; }

struct dsp_str { String str ; uint16_t len ; // Length of string to show uint16_t pos ; // Start on this position of string uint8_t row ; // Row on display
} ;

dsp_str dline[2] = { { "", 0, 0, 0 }, { "", 0, 0, 0 } } ;

//*** // D S P U P D A T E L I N E * //*** // Show a selected line * //*** void dsp_update_line ( uint8_t lnr ) { uint8_t i ; // Index in string const char* p ;

p = dline[lnr].str.c_str() ;

dline[lnr].len = strlen ( p ) ; //dbgprint ( "Strlen is %d, str is %s", len, p ) ; if ( dline[lnr].len > 16 ) { if ( dline[lnr].pos >= dline[lnr].len ) { dline[lnr].pos = 0 ; } else { p += dline[lnr].pos ; } dline[lnr].len -= dline[lnr].pos ; if ( dline[lnr].len > 16 ) { dline[lnr].len = 16 ; } } else { dline[lnr].pos = 0 ; // String fits on screen } dline[lnr].pos++ ; tft->scursor ( 0, lnr ) ; for ( i = 0 ; i < dline[lnr].len ; i++ ) { if ( (( p >= 0x20 ) && ( p <= 0x7A )) || (( p >= 0x41 ) && ( p <= 0xC7 ))|| (( p >= 0xE0 ) && ( p <= 0xE6 )) ) { tft->print ( *p ) ; // Yes

}
else
{
  tft->print ( ' ' ) ;                           // Yes, print space
}
p++ ;

} for ( i = 0 ; i < ( 16 - dline[lnr].len ) ; i++ ) // Fill remainder { tft->print ( ' ' ) ; } if ( *p == '\0' ) // At end of line? { dline[lnr].pos = 0 ; // Yes, start allover } }

//*** // D S P _U P D A T E * //*** // Show a selection of the 4 sections * //*** void dsp_update() { static uint16_t cnt = 0 ; // Reduce updates

if ( cnt++ != 8 ) // Action every 8 calls { return ; } cnt = 0 ; if ( enc_menu_mode != VOLUME ) // Encoder menu mode? { dline[0].str = lcd_rus(tftdata[3].str.substring(0,16)) ; // Yes, different lines dline[1].str = lcd_rus(tftdata[3].str.substring(16)) ; } else {// dline[0].str = lcd_rus("АБВГабвг"); dline[0].str = lcd_rus(tftdata[1].str); // Local copy dline[1].str = lcd_rus(tftdata[2].str); // Local copy }
dline[0].str.trim() ; // Remove non printing dline[1].str.trim() ; // Remove non printing if ( dline[0].str.length() > 16 ) { dline[0].str += String ( " " ) ; } if ( dline[1].str.length() > 16 ) { dline[1].str += String ( " " ) ; } dsp_update_line ( 0 ) ; dsp_update_line ( 1 ) ; }

//** // D I S P L A Y B A T T E R Y * //** // Dummy routine for this type of display. * //** void displaybattery() { }

//** // D I S P L A Y V O L U M E * //** // Dummy routine for this type of display. * //** void displayvolume() { }

//** // D I S P L A Y T I M E * //** // Dummy routine for this type of display. * //** void displaytime ( const char* str, uint16_t color ) { }