{"id":1064,"date":"2019-12-20T11:21:04","date_gmt":"2019-12-20T20:21:04","guid":{"rendered":"\/blog\/?p=1064"},"modified":"2023-09-21T09:26:44","modified_gmt":"2023-09-21T00:26:44","slug":"nexcom-lcd-lcm-%ed%94%84%eb%a1%9c%ea%b7%b8%eb%9e%98%eb%b0%8d","status":"publish","type":"post","link":"https:\/\/hasu0707.duckdns.org\/blog\/?p=1064","title":{"rendered":"NEXCOM LCD lcm \ud504\ub85c\uadf8\ub798\ubc0d"},"content":{"rendered":"\n<p>lcm.h<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#ifndef LCMMODULE_H\n#define LCMMODULE_H\n\n#define ENTER_KEY        0xA7\n#define ESC_KEY          0x87\n#define UP_KEY           0x8F\n#define DOWN_KEY         0xAF\n#define ENTER_ROKEY      0xE7\n#define ESC_ROKEY        0xC7\n#define UP_ROKEY         0xCF\n#define DOWN_ROKEY       0xEF\n\n#ifdef LCM_DEBUG\n#define DPRINT(fmt, args...) printk(KERN_ERR fmt, ## args)\n#else\n#define DPRINT(fmt, args...)\n#endif\n\n\/*\n * IOCTL Codes\n *\/\n#define LCM_MAGIC_NUM   0x95\n#define KPAD_MAGIC_NUM  0x96\n\n\/* Default IO port addresses for lpt ports 0, 1 and 2.\n*\/\n#define LPT0_ADDRESS 0x03bc     \/\/ corresponds to lpt0: on most PCs\n#define LPT1_ADDRESS 0x0378     \/\/ corresponds to lpt1: on most PCs\n#define LPT2_ADDRESS 0x0278     \/\/ corresponds to lpt2: on most PCs\n\n\/* IO port base address of your parallel port connect to LCD panel.\n*\/\n#define LCD_ADDRESS LPT1_ADDRESS    \/\/ corresponds to lpt port with LCD\n\n\n\/* IO port address for data, status and control bytes of LPT port.\n*\/\n#define LCD_DATA_ADDRESS    LCD_ADDRESS+0  \/\/ Data Port at base address + 0\n#define LCD_STATUS_ADDRESS  LCD_ADDRESS+1  \/\/ Status Port at base address + 1\n#define LCD_CONTROL_ADDRESS LCD_ADDRESS+2  \/\/ Control Port at base address + 2\n\n\n\/* LCD Display specific information\n*\/\n#define LCD_ROWS 2                      \/\/ number of rows (lines) displayed\n#define LCD_COLS 16                     \/\/ number of columns (characters) per row\n#define LCD_SIZE (LCD_ROWS * LCD_COLS)  \/\/ total chars displayed\n\n#endif \/* end LCMMODULE_H *\/<\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<p>lcm.c<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/*************************************************************************\n This program demostrates how the LCD module and keypad work.\n It will print out designated strings on the LCD module and get in a loop\n of echoing values back from Keypad\n when you press\/release any buttom in the keypad.\n\n release:        Apr, 6, 2009\n developer:      ginlin@nexcom\n                 stevenwu@nexcom\n***************************************************************************\/\n#include &lt;stdio.h>\n#include &lt;stdlib.h>\n#include &lt;fcntl.h>\n#include &lt;string.h>\n#include &lt;unistd.h>\n#include &lt;sys\/io.h>\n#include \"lcm.h\"\n\n#define DEBUG\n#define NEX_INVALID -1\n\n#ifdef DEBUG\n#define MYPRINT(msg...) printf(msg)\n#else\n#define MYPRINT(msg...) do { } while(0)\n#endif\n\n\/\/mapping from offset value to Address Counter, for 2*16 display\nstatic char offToDDr[32] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,\n    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f\n};\n\nstatic int f_pos = 0;\n\n\/\/ user functions\nvoid lcm_init(void);            \/\/ init LCM controller\nvoid lcm_clear(void);           \/\/ clear display and reset cursor position\nint lcm_write(char *s);         \/\/ write message to LCM display\nint lcm_lseek(int offset, int whence);  \/\/ move cursor\nunsigned char kpad_poll();      \/\/ check if key pressed\n\n\/\/ internal functions\nint acquire_io_privilege();\nvoid release_io_privilege();\nunsigned char inb(unsigned short port);\nvoid outb(unsigned char data, unsigned short port);\nvoid lcm_write_control(unsigned char cmd);\nvoid lcm_write_data(unsigned char data);\n\nint\nmain(int argc, char *argv[])\n{\n    int i;\n    int access;\n\n    char *string1 = \"booting...\";\n    char *string2 = \"shutting down...\";\n\n    \/\/ do this once at the beginning of program\n    if ((access = acquire_io_privilege()) &lt; 0)\n    {\n        fprintf(stderr, \"Couldn't get io privilege\\n\");\n        exit(1);\n    }\n    MYPRINT(\"1\\n\");\n\n    \/\/ demo how to init LCM\n    lcm_init();\n    MYPRINT(\"2\\n\");\n\n    \/\/ demo how to clear LCM display\n    lcm_clear();\n\n    sleep(2);\n\n    \/\/ demo how to move cursor to second line\n    if (lcm_lseek(16, 0) &lt; 0)\n    {\n        fprintf(stderr, \"lseek() failed\\n\");\n        exit(-1);\n    }\n    \/\/ demo how to write the desired string\n    lcm_write(string1);\n\n    sleep(1);\n\n    \/\/ demo how to move cursor to first line\n    if (lcm_lseek(0, 0) &lt; 0)\n    {\n        fprintf(stderr, \"lseek() failed\\n\");\n        exit(-1);\n    }\n    \/\/ demo how to write the desired string\n    lcm_write(string2);\n\n    \/\/ demo how to check keypad\n    while (1)\n    {\n        switch (kpad_poll())\n        {\n        case ENTER_KEY:\n            printf(\"Enter_key\\n\");\n            break;\n\n        case ENTER_ROKEY:\n            printf(\"Enter_ROkey\\n\");\n            break;\n\n        case ESC_KEY:\n            printf(\"ESC_key\\n\");\n            break;\n\n        case ESC_ROKEY:\n            printf(\"ESC_ROkey\\n\");\n            break;\n\n        case UP_KEY:\n            printf(\"UP_key\\n\");\n            break;\n\n        case UP_ROKEY:\n            printf(\"UP_ROkey\\n\");\n            break;\n\n        case DOWN_KEY:\n            printf(\"DOWN_key\\n\");\n            break;\n\n        case DOWN_ROKEY:\n            printf(\"DOWN_ROkey\\n\");\n            break;\n\n        default:\n            printf(\"The value you got is %x\\n\", i);\n            break;\n\n        }\n        sleep(1);\n    }\n\n    \/\/ do this once at end of program\n    release_io_privilege(access);\n    exit(0);\n}\n\nvoid\nlcm_clear()\n{\n    \/\/clear display - write 0x20 to DDRAM and set its address to AC\n    lcm_write_control(0x01);\n    \/\/move current position to the head\n    f_pos = 0;\n}\n\nunsigned char\nkpad_poll()\n{\n    return (inb(LCD_STATUS_ADDRESS));\n}\n\nint\nlcm_lseek(int offset, int whence)\n{\n    int newpos;\n    int ddram_addr;\n\n    if ((f_pos &lt; 0) || (f_pos > LCD_SIZE))\n    {\n        MYPRINT(\"LCM: device llseek: file position out of range (0x%x)\\n\",\n                f_pos);\n        return (-1);\n    }\n\n    switch (whence)\n    {\n    case 0:                 \/* SEEK_SET *\/\n        newpos = offset;\n        break;\n    case 1:                 \/* SEEK_CUR *\/\n        newpos = f_pos + offset;\n        break;\n    case 2:                 \/* SEEK_END *\/\n        newpos = LCD_SIZE - offset; \/\/ max size - offset\n        break;\n    default:                    \/* can't happen *\/\n        return (NEX_INVALID);\n    }\n\n    if ((newpos &lt; 0) || (newpos > LCD_SIZE))\n    {\n        MYPRINT(\"LCM: device llseek: new position out of range (0x%x)\\n\",\n                (int) newpos);\n        return (NEX_INVALID);\n    }\n\n    f_pos = newpos;\n\n    \/\/map the corresponding Address Counter\n    ddram_addr = offToDDr[newpos];\n\n    lcm_write_control(0x80 | ddram_addr);   \/\/ 0x80 - set ddram address cmd\n\n    MYPRINT(\"LCM: device llseek: new position (0x%x)\\n\", f_pos);\n\n    return (newpos);\n}\n\nint\nlcm_write(char *s)\n{\n    int length = strlen(s);\n    char c = 0;\n    int cur = f_pos;\n\n    \/*\n     * debug: Determine if position is at or past end of LCD. shouldn't be\n     *\/\n    if ((cur > (LCD_SIZE - 1)) || (cur &lt; 0))\n    {\n        MYPRINT(\"LCM: device write: file position out of range (0x%x)\\n\",\n                (int) cur);\n        return (-1);\n    }\n\n    \/*\n     * Determine if write will go past end. If so, modify length.\n     *\/\n    if ((cur + length) > LCD_SIZE)\n        length = LCD_SIZE - cur;\n\n    \/*\n     * Start writing (length) bytes at current location, length now won't be out of range\n     *\/\n    for (; length > 0; length--)\n    {\n        \/*\n         * Set real Address Counter to the current file position before write data\n         *\/\n        lcm_write_control(0x80 | offToDDr[f_pos]);\n        c = *s;\n        s++;\n        \/\/MYPRINT(\"LCM: device write: get_user (%c)\\n\", c);\n        lcm_write_data(c);\n        (f_pos)++;\n    }\n    MYPRINT(\"LCM: device write: current file position (0x%x)\\n\", f_pos);\n    MYPRINT(\"LCM: device write: current file position address (0x%x)\\n\",\n            offToDDr[f_pos]);\n    return (length);            \/\/ return number of bytes written\n}\n\n\/* End of lcm_write() *\/\n\n\n\/*\n** lcm_init: Initialize the display.\n*\/\nvoid\nlcm_init(void)\n{\n    lcm_write_control(0x30);\n    \/\/ delay >4.1ms\n    usleep(5000);\n    lcm_write_control(0x30);\n    \/\/ delay >100us\n    usleep(200);\n    lcm_write_control(0x30);\n    lcm_write_control(0x3e);    \/\/ 0x1110, 8 bits xfer, 2 lines and 5x10 dots\n    lcm_write_control(0x01);    \/\/ clear display\n    lcm_write_control(0x06);    \/\/ entry mode - increment on, no display shift\n    lcm_write_control(0x0e);    \/\/ display on, cursor on, blanking off\n    lcm_write_control(0x02);    \/\/ return cursor home (from sample code)\n}\n\n\/* Mapping of Control bits to LCD device\n *\n *  bit 7: N\/A\n *  bit 6: N\/A\n *  bit 5: N\/A\n *  bit 4: N\/A\n *  bit 3: LCD RS (HW INV)  0 -> DATA, 1 -> CMD\n *  bit 2: LCD R\/W  0 -> WRITE, 1 -> READ\n *  bit 1: LCD Enable (HW INV) 0 -> HIGH, 1 -> LO\n *  bit 0: N\/A\n *\/\n\n\/*\n** lcm_write_control: Write one byte control instruction to the LCD\n*\/\nvoid\nlcm_write_control(unsigned char cmd)\n{\n    if (ioperm(0x08, LCD_CONTROL_ADDRESS, 1))\n        return;\n\n    outb(0x08, LCD_CONTROL_ADDRESS);    \/\/command mode, RS = 1\n    usleep(600);\n\n    outb(cmd, LCD_DATA_ADDRESS);\n    usleep(600);\n\n    outb(0x08, LCD_CONTROL_ADDRESS);    \/\/cmmand mode plus the E -> 0 (hi)\n    usleep(600);\n\n    outb(0x0A, LCD_CONTROL_ADDRESS);    \/\/command mode but E -> 1 (lo)\n    usleep(600);\n}\n\n\n\/*\n** lcm_write_data: Write one byte of data to the LCD\n*\/\nvoid\nlcm_write_data(unsigned char data)\n{\n    outb(0x02, LCD_CONTROL_ADDRESS);    \/\/data mode, E -> 1 (lo)\n    usleep(100);\n    outb(data, LCD_DATA_ADDRESS);\n    usleep(100);\n    outb(0x00, LCD_CONTROL_ADDRESS);    \/\/cmmand mode plus the E -> 0 (hi)\n    usleep(100);\n    outb(0x02, LCD_CONTROL_ADDRESS);    \/\/command mode but E -> 1 (lo)\n}\n\nint\nacquire_io_privilege()\n{\n    int io;\n\n    if ((io = open(\"\/dev\/parport0\", O_RDONLY)) == -1)\n    {\n        printf(\"fail to get i\/o privilege\\n\");\n        return -1;\n    }\n    else\n        return io;\n}\n\nvoid\nrelease_io_privilege(int access)\n{\n    close(access);\n}\n\n\/*\nunsigned char\ninb(unsigned short port)\n{\n    unsigned char data;\n\n    __asm __volatile(\"inb %1,%0\":\"=a\"(data):\"id\"((unsigned short) (port)));\n\n    return (data);\n}\n\nvoid\noutb(unsigned char data, unsigned short port)\n{\n    __asm __volatile(\"outb %0,%1\"::\"a\"(data), \"id\"((unsigned short) (port)));\n}\n*\/<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>lcm.h lcm.c<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[19],"tags":[],"class_list":["post-1064","post","type-post","status-publish","format-standard","hentry","category-development_lib"],"_links":{"self":[{"href":"https:\/\/hasu0707.duckdns.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1064","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hasu0707.duckdns.org\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hasu0707.duckdns.org\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hasu0707.duckdns.org\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/hasu0707.duckdns.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1064"}],"version-history":[{"count":0,"href":"https:\/\/hasu0707.duckdns.org\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1064\/revisions"}],"wp:attachment":[{"href":"https:\/\/hasu0707.duckdns.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1064"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hasu0707.duckdns.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1064"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hasu0707.duckdns.org\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1064"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}