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