// PIC16F689 8bit SC2004 接続 文字表示 #include__CONFIG(INTIO & WDTDIS & PWRTEN & MCLREN & UNPROTECT); #define _XTAL_FREQ 4000000 #define RS RA1 #define E RA0 // ---------------------------------------------------- // 【設定】4行目の好きな位置をここに指定してください // ---------------------------------------------------- #define START_ADDRESS 0x80 // ---------------------------------------------------- // 【RAM不足対策】メモリを圧迫しないよう、固定配列や長い文字列は // 関数の外(グローバル領域)で「static const」として定義します // ---------------------------------------------------- static const unsigned char line_addresses[] = {0x80, 0xC0, 0x94, 0xD4}; static const char str[] = "CQ CQ DE JA3RUA PSE K"; void main(void) { // ---------------------------------------------------- // 変数の宣言(関数の最初) // ---------------------------------------------------- int i; int col_count = 0; // 現在の行で何文字送ったかを数えるカウンター int current_line = 0; // 現在の物理的な行(0=1行目, 1=2行目, 2=3行目, 3=4行目) int first_line_limit = 0; // ---------------------------------------------------- // 1. PICの初期設定 // ---------------------------------------------------- ANSEL = 0x00; ANSELH = 0x00; CM1CON0 = 0x00; CM2CON0 = 0x00; TRISA0 = 0; TRISA1 = 0; TRISC = 0x00; PORTA = 0x00; PORTC = 0x00; // ---------------------------------------------------- // 2. LCDの初期化処理 // ---------------------------------------------------- __delay_ms(30); RS = 0; PORTC = 0x38; E = 1; __delay_us(2); E = 0; __delay_ms(2); RS = 0; PORTC = 0x0C; E = 1; __delay_us(2); E = 0; __delay_ms(2); RS = 0; PORTC = 0x06; E = 1; __delay_us(2); E = 0; __delay_ms(2); RS = 0; PORTC = 0x01; E = 1; __delay_us(2); E = 0; __delay_ms(2); // ---------------------------------------------------- // 3. 開始アドレスから現在の物理行を特定 // ---------------------------------------------------- if (START_ADDRESS >= 0xD4) { current_line = 3; // 4行目 } else if (START_ADDRESS >= 0xC0) { current_line = 1; // 2行目 } else if (START_ADDRESS >= 0x94) { current_line = 2; // 3行目 } else if (START_ADDRESS >= 0x80) { current_line = 0; // 1行目 } else { current_line = 0; } // 最初の行(4行目)の右端までの残り文字数を自動計算 first_line_limit = 20 - (START_ADDRESS - line_addresses[current_line]); // 最初の表示位置コマンドを送信 RS = 0; PORTC = START_ADDRESS; E = 1; __delay_us(2); E = 0; __delay_ms(2); // ---------------------------------------------------- // 4. 無限ループ自動改行送信ロジック(4行目?1行目?2行目?3行目) // ---------------------------------------------------- for(i = 0; str[i] != '\0'; i++) { //for // 文字データの送信 RS = 1; PORTC = str[i]; E = 1; __delay_us(2); E = 0; __delay_us(50); col_count++; // 表示文字数をカウント // 行の右端に達した場合 if (col_count == first_line_limit) { //if1 current_line++; // 次の物理行へ進む // 4行目(3)の右端を超えたら、1行目(0)にループバックさせる if (current_line > 3) { //if2 current_line = 0; }//if2 // 安全対策:画面1周分(80文字)を超えて上書きしそうなら終了 if (i >= 80) { //if3 break; }//if3 // 次の行の先頭アドレス(1行目なら0x80、2行目なら0xC0)を送信 RS = 0; PORTC = line_addresses[current_line]; E = 1; __delay_us(2); E = 0; __delay_ms(2); // 以降の行は「20文字ぴったり」で改行 first_line_limit = 20; col_count = 0; // カウンターリセット }//if1 } //for // ---------------------------------------------------- // 5. メインループ(画面の点滅動作) // ---------------------------------------------------- while(1) { //while RS = 0; PORTC = 0x08; E = 1; __delay_us(2); E = 0; __delay_ms(2); for(i = 0; i < 5; i++) { __delay_ms(100); } RS = 0; PORTC = 0x0C; E = 1; __delay_us(2); E = 0; __delay_ms(2); for(i = 0; i < 5; i++) { __delay_ms(100); } }//while }