SSブログ

USBプロジェクト - USB制御液晶モジュールのその後 [USB]このエントリーを含むはてなブックマーク#

1516092

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基板側
#端子名#端子名
1VDDCN4-14VDD
2VSSCN2-14VSS
3VO--
4RSCN2-5PTE0
5R/WCN2-6PTE2
6ECN2-11PTC0
7DB0-N/C
8DB1-N/C
9DB2-N/C
10DB3-N/c
11DB4CN2-7PTA4
12DB5CN2-8PTA5
13DB6CN2-9PTA6
14DB7CN2-10PTA7

基板上には、LEDが4個搭載されます。 こちらは、前回から変更ありません。

マイコンとLEDの接続
#端子名LED
CN4-8PTD2
CN4-9PTD3
CN4-10PTD4
-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 */
}

nice!(0)  コメント(4)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 4

Tsuneo

>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) 

noritan

「Eに外付けプルダウンを付けていなかったので、ドライバがぶつかっていたのかも知れない」と、配線を切った後で、思いつきましたが、切っちゃった後なので究明はしていません。
きっと、中途半端なところで発振していたので、テスタで0.8Vだったのに、LOWとして認識されちゃったのでしょう。

やっぱり、オシロが無いと不便だな。

by noritan (2008-04-07 00:52) 

hamayan

> また、CN2-11はPTC1だと思っていたのですが、実際にはPTC0が
> つながっていましたので

すいません、そうです、JB8から変更になっています。
JB16になってPINに機能が多重化されたので、PTC0(TXD)とPTC1(RXD)を並べた方が拡張した時に使い易いかとおもって変更しています。

by hamayan (2008-04-07 09:52) 

Tsuneo

TTLで非同期回路を組んでた頃にはありましたね、ディジタル回路なのに発振しちゃうというのが。RCディレイとかワンショットとか確かに発振器を構成するのに充分な要素がそこここに盛り込んであるので発振して当然といえば当然なんですが。

Tsuneo
by Tsuneo (2008-04-07 17:42) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。