組み込み系をやり初めて最初に使って見たLCD(1602)はUSB接続のサブディスプレーとして今でも便利に使っていたりする。LCD制御用に下記のようなI2Cモジュールを組み合わせてPCとの接続にはFTDIチップを使うというLCDを表示するだけなのにずいぶん豪勢な構成となっている。
KKHMF 1602 LCD ブラック IIC/ I2C / TWI/SPI シリアル インタフェース ボード モジュール
設定画面を作りたくてC#で開発してしまったのでプログラムを修正するためにはVisual-Studioが必要になるのだが、経験上、Visual-Studioをインストールすると何かと問題が起こるのでメインPCにはインストールできない。そのためWindos10-Proの仮想マシン(Hyper-V)にインストールしていたのだが、現在はHyper-Vが使えないWindows10-HomeがメインPCだったりするのとC#はもう使う気もないので新しくUSB制御のLCDを作ることにしてみた。
まずHWだが、今回の用途にはPIC16F1455がピッタリだ。超シンプルかつDACによりバックライト調整までもできてしまうのでお勧めだ。
【完成基板】
Simple is Best!! 後付けのトランジスタが気になりますけど(笑)
ディスプレーの上って普通空いてるはずだからLCDなどはここに置くのがベスト。かも。
LCDは白黒表示のYB1602Aがアリエクスプレスにて1個350円ほどで売られていたのを購入。表示させて見ると白というか青っぽく見えてしまうが目(脳?)の錯覚かもしれないので気にしないでおこう。(-_-;)
バックライト制御は無理っぽいと思いつつもDAC出力により直接制御する予定で進めていたが試して見るとやっぱりDACの駆動能力が弱すぎてボツ。しょうがないのでリワークしてトランジスタを追加しDACソースを1.024Vにしてみたところちょうど良い感じに調整できるようになった。この辺はLCDにより違いがあるのかもしれないが...
【バックライト最大(少し明るすぎかな?、四角が光って見える)】
ファームウェアはシンプル&ストレートにLCDの全機能をUSB経由で呼び出せるようにしてみた。もちろん読み込みも可能である。ユーティリティコマンドからもLCDの全機能が使えるようになっているのでLCDコマンドを一つずつ実行しながらLCDの挙動を調べることも可能だ。
ファームウェアの書き込みを512ワードCDCブートローダー対応にする場合は、リンカーオプション(CodeOffset=0x200)を設定するだけだ。ICSPから書き込む場合はCodeOffsetを未設定にすれば良い。
【ファームウェア】
プロジェクト・ダウンロード(for MPLAB-X)
※ファイル数が多いためLCD関連ソースのみ掲載
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/* ioport.h - ioport macro Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef IOPORT_H #define IOPORT_H #include "xc.h" // // IOPORT_PULLUP/IOPORT_ANALOG values // #define DISABLE 0 #define ENABLE 1 // // IOPORT_MODE values // #define OUTPUT 0 #define INPUT 1 // // IOPORT_READ/IOPORT_WRITE values // #define LOW 0 #define HIGH 1 // // ioport macro // #define IOPORT_CONCAT(r, p) r##p #define IOPORT_MODE(pin) IOPORT_CONCAT(TRIS, pin) #define IOPORT_ANALOG(pin) IOPORT_CONCAT(ANS , pin) #define IOPORT_PULLUP(pin) IOPORT_CONCAT(WPU , pin) #define IOPORT_WRITE(pin) IOPORT_CONCAT(LAT , pin) #define IOPORT_READ(pin) (uint8_t)IOPORT_CONCAT(R, pin) #define IOPORT_CONCAT3(a, b, c) a##b##c #define IOPORT_HAS_ANS(pin) ( \ IOPORT_CONCAT3(_ANSELA_ANS, pin, _MASK) \ || IOPORT_CONCAT3(_ANSELB_ANS, pin, _MASK) \ || IOPORT_CONCAT3(_ANSELC_ANS, pin, _MASK) \ ) #endif /* IOPORT_H */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
/* config.h - Configuration File Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CONFIG_H #define CONFIG_H // // define lcd2 ports // #define LCD2_3V3 0 #define LCD2_RS C0 #define LCD2_RW C1 #define LCD2_E C5 #define LCD2_DB7 A5 #define LCD2_DB6 A4 #define LCD2_DB5 C3 #define LCD2_DB4 C4 #define LCD2_Vo DAC_OUT_RC2 #endif /* CONFIG_H */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
/* lcd2.h - LCD Library for HD44780U Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef LCD2_H #define LCD2_H #include <stdint.h> #include <stdbool.h> // // Parameter's of Entry mode set // #define LCD2_ENTRY_S 0x01 #define LCD2_ENTRY_ID 0x02 // // Parameter's of Display on off control // #define LCD2_DISPLAY_OFF 0x00 #define LCD2_DISPLAY_BLINK 0x01 #define LCD2_DISPLAY_CURSOR 0x02 #define LCD2_DISPLAY_DISPLAY 0x04 // // Parameter's of Cursor or display shift // #define LCD2_SHIFT_RL 0x04 #define LCD2_SHIFT_SC 0x08 // // Parameter's of Function set // #define LCD2_FUNCTION_F 0x04 #define LCD2_FUNCTION_N 0x08 #define LCD2_FUNCTION_DL 0x10 #define LCD2_FUNCTION_4BIT 0 #define LCD2_FUNCTION_8BIT LCD2_FUNCTION_DL #define LCD2_FUNCTION_1X8 0 #define LCD2_FUNCTION_1X10 LCD2_FUNCTION_F #define LCD2_FUNCTION_2X8 LCD2_FUNCTION_N extern void lcd2_init(uint8_t mode); extern void lcd2_reset(uint8_t mode); extern void lcd2_clear(void); extern void lcd2_home(void); extern void lcd2_entry(uint8_t mode); extern void lcd2_display(uint8_t mode); extern void lcd2_shift(uint8_t mode); extern void lcd2_function(uint8_t mode); extern void lcd2_cgram(uint8_t addr); extern void lcd2_ddram(uint8_t addr); extern uint8_t lcd2_address(void); extern void lcd2_write(uint8_t data); extern uint8_t lcd2_read(void); #endif /* LCD2_H */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
/* lcd2.c - LCD Library for HD44780U Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "ioport.h" #include "lcd2.h" // // Instruction's // #define LCD2_CLEAR 0x01 #define LCD2_HOME 0x02 #define LCD2_ENTRY 0x04 #define LCD2_DISPLAY 0x08 #define LCD2_SHIFT 0x10 #define LCD2_FUNCTION 0x20 #define LCD2_CGRAM 0x40 #define LCD2_DDRAM 0x80 // // RS Pin // #define RS_IR LOW #define RS_DR HIGH // // Delay Nanoseconds // #define FOSC (_XTAL_FREQ/4000000000.0) #define __delay_ns(x) _delay((unsigned long)(((x) + (FOSC - 1)) / FOSC)) // // Bus Timing // #if LCD2_3V3 // // Vcc = 2.7 to 4.5V, Ta = -30 to +75C // #define BUS_TCYCE 1000 // min #define BUS_PWEH 450 // min #define BUS_TAS 60 // min (not used) #define BUS_TAH 20 // min (not used) #define BUS_TDSW 195 // min (not used) #define BUS_TDDR 360 // max (not used) #define BUS_TH 10 // min (not used) #define BUS_THR 5 // min (not used) #else // // Vcc = 4.5 to 5.5V, Ta = -30 to +75C // #define BUS_TCYCE 500 // min #define BUS_PWEH 230 // min #define BUS_TAS 40 // min (not used) #define BUS_TAH 10 // min (not used) #define BUS_TDSW 80 // min (not used) #define BUS_TDDR 160 // max (not used) #define BUS_TH 10 // min (not used) #define BUS_THR 5 // min (not used) #endif static void read_mode(void) { IOPORT_MODE(LCD2_DB7) = INPUT; IOPORT_MODE(LCD2_DB6) = INPUT; IOPORT_MODE(LCD2_DB5) = INPUT; IOPORT_MODE(LCD2_DB4) = INPUT; IOPORT_WRITE(LCD2_RW) = HIGH; } static void write_mode(void) { IOPORT_WRITE(LCD2_RW) = LOW; IOPORT_MODE(LCD2_DB7) = OUTPUT; IOPORT_MODE(LCD2_DB6) = OUTPUT; IOPORT_MODE(LCD2_DB5) = OUTPUT; IOPORT_MODE(LCD2_DB4) = OUTPUT; } static uint8_t read4(void) { uint8_t rv; IOPORT_WRITE(LCD2_E) = HIGH; __delay_ns(BUS_PWEH); rv = (uint8_t)((IOPORT_READ(LCD2_DB7) << 7) | (IOPORT_READ(LCD2_DB6) << 6) | (IOPORT_READ(LCD2_DB5) << 5) | (IOPORT_READ(LCD2_DB4) << 4)); IOPORT_WRITE(LCD2_E) = LOW; __delay_ns(BUS_TCYCE - BUS_PWEH); return rv; } static void write4(uint8_t val) { IOPORT_WRITE(LCD2_DB7) = LOW; IOPORT_WRITE(LCD2_DB6) = LOW; IOPORT_WRITE(LCD2_DB5) = LOW; IOPORT_WRITE(LCD2_DB4) = LOW; if ((val & 0x80) != 0) IOPORT_WRITE(LCD2_DB7) = HIGH; if ((val & 0x40) != 0) IOPORT_WRITE(LCD2_DB6) = HIGH; if ((val & 0x20) != 0) IOPORT_WRITE(LCD2_DB5) = HIGH; if ((val & 0x10) != 0) IOPORT_WRITE(LCD2_DB4) = HIGH; IOPORT_WRITE(LCD2_E) = HIGH; __delay_ns(BUS_PWEH); IOPORT_WRITE(LCD2_E) = LOW; __delay_ns(BUS_TCYCE - BUS_PWEH); } static uint8_t read_ir(void) { uint8_t h, l; read_mode(); // read address and busy wait do { h = read4(); l = read4(); } while (h & 0x80); return (uint8_t)(h | (l >> 4)); } static uint8_t read_dr(void) { uint8_t h, l; // busy wait read_ir(); // read CGRAM or DDRAM IOPORT_WRITE(LCD2_RS) = RS_DR; h = read4(); l = read4(); IOPORT_WRITE(LCD2_RS) = RS_IR; return (uint8_t)(h | (l >> 4)); } static void write_ir(uint8_t val) { // busy wait read_ir(); // write instruction write_mode(); write4((uint8_t)(val << 0)); write4((uint8_t)(val << 4)); } static void write_dr(uint8_t val) { // busy wait read_ir(); // write CGRAM or DDRAM write_mode(); IOPORT_WRITE(LCD2_RS) = RS_DR; write4((uint8_t)(val << 0)); write4((uint8_t)(val << 4)); IOPORT_WRITE(LCD2_RS) = RS_IR; } void lcd2_clear(void) { write_ir(LCD2_CLEAR); } void lcd2_home(void) { write_ir(LCD2_HOME); } void lcd2_entry(uint8_t mode) { write_ir((uint8_t)(LCD2_ENTRY | (mode & (LCD2_ENTRY_S | LCD2_ENTRY_ID)))); } void lcd2_display(uint8_t mode) { write_ir((uint8_t)(LCD2_DISPLAY | (mode & (LCD2_DISPLAY_BLINK | LCD2_DISPLAY_CURSOR | LCD2_DISPLAY_DISPLAY)))); } void lcd2_shift(uint8_t mode) { write_ir((uint8_t)(LCD2_SHIFT | (mode & (LCD2_SHIFT_RL | LCD2_SHIFT_SC)))); } void lcd2_function(uint8_t mode) { write_ir((uint8_t)(LCD2_FUNCTION | LCD2_FUNCTION_4BIT | (mode & (LCD2_FUNCTION_F | LCD2_FUNCTION_N)))); } void lcd2_cgram(uint8_t addr) { write_ir((uint8_t)(LCD2_CGRAM | (addr & (LCD2_CGRAM - 1)))); } void lcd2_ddram(uint8_t addr) { write_ir((uint8_t)(LCD2_DDRAM | (addr & (LCD2_DDRAM - 1)))); } uint8_t lcd2_address(void) { return read_ir(); } void lcd2_write(uint8_t data) { write_dr(data); } uint8_t lcd2_read(void) { return read_dr(); } void lcd2_reset(uint8_t mode) { // // Same as initialization by LCD internal reset circuit // lcd2_function(mode); lcd2_clear(); lcd2_display(LCD2_DISPLAY_OFF); lcd2_entry(LCD2_ENTRY_ID); } void lcd2_init(uint8_t mode) { // // power on delay // __delay_ms(41); // // init ports // #if IOPORT_HAS_ANS(LCD2_DB7) IOPORT_ANALOG(LCD2_DB7) = DISABLE; #endif #if IOPORT_HAS_ANS(LCD2_DB6) IOPORT_ANALOG(LCD2_DB6) = DISABLE; #endif #if IOPORT_HAS_ANS(LCD2_DB5) IOPORT_ANALOG(LCD2_DB5) = DISABLE; #endif #if IOPORT_HAS_ANS(LCD2_DB4) IOPORT_ANALOG(LCD2_DB4) = DISABLE; #endif if (IOPORT_MODE(LCD2_E) == INPUT) // Pin-E: Do not change the pin state IOPORT_WRITE(LCD2_E) = HIGH; // IOPORT_WRITE(LCD2_RS) = RS_IR; IOPORT_MODE (LCD2_E) = OUTPUT; IOPORT_MODE (LCD2_RS) = OUTPUT; IOPORT_MODE (LCD2_RW) = OUTPUT; // // init to 4-bit mode // write_mode(); write4((uint8_t)(LCD2_FUNCTION | LCD2_FUNCTION_8BIT)); __delay_us(4100); write4((uint8_t)(LCD2_FUNCTION | LCD2_FUNCTION_8BIT)); __delay_us(100); write4((uint8_t)(LCD2_FUNCTION | LCD2_FUNCTION_8BIT)); __delay_us(100); write4((uint8_t)(LCD2_FUNCTION | LCD2_FUNCTION_4BIT)); // // software reset // lcd2_reset(mode); } |
【PC側コマンド・ユーティリティ】
プロジェクト・ダウンロード(for Eclipse-CDT + MinGW64)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
/* main.cpp - LCD2 Command Utility Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <stdint.h> #include <errno.h> #include <time.h> #include "lcd2.h" #include "sleep.h" LCD2 lcd2; void calendar(void) { const static char *WDAY[] = {"SUN","MON","TUE","WED","THU","FRI","SAT"}; char buf[32]; time_t start, sec; start = sec = time(NULL); lcd2.clear(); lcd2.display(LCD2_DISPLAY_DISPLAY); while (1) { time_t now = time(NULL); if (sec != now) { sec = now; struct tm ltm = *localtime(&now); int len = snprintf(buf, sizeof(buf), "%04d-%02d-%02d (%.3s)", ltm.tm_year + 1900, ltm.tm_mon + 1, ltm.tm_mday, WDAY[ltm.tm_wday]); // row=0, col=0 lcd2.ddram(0); lcd2.writeBytes((const uint8_t *)buf, len); len = snprintf(buf, sizeof(buf), "%02d:%02d:%02d (%02d:%02d)", ltm.tm_hour, ltm.tm_min, ltm.tm_sec, (int)(((now - start) / 3600) % 100), (int)(((now - start) / 60) % 60)); // row=1, col=0 lcd2.ddram(64); lcd2.writeBytes((uint8_t *)buf, len); } // sleep 100ms Sleep::sleep(100); } } void usage(void) { printf("\n"); printf("LCD2 Command Utility, Version 1.0\n"); printf("Copyright(c) 2021 Sasapea's Lab. All right reserved.\n"); printf("\n"); printf("Usage: lcd2 port-name command\n"); printf("\n"); printf("command: clear ... clear display\n"); printf(" home ... return home\n"); printf(" entry n ... entry mode set (1=S|2=ID)\n"); printf(" display n ... display on/off control (1=BLINK|2=CURSOR|4=DISPLAY)\n"); printf(" shift n ... cursor or display shift (4=RL|8=SC)\n"); printf(" function n ... function set (0=1x8,4=1x10,8=2x8)\n"); printf(" cgram n ... set CGRAM address (0-63) \n"); printf(" ddram n ... set DDRAM address (0-127)\n"); printf(" address ... read CG or DDRAM address\n"); printf(" write ^hex ... write data to CG or DDRAM\n"); printf(" write text ... write text to CG or DDRAM\n"); printf(" read ... read data from CG or DDRAM\n"); printf(" light n ... backlight (0-31)\n"); printf(" reset ... reset\n"); printf(" bootloader ... start bootloader mode\n"); printf(" calendar ... display calendar\n"); printf("\n"); exit(EXIT_FAILURE); } int main(int argc, char **argv) { int help; if (argc < 3) usage(); if (lcd2.open(argv[1]) < 0) { printf("[ERROR] LCD2.open(\"%s\"): %s\n", argv[1], strerror(errno)); usage(); } for (int i = 2; i < argc; help = false) { char *p = argv[i++]; help = true; if (strcmp(p, "bootloader") == 0) { lcd2.reset(0xDFBE); // start bootloader mode help = false; break; } else if (strcmp(p, "reset") == 0) { lcd2.reset(); help = false; break; } else if (strcmp(p, "clear") == 0) { if (!lcd2.clear()) { printf("[ERROR] LCD2.clear()\n"); break; } } else if (strcmp(p, "home") == 0) { if (!lcd2.home()) { printf("[ERROR] LCD2.home()\n"); break; } } else if (strcmp(p, "entry") == 0) { uint8_t val = 0; if (i >= argc) break; p = argv[i++]; val = strtol(p, &p, 10); if (*p) break; if (!lcd2.entry(val)) { printf("[ERROR] LCD2.entry(%u)\n", val); break; } } else if (strcmp(p, "display") == 0) { uint8_t val = 0; if (i >= argc) break; p = argv[i++]; val = strtol(p, &p, 10); if (*p) break; if (!lcd2.display(val)) { printf("[ERROR] LCD2.display(%u)\n", val); break; } } else if (strcmp(p, "shift") == 0) { uint8_t val = 0; if (i >= argc) break; p = argv[i++]; val = strtol(p, &p, 10); if (*p) break; if (!lcd2.shift(val)) { printf("[ERROR] LCD2.shift(%u)\n", val); break; } } else if (strcmp(p, "function") == 0) { uint8_t val; if (i >= argc) break; p = argv[i++]; val = strtol(p, &p, 10); if (*p) break; if (!lcd2.function(val)) { printf ("[ERROR] LCD2.function(%u)\n", val); break; } } else if (strcmp(p, "cgram") == 0) { uint8_t val; if (i >= argc) break; p = argv[i++]; val = strtol(p, &p, 10); if (*p) break; if (!lcd2.cgram(val)) { printf("[ERROR] LCD2.cgram(%u)\n", val); break; } } else if (strcmp(p, "ddram") == 0) { uint8_t val; if (i >= argc) break; p = argv[i++]; val = strtol(p, &p, 10); if (*p) break; if (!lcd2.ddram(val)) { printf ("[ERROR] LCD2.ddram(%u)\n", val); break; } } else if (strcmp(p, "address") == 0) { uint8_t val; if (!lcd2.address(val)) { printf("[ERROR] LCD2.address()\n"); break; } printf("%u\n", val); } else if (strcmp(p, "write") == 0) { uint8_t val; if (i >= argc) break; p = argv[i++]; if (*p == '^') { val = strtol(++p, &p, 16); if (*p) break; if (!lcd2.write(val)) { printf("[ERROR] LCD2.write(%u)\n", val); break; } } else { if (!lcd2.writeString(p)) { printf("[ERROR] LCD2.writeString(%s)\n", p); break; } } } else if (strcmp(p, "read") == 0) { uint8_t val; if (!lcd2.read(val)) { printf("[ERROR] LCD2.read()\n"); break; } printf("%02x\n", val); } else if (strcmp(p, "light") == 0) { uint8_t val; if (i >= argc) break; p = argv[i++]; val = strtol(p, &p, 10); if (*p) break; if (!lcd2.light(val > 31 ? 31 : val)) { printf("[ERROR] LCD2.light(%u)\n", val); break; } } else if (strcmp(p, "calendar") == 0) calendar(); else break; } if (lcd2.close() < 0) printf("[ERROR] LCD2.close()\n"); if (help) usage(); return 0; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
/* lcd2.h - USB-LCD Library Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LCD2_H #define _LCD2_H #include <stdint.h> #include <stdbool.h> #include <string.h> #include "serial.h" // // Parameter's of Entry mode set // #define LCD2_ENTRY_S 1 #define LCD2_ENTRY_ID 2 // // Parameter's of Display on/off control // #define LCD2_DISPLAY_OFF 0 #define LCD2_DISPLAY_BLINK 1 #define LCD2_DISPLAY_CURSOR 2 #define LCD2_DISPLAY_DISPLAY 4 // // Parameter's of Cursor or display shift // #define LCD2_SHIFT_RL 4 #define LCD2_SHIFT_SC 8 // // Parameter's of Function set // #define LCD2_FUNCTION_F 4 #define LCD2_FUNCTION_N 8 #define LCD2_FUNCTION_1X8 0 #define LCD2_FUNCTION_1X10 LCD2_FUNCTION_F #define LCD2_FUNCTION_2X8 LCD2_FUNCTION_N // // Device Command // #define LCD2_RESET 0x00 #define LCD2_CLEAR 0x01 #define LCD2_HOME 0x02 #define LCD2_ENTRY 0x03 #define LCD2_DISPLAY 0x04 #define LCD2_SHIFT 0x05 #define LCD2_FUNCTION 0x06 #define LCD2_CGRAM 0x07 #define LCD2_DDRAM 0x08 #define LCD2_ADDRESS 0x09 #define LCD2_WRITE 0x0A #define LCD2_READ 0x0B #define LCD2_LIGHT 0x0C class LCD2 : public Serial { private: uint8_t _count; struct { uint8_t len; uint8_t cmd; union { struct { uint16_t val; } reset; struct { uint8_t val; } entry; struct { uint8_t val; } display; struct { uint8_t val; } shift; struct { uint8_t val; } function; struct { uint8_t val; } cgram; struct { uint8_t val; } ddram; struct { uint8_t val; } address; struct { uint8_t val[16]; } write; struct { uint8_t val[16]; } read; struct { uint8_t val; } light; } arg; } __attribute__((packed)) _packet; // Hide method ssize_t read(void *buf, size_t len) override { return Serial::read(buf, len); } // Hide method ssize_t write(const void *buf, size_t len) override { return Serial::write(buf, len); } bool invoke(uint8_t size = 0) { uint8_t cmd = _packet.cmd; if (write(&_packet, sizeof(_packet.len) + _packet.len) == (ssize_t)(sizeof(_packet.len) + _packet.len)) { _count = 0; while (read((uint8_t *)&_packet + _count, 1) == 1) { if (++_count < sizeof(_packet.len)) continue; if (_count == sizeof(_packet.len) + _packet.len) return (_packet.len >= sizeof(_packet.cmd) + size) && (_packet.cmd == cmd); // invalid packet size ? if (_count == sizeof(_packet)) _count = 0; } } return false; } public: LCD2(void) : _count(0) { } virtual ~LCD2(void) override { } void reset(uint16_t mode = 0) { _packet.len = sizeof(_packet.cmd) + sizeof(_packet.arg.reset); _packet.cmd = LCD2_RESET; _packet.arg.reset.val = mode; invoke(); } bool clear(void) { _packet.len = sizeof(_packet.cmd); _packet.cmd = LCD2_CLEAR; return invoke(); } bool home(void) { _packet.len = sizeof(_packet.cmd); _packet.cmd = LCD2_HOME; return invoke(); } bool entry(uint8_t val) { _packet.len = sizeof(_packet.cmd) + sizeof(_packet.arg.entry); _packet.cmd = LCD2_ENTRY; _packet.arg.entry.val = val; return invoke(); } bool display(uint8_t val) { _packet.len = sizeof(_packet.cmd) + sizeof(_packet.arg.display); _packet.cmd = LCD2_DISPLAY; _packet.arg.display.val = val; return invoke(); } bool shift(uint8_t val) { _packet.len = sizeof(_packet.cmd) + sizeof(_packet.arg.shift); _packet.cmd = LCD2_SHIFT; _packet.arg.shift.val = val; return invoke(); } bool function(uint8_t val) { _packet.len = sizeof(_packet.cmd) + sizeof(_packet.arg.function); _packet.cmd = LCD2_FUNCTION; _packet.arg.function.val = val; return invoke(); } bool cgram(uint8_t val) { _packet.len = sizeof(_packet.cmd) + sizeof(_packet.arg.cgram); _packet.cmd = LCD2_CGRAM; _packet.arg.cgram.val = val; return invoke(); } bool ddram(uint8_t val) { _packet.len = sizeof(_packet.cmd) + sizeof(_packet.arg.ddram); _packet.cmd = LCD2_DDRAM; _packet.arg.ddram.val = val; return invoke(); } bool address(uint8_t &val) { _packet.len = sizeof(_packet.cmd); _packet.cmd = LCD2_ADDRESS; if (!invoke(sizeof(_packet.arg.address))) return false; val = _packet.arg.address.val; return true; } bool write(uint8_t val) { return writeBytes(&val, (uint8_t)sizeof(val)); } bool writeBytes(const uint8_t *buf, size_t len) { while (len) { size_t n = len < sizeof(_packet.arg.write.val) ? len : sizeof(_packet.arg.write.val); _packet.len = sizeof(_packet.cmd) + n; _packet.cmd = LCD2_WRITE; memcpy(_packet.arg.write.val, buf, n); if (!invoke()) return false; buf += n; len -= n; } return true; } bool writeString(const char *str) { return writeBytes((const uint8_t *)str, strlen(str)); } bool read(uint8_t &val) { return readBytes(&val, (uint8_t)sizeof(val)); } bool readBytes(uint8_t *buf, size_t len) { while (len) { size_t n = len < sizeof(_packet.arg.read.val) ? len : sizeof(_packet.arg.read.val); _packet.len = sizeof(_packet.cmd) + sizeof(_packet.arg.read.val[0]); _packet.cmd = LCD2_READ; _packet.arg.read.val[0] = n; if (!invoke(n)) return false; memcpy(buf, _packet.arg.read.val, n); buf += n; len -= n; } return true; } bool light(uint8_t val) { _packet.len = sizeof(_packet.cmd) + sizeof(_packet.arg.light); _packet.cmd = LCD2_LIGHT; _packet.arg.light.val = val; return invoke(); } }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
/* serial.h - Serial I/O Library Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _SERIAL_H #define _SERIAL_H #include <stdio.h> #include <stdint.h> #include <string.h> #include <fcntl.h> #ifdef __linux__ #include <unistd.h> #include <termios.h> #include <sys/time.h> #include <sys/types.h> #else #include <windows.h> #if SIZE_MAX == UINT64_MAX #define ssize_t long long #else #define ssize_t int #endif #endif typedef enum { SERIAL_FRAME_5N1, SERIAL_FRAME_6N1, SERIAL_FRAME_7N1, SERIAL_FRAME_8N1, SERIAL_FRAME_5N2, SERIAL_FRAME_6N2, SERIAL_FRAME_7N2, SERIAL_FRAME_8N2, SERIAL_FRAME_5O1, SERIAL_FRAME_6O1, SERIAL_FRAME_7O1, SERIAL_FRAME_8O1, SERIAL_FRAME_5O2, SERIAL_FRAME_6O2, SERIAL_FRAME_7O2, SERIAL_FRAME_8O2, SERIAL_FRAME_5E1, SERIAL_FRAME_6E1, SERIAL_FRAME_7E1, SERIAL_FRAME_8E1, SERIAL_FRAME_5E2, SERIAL_FRAME_6E2, SERIAL_FRAME_7E2, SERIAL_FRAME_8E2, } SERIAL_FRAME; typedef enum { SERIAL_FLOW_NONE, SERIAL_FLOW_RTSCTS, SERIAL_FLOW_XONOFF, } SERIAL_FLOW; #define SERIAL_FLOW_XONOFF_START 0x11 // DC1 #define SERIAL_FLOW_XONOFF_STOP 0x13 // DC3 #define SERIAL_FLOW_XONOFF_LIMIT 256 class Serial { private: int _fd; #ifdef __linux__ struct termios _tcattr; struct timeval _timeout; #endif void config(unsigned long speed, SERIAL_FRAME frame, SERIAL_FLOW flow, unsigned long timeout) { #ifdef __linux__ struct termios tcattr; tcgetattr(_fd, &tcattr); _tcattr= tcattr; cfmakeraw(&tcattr); speed = cfgetospeed(&tcattr); int cflags = tcattr.c_cflag & (CSIZE | CSTOPB | PARENB | PARODD); tcattr.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); switch (speed) { case 50: speed = B50; break; case 75: speed = B75; break; case 110: speed = B110; break; case 134: speed = B134; break; case 150: speed = B150; break; case 200: speed = B200; break; case 300: speed = B300; break; case 600: speed = B600; break; case 1200: speed = B1200; break; case 1800: speed = B1800; break; case 2400: speed = B2400; break; case 4800: speed = B4800; break; case 9600: speed = B9600; break; case 19200: speed = B19200; break; case 38400: speed = B38400; break; case 57600: speed = B57600; break; case 115200: speed = B115200; break; case 230400: speed = B230400; break; case 460800: speed = B460800; break; case 500000: speed = B500000; break; case 576000: speed = B576000; break; case 921600: speed = B921600; break; case 1000000: speed = B1000000; break; case 1152000: speed = B1152000; break; case 1500000: speed = B1500000; break; case 2000000: speed = B2000000; break; case 2500000: speed = B2500000; break; case 3000000: speed = B3000000; break; case 3500000: speed = B3500000; break; case 4000000: speed = B4000000; break; } switch (frame) { case SERIAL_FRAME_5N1: cflags = CS5; break; case SERIAL_FRAME_6N1: cflags = CS6; break; case SERIAL_FRAME_7N1: cflags = CS7; break; case SERIAL_FRAME_8N1: cflags = CS8; break; case SERIAL_FRAME_5N2: cflags = CS5 | CSTOPB; break; case SERIAL_FRAME_6N2: cflags = CS6 | CSTOPB; break; case SERIAL_FRAME_7N2: cflags = CS7 | CSTOPB; break; case SERIAL_FRAME_8N2: cflags = CS8 | CSTOPB; break; case SERIAL_FRAME_5O1: cflags = CS5 | PARENB | PARODD; break; case SERIAL_FRAME_6O1: cflags = CS6 | PARENB | PARODD; break; case SERIAL_FRAME_7O1: cflags = CS7 | PARENB | PARODD; break; case SERIAL_FRAME_8O1: cflags = CS8 | PARENB | PARODD; break; case SERIAL_FRAME_5O2: cflags = CS5 | CSTOPB | PARENB | PARODD; break; case SERIAL_FRAME_6O2: cflags = CS6 | CSTOPB | PARENB | PARODD; break; case SERIAL_FRAME_7O2: cflags = CS7 | CSTOPB | PARENB | PARODD; break; case SERIAL_FRAME_8O2: cflags = CS8 | CSTOPB | PARENB | PARODD; break; case SERIAL_FRAME_5E1: cflags = CS5 | PARENB; break; case SERIAL_FRAME_6E1: cflags = CS6 | PARENB; break; case SERIAL_FRAME_7E1: cflags = CS7 | PARENB; break; case SERIAL_FRAME_8E1: cflags = CS8 | PARENB; break; case SERIAL_FRAME_5E2: cflags = CS5 | CSTOPB | PARENB; break; case SERIAL_FRAME_6E2: cflags = CS6 | CSTOPB | PARENB; break; case SERIAL_FRAME_7E2: cflags = CS7 | CSTOPB | PARENB; break; case SERIAL_FRAME_8E2: cflags = CS8 | CSTOPB | PARENB; break; } cfsetspeed(&tcattr, speed); tcattr.c_cflag = (tcattr.c_cflag & ~(CSIZE | CSTOPB | PARENB | PARODD)) | cflags; #ifdef CRTSCTS if (flow == SERIAL_FLOW_RTSCTS) tcattr.c_iflag |= CRTSCTS; else tcattr.c_iflag &= ~CRTSCTS; #endif if (flow == SERIAL_FLOW_XONOFF) tcattr.c_iflag |= IXON; else tcattr.c_iflag &= ~IXON; tcattr.c_cc[VSTART] = SERIAL_FLOW_XONOFF_START; tcattr.c_cc[VSTOP] = SERIAL_FLOW_XONOFF_STOP; tcattr.c_oflag &= ~OPOST; tcflush(_fd, TCIOFLUSH); tcsetattr(_fd, TCSANOW, &tcattr); _timeout.tv_sec = (timeout / 1000); _timeout.tv_usec = (timeout % 1000) * 1000; #else DCB dcb; COMMTIMEOUTS tov; HANDLE hSerial = (HANDLE) _get_osfhandle(_fd); memset(&dcb, 0, sizeof(DCB)); dcb.DCBlength = sizeof(DCB); GetCommState(hSerial, &dcb); dcb.BaudRate = speed; dcb.ByteSize = (frame & 3) + 5; dcb.StopBits = (frame >> 1) & 2; dcb.Parity = (frame >> 3); dcb.fDtrControl = (flow == SERIAL_FLOW_RTSCTS ? DTR_CONTROL_HANDSHAKE : DTR_CONTROL_ENABLE); dcb.fRtsControl = (flow == SERIAL_FLOW_RTSCTS ? RTS_CONTROL_HANDSHAKE : DTR_CONTROL_ENABLE); dcb.fOutxCtsFlow = (flow == SERIAL_FLOW_RTSCTS); dcb.fOutxDsrFlow = (flow == SERIAL_FLOW_RTSCTS); dcb.fOutX = (flow == SERIAL_FLOW_XONOFF); dcb.fInX = (flow == SERIAL_FLOW_XONOFF); dcb.XonLim = SERIAL_FLOW_XONOFF_LIMIT; dcb.XoffLim = SERIAL_FLOW_XONOFF_LIMIT; dcb.XonChar = SERIAL_FLOW_XONOFF_START; dcb.XoffChar = SERIAL_FLOW_XONOFF_STOP; dcb.fTXContinueOnXoff = TRUE; dcb.fDsrSensitivity = FALSE; dcb.fErrorChar = FALSE; dcb.fNull = FALSE; dcb.fAbortOnError = FALSE; dcb.fBinary = TRUE; SetCommState(hSerial, &dcb); PurgeComm(hSerial, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); memset(&tov, 0, sizeof(tov)); tov.ReadTotalTimeoutConstant = timeout; tov.WriteTotalTimeoutConstant = timeout; SetCommTimeouts(hSerial, &tov); #endif } public: Serial(void) : _fd(-1) { } virtual ~Serial(void) { close(); } virtual int open(const char *device, unsigned long speed = 115200, SERIAL_FRAME frame = SERIAL_FRAME_8N1, SERIAL_FLOW flow = SERIAL_FLOW_NONE, unsigned long timeout = 1000) { char path[32]; #ifdef __linux__ snprintf(path, sizeof(path), "/dev/%s", device); if ((_fd = ::open(path, O_RDWR | O_NOCTTY)) >= 0) #else snprintf (path, sizeof(path), "\\\\.\\%s", device); if ((_fd = ::open(path, O_RDWR | _O_BINARY)) >= 0) #endif config(speed, frame, flow, timeout); return _fd < 0 ? _fd : 0; } virtual int close(void) { int rv = 0; if (_fd >= 0) { #ifdef __linux__ tcsetattr(_fd, TCSANOW, &_tcattr); #endif rv = ::close(_fd); _fd = -1; } return rv; } virtual ssize_t read(void *buf, size_t len) { #ifdef __linux__ fd_set rdfds; FD_ZERO(&rdfds); FD_SET(_fd, &rdfds); int rv = select(_fd + 1, &rdfds, NULL, NULL, &_timeout); return (rv > 0 ? ::read(_fd, buf, len) : rv); #else return ::read(_fd, buf, len); #endif } virtual ssize_t write(const void *buf, size_t len) { #ifdef __linux__ fd_set wrfds; FD_ZERO(&wrfds); FD_SET(_fd, &wrfds); int rv = select(_fd + 1, NULL, &wrfds, NULL, &_timeout); return (rv > 0 ? ::write(_fd, buf, len) : rv); #else return ::write(_fd, buf, len); #endif } }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/* sleep.h - Sleep Library Copyright (c) 2021 Sasapea's Lab. All right reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _SLEEP_H_ #define _SLEEP_H_ #ifdef __linux__ #include <time.h> #else #include <windows.h> #endif class Sleep { public: static void sleep(unsigned long ms) { #ifdef __linux__ struct timespec req; req.tv_sec = (ms / 1000); req.tv_nsec = (ms % 1000) * 1000000; nanosleep(&req, NULL); #else ::Sleep(ms); #endif } }; #endif /* _SLEEP_H_ */ |