AT90USB162でLCD(キャラクタディスプレイ)に表示しました。Atmel Studio 6.2でプログラムを開発し、FlipでAT90USB162フラッシュにプログラムを書き込みました。LCDは、PC 4002-B (POWERTIP TECHNOLOGY,INC.)で1行40文字で2行表示され、LCDコントローラにST7066Uを使用しています。LCDの仕様を次に示します。

LCDのピンアサイン

本LCDは、電源とGNDのピンアサインが通常のLCDと逆になっています。
LCDのピンアサイン


AT90USB162とLCD間の信号接続図

データ読み込み/書き込み信号(R/W)はグランドGNDに接続します。また、4ビットモードでLCDを制御しますのでバス幅は4ビットを設定します。
AT90USB162とLCD間の信号接続図

LCDユニット基板の配線

LCDユニットはAT90USB162と接続するために、上記の制御信号(RS,E)およびデータ信号(DB4,DB5,DB6,DB7)をLCDのコネクタからブレッドボード用のリード線を出します。また、電源(ピン番号:2)とGND(ピン番号:1)はAT90USB162に接続しているUSBから取ります。
LCDのアノード(A)、カソード(K)、R/W端子、コントラスト(Vo)についてはLCD基板の裏側で配線しました。配線したLCDユニットの裏側を次に示します。
配線したLCDユニットの裏側

LCDのバックライト端子は、アノード(A)を電源に、カソード(K)は22Ωの電流制限抵抗を介してGNDにつなぎました。
LCDのバックライト端子の接続
R/W端子はGND、コントラスト(Vo)は、本来はVSSとの間に可変抵抗をつないで文字の濃さを調節するのですが、ここではダイオード1S2076Aを介してGMDにつなげています。
LCDのR/W端子とコントラスト端子の接続

LCD表示プログラム

AT90USB162は16MHzで動作させるので、F_CPUに16000000ULと定義します。この定義は、util/delay.hで参照されます。AT90USB162とLCD間のの信号接続が異なる場合は、それぞれ定義しているデータラインと制御ラインの各信号の定義を変更します。
LCDコントローラへのコマンドは、HD44780の互換LCDコントローラを使用しています。このため、HD44780と同じdelayで同じコマンドデータが使用できます。

各信号とポート間の定義とコマンドデータの設定値を次のようにコード化します。起動時に実行されるMain関数から、LCD表示に表示するためにの制御関数を呼び出します。Atmel Studioでは、各CPUの定義がavr/io.hにまとめられており(AT90USB162では最終的にiousb162.hを呼び出す)、この値を参照しながらプログラムを作成します。

AVRのCPUでは、各ポートはあらかじめ定義されている3つのレジスタでコントロールされます。レジスタDDRは、ピンがINPUTかOUTPUTかを決定します。PORTレジスタはピンのHIGH/LOWを制御し、PINレジスタでINPUTピンの状態を読み取ります。レジスタの各ビットは1本のピンに対応付けられ、たとえば、DDRB、PORTB、PINBの最下位ビットは、PB0(デジタルピン8)となります。

#define F_CPU 16000000UL

#include <avr/io.h>
#include <util/delay.h>

#define lcd_D7_port     PORTB                   // lcd D7 connection
#define lcd_D7_bit      PORTB7
#define lcd_D7_ddr      DDRB

#define lcd_D6_port     PORTB                   // lcd D6 connection
#define lcd_D6_bit      PORTB6
#define lcd_D6_ddr      DDRB

#define lcd_D5_port     PORTB                   // lcd D5 connection
#define lcd_D5_bit      PORTB5
#define lcd_D5_ddr      DDRB

#define lcd_D4_port     PORTB                   // lcd D4 connection
#define lcd_D4_bit      PORTB4
#define lcd_D4_ddr      DDRB

#define lcd_E_port      PORTB                   // lcd Enable pin
#define lcd_E_bit       PORTB3
#define lcd_E_ddr       DDRB

#define lcd_RS_port     PORTB                   // lcd Register Select pin
#define lcd_RS_bit      PORTB2
#define lcd_RS_ddr      DDRB

// LCD module information
#define lcd_LineOne     0x00                    // start of line 1
#define lcd_LineTwo     0x40                    // start of line 2

// LCD instructions
#define lcd_Clear           0b00000001          // replace all characters with ASCII 'space'
#define lcd_Home            0b00000010          // return cursor to first position on first line
#define lcd_EntryMode       0b00000110          // shift cursor from left to right on read/write
#define lcd_DisplayOff      0b00001000          // turn display off
#define lcd_DisplayOn       0b00001100          // display on, cursor off, don't blink character
#define lcd_FunctionReset   0b00110000          // reset the LCD
#define lcd_FunctionSet4bit 0b00101000          // 4-bit data, 2-line display, 5 x 7 font
#define lcd_SetCursor       0b10000000          // set cursor position

// Program ID
uint8_t program_author[]   = "Tomosoft";
uint8_t program_version[]  = "Atmel Studio 6.2 + Flip 3.4.7";

// Function Prototypes
void lcd_write_4(uint8_t);
void lcd_write_instruction_4d(uint8_t);
void lcd_write_character_4d(uint8_t);
void lcd_write_string_4d(uint8_t *);
void lcd_init_4d(void);

int main(void)
{
	lcd_D7_ddr |= (1<<lcd_D7_bit);                  // 4 data lines - output
	lcd_D6_ddr |= (1<<lcd_D6_bit);
	lcd_D5_ddr |= (1<<lcd_D5_bit);
	lcd_D4_ddr |= (1<<lcd_D4_bit);
	
	lcd_E_ddr |= (1<<lcd_E_bit);                    // E line - output
	lcd_RS_ddr |= (1<<lcd_RS_bit);                  // RS line - output

	lcd_init_4d();                                  // initialize the LCD display for a 4-bit interface
	
	lcd_write_string_4d(program_author);			// display the first line of information

	lcd_write_instruction_4d(lcd_SetCursor | lcd_LineTwo);// set cursor to start of second line
	_delay_us(80);                                  // 40 uS delay (min)

	
	lcd_write_string_4d(program_version);			// display the second line of information
	
	
	while(1){};										// endless loop
	return 0;
}

4ビットLCDの初期化およびLCDへの1文字出力を行う制御関数を次に示します。これらは上記に示すMain関数から呼び出されます。

void lcd_init_4d(void)
{
	_delay_ms(100);                                 // initial 40 mSec delay

	lcd_RS_port &= ~(1<<lcd_RS_bit);                // select the Instruction Register (RS low)
	lcd_E_port &= ~(1<<lcd_E_bit);                  // make sure E is initially low

	lcd_write_4(lcd_FunctionReset);                 // first part of reset sequence
	_delay_ms(10);                                  // 4.1 mS delay (min)

	lcd_write_4(lcd_FunctionReset);                 // second part of reset sequence
	_delay_us(200);                                 // 100uS delay (min)

	lcd_write_4(lcd_FunctionReset);                 // third part of reset sequence
	_delay_us(200);                                 // this delay is omitted in the data sheet

	lcd_write_4(lcd_FunctionSet4bit);               // set 4-bit mode
	_delay_us(80);                                  // 40uS delay (min)

	lcd_write_instruction_4d(lcd_FunctionSet4bit);   // set mode, lines, and font
	_delay_us(80);                                  // 40uS delay (min)

	lcd_write_instruction_4d(lcd_DisplayOff);        // turn display OFF
	_delay_us(80);                                  // 40uS delay (min)

	lcd_write_instruction_4d(lcd_Clear);             // clear display RAM
	_delay_ms(4);                                   // 1.64 mS delay (min)

	lcd_write_instruction_4d(lcd_EntryMode);         // set desired shift characteristics
	_delay_us(80);                                  // 40uS delay (min)

	lcd_write_instruction_4d(lcd_DisplayOn);         // turn the display ON
	_delay_us(80);                                  // 40uS delay (min)
}

void lcd_write_string_4d(uint8_t theString[])
{
	volatile int i = 0;                             // character counter*/
	while (theString[i] != 0)
	{
	   lcd_write_character_4d(theString[i]);
	   i++;
	   _delay_us(80);                              // 40 uS delay (min)
	}
}

void lcd_write_character_4d(uint8_t theData)
{
	lcd_RS_port |= (1<<lcd_RS_bit);                 // select the Data Register (RS high)
	lcd_E_port &= ~(1<<lcd_E_bit);                  // make sure E is initially low
	lcd_write_4(theData);                           // write the upper 4-bits of the data
	lcd_write_4(theData << 4);                      // write the lower 4-bits of the data
}

void lcd_write_instruction_4d(uint8_t theInstruction)
{
	lcd_RS_port &= ~(1<<lcd_RS_bit);                // select the Instruction Register (RS low)
	lcd_E_port &= ~(1<<lcd_E_bit);                  // make sure E is initially low
	lcd_write_4(theInstruction);                    // write the upper 4-bits of the data
	lcd_write_4(theInstruction << 4);               // write the lower 4-bits of the data
}
void lcd_write_4(uint8_t theByte)
{
	lcd_D7_port &= ~(1<<lcd_D7_bit);                        // assume that data is '0'
	if (theByte & 1<<7) lcd_D7_port |= (1<<lcd_D7_bit);     // make data = '1' if necessary

	lcd_D6_port &= ~(1<<lcd_D6_bit);                        // repeat for each data bit
	if (theByte & 1<<6) lcd_D6_port |= (1<<lcd_D6_bit);

	lcd_D5_port &= ~(1<<lcd_D5_bit);
	if (theByte & 1<<5) lcd_D5_port |= (1<<lcd_D5_bit);

	lcd_D4_port &= ~(1<<lcd_D4_bit);
	if (theByte & 1<<4) lcd_D4_port |= (1<<lcd_D4_bit);

	lcd_E_port |= (1<<lcd_E_bit);                   // Enable pin high
	_delay_us(1);                                   // implement 'Data set-up time' (80 nS) and 'Enable pulse width' (230 nS)
	lcd_E_port &= ~(1<<lcd_E_bit);                  // Enable pin low
	_delay_us(1);                                   // implement 'Data hold time' (10 nS) and 'Enable cycle time' (500 nS)
}

プログラムを実行した結果を次に示します。
プログラム実行によるLCD表示