概要

PIC18F46K22のEUSARTモジュールを使用しRS232Cを経由してパソコンと通信するプログラムである。
パソコンからターミナルで文字列を入力するとPICで受信してパソコンへ同じ文字を送信する。RETURNキーを押すとAQM0802A-RN-GBW液晶にも文字を表示する。
秋月電子 PIC18F46K22使用 マイコンボードをベースとし半田付けされている水晶20MHzをH8/3048ボードの16MHzと交換し64MHzで動作可能とした。このボードはICSP端子を備えておりPICKIT 3で書き込みができ、電源はミニUSBで供給可能である。またユニバーサル基板になっているので簡単に回路を追加することができる。
ちなみに水晶が20MHzの場合は、通信速度がかわるので設定を変更しなければならない。
回路は次のとおりである。
cir.svg
回路図(PDF) 回路図(DXF)

プログラムの説明

ソースファイル

以下のファイルで構成されている
lcd1c.asm ・・・ メインプログラムとLCD制御の関数

ソースファイルのダウンロード rs232c1c.zip


/*
 * RS232C送受信サンプル(割り込みなし) Version 1.00
 *
 * RS232Cから文字を受信しRS232Cへその文字を出力する
 * BSキーを押すとカーソルの前の文字を削除する。RETURNキーを押すと、LCD(AQM0802A-RN-GBW)に受信した文字列を表示。
 *
 * File:        rs232c1c.c
 * Target:      PIC18F46K22 64MHz
 * コンパイラ:   Microchip MPLAB XC8 C Compiler V1.20
 * 書き込み:     PICKit 3
 * リリース:     2014/01/2 20:30
 * EUSART1:RS232C
 * I2C1:AQM0802A-RN-FBW
 * ターミナル設定例
 *   19200bps パリティ無 フロー制御無 改行コードCR VT100
 *
*/

#include <stdio.h>
#include <stdlib.h>
#include <p18f46k22.h>
#include <plib\delays.h>
#include <plib\i2c.h>
#include <plib\usart.h>

#pragma config  FOSC = HSHP,PRICLKEN=ON,PLLCFG=ON,WDTEN=OFF,LVP=OFF

#define LED0 PORTBbits.RB5
#define LCD_SADS 0x7c   //  液晶のスレーブアドレス
#define LCD_RSDATA  0x40
#define LCD_RSCMD  0x0
#define LCD_C01  0x80
#define LCD_C00  0x80
#define lcd_putc(c) lcd_data(c) // LCDへ1文字出力

signed char i2c_write(unsigned char d); // i2cへ1byte送信
void lcd_cmd(unsigned char cmd); //  LCDへコマンドを1byte送信
void lcd_clear(void); //  LCDをクリア
void lcd_init(void); //  LCD初期化
void lcd_cont(unsigned char c); //  LCDコントラスト変更(0?63)
void lcd_data(unsigned char c); //  LCDへデータを1byte送信
void lcd_ddram(unsigned char ads); //  LCDの表示アドレスを設定
void lcd_puts(const char* buf); //  LCDに文字列を表示
void usart_gets(char* buf); // RS232Cから文字列を受け取る

char buf[32];

void main(void) {
    unsigned char data;
    ANSELCbits.ANSC6=0; // EUSART TX1
    ANSELCbits.ANSC7=0; // EUSART RX1

    ANSELCbits.ANSC3=0; // I2C SCK1
    ANSELCbits.ANSC4=0; // I2C SDA1

   // BRGH=1 BRG16=0 64MHz/(16*19200)-1=207 
    Open1USART(USART_TX_INT_OFF & USART_RX_INT_OFF & USART_ASYNCH_MODE & USART_EIGHT_BIT & USART_CONT_RX,207);
   // 上記関数を実行するとTX1STA=0xa6,RC1STA=0x98,SP1BRGH=0x00,SP1BRG=0xc8,PIE1=0x00,BAUDCON1=0x40となる。
    OpenI2C(MASTER,SLEW_ON);    // マスター
    SSPADD=39; //   400kHz
    Delay1KTCYx( 64);
    lcd_init();
    lcd_cont(30);

    putrs1USART("PIC18F46K22 USART1 Test\n\r");

    for(;;){
        usart_gets(buf); // RS232Cから1行受信する
        lcd_clear();     // LCDをクリア
        lcd_puts(buf);   // RS232Cへ受信した文字列を送信する
    }
}

//  LCDへコマンドを1byte送信

void lcd_cmd(unsigned char cmd){
    SSPCON1bits.WCOL=0;
    IdleI2C();
    StartI2C();
    while(SSPCON2bits.SEN);
    i2c_write( LCD_SADS);
    i2c_write( LCD_RSCMD | LCD_C01 );
    i2c_write(cmd);
    StopI2C();
    while(SSPCON2bits.PEN);
}

//  LCDをクリア

void lcd_clear(void){
    lcd_cmd(0x01);    //  Clear Display
    Delay1KTCYx( 17);  //  1.06ms/(64MHz/4)=  17000
}

//  LCD初期化

void lcd_init(void){
    lcd_cmd(0x38);    //  Function Set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x39);    //  Function Set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x14);    //  Internal OSC frequency
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x73);    //  Contrast set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x56);    //  Power/ICON/Contrast control
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x6c);    //  Follower control
    Delay10KTCYx( 160);  //  100ms/(64MHz/4)=  1600000
    Delay10KTCYx( 160);  //  100ms/(64MHz/4)=  1600000
    lcd_cmd(0x38);    //  Function Set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x0c);    //  Display On/Off
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_clear();
}

//  LCDコントラスト変更(0?63)

void lcd_cont(unsigned char c){
    lcd_cmd(0x39);    //  Function Set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x70 | c);    //  Contrast set
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
    lcd_cmd(0x54 | (c>>4));    //  Power/ICON/Contrast control
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430

}

//  LCDへデータを1byte送信

void lcd_data(unsigned char c){
    SSPCON1bits.WCOL=0;
    IdleI2C();
    StartI2C();
    while(SSPCON2bits.SEN);
    i2c_write(LCD_SADS);
    i2c_write( LCD_RSDATA | (LCD_C01) );
    i2c_write(c);
    StopI2C();
    while(SSPCON2bits.PEN);
}

//  LCDの表示アドレスを設定

void lcd_ddram(unsigned char ads){
    lcd_cmd(0x80 | ads);
    Delay10TCYx( 43);  //  26.3μs/(64MHz/4)=  430
}

//  LCDに文字列を表示

void lcd_puts(const char* buf){
    const char* p=buf;
    while(*p){
        if(*p=='\n')
            lcd_ddram(0x40);   //2行目
        else{
           lcd_data(*p);
            Delay10TCYx( 43);  //  26.3μs*(64MHz/4)=  430
        }
        ++p;
    }
}
 
// i2cへ1byte送信

signed char i2c_write(unsigned char d){
    signed char ret;
    ret=WriteI2C(d);
    IdleI2C();
    return ret;
}

//  RS232Cから1行を入力後、bufに受信文字列を格納し関数をreturn
//  RS232Cへは1文字受信するたびにその文字を送信する。
//  受信した改行文字はbufにふくまれない。

void usart_gets(char* buf){ // RS232Cから文字列を受け取る
    char* p=buf;
    char c;
    for(;;){
        while(!DataRdy1USART());
        c = Read1USART();
        switch(c){
            case 0x8:
                if(buf<p){
                    --p;
                    *p='\0';
                    putrs1USART("\x1b[1D\x1b[K");
                }
                break;
            case 0xd:
                *p=0;
                putrs1USART("\n\r");
                return;
            case 0xa:
                break;
            default:
                if(' '<=c){
                    *p=c;
                    ++p;
                    putc1USART(c);
                }
                break;
        }
        *p=0;
    }
}