テキストからは逸れるが今度は4ビットモードでポートもピンもすべて任意に指定できるようにする。ビットのセット、クリアを、たとい同じポートであったとしてもポート単位ではなくピン1本ずつおこなう。
https://github.com/ti-nspire/AVR/tree/master/LCD_Character
サンプルファイル:
#define F_CPU 8000000UL #include <avr/io.h> #include <util/delay.h> #include "LCDClass.h" int main(){ LCDClass lcd("PB0","PD7","PD6","PD5","PB7","PB6"); // (RS,EN,D4,D5,D6,D7)の順番で指定する。 lcd.init(); lcd.gotoRowCol(1, 1) ; lcd.print("123abcXYZ"); lcd.gotoRowCol(1, 11); lcd.print("ハロー,"); lcd.gotoRowCol(2, 2) ; lcd.print("world"); while(1){ for(int i=50; i>-50; i--){ lcd.gotoRowCol(2, 10); lcd.print(i); _delay_ms(100); } } return 0; }
ライブラリーのヘッダーファイル:
#ifndef LCDClass_H_ #define LCDClass_H_ #define F_CPU 8000000UL #include <avr/io.h> #include <util/delay.h> #include <stdio.h> const uint8_t LEFT_MOST[] = {0x80, 0xC0,}; class LCDClass{ private: volatile uint8_t *DDR_RS, *DDR_EN, *DDR_D4, *DDR_D5, *DDR_D6, *DDR_D7; // DDRnレジスタのアドレスを格納する変数。 volatile uint8_t *PORT_RS, *PORT_EN, *PORT_D4, *PORT_D5, *PORT_D6, *PORT_D7; // PORTnのアドレスを格納する変数。 uint8_t RS, EN, D4, D5, D6, D7; // ポート番号を格納する変数。 void triggerWriting(); // EN信号をHi→Loと変化させる函数。 void writeByte2LCD(uint8_t byte); // 1バイトを上位ニブル、下位ニブルの順にLCDへ書き込む函数。 public: void init(); void writeCommand(uint8_t command); // コマンドを書き込む函数。 void writeChar(char ch); // 1文字を表示する函数。 void print(const char *str); // 文字列を表示する函数。 void print(int16_t val); // 数字を表示する函数。 void gotoRowCol(uint8_t row, uint8_t col); // カーソル位置を指定する函数。 void clearDisplay(); LCDClass(const char*rs, const char*en, const char*d4, const char*d5, const char*d6, const char*d7); }; #endif
ライブラリーの実装ファイル:
#include "LCDClass.h" void LCDClass::init(){ *DDR_RS |= (1 << RS); // LCDに接続するマイコンの端子のIOをOUTにする。 *DDR_EN |= (1 << EN); *DDR_D4 |= (1 << D4); *DDR_D5 |= (1 << D5); *DDR_D6 |= (1 << D6); *DDR_D7 |= (1 << D7); *PORT_EN &= ~(1 << EN); // 念のため最初はdisableにしておく。しなくてもよい。 writeCommand(0x33); _delay_ms(2); writeCommand(0x32); _delay_ms(2); writeCommand(0x28); _delay_ms(2); writeCommand(0x0F); _delay_ms(2); writeCommand(0x01); _delay_ms(2); writeCommand(0x06); _delay_ms(2); } void LCDClass::triggerWriting(){ *PORT_EN |= (1 << EN); _delay_us(1); // LCDのEN端子をHi→ *PORT_EN &= ~(1 << EN); _delay_us(100); // Loと切り換えて、LoになったタイミングでLCDへ書き込む。 } void LCDClass::writeByte2LCD(uint8_t byte){ uint8_t nibbles[2] = {(uint8_t)(byte >> 4), (uint8_t)(byte & 0x0F)}; for(int i=0; i<2; i++){ *PORT_D4 &= ~(1 << D4); // 一旦4ビット全部を1ビットずつクリアしてから、 *PORT_D5 &= ~(1 << D5); *PORT_D6 &= ~(1 << D6); *PORT_D7 &= ~(1 << D7); *PORT_D4 |= ( nibbles[i] & 1) << D4; // 1ビットずつセットし直して、 *PORT_D5 |= ((nibbles[i] >> 1) & 1) << D5; *PORT_D6 |= ((nibbles[i] >> 2) & 1) << D6; *PORT_D7 |= ((nibbles[i] >> 3) & 1) << D7; triggerWriting(); // 書き込む。 } // をニブル2個分繰り返す。 } void LCDClass::writeCommand(uint8_t command){ *PORT_RS &= ~(1 << RS); writeByte2LCD(command); } void LCDClass::writeChar(char ch){ *PORT_RS |= (1 << RS); writeByte2LCD((uint8_t)ch); } void LCDClass::print(const char *str){ int i=0; while(str[i]){ // null文字が見つかるまで、 writeChar(str[i++]); // 1文字ずつ順番に表示する。 } } void LCDClass::print(int16_t val){ char str[6]; sprintf(str, "%05d", val); // 数値を文字列に変換して、 print(str); // 1数字ずつ順番に表示する。 } void LCDClass::gotoRowCol(uint8_t row, uint8_t col){ writeCommand(LEFT_MOST[row-1] + (col-1)); _delay_us(100); } void LCDClass::clearDisplay(){ writeCommand(1); _delay_ms(2); } LCDClass::LCDClass(const char*rs, const char*en, const char*d4, const char*d5, const char*d6, const char*d7){ volatile uint8_t **DDRs[6] = { &DDR_RS, &DDR_EN, &DDR_D4, &DDR_D5, &DDR_D6, &DDR_D7}; // DDRnレジスタのアドレスを格納する変数のアドレスを排列化しておく。 volatile uint8_t **PORTs[6] = {&PORT_RS, &PORT_EN, &PORT_D4, &PORT_D5, &PORT_D6, &PORT_D7}; // PORTnレジスタのアドレスを格納する変数のアドレスを排列化しておく。 // 指定した端子のDDRnとPORTnとを取得しておく。 const char*sute[] = {rs, en, d4, d5, d6, d7}; for(int i=0; i<6; i++){ switch(sute[i][1]){ case 'B': *DDRs[i] = &DDRB; *PORTs[i] = &PORTB; break; case 'C': *DDRs[i] = &DDRC; *PORTs[i] = &PORTC; break; case 'D': *DDRs[i] = &DDRD; *PORTs[i] = &PORTD; break; default : break; } } // 指定した端子のポート番号を取得しておく。 RS = (uint8_t)(rs[2]-'0'); EN = (uint8_t)(en[2]-'0'); D4 = (uint8_t)(d4[2]-'0'); D5 = (uint8_t)(d5[2]-'0'); D6 = (uint8_t)(d6[2]-'0'); D7 = (uint8_t)(d7[2]-'0'); }