Implementation of Human-Machine Interface on SMS Telephone
2026-04-06 06:21:45··#1
1. Introduction In this paper, one element refers to one character, or one Chinese character (the display space occupied by a Chinese character on the LCD is twice that of a regular character). Characters include English letters, numbers, and English punctuation. One position refers to the size of the display space occupied by one character on the LCD. The arrays content[>, contentram[>, and contentLCD[>] in this paper are all defined as INT8U (8-bit unsigned integers), storing the GBK and ASCII codes of Chinese characters. The LCD used is the SRL-0978GB LCD module from Shanghai Chenxing Electronics Technology Co., Ltd., which can display 21 characters per row, and 5 rows per screen (referred to as row0, row1, row2, row3, and row4). This gives the LCD 105 character positions, numbered starting from 0. This allows 105 ASCII characters to be displayed per screen, but how many Chinese characters can be displayed? A maximum of 50 Chinese characters can be displayed. With good luck, up to 5 more characters can be displayed. In this case, each row will only have one character. If you can understand this passage, then you will know the characteristics of LCD display. 2. Menu display (1) How to display different menus? In the user interface, the most frequently displayed item is the menu. So how are different menus displayed? First, I assign a status number to each state, and each state corresponds to a different menu. I use an array of pointers to strings to point to the menus in different states. In different states, I use three different global variables to record the sequence number of the menu item displayed on row1, the sequence number of the menu item displayed on the last valid row (when the number of menu items is less than or equal to 4, its value is the number of menu items; when the number of menu items is greater than 4, its value is 4), and the sequence number of the currently highlighted menu item (initially 1, indicating that the first menu item is highlighted. When the confirmation key is pressed, it means that the highlighted menu item is selected). row0 always displays the title of the menu. For example: #define S_Mainmenu 1 file://The status number of the main menu #define MAINMENU_MAXLEN 6 file://The number of menu items in the main menu static char *Mainmenu[MAINMENU_MAXLEN+1>= { “Main Menu”; “1. Jiajia e”; “2. SMS”; “3. Call Log”; “4. Personal Assistant”; “5. New Telephone Services”; “6. Phone Settings” }; file://A pointer array to the strings of the main menu. The first to enter this state, Smstart=1; file://The index of the menu item displayed on row1, Snend=4; file://The index of the menu item displayed on the last valid line. Smindex=1; file://The order of the menu items to be displayed is called by calling the Dispmenu(Smmenu, Smstart, Smend, Smindex, SM_MAXLEN) function to display the title and menu items 1 to 4 of the Smmenu menu on the LCD in sequence. Thus, there are these menu item combination methods: 1234, 2345, 3456, 4561, 5612, 6123 (2) The implementation idea of the Dispmenu function a) Call PutMSG(0,0,Mainmenu[0>,0) to display the "main menu" of the menu title in row0; b) If Smstart>Smend (that is, the 3rd, 4th and 5th menu item combination methods), then call the PutMSG function to display each menu item from Smstart to SM_MAXLEN in sequence starting from row1, and then display the menu items from 1 to Smend. One menu item is displayed in each row. Note the reverse display. c) If Smstart>Smend is not satisfied, then start from row1 and display the menu items from Smstart to Smend in sequence. Also note the reverse display. d) Call the LCDDisplay() function. The PutMSG() function calls the PutHZ and PutZF functions respectively to convert the code of the content to be displayed into a dot matrix and store it in disp_ram[>[>]. The LCDDisplay() function writes the dot matrix in disp_ram[>[>] to the LCD's buffer, and then it can be displayed. See the following for details. 3 Menu flipping 3.1 Flipping operation When the menu is displayed on the LCD, the flipping operation is as follows: (1) Click the Up button to flip the menu up. First, call OVERFLOW(&Smstart, &Smend, &Smindex, SM_MAXLEN) to adjust Smstart, Smend, and Smindex, and then call Dispmenu Dispmenu(Smmenu, Smstart, Smend, Smindex, SM_MAXLEN). (2) Click the Down key to scroll down the menu. First, call UNDERFLOW() to adjust Smstart, Smend, and Smindex, and then call Dispmenu() to display the menu. (3) Press Enter to enter the new state corresponding to the highlighted menu item (after initializing the 3 global variables in this state, calling the Dispmenu function will display the menu of this state) (4) Press Esc to return to the previous state (calling the Dispmenu function will display the menu of this state, and the 3 global variables of this state have recorded the relevant parameters.) 3.2 Implementation of OVERFLOW function (1) If the condition (Smstart==Smindex&&SM_MAXLEN>4) is met, a) If Smstart==1, then Smsatrt=SM_MAXLEN; otherwise, Smstart is decremented by 1. b) If Smend==1, then Smend=SM_MAXLEN; otherwise, Smend is decremented by 1. c) Change Smindex to the same value as Smstart. (2) If the condition (Smstart==Smindex&&SM_MAXLEN>4) is not met, Smstart and Smend remain unchanged. If Smindex == 1, then Smindex = SM_MAXLEN; otherwise, Smindex is decremented by 1. The implementation of the UNDERFLOW function is similar to that of the OVERFLOW function. 4. Text Display If we want to display a piece of content that cannot be displayed in one screen, how do we know which element the first screen ends at, and which element the second, third, and so on should start and end at? At first glance, this problem seems simple, but it is not. It is impossible to display a Chinese character in the last position of each line on the LCD, so the Chinese character to be displayed needs to be moved to the next line. This is the reason why it is necessary to determine which element each subsequent screen should start from. The method used is as follows: 4.1 The content to be displayed is fixed. If we want to view the content of a short message but do not modify the content, suppose the entire content of the short message is stored in the array content[>. Now we want to display the content of content[>. (1) First copy the content in the array content[> to the array contentram[>. contentram[> is a virtual LCD screen, which is much larger than the actual screen. contentLCD[> is an array of the same size as the actual screen. Note that after copying, add an end character at the end of contentram[>. The copying process is to adjust the position of the content in content[> so that the adjusted content conforms to the principle of LCD display. The principle is that it is impossible to display a Chinese character in the last position of each line of the LCD. Therefore, a space is used to fill the position, and the Chinese character is placed at the beginning of the next line. (2) After the copying from content[> to contentram[> is completed, the value of j can be used to know how many screens the short message content will be displayed. Generally, when displaying the first screen of the short message content, a title line needs to be displayed on row0. netpagemax is the total number of screens occupied by the short message. (3) netpage indicates which screen content to display, starting from 1. Initially, its value is 1. Press the Up key to decrement netpage by 1. If netpage == 0, then netpage becomes 1. Press the Down key to increment netpage by 1. If netpage == netpagemax + 1, then netpage becomes netpagemax. a) When netpage == 1, copy contentram[i] (i from 0 to 83) into contentLCD[>. If the end character is encountered before reaching number 83, then there is no need to continue copying. Then call the PutMSG function to output contentLCD[> from row1 of LCD. row0 is used to display the title. b) When netpage != 1, copy *(contentram + (netpage - 2) * 105 + 84 + i) (i from 0 to 104) into contentLCD[>. If the end character is encountered before reaching number 103, then there is no need to continue copying. Then call the PutMSG function to output the content of contentLCD[> from row0. 4.2 The content to be displayed is changing. For example, to edit a short message, and the content of the short message is changing. content[> is used to store the content of the edited short message. `convertindex` indicates the element number being highlighted (starting from 1). It's a tangible value; the user knows the `convertindex` value simply by seeing the highlighted element. `cursorindex` indicates the cursor position (starting from 1). It's a virtual value, not displayed to the user; it's used to assist in calculating the `convertindex` value. Here, highlighting is analogous to the cursor on a computer. Deleting removes the highlighted element, and inserting inserts before the highlighted element. Because `convertindex` and `cursorindex` use different units, mutual conversion is necessary, and they need to be synchronized. These two variables are relative to the content within `content[>`. Suppose the entire content of a short message is placed within `content[>`, and the content has a maximum of 255 characters. We now want to display the content of `content[>`. Suppose the content is "I've been busy with my graduation project lately, what are you guys doing?", and I realize I made a typo. I move the highlight to "芒" (mang). At this point, `cursorindex` is 29, and `convertindex` is 15. Now we want to display the content of `content[>` on the LCD. (1) Copy the content in content[> to contentram[>. The copying method is the same as above. And the value of cursorindextemp in contentram[> must be calculated from cursorindex in content[>. The value of cursorindex is the number of spaces filled before copying content[cursorindex>. When displaying the first screen, row0 displays the title. When displaying other screens, row0 is also used to display content. row4 does not display content, but is used to display the available pinyin combination and Chinese character combination under Chinese input method. (2) When we edit the content of the short message, cursorindex and convertindex are constantly changing. At the same time, cursorindextemp in the virtual screen contentram[> is also constantly changing. According to cursorindextemp, we can determine which screen content should be displayed on the LCD. netpage is used to record the sequence number of the screen to be displayed (starting from 1). (3) Use netpage to indicate which screen content to display, starting from 1. It is determined by cursorindextemp. a) When netpage==1, copy contentram[i] from 0 to 62 to contentLCD[>. If the end character is encountered before the 62nd character is copied, then there is no need to continue copying. Then call the PutMSG function to output contentLCD[> from row1 of LCD. row0 is used to display the title. b) When netpage!=1, copy *(contentram+(netpage-2)*84+63+i), (i from 0 to 83) to contentLCD[>. If the end character is encountered before the 103rd character is copied, then there is no need to continue copying. Then call the PutMSG function to display contentLCD[> from row0 of LCD. (4) When displaying contentLCD[>, the position of the reverse display is determined as follows: a) When netpage==1, calculate the number of elements before cursorindextemp in contentram[> and store it in i. i+1 is the sequence number of the element to be reversed in this screen. b) When netpage!==1, calculate the number of elements before cursorindextemp in contentram[> and store it in i. Then calculate the total number of elements in the pages preceding cursorindextemp and store them in j. i-j+1 is the index of the element to be displayed on this screen. 5 Displaying the content in LCD[> The LCD used is 128 dots (horizontal) × 64 dots (vertical), with the coordinates at the top left corner. I allocated a buffer with the same number of dots as one LCD screen—a character array disp_ram[8>[128>] (which is used to store the dot matrix of one LCD screen). Vertical 8 represents 8 bytes per column, 8×8=64 dots. 128 represents 128 dots per row. As long as the data in disp_ram[>[>] is written into the LCD's buffer, the desired characters can be displayed. The characters here include Chinese characters and ASCII codes. The Chinese character dot matrix is 12 (horizontal) × 12 (vertical), requiring 18 bytes to store the dot matrix of one Chinese character. The ASCALL dot matrix is 6 (horizontal) × 12 (vertical), requiring 9 bytes to store the dot matrix of one ASCALL code. The steps to display the content of contentLCD[> are: (1) First, call the PutMSG(INT8U x, INT8U y, UINT8 *str, UINT8 style) function, where str points to the first address of the contentLCD[> array. a) PutMSG(INT8U x, INT8U y, UINT8 *str, UINT8 style) function. x and y are the positions of the first element of the string pointed to by str on the LCD. Here, 'x' is measured in units of 8 dots (the number of horizontal dots used to display one ASCII code, in units of position) (horizontal, with values from 0 to 21), and 'y' is measured in units of 4 dots (vertical, with values of 0, 3, 6, 9, 12; y=0 indicates displaying from row0, y=3 indicates displaying from row1, and so on). 'str' is a pointer to the string to be displayed, and 'style' is a flag (0x00 - all content pointed to by str is not highlighted, 0xff - all content pointed to by str is highlighted; other numbers indicate that the element at that index is highlighted, and other characters are not highlighted; indexing starts from 1). Functionality: The PutHZ() or PutZF() function is called repeatedly to display the elements pointed to by str at a specified position on the LCD. b) PutHZ(INT8U xx, INT8U yy, UINT8 * pStr, UINT8 style) xx is the horizontal dot matrix position of the Chinese character to be displayed on the LCD, and yy is the vertical dot matrix position of the Chinese character to be displayed on the LCD. Both are counted starting from 0. The descriptions of pStr and style are the same as the PutMSG() function, except that style here cannot be 0xff. The function's purpose is to: determine the starting position of the Chinese character's dot matrix in the Chinese character dot matrix table based on the character's GB code, and copy its dot matrix to HZgroup[>. A total of 18 bytes. If reverse display is required, the bytes used in Hzgroup[> must be inverted. Then, these 18 bytes are filled into the corresponding positions in disp_ram[>[>]. How to fill them? Refer to Table 1, assign the result of yy/8 to page, and then process them according to the result of yy%8. One cell in the appendix represents one dot on the LCD. This point corresponds to a certain bit (i,j)(k,m,n) in disp_ram[>[>] — indicating that the j-th bit of Hzgroup[i>] is placed into the n-th bit of disp_ram[k>[m>]. ) c) PutZF(INT8U xx,INT8U yy,UINT8 * pStr,UINT8 style) The description of each parameter is the same as that of the PutHZ() function. The function of this function is to determine the starting position of the dot matrix of the character in the character dot matrix table based on the ASCII code of the character. And copy its dot matrix into ZFgroup[>. A total of 9 bytes. If it is necessary to display it in reverse, the bytes used in ZFgroup[>] must be inverted. Then these 9 bytes are filled into the corresponding positions in disp_ram[>[>]. The method is similar to the processing of Chinese characters. (2) Then call the LCDDisplay(UINT8 *) function. This function copies the contents of disp_ram[>[>] into the LCD's memory. This is written in assembly language (for EPSON 8-bit microcontrollers). In this way, the content is displayed on the LCD from the specified starting position. void LCDDisplay(UINT8 *src) { src=src; /* src is passed in register YP:IY */ #pragma asm LD EP,#@DPAG(SFR_MEM_WaitSet) file://Save the value of register FF02 LD HL, #@DOFF(SFR_MEM_WaitSet) LD A,[HL> PUSH A AND A,#8FH file://Clear wait state OR A,#10H LD [HL>,A file://Set wait state LD BR,#0 LD L,#0_LCDWirte_1: LD EP,#18H file://LCD control data storage area page number LD A,L ADD A,#0B0H file://Calculate display buffer page address LD [0H>,A file://Set display buffer page address LD A,#10H LD [0H>,A file://Set display buffer column address high four bits LD A,#0 LD [0H>,A // Set the lower four bits of the column address of the display buffer LD B,#80h_LCDWrite_2: // Total 128 columns LD [BR:08H>,[IY> INC IY DJR NZ,_LCDWrite_2 INC L CP L,#8 // Total 8 pages JR NZ,_LCDWrite_1 POP A // Restore the value of register FF02 LD EP,#0 LD HL, #@DOFF(SFR_MEM_WaitSet) LD [HL>,A #pragma endasm } Why organize the dot matrix of the elements into disp_ram in the above way? This is because the generation of the dot matrix table is the reverse process of the above organization. Our organization of disp_ram in this way is determined by the dot matrix table generation mechanism. If the dot matrix table is not generated in this way, then another method must be used for organization. LD BR,#0 LD L,#0_LCDWirte_1: LD EP,#18H file://LCD control data storage area page number LD A,L ADD A,#0B0H file://Calculate display buffer page address LD [0H>,A file://Set display buffer page address LD A,#10H LD [0H>,A file://Set display buffer column address high four bits LD A,#0 LD [0H>,A file://Set display buffer column address low four bits LD B,#80h_LCDWrite_2: file://Total 128 columns LD [BR:08H>,[IY> INC IY DJR NZ,_LCDWrite_2 INC L CP L,#8 file://Total 8 pages JR NZ,_LCDWirte_1 POP A file://Restore register FF02 value LD EP,#0 LD HL, #@DOFF (SFR_MEM_WaitSet) LD [HL>,A #pragma endasm Why organize the element's dot matrix into disp_ram using the above method? This is because the generation of the dot matrix table is the reverse process of this organization. Our organization of disp_ram in this way is determined by the dot matrix table generation mechanism. If the dot matrix table were not generated in this way, then a different method would be needed for organization.