USBプロジェクト - USB制御液晶モジュールのその後 [USB]
USBで制御させようと思っていた「USB制御液晶モジュール」ですが、液晶表示の機能のテストをしていませんでした。 ひとまず、文字を表示させてみました。 液晶モジュールには、サンライク社のSC1602Bを使用しています。
端子の割り当て
SC1602Bには、4-bitバスモードと8-bitバスモードがあります。 MC908JB16には、多くの端子があるので、贅沢に8-bitモードを使用するつもりだったのですが、そのままではMON08インターフェースがつながらないことがわかりました。
DB2を制御しようとしていたPTA2は、MON08接続時には、"LOW"レベルを保持しなくてはなりません。 SC1602BのDB2にはプルアップ抵抗がつながっているようで、テスタで0.8Vの電圧が出ていました。 このマイコンのVILは、最大0.3VDDなので、十分に"LOW"レベルだと思います。 10KΩのプルダウン抵抗を追加したらつながるようでした。
真の原因は良くわからないけど、4-bitモードを使用すべくDB3からDB0の線を切ってしまいました。 切っちゃったら、何とかなったので、いいことにしてしまおう。
また、CN2-11はPTC1だと思っていたのですが、実際にはPTC0がつながっていましたので、"E"端子は、PTC0で制御するようにしました。
SC1602B側 | USBDEV基板側 | ||
---|---|---|---|
# | 端子名 | # | 端子名 |
1 | VDD | CN4-14 | VDD |
2 | VSS | CN2-14 | VSS |
3 | VO | - | - |
4 | RS | CN2-5 | PTE0 |
5 | R/W | CN2-6 | PTE2 |
6 | E | CN2-11 | PTC0 |
7 | DB0 | - | N/C |
8 | DB1 | - | N/C |
9 | DB2 | - | N/C |
10 | DB3 | - | N/c |
11 | DB4 | CN2-7 | PTA4 |
12 | DB5 | CN2-8 | PTA5 |
13 | DB6 | CN2-9 | PTA6 |
14 | DB7 | CN2-10 | PTA7 |
基板上には、LEDが4個搭載されます。 こちらは、前回から変更ありません。
# | 端子名 | LED |
---|---|---|
CN4-8 | PTD2 | 赤 |
CN4-9 | PTD3 | 黄 |
CN4-10 | PTD4 | 緑 |
- | PTD5 | 青(USBDEV上) |
表示テスト
一秒ごとに数字を表示していくプログラムを作成してみました。 そうか、SC1602って、勝手にスクロールしてくれるんじゃなかったのか。
//============================================================== // $Id: main.c,v 1.1 2008/04/06 02:43:58 noritan Exp $ // $Source: /mnt/cvs/rep/CW/JB01/Sources/main.c,v $ //============================================================== #include <hidef.h> /* for EnableInterrupts macro */ #include "derivative.h" /* include peripheral declarations */ //-------------------------------------------------------------- // Time constants //-------------------------------------------------------------- #define _CPU_CLOCK_ (12000000UL) #define _BUS_CLOCK_ (6000000UL) #define PERIOD_PS (1) #define PERIOD_1m00 ((_BUS_CLOCK_ / PERIOD_PS / 1000) - 1) //-------------------------------------------------------------- // Alias for I/O ports. //-------------------------------------------------------------- #define LCD_RS PTE_PTE0 #define LCD_RW PTE_PTE2 #define LCD_E PTC_PTC0 #define LCD_DB PTA #define LCD_DDRRS DDRE_DDRE0 #define LCD_DDRRW DDRE_DDRE2 #define LCD_DDRE DDRC_DDRC0 #define LCD_DDRDB DDRA dword systime; //-------------------------------------------------------------- // MSEC sleep. //-------------------------------------------------------------- void msleep(dword reltim) { dword expire = systime + reltim; while (systime <= expire) ; } //-------------------------------------------------------------- // Periodic interrupt //-------------------------------------------------------------- void interrupt VectorNumber_TIM1Ovr isrTim1Ovf() { T1SC_TOF = 0; // Clear flag. systime++; // Increase system time. PTD_PTD5 = (systime & 0x40)?(1):(0); } //-------------------------------------------------------------- // Toggle E clock. //-------------------------------------------------------------- static void lcd_toggleE(void) { LCD_E = 1; // assert LCD enable LCD_E = 0; // negate LCD enable } //-------------------------------------------------------------- // Get a byte. //-------------------------------------------------------------- byte lcd_getByte(void) { byte data; LCD_E = 1; // assert LCD enable data = LCD_DB; // Get Status. LCD_E = 0; // negate LCD enable return data; } //-------------------------------------------------------------- // Get two nibbles. //-------------------------------------------------------------- byte lcd_getNibbles(void) { byte data; LCD_E = 1; // assert LCD enable data = LCD_DB & 0xF0; // Get MSB part. LCD_E = 0; // negate LCD enable LCD_E = 1; // assert LCD enable data |= (LCD_DB >> 4); // Get LSB part. LCD_E = 0; // negate LCD enable return data; } //-------------------------------------------------------------- // Get status word. //-------------------------------------------------------------- byte lcd_getStatus(void) { byte status; LCD_RS = 0; // Select command. status = lcd_getNibbles(); // Get Status as nibbles. return status; } //-------------------------------------------------------------- // Get data word. //-------------------------------------------------------------- byte lcd_getData(void) { byte data; LCD_RS = 1; // Select register. data = lcd_getNibbles(); // Get Data as nibbles. return data; } //-------------------------------------------------------------- // Check if LCD is busy. //-------------------------------------------------------------- byte lcd_isBusy(void) { return (lcd_getStatus() & 0x80); } //-------------------------------------------------------------- // Send two nibbles //-------------------------------------------------------------- void lcd_sendNibbles(byte data) { // Set MSB nibble LCD_DB = (LCD_DB & 0x0F) | (data & 0xF0); LCD_DDRDB |= 0xF0; // Drive DB(7:4) as output lcd_toggleE(); // Toggle LCD E clock. // Set LSB nibble LCD_DB = (LCD_DB & 0x0F) | ((data << 4) & 0xF0); lcd_toggleE(); // Toggle LCD E clock. LCD_DDRDB &= 0x0F; // Release DB(7:4) as input } //-------------------------------------------------------------- // Send one bytes //-------------------------------------------------------------- void lcd_sendByte(byte data) { LCD_DB = data; // Set a byte. LCD_DDRDB = 0xFF; // Drive DB as output lcd_toggleE(); // Toggle LCD E clock. LCD_DDRDB = 0x00; // Release DB as input } //-------------------------------------------------------------- // Send a byte as a command //-------------------------------------------------------------- void lcd_sendCommand(byte command) { LCD_RS = 0; // Select command. LCD_RW = 0; // Prepare for WRITE. lcd_sendNibbles(command); // Send as nibbles. LCD_RW = 1; // Prepare for READ. } //-------------------------------------------------------------- // Send a byte as a data //-------------------------------------------------------------- void lcd_sendData(byte data) { LCD_RS = 1; // Select data. LCD_RW = 0; // Prepare for WRITE. lcd_sendNibbles(data); // Send as nibbles. LCD_RW = 1; // Prepare for READ. } //-------------------------------------------------------------- // Locate cursor //-------------------------------------------------------------- void lcd_cursor(byte addr) { while (lcd_isBusy()) ; // Wait for instruction ends. lcd_sendCommand(addr | 0x80); // Send an address set command. } //-------------------------------------------------------------- // Initialization sequence //-------------------------------------------------------------- void lcd_init(void) { void putc(char); LCD_E = 0; // clear LCD enable LCD_RS = 0; // clear register select. LCD_RW = 1; // Prepare for READ. LCD_DDRE = 1; // configure LCD_E as output. LCD_DDRRS = 1; // configure LCD_RS as output. LCD_DDRRW = 1; // configure LCD_RW as output. PTD_PTD5 = 1; PTD_PTD4 = 1; PTD_PTD3 = 1; PTD_PTD2 = 1; DDRD_DDRD5 = 1; // Enable BLUE DDRD_DDRD4 = 1; // Enable GREEN DDRD_DDRD3 = 1; // Enable YELLOW DDRD_DDRD2 = 1; // Enable RED // Initialization sequence. LCD_RS = 0; // Select command. LCD_RW = 0; // Prepare for WRITE. msleep(100); // wait for 100ms LCD_DB = (LCD_DB & 0x0F) | (0x30); // 1st command. LCD_DDRDB |= 0xF0; // Drive DB(7:4) as output lcd_toggleE(); // Toggle LCD E clock. PTD_PTD4 = 0; msleep(10); // wait for 10ms lcd_toggleE(); // Toggle LCD E clock. msleep(1); // wait for 1ms LCD_DB = (LCD_DB & 0x0F) | (0x20); // 4-bit mode. lcd_toggleE(); // Toggle LCD E clock. LCD_DDRDB &= 0x0F; // Release DB(7:4) as output LCD_RW = 1; // Prepare for READ. msleep(1); // wait for 1ms while (lcd_isBusy()) ; // Wait for instruction ends. lcd_sendCommand(0x28); // Set DL as 4-bit, N as 2 lines, F as 5x7 dots. while (lcd_isBusy()) ; // Wait for instruction ends. PTD_PTD3 = 0; lcd_sendCommand(0x10); // Set S/C as move, R/L as left. while (lcd_isBusy()) ; // Wait for instruction ends. PTD_PTD2 = 0; lcd_sendCommand(0x0F); // Set D as ON, C as ON, B as blink. while (lcd_isBusy()) ; // Wait for instruction ends. lcd_sendCommand(0x06); // Set I/D as INC, S as no Shift. while (lcd_isBusy()) ; // Wait for instruction ends. lcd_sendCommand(0x01); // Clear Display. } void main(void) { byte i; byte x; systime = 0; CONFIG = 0b01100001; // |||||||+--- COPD=1 No COP function // ||||||+---- STOP=0 No STOP instruction // |||||+----- COPRS=0 Default COP rate // ||||+------ SSREC=0 No STOP // |||+------- LVID=0 Enable LVI function // ||+-------- URSTD=1 Disable RESET by USB // |+--------- LVI5OR3=1 Configure for VDD=5V // +---------- LVIDR=0 Enable LVI for VREG T1MOD = PERIOD_1m00; // Set modulo period T1SC = 0b01110000; // |||||+++--- PS=000 prescaler x1 // ||||+------ Reserved // |||+------- TRST=1 Reset counter // ||+-------- TSTOP=1 Disable counter // |+--------- TOIE=1 Enable OVF interrupt // +---------- Not affected T1SC_TSTOP = 0; // Enable counter EnableInterrupts; /* enable interrupts */ lcd_init(); x = 0; for (;;) { for (i = 0; i < 10; i++) { msleep(1000); PTD_PTD3 = 0; while (lcd_isBusy()) ; lcd_sendData(i + '0'); if (++x >= 16) { while (lcd_isBusy()) ; lcd_sendCommand(0x02); // Return home x = 0; } PTD_PTD3 = 1; PTD_PTD2 = ~PTD_PTD2; } } /* loop forever */ /* please make sure that you never leave main */ }
>SC1602BのDB2にはプルアップ抵抗がつながっているようで、テスタで0.8Vの電圧が出ていました。
なんか中途半端な電圧ですね。
R/W ピンがHで、双方とも出力がぶつかっていたんじゃないでしょうか。SC1602Bに乗っているKS0066は出力ドライブ能力が低そうなのでほぼ負けていたと。
MC68HC908JB16
Output low voltage (ILoad = 1.6 mA) All I/O pins
VOL 0.4V (max)
KS0066
Output Voltage (DB0 to DB7)
VOH 2.4V (min), on IOH = -0.205 mA
Tsuneo
by Tsuneo (2008-04-06 23:25)
「Eに外付けプルダウンを付けていなかったので、ドライバがぶつかっていたのかも知れない」と、配線を切った後で、思いつきましたが、切っちゃった後なので究明はしていません。
きっと、中途半端なところで発振していたので、テスタで0.8Vだったのに、LOWとして認識されちゃったのでしょう。
やっぱり、オシロが無いと不便だな。
by noritan (2008-04-07 00:52)
> また、CN2-11はPTC1だと思っていたのですが、実際にはPTC0が
> つながっていましたので
すいません、そうです、JB8から変更になっています。
JB16になってPINに機能が多重化されたので、PTC0(TXD)とPTC1(RXD)を並べた方が拡張した時に使い易いかとおもって変更しています。
by hamayan (2008-04-07 09:52)
TTLで非同期回路を組んでた頃にはありましたね、ディジタル回路なのに発振しちゃうというのが。RCディレイとかワンショットとか確かに発振器を構成するのに充分な要素がそこここに盛り込んであるので発振して当然といえば当然なんですが。
Tsuneo
by Tsuneo (2008-04-07 17:42)