FrontPage > マイクロコントローラ > AVRの覚書
キャラクタLCDへの表示 †
ATmega328PへキャラクタLCDを接続し、文字列を表示してみる。
- 使用するLCDはSC2004CBWB-XA-GB(秋月電子で購入)
- LCDは付属の説明書に従って、基盤裏面のジャンパーポイント「J2」を半田ショートし、
パターン「R8」に付属の抵抗2本を並列に半田付けしておく。
1. 回路図 †
マイコン周りの回路はATmega328Pテスト用ボード参照。
- 図のようにマイコンと接続する。LCDはデータ長4bitモードで使用する。
- ディスプレイのコントラスト調整用に可変抵抗を接続する。
2. プログラム †
- ヘッダファイル
(lcd.h)
#ifndef LCD_H_INCLUDED
#define LCD_H_INCLUDED
// Command Instruction code定義
#define LCD_CLEAR 0b00000001
#define LCD_RTN_HOME 0b00000010
#define LCD_ENTRY 0b00000100
#define LCD_ENTRY_ID_DEC 0b0000
#define LCD_ENTRY_ID_INC 0b0010
#define LCD_ENTRY_S_NO 0b0000
#define LCD_ENTRY_S_YES 0b0001
#define LCD_DISPLAY 0b00001000
#define LCD_DISP_OFF 0b0000
#define LCD_DISP_ON 0b0100
#define LCD_DISP_CUR_OFF 0b0000
#define LCD_DISP_CUR_ON 0b0010
#define LCD_DISP_BLK_OFF 0b0000
#define LCD_DISP_BLK_ON 0b0001
#define LCD_FUNCTION_DL_8 0b00110000
#define LCD_FUNCTION_DL_4 0b00100000
#define LCD_FUNCTION LCD_FUNCTION_DL_4 // データ長4bitで使用
#define LCD_FUNCTION_N_1 0b0000
#define LCD_FUNCTION_N_2 0b1000
#define LCD_FUNCTION_F_5x8 0b0000
#define LCD_FUNCTION_F_5x11 0b0100
#define LCD_DD_ADDR 0b10000000
// 接続情報
#define LCD_PORT_CTRL PORTD // E,RS,R/W信号に使用するポートを指定
#define LCD_PORT_DATA PORTD // データーポートを指定
#define LCD_DDR_CTRL DDRD // E,RS,R/W信号に使用するポートのDDR
#define LCD_DDR_DATA DDRD // データーポートのDDR
#define LCD_BIT_E 0b01000000 // Enableビット指定
#define LCD_BIT_RS 0b00100000 // Register Selectビット指定
#define LCD_BIT_RW 0b00010000 // R/Wビット指定
#define LCD_BIT_DATA 0b00001111 // データビット指定
// Register Select
#define LCD_RS_CTRL ~LCD_BIT_RS
#define LCD_RS_DATA LCD_BIT_RS
// LCDに対するデータ出力
void lcd_write_(unsigned char, unsigned char);
// LCDに対するデータ出力(4bit長用)
void lcd_write(unsigned char, unsigned char);
// LCDデータ長4bit指定
void lcd_setDL4Bit();
// LCD Entry Mode
void lcd_entryMode(unsigned char);
// LCD Display Set
void lcd_display(unsigned char);
// LCD Clear Display
void lcd_clear();
// LCD Function Set
void lcd_setFunction(unsigned char);
// カーソル移動
void lcd_moveCursor(unsigned char, unsigned char);
// LCD初期化
void lcd_init();
// LCD 文字列表示
void lcd_print(char*);
// 数値を表示する(2Byte)
void lcd_printInt(unsigned int);
// 数値を表示する(1Byte)
void lcd_printByte(unsigned char);
#endif // LCD_H_INCLUDED
- LCD表示用ソース
(lcd.c)
#ifndef F_CPU
#define F_CPU 16000000UL // 動作周波数に16MHzを指定
#endif
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
// LCD 行に対応するDDRAM開始アドレス
const unsigned char lcd_ddram_addr_row[] = {0x0, 0x40, 0x14, 0x54};
/************************************************************************/
/* LCDに対するデータ出力 */
/************************************************************************/
void lcd_write_(unsigned char rs, unsigned char data) {
// R/W -> W
LCD_PORT_CTRL &= ~LCD_BIT_RW;
// RSをセット
if (rs == LCD_RS_DATA) {
LCD_PORT_CTRL |= rs;
} else {
LCD_PORT_CTRL &= rs;
}
// E -> H
LCD_PORT_CTRL |= LCD_BIT_E;
// データ出力
LCD_PORT_DATA = (LCD_PORT_DATA & ~LCD_BIT_DATA) | (data & LCD_BIT_DATA);
// E -> L
LCD_PORT_CTRL &= ~LCD_BIT_E;
}
/************************************************************************/
/* LCDに対するデータ出力(4bit長) */
/************************************************************************/
void lcd_write(unsigned char rs, unsigned char data) {
lcd_write_(rs, data >> 4);
_delay_us(50);
lcd_write_(rs, data);
}
/************************************************************************/
/* LCDデータ長4bit指定 */
/************************************************************************/
void lcd_setDL4Bit() {
// 4bit mode
lcd_write_(LCD_RS_CTRL, LCD_FUNCTION_DL_8 >> 4);
_delay_ms(5);
lcd_write_(LCD_RS_CTRL, LCD_FUNCTION_DL_8 >> 4);
_delay_us(150);
lcd_write_(LCD_RS_CTRL, LCD_FUNCTION_DL_8 >> 4);
_delay_us(50);
lcd_write_(LCD_RS_CTRL, LCD_FUNCTION_DL_4 >> 4);
_delay_us(50);
}
/************************************************************************/
/* LCD Entry Mode */
/************************************************************************/
void lcd_entryMode(unsigned char data) {
lcd_write(LCD_RS_CTRL, LCD_ENTRY | data);
_delay_us(50);
}
/************************************************************************/
/* LCD Display Set */
/************************************************************************/
void lcd_display(unsigned char data) {
lcd_write(LCD_RS_CTRL, LCD_DISPLAY | data);
_delay_us(50);
}
/************************************************************************/
/* LCD Clear Display */
/************************************************************************/
void lcd_clear() {
lcd_write(LCD_RS_CTRL, LCD_CLEAR);
_delay_ms(5);
}
/************************************************************************/
/* LCD Function Set */
/************************************************************************/
void lcd_setFunction(unsigned char data) {
lcd_write(LCD_RS_CTRL, LCD_FUNCTION | data);
_delay_us(50);
}
/************************************************************************/
/* カーソル移動 */
/************************************************************************/
void lcd_moveCursor(unsigned char col, unsigned char row) {
unsigned char addr = lcd_ddram_addr_row[row] + col;
lcd_write(LCD_RS_CTRL, LCD_DD_ADDR | addr);
_delay_us(50);
}
/************************************************************************
* LCD初期化
* 4bit Mode
************************************************************************/
void lcd_init() {
// LCDで使用するポートのビットを出力に指定
LCD_DDR_CTRL = LCD_DDR_CTRL | LCD_BIT_E | LCD_BIT_RS | LCD_BIT_RW;
LCD_DDR_DATA = LCD_DDR_CTRL | LCD_BIT_DATA;
_delay_ms(50);
// データ長4bit指定
lcd_setDL4Bit();
// Functionセット display line = 2, font = 5x8dots
lcd_setFunction(LCD_FUNCTION_N_2 | LCD_FUNCTION_F_5x8);
// Displayセット
lcd_display(LCD_DISP_ON | LCD_DISP_CUR_OFF | LCD_DISP_BLK_OFF);
// Clear Display
lcd_clear();
// Entry Mode カーソル移動方向 = Increment, Display shift = disable
lcd_entryMode(LCD_ENTRY_ID_INC | LCD_ENTRY_S_NO);
}
/************************************************************************/
/* LCD 文字列出力 */
/************************************************************************/
void lcd_print(char* str) {
for (int i = 0; str[i]; i++) {
lcd_write(LCD_RS_DATA, str[i]);
_delay_us(50);
}
}
// 数字に対応するキャラクタコード
char lcd_numChars[] = {"0123456789ABCDEF"};
/************************************************************************/
/* 数値を表示する(2Byte) */
/************************************************************************/
void lcd_printInt(unsigned int num) {
lcd_printByte(num >> 8);
lcd_printByte(num & 0x00FF);
}
/************************************************************************/
/* 数値を表示する(1Byte) */
/************************************************************************/
void lcd_printByte(unsigned char byte) {
lcd_write(LCD_RS_DATA, lcd_numChars[byte >> 4]);
_delay_us(50);
lcd_write(LCD_RS_DATA, lcd_numChars[byte & 0x0F]);
_delay_us(50);
}
- メイン
(LCD_test.c)
#ifndef F_CPU
#define F_CPU 16000000UL // 動作周波数に16MHzを指定
#endif
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
/************************************************************************/
/* Main */
/************************************************************************/
int main(void)
{
lcd_init();
lcd_print("Hello");
lcd_moveCursor(0,1);
lcd_print("LCD");
lcd_moveCursor(0,2);
lcd_print("World !");
lcd_moveCursor(0,3);
lcd_printByte(0b11111111);
while(1)
{
//TODO:: Please write your application code
}
}
3. ヒューズビット設定 †
今回は外部クロック16MHzを分周なしで使用するので、Atmel Studioの
Device Programming画面のFuses設定より、「SUT_CKSEL」に
「EXTXOSC_8MHZ_XX_16KCK_14CK_65MS」を選択。
4. 実行結果 †