■ RS232C通信 ( PC − PIC間 )
■ PCのCOMポート
最近(2007/3時点市販)のPCに取り付けられているRS232C準拠のCOMポートはおおむね以下のような諸元に
なっています。
・ 通信方式 …… 調歩同期通信方式
・ 双方向通信 …… 全二重 or 半二重
・ フロー制御 …… ハードウェア or ソフトウェア or なし
・ 最大伝送速度(注) …… 200Kbps以上
・ UARTのFIFO 送信、受信バッファー容量 …… 各々 64バイト以上
・ ドライバ出力電圧 …… ±5 〜 ±15V
・ レシーバー スレッシュホールド電圧 …… ±3V
・ 論理 ”0”(スペース) …… +3V 〜 +15V
・ 論理 ”1”(マーク) …… −3V 〜 - 15V
(注) 最大伝送速度を規定するPCのハードウェアとしてはCPUの処理速度、メモリとともにUARTの送受信バッファーの容量があります。 IBMが
1981年に発売したIBM/PCには8250という送受信バッファー各1バイトのUART専用ICが使われていました。その後
ICの高密度化とともに
UART ICも16550、16650、16750と進化し、ボーレートジェネレータも追加されてまたバッファーも16バイト、32バイト、64バイトと増え続け通信時の
CPU負荷軽減に寄与してきました。更に、1990年代の後半にはUARTはチップセットの中に吸収されてしまいました。最近のチップセット内の
UARTは単体で最大伝送速度 1.5Mbps(PCのシリアルポートの能力アップにはドライバー回路等の高速化も必要)、送受信バッファー
1Kバイト
程度はあるようです。PICのUARTも16バイト程度のFIFOバッファがほしいですね
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> <CCS編>
//PCハイパーターミナル → RS232C → PIC18F452 (液晶なし) #include "18f452.h" #use delay(clock=40000000) // 40MHz(システムクロック周波数)=10MHz(外部発振子周波数)×4(PLL倍率) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // ボーレート = 9600bps TX=RC6,RX=RC7 main() { char cmnd; set_tris_c(0b10000000); // ポート入出力モードの設定 while(1) { cmnd = getc(); // UARTのピンRC7に1バイトのデータが送られてくるのを待つ printf("(Local echo of PC) \n\rRespons="); // stdout(標準出力)に設定されているピンRC7からPCへ送信 putc(cmnd); //受信した文字をそのまま送信 printf("(Data from PIC of No INT)\n\r"); printf("\n\rCommand= "); //message } return 0; }
<プログラム例> <C18編> #include <p18f452.h> #include <usart.h> #include <stdio.h> #pragma config OSC = HSPLL // f = 40MHz ( = 10MHz × 4(PLL)) #pragma config WDT = OFF #pragma config LVP = OFF void main (void) { char cmnd; // configure USART OpenUSART( USART_TX_INT_OFF & //割込み送信:OFF USART_RX_INT_OFF & //割込み受信:OFF USART_ASYNCH_MODE & //調歩同期通信モード USART_EIGHT_BIT & //データ長:8ビット USART_CONT_RX & //連続受信モード USART_BRGH_LOW, //ボーレート:低伝送速度モード //bau rate = Fosc/(64*(spbrg + 1)) 64 ); // bau rate = 40000000/(64*(64 + 1)) = 9615.4 bps // error rate = (9615.4-9600)/9600 = 0.0016 TRISC = 0b11111101; //RC7(RX): input mode RC6(TX): output mode while (1) { while (!DataRdyUSART()); // UARTのピンRC7に1バイトのデータが受信完了となるのを待つ cmnd = getcUSART(); //受信データを読み込む printf("(Local echo of PC) \n\rRespons="); // stdout(標準出力)に設定されているピンRC7からPCへ送信 putcUSART(cmnd); //受信した文字をそのまま送信(エコーバック) printf("(Data from PIC of No INT)\n\r"); printf("\n\rCommand= "); //message } CloseUSART(); }
<動作結果>
・PCのキーボードから ”8”のあとに”G”を入力した時のハイパーターミナルの画面です。ハイパーターミナルのローカル
エコー設定はONにしておきます。
尚、ハイパーターミナルのローカルエコーがOFFになっていると 以下のように Command = のあとに文字が表示されま
せん。
★ Tera Term -PIC間 送受信 < C30 PIC24編>
<試作品仕様>
・ PCのCOMポートとPICをつなぎ WindowsのTera Termの画面に以下を表示する。
・ PCのキーボードからキーインした文字(PICへの送信文字)をローカルエコーにより ”SendData=”のあとに表示する。
・ PICは文字データを受信したら改行・復帰の制御文字を送信後、”文字列”Receive_Data=”をPCへ送信する。
・ 更に PICは受信文字、ASCIIコードで受信文字の次の文字 及びASCIIコードで次の次の文字を3つ続けてPCへ返信する。
・ Tera Term の ローカルエコーはONにしておくこと
<試作品の回路図> (→ 回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> /********************************************** RS232C PC(Tera Term) 〜 PIC C30 PIC24FJ64GA002 ***********************************************/ #include "p24FJ64GA002.h" #include <stdio.h> #include <uart.h> /// コンフィギュレーション ビットの設定 _CONFIG1 ( JTAGEN_OFF & //JTAGポート: OFF GCP_OFF & //コードプロテクト: OFF GWRP_OFF & //書き込みプロテクト: OFF BKBUG_OFF & //バックグランドデバック: OFF COE_OFF & //クリップオン エミュレーション: OFF ICS_PGx1& //ICDピンの選択: EMUC/EMUDをPGC1/PGD1と共用 FWDTEN_OFF //ウォッチドックタイマ: OFF ) _CONFIG2 ( FNOSC_PRI & //外付け発振子20MHZ PLLなし → システムクロック:20MHZ POSCMOD_HS //発振回路モード Oscillator Selection: HS (外付け発振回路 発振周波数レベル:HS) ) char Buffer[2]; int main(void) { CLKDIV = 0; // set 1:1 AD1PCFG = 0xFFFF; // ポートA全ディジタルに指定//ANxのポートすべてに対して必須 TRISB = 0b0000000000001000; // ポートB RB3:RXは入力に 、その他RB5:SDA、RB6:SCL等は出力に設定 // UART1ピン割付 リマッピング RPINR18bits.U1RXR = 3; // UART1 RX to RP3 RPOR1bits.RP2R = 3; // UART1 TX to RP2 /// UART1初期設定 9600bps 8ビット パリティなし、フロー制御なし U1BRG = 64; // 9600bps at システムクロック20MHz //U1BRG = (Fosc(Hz)/2/16/baud(bps) - 1 // = 20000000/2/16/9600 - 1 = 64.1 → 64) U1MODE = 0b1000100000000000; // UART1初期設定 //U1MODEレジスタ設定 U1STA = 0b0000010000000000; // UART1初期設定 //U1STAレジスタ設定 while(1) { //永久ループ putsUART1("Send_Data="); //データ送信要求 while(!DataRdyUART1()); //UARTバッファーにデータがくるまでまつ Buffer[0] = getcUART1(); //バッファーデータ読み込み Buffer[1] = Buffer[0] + 1; //ASCIIコードで次の値をセット Buffer[2] = Buffer[0] + 2; //ASCIIコードで次の次の値をセット putsUART1("\n\r"); //改行、復帰 printf("Receive_Data=%c%c%c",Buffer[0],Buffer[1],Buffer[2]); //返信データを送信 putsUART1("\n\r"); //改行、復帰 putsUART1("\n\r"); //改行、復帰 } }
<動作結果>
Tera Term をPCで動作させたあと、PICの電源をONにして、下記文字を順番にキーボードから入力した場合の Tera Termの画面を示します。
@ 1
A a
B 5
<補足>
・ Send_Data= のあとにきている文字はローカルエコーによる文字です。
・ 最後の行で Send_Data= となって、キーボードがからの入力待ち状態となっています。
■ 文字列の送受信 Tera Term - PIC間 ( Harmony + PIC32MZ2048ECH100編 )
<試作品仕様>
・PCとターゲットボード間はUSB/RS232C変換ケーブルを使い PIC側からみてのインターフェースはRS232Cとする
・USB/RS232C変換ケーブルはUSBシリアルコンバーター REX-USB60F(ラトックシステム(株))とする
・RS232C通信は以下とする。
フロー制御なし、9600bps、ストップビットx1、パリティなし
・PICは起動するとすぐに Tera Term (PC)に " Hellow Worod !!" の文字列を送信する。
・PICは、Tera Term(PC)から 文字が送信されてきたら data=を 前に追加して 受信文字を返信する。
(例)
受信文字が A の場合の返信文字 ・・・・・・ data=A
受信文字が B の場合の返信文字 ・・・・・・ data=B
<試作品回路図>(→回路図のPDFファイル)
PIC32MZ2048ECH100をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //以下、main.c //------------------------------------------------------------------------------------------------ /******************************************************************************* MPLAB Harmony Project Main Source File Company: Microchip Technology Inc. File Name: main.c Summary: This file contains the "main" function for an MPLAB Harmony project. Description: This file contains the "main" function for an MPLAB Harmony project. The "main" function calls the "SYS_Initialize" function to initialize the state machines of all MPLAB Harmony modules in the system and it calls the "SYS_Tasks" function from within a system-wide "super" loop to maintain their correct operation. These two functions are implemented in configuration-specific files (usually "system_init.c" and "system_tasks.c") in a configuration-specific folder under the "src/system_config" folder within this project's top-level folder. An MPLAB Harmony project may have more than one configuration, each contained within it's own folder under the "system_config" folder. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. //Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include <stddef.h> // Defines NULL #include <stdbool.h> // Defines true #include <stdlib.h> // Defines EXIT_FAILURE #include "system/common/sys_module.h" // SYS function prototypes // ***************************************************************************** // ***************************************************************************** // Section: Main Entry Point // ***************************************************************************** // ***************************************************************************** int main ( void ) { /* Initialize all MPLAB Harmony modules, including application(s). */ SYS_Initialize ( NULL ); while ( true ) { /* Maintain state machines of all polled MPLAB Harmony modules. */ SYS_Tasks ( ); } /* Execution should not come here during normal operation */ return ( EXIT_FAILURE ); } /******************************************************************************* End of File */ //以下、app.c //----------------------------------------------------------------------- /******************************************************************************* MPLAB Harmony Application Source File Company: Microchip Technology Inc. File Name: app.c Summary: This file contains the source code for the MPLAB Harmony application. Description: This file contains the source code for the MPLAB Harmony application. It implements the logic of the application's state machine and it may call API routines of other MPLAB Harmony modules in the system, such as drivers, system services, and middleware. However, it does not call any of the system interfaces (such as the "Initialize" and "Tasks" functions) of any of the modules in the system or make any assumptions about when those functions are called. That is the responsibility of the configuration-specific system files. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include "app.h" void Write_Byte(char chr) //1バイト送信関数 { PLIB_USART_TransmitterByteSend(USART_ID_4, chr); //送信バッファーに1バイト書込み・送信 // U4TXREG = chr; ////送信バッファーに1バイト書込み・送信 while (!PLIB_USART_TransmitterIsEmpty(USART_ID_4)); //送信バッファーが空になるまで待つ // while(!U4STAbits.TRMT); //送信バッファーが空になるまで待つ } void WriteString(const char *str) //文字列送信関数 { while(*str) { Write_Byte(*str); //データ送信 str++; } } // ***************************************************************************** // ***************************************************************************** // Section: Global Data Definitions // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** /* Application Data Summary: Holds application data Description: This structure holds the application's data. Remarks: This structure should be initialized by the APP_Initialize function. Application strings and buffers are be defined outside this structure. */ APP_DATA appData; // ***************************************************************************** // ***************************************************************************** // Section: Application Callback Functions // ***************************************************************************** // ***************************************************************************** /* TODO: Add any necessary callback funtions. */ // ***************************************************************************** // ***************************************************************************** // Section: Application Local Functions // ***************************************************************************** // ***************************************************************************** /* TODO: Add any necessary local functions. */ // ***************************************************************************** // ***************************************************************************** // Section: Application Initialization and State Machine Functions // ***************************************************************************** // ***************************************************************************** /******************************************************************************* Function: void APP_Initialize ( void ) Remarks: See prototype in app.h. */ void APP_Initialize ( void ) { /* Place the App state machine in its initial state. */ appData.state = APP_STATE_INIT; /* TODO: Initialize your application's state machine and other * parameters. */ //文字列送信 WriteString("Hellow World !!\r\n"); } /****************************************************************************** Function: void APP_Tasks ( void ) Remarks: See prototype in app.h. */ void APP_Tasks ( void ) { /* Check the application's current state. */ switch ( appData.state ) { /* Application's initial state. */ case APP_STATE_INIT: { break; } /* TODO: implement your application state machine.*/ /* The default state should never be executed. */ default: { /* TODO: Handle error in application's state machine. */ break; } } } /******************************************************************************* End of File */ //以下、sys_ports_static.c //------------------------------------------------------------------------- /******************************************************************************* SYS PORTS Static Functions for PORTS System Service Company: Microchip Technology Inc. File Name: sys_ports_static.c Summary: SYS PORTS static function implementations for the Ports System Service. Description: The Ports System Service provides a simple interface to manage the ports on Microchip microcontrollers. This file defines the static implementation for the Ports System Service. Remarks: Static functions incorporate all system ports configuration settings as determined by the user via the Microchip Harmony Configurator GUI. It provides static version of the routines, eliminating the need for an object ID or object handle. *******************************************************************************/ //DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ //DOM-IGNORE-END #include "system_config.h" #include "peripheral/ports/plib_ports.h" #include "peripheral/int/plib_int.h" void SYS_PORTS_Initialize(void) { //リマップ /* PPS Input Remapping */ PLIB_PORTS_RemapInput(PORTS_ID_0, INPUT_FUNC_U4RX, INPUT_PIN_RPE8 ); //U4RXにRE8を設定 /* PPS Output Remapping */ PLIB_PORTS_RemapOutput(PORTS_ID_0, OUTPUT_FUNC_U4TX, OUTPUT_PIN_RPE9 ); //U4TXにRE9を設定 PLIB_PORTS_PinDirectionInputSet( PORTS_ID_0, PORT_CHANNEL_E, 8);//入力ポートに設定 // TRISEbits.TRISE8 = 1; //RE8:入力(RX)ポートに設定 PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_E, 9);//出力ポートに設定 // TRISEbits.TRISE9 = 0; //RE9:出力(TX) ポートに設定 PLIB_PORTS_PinModeSelect(PORTS_ID_0, PORTS_ANALOG_PIN_25, PORTS_PIN_MODE_DIGITAL); //RE8/AN25ポートをデジタルモードに設定 // ANSELEbits.ANSE8 = 0; //RE8 デジタルモード PLIB_PORTS_PinModeSelect(PORTS_ID_0, PORTS_ANALOG_PIN_26, PORTS_PIN_MODE_DIGITAL); //RE9/AN26ポートをデジタルモードに設定 // ANSELEbits.ANSE9 = 0; //RE9 デジタルモード } /******************************************************************************* End of File */ //以下、system_init.c //------------------------------------------------------------------------ /******************************************************************************* System Initialization File File Name: system_init.c Summary: This file contains source code necessary to initialize the system. Description: This file contains source code necessary to initialize the system. It implements the "SYS_Initialize" function, configuration bits, and allocates any necessary global system resources, such as the systemObjects structure that contains the object handles to all the MPLAB Harmony module objects in the system. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include "system_config.h" #include "system_definitions.h" #include "app.h" // **************************************************************************** // **************************************************************************** // Section: Configuration Bits // **************************************************************************** // **************************************************************************** /*** DEVCFG0 ***/ #pragma config DEBUG = OFF #pragma config JTAGEN = OFF #pragma config ICESEL = ICS_PGx1 #pragma config TRCEN = OFF #pragma config BOOTISA = MIPS32 #pragma config FECCCON = OFF_UNLOCKED #pragma config FSLEEP = OFF #pragma config DBGPER = PG_ALL #pragma config EJTAGBEN = NORMAL #pragma config CP = OFF /*** DEVCFG1 ***/ #pragma config FNOSC = SPLL #pragma config DMTINTV = WIN_127_128 #pragma config FSOSCEN = OFF #pragma config IESO = OFF #pragma config POSCMOD = HS #pragma config OSCIOFNC = OFF #pragma config FCKSM = CSECME #pragma config WDTPS = PS1048576 #pragma config WDTSPGM = STOP #pragma config FWDTEN = OFF #pragma config WINDIS = NORMAL #pragma config FWDTWINSZ = WINSZ_25 #pragma config DMTCNT = DMT31 #pragma config FDMTEN = OFF /*** DEVCFG2 ***/ #pragma config FPLLIDIV = DIV_3 #pragma config FPLLRNG = RANGE_5_10_MHZ #pragma config FPLLICLK = PLL_FRC //バグ修正 //#pragma config FPLLICLK = PLL_POSC #pragma config FPLLMULT = MUL_50 #pragma config FPLLODIV = DIV_2 #pragma config UPLLFSEL = FREQ_24MHZ #pragma config UPLLEN = ON /*** DEVCFG3 ***/ #pragma config USERID = 0xffff #pragma config FMIIEN = ON #pragma config FETHIO = ON #pragma config PGL1WAY = ON #pragma config PMDL1WAY = ON #pragma config IOL1WAY = ON #pragma config FUSBIDIO = OFF /*** BF1SEQ0 ***/ #pragma config TSEQ = 0xffff #pragma config CSEQ = 0xffff // ***************************************************************************** // ***************************************************************************** // Section: Library/Stack Initialization Data // ***************************************************************************** // *****************************************************************************/ // ***************************************************************************** // ***************************************************************************** // Section: Driver Initialization Data // ***************************************************************************** // ***************************************************************************** //<editor-fold defaultstate="collapsed" desc="DRV_Timer Configuration"> /*** TMR Driver Initialization Data ***/ const DRV_TMR_INIT drvTmr0InitData = { .moduleInit.sys.powerState = DRV_TMR_POWER_STATE_IDX0, .tmrId = DRV_TMR_PERIPHERAL_ID_IDX0, .clockSource = DRV_TMR_CLOCK_SOURCE_IDX0, .prescale = DRV_TMR_PRESCALE_IDX0, .mode = DRV_TMR_OPERATION_MODE_IDX0, .interruptSource = DRV_TMR_INTERRUPT_SOURCE_IDX0, .asyncWriteEnable = false, }; // </editor-fold> //<editor-fold defaultstate="collapsed" desc="DRV_USART Configuration"> const DRV_USART_INIT drvUsart0InitData = { .moduleInit = DRV_USART_POWER_STATE_IDX0, .usartID = DRV_USART_PERIPHERAL_ID_IDX0, .mode = DRV_USART_OPER_MODE_IDX0, .modeData = DRV_USART_OPER_MODE_DATA_IDX0, .flags = DRV_USART_INIT_FLAGS_IDX0, .brgClock = DRV_USART_BRG_CLOCK_IDX0, .lineControl = DRV_USART_LINE_CNTRL_IDX0, .baud = DRV_USART_BAUD_RATE_IDX0, .handshake = DRV_USART_HANDSHAKE_MODE_IDX0, .interruptTransmit = DRV_USART_XMIT_INT_SRC_IDX0, .interruptReceive = DRV_USART_RCV_INT_SRC_IDX0, .queueSizeTransmit = DRV_USART_XMIT_QUEUE_SIZE_IDX0, .queueSizeReceive = DRV_USART_RCV_QUEUE_SIZE_IDX0, }; // </editor-fold> //<editor-fold defaultstate="collapsed" desc="SYS_TMR Configuration"> /*** TMR Service Initialization Data ***/ const SYS_TMR_INIT sysTmrInitData = { .moduleInit = {SYS_MODULE_POWER_RUN_FULL}, .drvIndex = DRV_TMR_INDEX_0, .tmrFreq = 1000, }; // </editor-fold> // ***************************************************************************** // ***************************************************************************** // Section: System Data // ***************************************************************************** // ***************************************************************************** /* Structure to hold the object handles for the modules in the system. */ SYSTEM_OBJECTS sysObj; // ***************************************************************************** // ***************************************************************************** // Section: Module Initialization Data // ***************************************************************************** // ***************************************************************************** //<editor-fold defaultstate="collapsed" desc="SYS_DEVCON Configuration"> /*** System Device Control Initialization Data ***/ const SYS_DEVCON_INIT sysDevconInit = { .moduleInit = {0}, }; // </editor-fold> // ***************************************************************************** // ***************************************************************************** // Section: Static Initialization Functions // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // Section: System Initialization // ***************************************************************************** // ***************************************************************************** /******************************************************************************* Function: void SYS_Initialize ( SYS_INIT_DATA *data ) Summary: Initializes the board, services, drivers, application and other modules. Remarks: See prototype in system/common/sys_module.h. */ void SYS_Initialize ( void* data ) { /* Core Processor Initialization */ SYS_CLK_Initialize( NULL ); sysObj.sysDevcon = SYS_DEVCON_Initialize(SYS_DEVCON_INDEX_0, (SYS_MODULE_INIT*)&sysDevconInit); SYS_DEVCON_PerformanceConfig(SYS_CLK_SystemFrequencyGet()); SYS_PORTS_Initialize(); /* Initialize Drivers */ sysObj.drvTmr0 = DRV_TMR_Initialize(DRV_TMR_INDEX_0, (SYS_MODULE_INIT *)&drvTmr0InitData); SYS_INT_VectorPrioritySet(INT_VECTOR_T9, INT_PRIORITY_LEVEL1); SYS_INT_VectorSubprioritySet(INT_VECTOR_T9, INT_SUBPRIORITY_LEVEL0); sysObj.drvUsart0 = DRV_USART_Initialize(DRV_USART_INDEX_0, (SYS_MODULE_INIT *)&drvUsart0InitData); SYS_INT_VectorPrioritySet(INT_VECTOR_UART4_TX, INT_PRIORITY_LEVEL3); SYS_INT_VectorSubprioritySet(INT_VECTOR_UART4_TX, INT_SUBPRIORITY_LEVEL0); SYS_INT_VectorPrioritySet(INT_VECTOR_UART4_RX, INT_PRIORITY_LEVEL1); SYS_INT_VectorSubprioritySet(INT_VECTOR_UART4_RX, INT_SUBPRIORITY_LEVEL3); SYS_INT_VectorPrioritySet(INT_VECTOR_UART4_FAULT, INT_PRIORITY_LEVEL3); SYS_INT_VectorSubprioritySet(INT_VECTOR_UART4_FAULT, INT_SUBPRIORITY_LEVEL0); /* //レジスタ直接設定 U4MODEbits.ON = 1; //UART4 イネーブル U4MODEbits.PDSEL = 0b00; //データ幅8ビット、パリティなし U4MODEbits.STSEL = 0; //ストップビットx1個 // U4MODEbits.BRGH = 1; //ハイスピードボーレート イネーブル U4MODEbits.UEN = 0; //UARTx Enable bits //00: UxTX and UxRX pins are enabled and used; UxCTS and UxRTS/UxBCLK pins are controlled //by corresponding bits in the PORTx register U4STAbits.URXEN = 1; //レシーバーイネーブル U4STAbits.UTXEN = 1; //トランスミッターイネーブル U4STAbits.URXISEL = 0; //00: バッファに1文字受信したら割込みフラグがたつ //Interrupt flag bit is asserted while receive buffer is not empty (i.e., has at least 1 data character) U4BRG = (unsigned int)(100000000/16/9600 - 1); //baud rate: 9600bps //U4BRG = Fosc/BRGH/Baud Rate -1 */ /* Initialize RX interrupt */ PLIB_INT_SourceEnable(INT_ID_0, INT_SOURCE_USART_4_RECEIVE); //UART4受信割込み許可 // IEC5bits.U4RXIE = 1; //UART4受信割込み許可 //IEC5<11> /* Initialize System Services */ SYS_INT_Initialize(); /*** TMR Service Initialization Code ***/ sysObj.sysTmr = SYS_TMR_Initialize(SYS_TMR_INDEX_0, (const SYS_MODULE_INIT * const)&sysTmrInitData); /* Initialize Middleware */ /* Enable Global Interrupts */ SYS_INT_Enable(); /* Initialize the Application */ APP_Initialize(); } /******************************************************************************* End of File */ //以下、system_interrupt.c //---------------------------------------------------------------------- /******************************************************************************* System Interrupts File File Name: system_int.c Summary: Raw ISR definitions. Description: This file contains a definitions of the raw ISRs required to support the interrupt sub-system. Summary: This file contains source code for the interrupt vector functions in the system. Description: This file contains source code for the interrupt vector functions in the system. It implements the system and part specific vector "stub" functions from which the individual "Tasks" functions are called for any modules executing interrupt-driven in the MPLAB Harmony system. Remarks: This file requires access to the systemObjects global data structure that contains the object handles to all MPLAB Harmony module objects executing interrupt-driven in the system. These handles are passed into the individual module "Tasks" functions to identify the instance of the module to maintain. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2011-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include <xc.h> #include <sys/attribs.h> #include "app.h" #include "system_definitions.h" char Buf[17]; // ***************************************************************************** // ***************************************************************************** // Section: System Interrupt Vector Functions // ***************************************************************************** // ***************************************************************************** void __ISR(_TIMER_9_VECTOR, ipl1) _IntHandlerDrvTmrInstance0(void) { DRV_TMR_Tasks_ISR(sysObj.drvTmr0); } void __ISR(_UART4_TX_VECTOR, ipl3) _IntHandlerDrvUsartTransmitInstance0(void) { DRV_USART_TasksTransmit(sysObj.drvUsart0); DRV_USART_TasksError(sysObj.drvUsart0); } void __ISR(_UART4_RX_VECTOR, ipl1) _IntHandlerDrvUsartReceiveInstance0(void) { if (PLIB_USART_ReceiverDataIsAvailable(USART_ID_4)) //受信データ有の場合 // if(U4STAbits.URXDA == 1) //受信データ有の場合 //Receive buffer has data, at least one more character can be read { char data; data = PLIB_USART_ReceiverByteReceive(USART_ID_4); //受信データ読み込み //data = U4RXREG; //受信バッファ読み込み sprintf(Buf,"data=%c\r\n",data); WriteString(Buf); //文字列送信 } /* Clear pending interrupt */ PLIB_INT_SourceFlagClear(INT_ID_0, INT_SOURCE_USART_4_RECEIVE); //IFS5bits.U4RXIF = 0; //RX割込みフラグクリア } void __ISR(_UART4_FAULT_VECTOR, ipl3) _IntHandlerDrvUsartErrorInstance0(void) { SYS_ASSERT(false, "USART Driver Instance 0 Error"); } /******************************************************************************* End of File */
<動作結果>
下記操作結果後の Tera Term画面です。
1. Tera Term を立ち上げた状態で PIC32MZ2048ECH100を起動する。 → Hellow Wolrd !!
2. キーボードで Aを 打鍵 → data=A
3. キーボードで Bを 打鍵 → data=B
4. キーボードで Cを 打鍵 → data=C
(2)文字列の送受信 (フロー制御なし、PIC側:LCD付、 割込みあり、タイムアウトなし、ハイパーターミナル - PIC間)
割込み制御レジスタのUSART受信完了フラグがたった時、割込みを発生させることができます。この受信割込みをつか
ってデータを受信する方法を紹介します。
<試作品仕様>
PCのCOMポートとPICをつなぎ Windowsのハイパーターミナルの画面に以下を表示する。
・ PCのキーボードからキーインした文字をエコーバックにより 以下のように表示する
(例) 3番目にキーインした文字がDの場合 …… buf[2]=D
・ エンターキーが押された場合は、それまでにキーインした文字がすべて1行に連続して表示されること
(例) ”A” ”B” ”C” ”D” ”E” とキーインしたあとにエンターきーがキーインされた場合 …… ABCDE
<試作品回路図>(→回路図のPDFファイル)
PIC18F452をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
以下のプログラム例の中にある液晶表示器制御ライブラリ 1llcd_lib.cは 後閑哲也さんが設計されたものです |
<プログラム例> <CCS編>
// PCのハイパーターミナル → RS232C → PIC18F452 + LCD // RDA割込みによる受信 /* PCモニタ出力 buf[0]=a buf[1]=b buf[2]=c abc buf[0]=1 buf[1]=2 buf[2]=3 buf[3]=4 buf[4]=5 12345 */ #include "18f452.h" #use delay(clock=40000000) // 40MHz(システムクロック周波数)=10MHz(外部発振子周波数)×4(PLL倍率) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7,stream=PC) // ボーレート = 9600bps TX=RC6,RX=RC7 #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //rs #define stb PIN_D0 //strobe #include <1lcd_lib.c> char buf[20]; int i =0; #INT_RDA void rs232c() { buf[i] = getc(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; printf(buf); // 送信されてきていた文字を 文字列としてPCに一括送信 putc('\r');putc('\n');putc('\r');putc('\n'); //1行あける //液晶に出力 lcd_clear();// 液晶オールクリア lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,buf); // 送信されてきていた文字を液晶の2行目に一括表示 i = 0; } else //Enter キー以外が押された場合 { printf("buf[%d]=%c\r\n",i,buf[i]); // PCへエコーバック → ハイパーターミナルに表示 //液晶に出力 lcd_clear();// 液晶オールクリア printf(lcd_data,"buf[%d]=%c",i,buf[i]);// PICに接続してある液晶に受信文字を表示 i++; } } main(){ set_tris_c(0b10000000);// 必須 in = RC7 & RC4 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"start!!"); enable_interrupts(INT_RDA); enable_interrupts(GLOBAL); while(1) { } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<プログラム例><C18編>
/* PC-PIC間 RS232C通信 受信 : 受信時割込み方式 PC : ハイパーターミナル PIC : 18F452 液晶付 */ #include <p18f452.h> #include <usart.h> #include <stdio.h> #include "1lcd_lib_C18.h" #include "1lcd_lib_C18.c" #pragma config OSC = HSPLL // f = 40MHz ( = 10MHz × 4(PLL)) #pragma config WDT = OFF #pragma config LVP = OFF char buf[20]; // タイプした文字用のレジスタ int i = 0; void RS232(void); #pragma code low_vector=0x18 //低位レベル割込み void low_interrupt (void) { _asm GOTO RS232 _endasm } #pragma code #pragma interruptlow RS232 void RS232() // 受信割込み関数 { char Buffer[17]; //液晶表示データの一時保存レジスタ char* str; PIR1bits.RCIF = 0; //PIR1 レジスタのRCIFビット(受信フラグ)をクリア buf[i] = getcUSART(); //受信データを読み込む if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; str = &buf[0]; // ポインタにアドレスを代入 printf("%s",str); // 送信されてきていた文字を 文字列としてPCに一括送信 printf("\n\r\n\r"); //1行あける //PIC側液晶への表示 lcd_clear();// 液晶オールクリア lcd_cmd(0xC0);//2行目の先頭へ while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; } i = 0; } else //Enter キー以外が押された場合 { printf("buf[%d]=%c\r\n",i,buf[i]); // PCへエコーバック → ハイパーターミナルに表示 //PIC側液晶への表示 lcd_clear();// 液晶オールクリア sprintf(Buffer,"buf[%d]=%c",i,buf[i]);// PICに接続してある液晶に受信文字を表示 str = &Buffer[0]; // ポインタにアドレスを代入 while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; } i++; } } void main (void) { char tempBuf[17]; //液晶表示データの一時保存レジスタ char* tempStr; TRISC = 0b11111101; //RC7(RX): input mode RC6(TX): output mode OpenUSART( USART_TX_INT_OFF & //送信割込み:OFF USART_RX_INT_ON & //割込み受信:ON USART_ASYNCH_MODE & //調歩同期通信モード USART_EIGHT_BIT & //データ長:8ビット USART_CONT_RX & //連続受信モード USART_BRGH_LOW, //ボーレート:低伝送速度モード //bau rate = Fosc/(64*(spbrg + 1)) 64 ); // = 40000000/(64*(64 + 1)) = 9615.4 bps // error rate = (9615.4-9600)/9600 = 0.0016 //PIC側液晶表示 lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF sprintf(tempBuf,"Start !!"); //文字列としてバッファーに収納 tempStr = &tempBuf[0]; // ポインタにアドレスを代入 while(*tempStr) //文字列終端の '\0'を検出するまで { lcd_data(*tempStr); // 1文字表示 tempStr++; } RCONbits.IPEN = 0; //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0) INTCONbits.GIE = 1; //全割込み許可 INTCONbits.PEIE = 1; //周辺機能の割込み有効 while (1) { } CloseUSART(); } //************************************************************************* //インクルードファイル 1lcd_lib_C18.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ //1lcd_lib.cをC18コンパイラ用に変更したものです。 //************************************************************************* #define lcd_port LATD //DataOutPort pin : 上位4bit #define lcd_stb LATDbits.LATD0 //stb OutPort #define lcd_rs LATDbits.LATD2 // rs OutPort #define port_Mode TRISD // Port Mode set void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_out(char code, char flag); //************************************************************************** //インクルードファイル 1lcd_lib_C18.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ //1lcd_lib.cをC18コンパイラ用に変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C18コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 ////////////////////////////////////////////// #include "delays.h" #include "1lcd_lib_C18.h" //////// データ出力サブ関数 void lcd_out(char code, char flag) { port_Mode = 0; // PIC側の DataPort、stbPort、 rsPort を出力モードに設定 lcd_port = code & 0xF0; if (flag == 0) lcd_rs = 1; //表示データの場合 else lcd_rs = 0; //コマンドデータの場合 Delay10TCYx(1); //10NOP lcd_stb = 1; //strobe out Delay10TCYx(1); //10NOP lcd_stb = 0; //reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 Delay10TCYx(50); //500NOP (50μsec待ち at 40MHz) } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 if((cmd & 0x03) != 0) Delay10KTCYx(2); //2msec待ち at 40MHz else Delay10TCYx(50); //50usec待ち at 40MHz } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); //初期化コマンド出力 // Delay10KTCYx(15); //15msec待ち at 40MHz } /////// 初期化関数 void lcd_init(void) { lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(5); //5msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x20, 1); //4bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x01); //all clear }
<動作結果>
1.PCのキーボードから”Hello”をキーインして、次のキーインを待っている状態における ハイパーターミナルと液晶の
画面を以下に示します。
<ハイパーターミナルの画面> | <液晶画面> | |
2.PCのキーボードから”Hellow” ”エンター” ”World !!” ”エンター” と キーインした後のハイパーターミナルと液晶の
画面を以下に示します。
<ハイパーターミナル画面> | <液晶画面> | |
文字列の送受信 (フロー制御なし、PIC側:LCD付、 割込みあり、Tera Term - PIC間)
<PIC18F4550 CCS編>
割込み制御レジスタのUSART受信完了フラグがたった時、割込みを発生させることができます。この受信割込みをつか
ってデータを受信する方法を紹介します。
<試作品仕様>
PCのCOMポートとPICをつなぎ Windowsの Tera Term の画面に以下を表示する。
・ PCのキーボードからキーインした文字をエコーバックにより 以下のように表示する
(例) 3番目にキーインした文字がDの場合 …… buf[2]=D
・ エンターキーが押された場合は、それまでにキーインした文字がすべて1行に連続して表示されること
(例) ”A” ”B” ”C” ”D” ”E” とキーインしたあとにエンターきーがキーインされた場合 …… ABCDE
<試作品回路図>(→回路図のPDFファイル)
PIC18F4550をつかった場合の回路図を以下に示します。
<プログラム例>
// PC側 Tera Term → RS232C → PIC18F4550 + LCD // RDA割込みによる受信 /* PCモニタ出力 buf[0]=a buf[1]=b buf[2]=c abc buf[0]=1 buf[1]=2 buf[2]=3 buf[3]=4 buf[4]=5 12345 */ #include "18f4550.h" #use delay(clock=20000000) // 20MHz(システムクロック周波数) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7,stream=PC) // ボーレート = 9600bps TX=RC6,RX=RC7 #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //rs #define stb PIN_D0 //strobe #include <1lcd_lib.c> char buf[20]; int i =0; #INT_RDA void rs232c() { buf[i] = getc(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; printf(buf); // 送信されてきていた文字を 文字列としてPCに一括送信 putc('\r');putc('\n');putc('\r');putc('\n'); //1行あける //液晶に出力 lcd_clear();// 液晶オールクリア lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,buf); // 送信されてきていた文字を液晶の2行目に一括表示 i = 0; } else //Enter キー以外が押された場合 { printf("buf[%d]=%c\r\n",i,buf[i]); // PCへエコーバック → ハイパーターミナルに表示 //液晶に出力 lcd_clear();// 液晶オールクリア printf(lcd_data,"buf[%d]=%c",i,buf[i]);// PICに接続してある液晶に受信文字を表示 i++; } } main(){ set_tris_c(0b10000000);// 必須 in = RC7 & RC4 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"start!!"); enable_interrupts(INT_RDA); enable_interrupts(GLOBAL); while(1) { } return 0; }
//--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<動作結果>
Tera Termの画面 | 液晶 | |
文字列の送受信 PC(Tera Term)−PIC間 割り込みなし PIC32MX編
<試作品仕様>
・ PCのCOMポートとPICをつなぎ WindowsのTera Termの画面に以下を表示する。
・ PCのキーボードからキーインした文字(PICへの送信文字)をローカルエコーにより ”SendData=”のあとに表示する。
・ PICは文字データを受信したら改行・復帰の制御文字を送信後、”文字列”Receive_Data=”をPCへ送信する。
・ 更に PICは受信文字、ASCIIコードで受信文字の次の文字 及びASCIIコードで次の次の文字を3つ続けてPCへ返信する。
・ Tera Term の ローカルエコーはONにしておくこと
・ PIC側では 液晶1行目に受信文字を、2行目には送信文字を表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC32MX795F512Lをつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> // UART PC-PIC // PIC32MX795F512L #include <proc/p32mx795f512l.h> //PIC32MX795F512L #include <plib.h> // PIC32 peripheral library //for SYSTEMConfigPerformance() #include <stdio.h> #include "1lcd_lib_C32.h" // Configuration // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 char Buffer[3]; char Buf[17]; // int main(void) { SYSTEMConfigPerformance(80000000); // システム最適化 TRISE = 0; //Eポートを出力モードに設定 OpenUART2 //UART2の設定(U2MODEレジスタ,U2STAレジスタ,U2BRGレジスタの設定) ( UART_EN | // UART enable/disable // UART_RX_TX | //UART communication with ALT pins // UART_DIS_WAKE | //UART Wake-up on Start // UART_DIS_LOOPBACK | //UART Loopback mode enable/disable // UART_DIS_ABAUD | //Input to Capture module UART_NO_PAR_8BIT | // Parity and data bits select UART_1STOPBIT | // Number of Stop bits // UART_IRDA_DIS | //IRDA Enable/Disable // UART_MODE_SIMPLEX | //RTS Mode Select // UART_MODE_FLOWCTRL | //RTS Mode Select // UART_DIS_BCLK_CTS_RTS | // // UART_NORMAL_RX | //Recievie Polarity UART_BRGH_SIXTEEN, //BRGH = 16 //High Baud Rate Select // UART_INT_TX_BUF_EMPTY | //UART Transmission mode interrupt flag select // UART_TX_PIN_LOW | //UART Transmit Break bit UART_TX_ENABLE | //UART transmit enable/disable UART_RX_ENABLE , //UART recieve enable/disable // UART_INT_RX_CHAR | //UART Receive Interrupt mode select // UART_ADR_DETECT_DIS | //UART address detect enable/disable // UART_RX_OVERRUN_CLEAR //UART OVERRUN bit clear (unsigned int)(80000000/16/9600-1) // = Fosc/BRGH/Baud Rate -1 //baud rate: 9600bps ); setbuf(stdout,NULL); //Line buffering off lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"UART PC_PIC !!");//C30とは異なり、arguement 不要 lcd_str(Buf); //液晶表示 while(1) { //永久ループ putsUART2("Send_Data="); //データ送信要求 while(!DataRdyUART2()); //UARTバッファーにデータがくるまでまつ Buffer[0] = getcUART2(); //バッファーデータ読み込み Buffer[1] = Buffer[0] + 1; //ASCIIコードで次の値をセット Buffer[2] = Buffer[0] + 2; //ASCIIコードで次の次の値をセット putsUART2("\n\r"); //改行、復帰 printf("Receive_Data=%c%c%c",Buffer[0],Buffer[1],Buffer[2]); //返信データを送信 lcd_clear(); //全消去 sprintf(Buf,"Buf[0]=%c",Buffer[0]); //バッファーに文字列をセット lcd_str(Buf); // 開始メッセージ1行目表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"[0][1][2]=%c%c%c",Buffer[0],Buffer[1],Buffer[2]); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ1行目表示 putsUART2("\n\r"); //改行、復帰 putsUART2("\n\r"); //改行、復帰 } }
<動作結果>
PC(Tera Term) | ||
PIC側液晶表示 | 1を送信した場合 | |
2を送信した場合 | ||
aを送信した場合 | ||
bを送信した場合 |
文字列の送受信 PC(Tera Term)−PIC間 割り込み有 PIC32MX編
<試作品仕様>
・ PCのCOMポートとPICをつなぎ WindowsのTera Termの画面に以下を表示する。
・ PCのキーボードからキーインした文字(PICへの送信文字)をローカルエコーにより ”SendData=”のあとに表示する。
・ PICは文字データを受信したら改行・復帰の制御文字を送信後、”文字列”Receive_Data=”をPCへ送信する。
・ 更に PICは受信文字、ASCIIコードで受信文字の次の文字 及びASCIIコードで次の次の文字を3つ続けてPCへ返信する。
・ Tera Term の ローカルエコーはONにしておくこと
・ PIC側では 液晶1行目に受信文字を、2行目には送信文字を表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC32MX795F512Lをつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> // UART PC-PIC //割り込み方式 // PIC32MX795F512L #include <proc/p32mx795f512l.h> //PIC32MX795F512L #include <plib.h> // PIC32 peripheral library //for SYSTEMConfigPerformance() #include <stdio.h> #include "1lcd_lib_C32.h" // Configuration // CPU=80MHz Peri=80MHz,HS+PLL,Divider=1/2,PLL=x20,WDT=Off #pragma config FNOSC=PRIPLL, POSCMOD=HS, FPLLIDIV=DIV_2 #pragma config FPLLMUL=MUL_20, FPBDIV=DIV_1, FPLLODIV=DIV_1 #pragma config FWDTEN=OFF, ICESEL=ICS_PGx2 char Buffer[3]; char Buf[17]; // void __ISR(_UART2_VECTOR, ipl2) IntUart2Handler(void) { if(mU2RXGetIntFlag()) // RXの割り込み? { mU2RXClearIntFlag(); // 割り込みフラグクリア putsUART2("Send_Data="); //データ送信要求 while(!DataRdyUART2()); //UARTバッファーにデータがくるまでまつ Buffer[0] = getcUART2(); //バッファーデータ読み込み Buffer[1] = Buffer[0] + 1; //ASCIIコードで次の値をセット Buffer[2] = Buffer[0] + 2; //ASCIIコードで次の次の値をセット putsUART2("\n\r"); //改行、復帰 printf("Receive_Data=%c%c%c",Buffer[0],Buffer[1],Buffer[2]); //返信データを送信 lcd_clear(); //全消去 sprintf(Buf,"Buf[0]=%c",Buffer[0]); //バッファーに文字列をセット lcd_str(Buf); // 開始メッセージ1行目表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"[0][1][2]=%c%c%c",Buffer[0],Buffer[1],Buffer[2]); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ1行目表示 putsUART2("\n\r"); //改行、復帰 putsUART2("\n\r"); //改行、復帰 } } int main(void) { SYSTEMConfigPerformance(80000000); // システム最適化 TRISE = 0; //Eポートを出力モードに設定 OpenUART2 //UART2の設定(U2MODEレジスタ,U2STAレジスタ,U2BRGレジスタの設定) ( UART_EN | // UART enable/disable // UART_RX_TX | //UART communication with ALT pins // UART_DIS_WAKE | //UART Wake-up on Start // UART_DIS_LOOPBACK | //UART Loopback mode enable/disable // UART_DIS_ABAUD | //Input to Capture module UART_NO_PAR_8BIT | // Parity and data bits select UART_1STOPBIT | // Number of Stop bits // UART_IRDA_DIS | //IRDA Enable/Disable // UART_MODE_SIMPLEX | //RTS Mode Select // UART_MODE_FLOWCTRL | //RTS Mode Select // UART_DIS_BCLK_CTS_RTS | // // UART_NORMAL_RX | //Recievie Polarity UART_BRGH_SIXTEEN, //BRGH = 16 //High Baud Rate Select // UART_INT_TX_BUF_EMPTY | //UART Transmission mode interrupt flag select // UART_TX_PIN_LOW | //UART Transmit Break bit UART_TX_ENABLE | //UART transmit enable/disable UART_RX_ENABLE , //UART recieve enable/disable // UART_INT_RX_CHAR | //UART Receive Interrupt mode select // UART_ADR_DETECT_DIS | //UART address detect enable/disable // UART_RX_OVERRUN_CLEAR //UART OVERRUN bit clear (unsigned int)(80000000/16/9600-1) // = Fosc/BRGH/Baud Rate -1 //baud rate: 9600bps ); setbuf(stdout,NULL); //Line buffering off lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"UART PC_PIC !!");//C30とは異なり、arguement 不要 lcd_str(Buf); //液晶に表示 ConfigIntUART2(UART_INT_PR2 | UART_RX_INT_EN); //UART2割り込みレベルをレベル2に設定 INTEnableSystemMultiVectoredInt(); //マルチベクトル割り込み許可 while(1) { //永久ループ } }
<動作結果>
PC(Tera Term) | ||
PIC側液晶表示 | 1を送信した場合 | |
2を送信した場合 | ||
aを送信した場合 | ||
bを送信した場合 |
■ 文字列の送受信 PC - PIC間 ( Harmony + PIC32MZ2048ECH100編 )
PC側のソフトについては VC# PCソフト 文字列送受信 を参照願います。
<試作品仕様>
・PCとターゲットボード間はUSB/RS232C変換ケーブルを使い PIC側からみてのインターフェースはRS232Cとする
・USB/RS232C変換ケーブルはUSBシリアルコンバーター REX-USB60F(ラトックシステム(株))とする
・RS232C通信は以下とする。
フロー制御なし、9600bps、ストップビットx1、パリティなし
・パソコン側より 下記送信文字列に対し PIC側は対応する文字列を返信すること
Japan ---> Tokyo
America ---> Washinton
U.K. ---> London
France --> Paris
その他 --> Pardon ?
・PC側は、受信文字列をテキストエディタに表示のこと
・PIC側は、 受信文字列 及び返信文字列をキャラクタ液晶のそれぞれ上段と下段に表示のこと
・開発環境 ver.1.02 Harmony ver.1.34 XC32 ver2.30 MPLABX rev.5 PIC32MZ2048ECH100
Windows 8.1 VC#2012
<試作品回路図>(→回路図のPDFファイル)
PIC32MZ2048ECH100をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //以下、main.c //------------------------------------------------------------------------------------ /******************************************************************************* MPLAB Harmony Project Main Source File Company: Microchip Technology Inc. File Name: main.c Summary: This file contains the "main" function for an MPLAB Harmony project. Description: This file contains the "main" function for an MPLAB Harmony project. The "main" function calls the "SYS_Initialize" function to initialize the state machines of all MPLAB Harmony modules in the system and it calls the "SYS_Tasks" function from within a system-wide "super" loop to maintain their correct operation. These two functions are implemented in configuration-specific files (usually "system_init.c" and "system_tasks.c") in a configuration-specific folder under the "src/system_config" folder within this project's top-level folder. An MPLAB Harmony project may have more than one configuration, each contained within it's own folder under the "system_config" folder. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. //Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include <stddef.h> // Defines NULL #include <stdbool.h> // Defines true #include <stdlib.h> // Defines EXIT_FAILURE #include "system/common/sys_module.h" // SYS function prototypes // ***************************************************************************** // ***************************************************************************** // Section: Main Entry Point // ***************************************************************************** // ***************************************************************************** int main ( void ) { /* Initialize all MPLAB Harmony modules, including application(s). */ SYS_Initialize ( NULL ); while ( true ) { /* Maintain state machines of all polled MPLAB Harmony modules. */ SYS_Tasks ( ); } /* Execution should not come here during normal operation */ return ( EXIT_FAILURE ); } /******************************************************************************* End of File */ //以下、app.c //---------------------------------------------------------------------------------- /******************************************************************************* MPLAB Harmony Application Source File Company: Microchip Technology Inc. File Name: app.c Summary: This file contains the source code for the MPLAB Harmony application. Description: This file contains the source code for the MPLAB Harmony application. It implements the logic of the application's state machine and it may call API routines of other MPLAB Harmony modules in the system, such as drivers, system services, and middleware. However, it does not call any of the system interfaces (such as the "Initialize" and "Tasks" functions) of any of the modules in the system or make any assumptions about when those functions are called. That is the responsibility of the configuration-specific system files. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include "app.h" #include "1lcd_lib_C32.h" int delay_Clock = 200000000; //200MHz char Buf[17]; //1液晶表示バッファー int ix = 0; char* str; char buf[20]; extern char data; extern int Flag ; char Japan[] = "Japan"; char America[] = "America"; char UK[] = "U.K."; char France[] = "France"; char Tokyo[] = "Tokyo"; char Washinton[] = "Washinton"; char London[] = "London"; char Paris[] = "Paris"; char Pardon[] = "Pardon ?"; void delay_us(volatile unsigned int usec) //1μsec遅延 { volatile int count; count = (int)(delay_Clock/20000000)*usec; do //実測 at 200MH (Clock=200000000) { //delay_us(1000):1000.4μsec delay_us(100):100.6μsec delay_us(10):10.5μsec delay_us(1):1.5μsec asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void delay_ms(volatile unsigned int msec) //1msec遅延 { volatile unsigned int i; //実測:at200MH (Clock=200000000)//delay_ms(1): 1.0006msec delay_ms(100):100.04msec for(i=0; i<msec; i++) delay_us(1000); } void Write_Byte(char chr) //1バイト送信関数 { PLIB_USART_TransmitterByteSend(USART_ID_4, chr); //送信バッファーに1バイト書込み・送信 // U4TXREG = chr; ////送信バッファーに1バイト書込み・送信 while (!PLIB_USART_TransmitterIsEmpty(USART_ID_4)); //送信バッファーが空になるまで待つ // while(!U4STAbits.TRMT); //送信バッファーが空になるまで待つ } void WriteString(const char *str) //文字列送信関数 { while(*str) { Write_Byte(*str); //データ送信 str++; } } void SendData(void) { buf[ix] = data; if(buf[ix] == '\r') // Enter キーが押された場合 { buf[ix] = '\0'; if(strcmp(buf,Japan) == 0)str = Tokyo; else if(strcmp(buf,America) == 0) str = Washinton; else if(strcmp(buf,UK) == 0) str = London; else if(strcmp(buf,France) == 0) str = Paris; else str = Pardon; ix = 0; sprintf(Buf,"%s\n",str); WriteString(Buf); //文字列送信 lcd_cmd(0x80); //1目の先頭へ sprintf(Buf,"%s ",buf); lcd_str(Buf); //液晶表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"%s ",str); lcd_str(Buf); // 開始メッセージ1行目表示 } else //Enter キー以外が押された場合 { ix++; } } // ***************************************************************************** // ***************************************************************************** // Section: Global Data Definitions // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** /* Application Data Summary: Holds application data Description: This structure holds the application's data. Remarks: This structure should be initialized by the APP_Initialize function. Application strings and buffers are be defined outside this structure. */ APP_DATA appData; // ***************************************************************************** // ***************************************************************************** // Section: Application Callback Functions // ***************************************************************************** // ***************************************************************************** /* TODO: Add any necessary callback funtions. */ // ***************************************************************************** // ***************************************************************************** // Section: Application Local Functions // ***************************************************************************** // ***************************************************************************** /* TODO: Add any necessary local functions. */ // ***************************************************************************** // ***************************************************************************** // Section: Application Initialization and State Machine Functions // ***************************************************************************** // ***************************************************************************** /******************************************************************************* Function: void APP_Initialize ( void ) Remarks: See prototype in app.h. */ void APP_Initialize ( void ) { /* Place the App state machine in its initial state. */ appData.state = APP_STATE_INIT; /* TODO: Initialize your application's state machine and other * parameters. */ lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_cmd(0x80); //1目の先頭へ sprintf(Buf,"UART to PC ");// lcd_str(Buf); //液晶表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf," Start !! "); // lcd_str(Buf); // 開始メッセージ1行目表示 delay_ms(2000); } /****************************************************************************** Function: void APP_Tasks ( void ) Remarks: See prototype in app.h. */ void APP_Tasks ( void ) { /* Check the application's current state. */ switch ( appData.state ) { /* Application's initial state. */ case APP_STATE_INIT: { break; } /* TODO: implement your application state machine.*/ /* The default state should never be executed. */ default: { /* TODO: Handle error in application's state machine. */ break; } } } /******************************************************************************* End of File */ //以下、sys_ports_static.c //------------------------------------------------------------------------------- /******************************************************************************* SYS PORTS Static Functions for PORTS System Service Company: Microchip Technology Inc. File Name: sys_ports_static.c Summary: SYS PORTS static function implementations for the Ports System Service. Description: The Ports System Service provides a simple interface to manage the ports on Microchip microcontrollers. This file defines the static implementation for the Ports System Service. Remarks: Static functions incorporate all system ports configuration settings as determined by the user via the Microchip Harmony Configurator GUI. It provides static version of the routines, eliminating the need for an object ID or object handle. *******************************************************************************/ //DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ //DOM-IGNORE-END #include "system_config.h" #include "peripheral/ports/plib_ports.h" #include "peripheral/int/plib_int.h" void SYS_PORTS_Initialize(void) { //リマップ /* PPS Input Remapping */ PLIB_PORTS_RemapInput(PORTS_ID_0, INPUT_FUNC_U4RX, INPUT_PIN_RPE8 ); //U4RXにRE8を設定 /* PPS Output Remapping */ PLIB_PORTS_RemapOutput(PORTS_ID_0, OUTPUT_FUNC_U4TX, OUTPUT_PIN_RPE9 ); //U4TXにRE9を設定 PLIB_PORTS_PinDirectionInputSet( PORTS_ID_0, PORT_CHANNEL_E, 8);//入力ポートに設定 // TRISEbits.TRISE8 = 1; //RE8:入力(RX)ポートに設定 PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_E, 9);//出力ポートに設定 // TRISEbits.TRISE9 = 0; //RE9:出力(TX) ポートに設定 PLIB_PORTS_PinModeSelect(PORTS_ID_0, PORTS_ANALOG_PIN_25, PORTS_PIN_MODE_DIGITAL); //RE8/AN25ポートをデジタルモードに設定 // ANSELEbits.ANSE8 = 0; //RE8 デジタルモード PLIB_PORTS_PinModeSelect(PORTS_ID_0, PORTS_ANALOG_PIN_26, PORTS_PIN_MODE_DIGITAL); //RE9/AN26ポートをデジタルモードに設定 // ANSELEbits.ANSE9 = 0; //RE9 デジタルモード //液晶ポート入出力設定----------------------------- PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_B, 15 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_B, 14 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_B, 13 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_B, 12 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_A, 10 ); PLIB_PORTS_PinDirectionOutputSet( PORTS_ID_0, PORT_CHANNEL_A, 9 ); /* TRISBbits.TRISB15 = 0; //キャラクタ液晶ポート設定 TRISBbits.TRISB14 = 0; //キャラクタ液晶ポート設定 TRISBbits.TRISB13 = 0; //キャラクタ液晶ポート設定 TRISBbits.TRISB12 = 0; //キャラクタ液晶ポート設定 TRISAbits.TRISA10 = 0; //キャラクタ液晶ポート設定 TRISAbits.TRISA9 = 0; //キャラクタ液晶ポート設定 */ } /******************************************************************************* End of File */ //以下、system_init.c //------------------------------------------------------------------------------------- /******************************************************************************* System Initialization File File Name: system_init.c Summary: This file contains source code necessary to initialize the system. Description: This file contains source code necessary to initialize the system. It implements the "SYS_Initialize" function, configuration bits, and allocates any necessary global system resources, such as the systemObjects structure that contains the object handles to all the MPLAB Harmony module objects in the system. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2013-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include "system_config.h" #include "system_definitions.h" #include "app.h" // **************************************************************************** // **************************************************************************** // Section: Configuration Bits // **************************************************************************** // **************************************************************************** /*** DEVCFG0 ***/ #pragma config DEBUG = OFF #pragma config JTAGEN = OFF #pragma config ICESEL = ICS_PGx1 #pragma config TRCEN = OFF #pragma config BOOTISA = MIPS32 #pragma config FECCCON = OFF_UNLOCKED #pragma config FSLEEP = OFF #pragma config DBGPER = PG_ALL #pragma config EJTAGBEN = NORMAL #pragma config CP = OFF /*** DEVCFG1 ***/ #pragma config FNOSC = SPLL #pragma config DMTINTV = WIN_127_128 #pragma config FSOSCEN = OFF #pragma config IESO = OFF #pragma config POSCMOD = HS #pragma config OSCIOFNC = OFF #pragma config FCKSM = CSECME #pragma config WDTPS = PS1048576 #pragma config WDTSPGM = STOP #pragma config FWDTEN = OFF #pragma config WINDIS = NORMAL #pragma config FWDTWINSZ = WINSZ_25 #pragma config DMTCNT = DMT31 #pragma config FDMTEN = OFF /*** DEVCFG2 ***/ #pragma config FPLLIDIV = DIV_3 #pragma config FPLLRNG = RANGE_5_10_MHZ #pragma config FPLLICLK = PLL_FRC //バグ修正 //#pragma config FPLLICLK = PLL_POSC #pragma config FPLLMULT = MUL_50 #pragma config FPLLODIV = DIV_2 #pragma config UPLLFSEL = FREQ_24MHZ #pragma config UPLLEN = ON /*** DEVCFG3 ***/ #pragma config USERID = 0xffff #pragma config FMIIEN = ON #pragma config FETHIO = ON #pragma config PGL1WAY = ON #pragma config PMDL1WAY = ON #pragma config IOL1WAY = ON #pragma config FUSBIDIO = OFF /*** BF1SEQ0 ***/ #pragma config TSEQ = 0xffff #pragma config CSEQ = 0xffff // ***************************************************************************** // ***************************************************************************** // Section: Library/Stack Initialization Data // ***************************************************************************** // *****************************************************************************/ // ***************************************************************************** // ***************************************************************************** // Section: Driver Initialization Data // ***************************************************************************** // ***************************************************************************** //<editor-fold defaultstate="collapsed" desc="DRV_Timer Configuration"> /*** TMR Driver Initialization Data ***/ const DRV_TMR_INIT drvTmr0InitData = { .moduleInit.sys.powerState = DRV_TMR_POWER_STATE_IDX0, .tmrId = DRV_TMR_PERIPHERAL_ID_IDX0, .clockSource = DRV_TMR_CLOCK_SOURCE_IDX0, .prescale = DRV_TMR_PRESCALE_IDX0, .mode = DRV_TMR_OPERATION_MODE_IDX0, .interruptSource = DRV_TMR_INTERRUPT_SOURCE_IDX0, .asyncWriteEnable = false, }; // </editor-fold> //<editor-fold defaultstate="collapsed" desc="DRV_USART Configuration"> const DRV_USART_INIT drvUsart0InitData = { .moduleInit = DRV_USART_POWER_STATE_IDX0, .usartID = DRV_USART_PERIPHERAL_ID_IDX0, .mode = DRV_USART_OPER_MODE_IDX0, .modeData = DRV_USART_OPER_MODE_DATA_IDX0, .flags = DRV_USART_INIT_FLAGS_IDX0, .brgClock = DRV_USART_BRG_CLOCK_IDX0, .lineControl = DRV_USART_LINE_CNTRL_IDX0, .baud = DRV_USART_BAUD_RATE_IDX0, .handshake = DRV_USART_HANDSHAKE_MODE_IDX0, .interruptTransmit = DRV_USART_XMIT_INT_SRC_IDX0, .interruptReceive = DRV_USART_RCV_INT_SRC_IDX0, .queueSizeTransmit = DRV_USART_XMIT_QUEUE_SIZE_IDX0, .queueSizeReceive = DRV_USART_RCV_QUEUE_SIZE_IDX0, }; // </editor-fold> //<editor-fold defaultstate="collapsed" desc="SYS_TMR Configuration"> /*** TMR Service Initialization Data ***/ const SYS_TMR_INIT sysTmrInitData = { .moduleInit = {SYS_MODULE_POWER_RUN_FULL}, .drvIndex = DRV_TMR_INDEX_0, .tmrFreq = 1000, }; // </editor-fold> // ***************************************************************************** // ***************************************************************************** // Section: System Data // ***************************************************************************** // ***************************************************************************** /* Structure to hold the object handles for the modules in the system. */ SYSTEM_OBJECTS sysObj; // ***************************************************************************** // ***************************************************************************** // Section: Module Initialization Data // ***************************************************************************** // ***************************************************************************** //<editor-fold defaultstate="collapsed" desc="SYS_DEVCON Configuration"> /*** System Device Control Initialization Data ***/ const SYS_DEVCON_INIT sysDevconInit = { .moduleInit = {0}, }; // </editor-fold> // ***************************************************************************** // ***************************************************************************** // Section: Static Initialization Functions // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // ***************************************************************************** // Section: System Initialization // ***************************************************************************** // ***************************************************************************** /******************************************************************************* Function: void SYS_Initialize ( SYS_INIT_DATA *data ) Summary: Initializes the board, services, drivers, application and other modules. Remarks: See prototype in system/common/sys_module.h. */ void SYS_Initialize ( void* data ) { /* Core Processor Initialization */ SYS_CLK_Initialize( NULL ); sysObj.sysDevcon = SYS_DEVCON_Initialize(SYS_DEVCON_INDEX_0, (SYS_MODULE_INIT*)&sysDevconInit); SYS_DEVCON_PerformanceConfig(SYS_CLK_SystemFrequencyGet()); SYS_PORTS_Initialize(); /* Initialize Drivers */ sysObj.drvTmr0 = DRV_TMR_Initialize(DRV_TMR_INDEX_0, (SYS_MODULE_INIT *)&drvTmr0InitData); SYS_INT_VectorPrioritySet(INT_VECTOR_T9, INT_PRIORITY_LEVEL1); SYS_INT_VectorSubprioritySet(INT_VECTOR_T9, INT_SUBPRIORITY_LEVEL0); sysObj.drvUsart0 = DRV_USART_Initialize(DRV_USART_INDEX_0, (SYS_MODULE_INIT *)&drvUsart0InitData); SYS_INT_VectorPrioritySet(INT_VECTOR_UART4_TX, INT_PRIORITY_LEVEL3); SYS_INT_VectorSubprioritySet(INT_VECTOR_UART4_TX, INT_SUBPRIORITY_LEVEL0); SYS_INT_VectorPrioritySet(INT_VECTOR_UART4_RX, INT_PRIORITY_LEVEL1); SYS_INT_VectorSubprioritySet(INT_VECTOR_UART4_RX, INT_SUBPRIORITY_LEVEL3); SYS_INT_VectorPrioritySet(INT_VECTOR_UART4_FAULT, INT_PRIORITY_LEVEL3); SYS_INT_VectorSubprioritySet(INT_VECTOR_UART4_FAULT, INT_SUBPRIORITY_LEVEL0); /* //レジスタ直接設定 U4MODEbits.ON = 1; //UART4 イネーブル U4MODEbits.PDSEL = 0b00; //データ幅8ビット、パリティなし U4MODEbits.STSEL = 0; //ストップビットx1個 // U4MODEbits.BRGH = 1; //ハイスピードボーレート イネーブル U4MODEbits.UEN = 0; //UARTx Enable bits //00: UxTX and UxRX pins are enabled and used; UxCTS and UxRTS/UxBCLK pins are controlled //by corresponding bits in the PORTx register U4STAbits.URXEN = 1; //レシーバーイネーブル U4STAbits.UTXEN = 1; //トランスミッターイネーブル U4STAbits.URXISEL = 0; //00: バッファに1文字受信したら割込みフラグがたつ //Interrupt flag bit is asserted while receive buffer is not empty (i.e., has at least 1 data character) U4BRG = (unsigned int)(100000000/16/9600 - 1); //baud rate: 9600bps //U4BRG = Fosc/BRGH/Baud Rate -1 */ /* Initialize RX interrupt */ PLIB_INT_SourceEnable(INT_ID_0, INT_SOURCE_USART_4_RECEIVE); //UART4受信割込み許可 // IEC5bits.U4RXIE = 1; //UART4受信割込み許可 //IEC5<11> /* Initialize System Services */ SYS_INT_Initialize(); /*** TMR Service Initialization Code ***/ sysObj.sysTmr = SYS_TMR_Initialize(SYS_TMR_INDEX_0, (const SYS_MODULE_INIT * const)&sysTmrInitData); /* Initialize Middleware */ /* Enable Global Interrupts */ SYS_INT_Enable(); /* Initialize the Application */ APP_Initialize(); } /******************************************************************************* End of File */ //以下、system_interrupt.c //--------------------------------------------------------------------------------------- /******************************************************************************* System Interrupts File File Name: system_int.c Summary: Raw ISR definitions. Description: This file contains a definitions of the raw ISRs required to support the interrupt sub-system. Summary: This file contains source code for the interrupt vector functions in the system. Description: This file contains source code for the interrupt vector functions in the system. It implements the system and part specific vector "stub" functions from which the individual "Tasks" functions are called for any modules executing interrupt-driven in the MPLAB Harmony system. Remarks: This file requires access to the systemObjects global data structure that contains the object handles to all MPLAB Harmony module objects executing interrupt-driven in the system. These handles are passed into the individual module "Tasks" functions to identify the instance of the module to maintain. *******************************************************************************/ // DOM-IGNORE-BEGIN /******************************************************************************* Copyright (c) 2011-2014 released Microchip Technology Inc. All rights reserved. Microchip licenses to you the right to use, modify, copy and distribute Software only when embedded on a Microchip microcontroller or digital signal controller that is integrated into your product or third party product (pursuant to the sublicense terms in the accompanying license agreement). You should refer to the license agreement accompanying this Software for additional information regarding your rights and obligations. SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS. *******************************************************************************/ // DOM-IGNORE-END // ***************************************************************************** // ***************************************************************************** // Section: Included Files // ***************************************************************************** // ***************************************************************************** #include <xc.h> #include <sys/attribs.h> #include "app.h" #include "system_definitions.h" char data; int Flag = 0; //読み込み割込み検出フラグ // ***************************************************************************** // ***************************************************************************** // Section: System Interrupt Vector Functions // ***************************************************************************** // ***************************************************************************** void __ISR(_TIMER_9_VECTOR, ipl1) _IntHandlerDrvTmrInstance0(void) { DRV_TMR_Tasks_ISR(sysObj.drvTmr0); } void __ISR(_UART4_TX_VECTOR, ipl3) _IntHandlerDrvUsartTransmitInstance0(void) { DRV_USART_TasksTransmit(sysObj.drvUsart0); DRV_USART_TasksError(sysObj.drvUsart0); } void __ISR(_UART4_RX_VECTOR, ipl1) _IntHandlerDrvUsartReceiveInstance0(void) { /* TODO: Add code to process interrupt here */ if (PLIB_USART_ReceiverDataIsAvailable(USART_ID_4)) //受信データ有の場合 // if(U4STAbits.URXDA == 1) //受信データ有の場合 //Receive buffer has data, at least one more character can be read { data = PLIB_USART_ReceiverByteReceive(USART_ID_4); //受信データ読み込み //data = U4RXREG; //受信バッファ読み込み // Flag = 1; SendData(); } /* Clear pending interrupt */ PLIB_INT_SourceFlagClear(INT_ID_0, INT_SOURCE_USART_4_RECEIVE); //IFS5bits.U4RXIF = 0; //RX割込みフラグクリア } void __ISR(_UART4_FAULT_VECTOR, ipl3) _IntHandlerDrvUsartErrorInstance0(void) { SYS_ASSERT(false, "USART Driver Instance 0 Error"); } /******************************************************************************* End of File */ //以下、1lcd_lib_C32.h //---------------------------------------------------------------------------- //************************************************************************* //インクルードファイル 1lcd_lib_C32.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //XC32コンパイラ対応等で変更したものです。 //************************************************************************* #include <p32xxxx.h> #define lcd_Clock 200000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB15 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB14 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB13 //のDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB12 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_rs LATAbits.LATA9 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 #define lcd_stb LATAbits.LATA10 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //以下、1lcd_lib_C32.c //---------------------------------------------------------------------------------- //************************************************************************** //インクルードファイル 1lcd_lib_C32.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C32コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C32コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C32.h" void lcd_delay_us(unsigned int usec) //1μsec遅延関数 { int count; count = (int)(lcd_Clock/20000000)*usec; do //実測: at 200MH (Clock=200000000) { //delay_us(1000)→1000.4μsec、 delay_us(100)→100.6μsec、delay_us(10)→10.5μsec、delay_us(1)→1.5μsec asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); count--; }while(count != 0); } void lcd_delay_ms(unsigned int msec) //1msec遅延関数 { unsigned int i; for(i=0; i<msec; i++) lcd_delay_us(1000); } //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 lcd_delay_us(3); //1μsecウェイト // lcd_delay_us(1); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) lcd_delay_us(3); //1μsecウェイト // lcd_delay_us(1); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 lcd_delay_us(50); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 lcd_delay_ms(2); // 2msec待ち else lcd_delay_us(50); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { lcd_delay_ms(20); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(5); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(1); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set lcd_delay_ms(1); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set lcd_delay_ms(1); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home } <動作結果>
PC画面 | 液晶画面 上段: 受信文字列 下段: 返信文字列 |
||
@ | コンボボックスで"Japan"を選択して送信後 "Tokyo"を受信した場合 | ||
A | Japan America U.K. France I am fine を 順次送信した 結果 |
(3)文字列の送受信 (フロー制御なし、PIC側:LCD付、 割込みなし、タイムアウトあり、ハイパーターミナル - PIC間)
getc()は、1バイトの受信データを取得するまで永遠に待ちつづけます。 ノイズ等でUARTが受信に失敗するとプログラムは
このgetc()のところで停止してフリーズの状態となってしまいます。これを避けるための対策としてよく使われる、ある時間
(タイムアウト時間)経ってもデータを取得できない場合は取得を中止して別の処理に移る”タイムアウト処理”の例を紹介
します。
<試作品仕様>
PCのCOMポートとPICをつなぎ Windowsのハイパーターミナルの画面に以下を表示する。
・ PCのキーボードからキーインした文字をエコーバックにより 以下のように表示する
(例) 3番目にキーインした文字がDの場合 …… buf[2]=D
・ エンターキーが押された場合は、それまでにキーインした文字がすべて1行に連続して表示されること
(例) ”A” ”B” ”C” ”D” ”E” とキーインしたあとにエンターキーがキーインされた場合 …… ABCDE
・ キーインする時間間隔が3秒以上経ったらタイムアウト処理をおこない ハイパーターミナル画面に ”Timeout !
Too Slow !”と表示する。そして改行後”Type Please !!”と表示してはじめのキー入力モードに移る
<試作品回路図> 及び <試作品外観>は 上記(2)と全く同じです。
<プログラム例>
// PCのハイパーターミナル → RS232C → PIC18F452 + LCD /* PCモニタ出力 Type Please !! buf[0]=a buf[1]=b buf[2]=c buf[3]=d abcd Type Please !! buf[0]=a buf[1]=b // 3秒以上経過 Timeout ! Too slow ! Type Please !! */ #include "18f452.h" #use delay(clock=40000000) // 40MHz(システムクロック周波数)=10MHz(外部発振子周波数)×4(PLL倍率) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7,stream=PC) // ボーレート = 9600bps TX=RC6,RX=RC7 #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //rs #define stb PIN_D0 //strobe #define timeout_Time 3000 // タイムアウト時間の設定 : 単位msec #define NAK 0x15 // タイムアウトした場合の送信文字としてNAKを使用 #define StartMode 0 //文字列の最初の文字をキーインするモード #define NomalMode 1 //文字列の2番目以降をキーインするモード #define TimeoutMode 2 //タイムアウトのモード #include <1lcd_lib.c> char buf[20]; int i =0; char Status = StartMode; char timed_getc() { int32 timeout; char returnValue; timeout = 0; while(!kbhit()&&(++timeout<timeout_Time*100)) // タイムアウト時間内にデータを受信しなければwhile()ループを抜ける //タイムアウト時間 = 3(10μsec × 100 × 3000)sec delay_us(10); // 10μsec if(kbhit()) //タイムアウト時間内にデータを取得した場合はデータを取得し、そのデータを返す returnValue = getc(); else // タイムアウト時間内でデータを取得できなかった場合はNAKを返す returnValue = NAK; return(returnValue); } char Monitor(char getValue) //取得したデータをPCのモニタと液晶に表示する { buf[i] = getValue; if(buf[i] == NAK) //タイムアウトの場合 { i = 0; Status = TimeoutMode; printf("Timeout ! Too slow !\r\n"); } else if(buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; printf(buf); // 送信されてきていた文字を 文字列としてPCに一括送信 putc('\r');putc('\n');putc('\r');putc('\n'); //1行あける //液晶に出力 lcd_clear();// 液晶オールクリア lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,buf); // 送信されてきていた文字を液晶の2行目に一括表示 i = 0; Status = StartMode; } else //その他の場合 { printf("buf[%d]=%c\r\n",i,buf[i]); // PCへエコーバック → ハイパーターミナルに表示 //液晶に出力 lcd_clear();// 液晶オールクリア printf(lcd_data,"buf[%d]=%c",i,buf[i]);// PICに接続してある液晶に受信文字を表示 i++; Status = NomalMode; } return Status; } main() { char value; set_tris_c(0b10000000);// 必須 in = RC7 & RC4 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"start!!"); while(1) { printf("\r\nType Please !!\r\n"); while(!kbhit()); //キーインを待つ do { value = timed_getc(); //受信データを取得する(タイムアウト時はNAKが返ってくる) Status = Monitor(value); //データの表示 及び判別 }while(Status == NomalMode); //タイムアウトまたはエンターキー以外が押された場合は次のキーインを待つ } return 0; }
<動作結果>
下記のハイパーターミナルの画面は以下の操作をした場合のものです。
・ ”Type Please !!”と表示がでたら ”1”、”2”、”3”、”4”、”5”、 ”エンター”と間隔3秒以内に各キーをキーインする
・ 再び”Type Please !!”と表示がでたら ”a”、” b” 、”c”と間隔3秒以内にキーインする。”c”をキーインしたあと3秒
以上の間キーインしないで待つ
・ タイムアウトが発生し ”Timeout ! Too slow !”の表示がでる
(4)文字列の送受信 ( Win32API - PIC間 フロー制御なし、PIC側:LCD付、 割込みなし、タイムアウトなし)
自作のWindowsアプリからWin32API関数をつかってCOMポートを制御してPICと通信した例を紹介します。Windowsアプリは
BCB(Borland C++ Buider Ver.6)をつかって作成されています。尚、COMポート制御に関してはBCB専用のコンポーネント、
及び関数がありませんので、すぺてWin32API関数及び構造体を使用しています。
Windowsアプリ側の説明はPC側 RS232Cシリアル通信を参照してください。
<試作品仕様>
PCのCOMポートとPICをつなぎ 自作Windowsアプリを起動する。
★ PC側
・ Window内のコンボボックスにあらかじめ送信用の文字列として”Japan”、”America”、”Iraque”を用意しておく。
・ マウスで上記3つのいずれかの文字列ひとつを選択すると文字列が1つ送信データとして選択される。
・ 送信ボタンをマウスでクリックするとセットされた文字列がCOM2ポートから9600bpsの通信速度で送信される。
・ 送信後トータルタイムアウト時間100msecでPICからのデータを待つ
・ PICからのデータを受信したらエディットボックスに表示する。
★ PIC側
・ PC側からRX端子経由で受信したデータを液晶の1行目に表示する。
・ PC側からのデータを判別しPC側にTX端子経由で返信する。
返信データは以下とする
PCからの受信データ | PCへの返信データ | |
1 | Japan | Tokyo |
2 | America | Washinton |
3 | その他のデータ | Pardon ? |
・ 返信データを液晶の2行目に表示する。
<試作品回路図> 及び <試作品外観>は 上記(2)と全く同じです。
<プログラム例 PIC側 > <CCS編>
/* ------------------------------------------------------------------ < 構成> PC(C++ Builder:Win32 API) → RS232C → PIC18F452 + 16文字キャラクタ液晶 -------------------------------------------------------------------- PC側 PIC側 送信データ Japan → 受信データ Japan 受信データ Tokyo ← 送信データ Tokyo 送信データ America → 受信データ America 受信データ Washinton ← 送信データ Washinton 送信データ Iraque → 受信データ Iraque 受信データ pardon ? ← 送信データ pardon ? */ #include "18f452.h" #include "string.h" #use delay(clock=40000000) // 40MHz(システムクロック周波数)=10MHz(外部発振子周波数)×4(PLL倍率) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // TX=RC6,RX=RC7 #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> int i = 0; char buf[20]; char Japan[] = "Japan"; char America[] = "America"; char Tokyo[] = "Tokyo"; char Washinton[] = "Washinton"; char Pardon[] = "Pardon ?"; char* str; void LCD() { buf[i] = getc(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Japan) == 0)str = Tokyo; else if(strcmp(buf,America) == 0) str = Washinton; else str = Pardon; printf(str); // 送信されてきていた文字を 文字列としてPCに一括送信 //液晶に出力 lcd_clear();// 液晶オールクリア printf(lcd_data,buf); // 送信されてきていた文字を液晶の1行目に一括表示 lcd_cmd(0xC0); // 2行目の先頭へ printf(lcd_data,str); // 送信されてきていた文字を液晶の2行目に一括表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } main(){ set_tris_c(0b10010000);// 必須 in = RC7 & RC4 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"Open COM port !!"); delay_ms(1000); // while(1) { LCD(); } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home } /* ************************************************************************* ************************************************************************* < プログラム例 Windows側 > このプログラムは C++ Buider Ver.6 でかかれています。 プログラムのソースコード ************************************************************************* ************************************************************************* */ #include <vcl.h> #include <stdio.h> #pragma hdrstop #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; HANDLE hPort; // ポートハンドル DCB dcb; // DCB構造体 COMMTIMEOUTS timeout; // COMMTIMEOUTS構造体 BOOL Ret; // 関数戻り値 //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { TransmitComboBox->ItemIndex = 0; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) // ”送信開始”ボタンをクリックした時の処理 { char* szStr; // BYTE bSendBuffer[10]; // 送信データ DWORD nNumberOfBytesToWrite; // 送信データのバイト数 DWORD nNumberOfBytesWritten; // 実際に送信されたデータのバイト数 BYTE bReceiveBuffer[10]; // 受信データ DWORD nNumberOfBytesRead; // 実際に受信されたデータのバイト数 // (COM2ポートの)ポートハンドルを取得する hPort = CreateFile( "COM2", // ポートの名前: どのポートを開くのか GENERIC_READ|GENERIC_WRITE, // アクセスモード: 通常送受信ともするので読書き両方を指定 0, // 共有モード: 通常0に設定 再オープン禁止 NULL, //セキュリティアトリビュート:通信では通常NULLに設定 OPEN_EXISTING, // クリエイトディストリビューション:通常COMポートはすでに存在しているのでOPEN_EXISTINGとします。 FILE_ATTRIBUTE_NORMAL, // 属性:通信の場合属性はないのでFILE_ATTRIBUTE_NORMAL(属性なし)を指定 NULL // テンプレートのハンドル: 通信の場合関係ない 通常NULLを指定 ); if(hPort == INVALID_HANDLE_VALUE) //ハンドル取得に失敗した場合 { MessageBox(NULL , "Port could not open" , "警告" , MB_OK); exit(0); } Ret = SetupComm( //設定 hPort, // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 512, // 受信バッファーサイズ: 受信のバッファーサイズをバイト単位で指定 512 // 送信バッファーサイズ: 送信のバッファーサイズをバイト単位で指定 ); if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetupComm failed" , TEXT("警告") , MB_OK); CloseHandle(hPort); exit(0); } Ret = PurgeComm( //消去 hPort, //通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR // 実行する操作: 上記は未処理の読書きの中止及び送受信のバッファーのクリアを指定 ); if(Ret == FALSE) //失敗した場合 { MessageBox(NULL , "PurgeComm failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } dcb.DCBlength = sizeof(DCB); // DCBのサイズ: //データ dcb.BaudRate = 9600; // 伝送速度: ボーレートをbps単位で指定 dcb.fBinary = TRUE; // バイナリモード: 通常TRUEに設定 dcb.ByteSize = 8; // データサイズ : 通常 8 ビット dcb.fParity = NOPARITY; // パリティ有無種類 : パリティなしの場合はNOPARITYを指定 // 奇数パリティの場合は ODDPARITY 他 dcb.StopBits = ONESTOPBIT; // ストップビットの数: 通常1ビット→ ONESTOPBIT; //ハードウェアフロー制御 dcb.fOutxCtsFlow = FALSE; // CTSハードウェアフロー制御:CTS制御を使用しない場合はFLASEを指定 // CTS制御をする場合はTRUEを指定してCTS信号を監視します。 dcb.fOutxDsrFlow = FALSE; // DSRハードウェアフロー制御:使用しない場合はFALSEを指定 dcb.fDtrControl = DTR_CONTROL_DISABLE;// DTR有効/無効: 無効なら DTR_CONTROL_DISABLE;ISABLE dcb.fRtsControl = RTS_CONTROL_DISABLE; // RTS制御: RTS制御をしない場合はRTS_CONTROL_DISABLEを指定 // RTS制御をする場合はRTS_CONTROL_ENABLEを指定 他 // ソフトウェアフロー制御 dcb.fOutX = FALSE; // 送信時XON/OFF制御の有無: なし→FLALSE dcb.fInX = FALSE; // 受信時XON/XOFF制御の有無:なし→FALSE dcb.fTXContinueOnXoff = TRUE; // 受信バッファー満杯&XOFF受信後の継続送信可否:送信可→TRUE dcb.XonLim = 512; // XONが送られるまでに格納できる最小バイト数: dcb.XoffLim = 512; // XOFFが送られるまでに格納できる最小バイト数: dcb.XonChar = 0x11; // 送信時XON文字 ( 送信可:ビジィ解除 ) の指定: // 一般に、XON文字として11H ( デバイス制御1:DC1 )がよく使われます dcb.XoffChar = 0x13; // XOFF文字(送信不可:ビジー通告)の指定:なし→FALSE // 一般に、XOFF文字として13H ( デバイス制御3:DC3 )がよく使われます //その他 dcb.fNull = TRUE; // NULLバイトの破棄: 破棄する→TRUE dcb.fAbortOnError = TRUE; // エラー時の読み書き操作終了: 終了する→TRUE dcb.fErrorChar = FALSE; // パリティエラー発生時のキャラクタ(ErrorChar)置換: なし→FLALSE dcb.ErrorChar = 0x00; // パリティエラー発生時の置換キャラクタ dcb.EofChar = 0x03; // データ終了通知キャラクタ : 一般に0x03(ETX)がよく使われます。 dcb.EvtChar = 0x02; // イベント通知キャラクタ : 一般に0x02(STX)がよく使われます Ret = SetCommState(hPort, &dcb); //SetCommState()関数にポートハンドルおよびdcb構造体のアドレスを代入する if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetCommState failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } timeout.ReadIntervalTimeout = 5; // 文字読込時の1文字あたりのタイムアウトまでの待ち時間(msec) timeout.ReadTotalTimeoutMultiplier = 0; //読込の1文字あたりの時間 timeout.ReadTotalTimeoutConstant = 100; //読込エラー検出用のタイムアウト時間 //(受信トータルタイムアウト) = ReadTotalTimeoutMultiplier * (受信予定バイト数) + ReadTotalTimeoutConstant timeout.WriteTotalTimeoutMultiplier = 5; //書き込み1文字あたりのタイムアウトまでの待ち時間 timeout.WriteTotalTimeoutConstant = 100;//書き込みエラー検出用のタイムアウト時間 //(送信トータルタイムアウト) = WriteTotalTimeoutMultiplier * (送信予定バイト数) + WriteTotalTimeoutConstant Ret = SetCommTimeouts(hPort, &timeout);//SetCommTimeOut()関数にポートハンドルおよびCOMMTIMEOUTS構造体の //アドレスを代入します。 if(Ret == FALSE) //失敗した場合 { MessageBox(NULL,"SetCommTimeouts failed","警告", MB_OK); CloseHandle(hPort); exit(0); } szStr = (TransmitComboBox->Text + "\r" ).c_str(); //コンボボックスから取得した文字列の最後にCR(\r)を追加 // → 受信側に送信データの終端であることを通知 nNumberOfBytesToWrite = strlen(szStr); Ret = WriteFile( //データの送信 hPort, // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 szStr,// 送信データのポインタを指定 nNumberOfBytesToWrite, // 送信するデータのバイト数を指定 &nNumberOfBytesWritten, // 実際に送信されたバイト数が格納されるポインタを指定 NULL // 通信とは関係ない引数なのでNULLを指定 ); if(Ret == FALSE) //失敗した場合 { MessageBox(NULL,"WriteFile failed","警告", MB_OK); CloseHandle(hPort); exit(0); } Ret = ReadFile( // データの受信 hPort, // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 &bReceiveBuffer, // 受信バッファーのポインタを指定: 受信データがここに格納されます。 10, // 受信するバイト数を指定: ここで指定するバイト数を受信するかまたはタイムアウト時間がくるまで // ReadFile()関数は( getc()のように )待ちます &nNumberOfBytesRead, // 実際に受信したバイト数が格納されるDWORD値のポインタを指定 NULL // 通信とは関係ない引数なのでNULLを指定 ); if(Ret == FALSE) //失敗した場合 { Application->MessageBox("データの読み出しでエラーが発生", "警告", MB_OK ) ; CloseHandle(hPort); exit(0); } bReceiveBuffer[nNumberOfBytesRead] = '\0'; szStr = &bReceiveBuffer[0]; ReceiveEdit -> Text = szStr; //受信データをエディットボックスに表示 CloseHandle( hPort // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 ); } //--------------------------------------------------------------------------- <動作結果> @ PCのコンボボックスから 送信文字として”Japan”を選択します。次に”送信開始ボタン”を クリックするとPIC側に”Japan”が送信されます。この結果、PIC側から”Tokyo”が返信されて きます。この返信データ”Tokyo”がエディットボックスに表示された時のWindows画面を以下に 示します。一方、液晶画面のの1行目には受信文字”Japan”が、2行目には送信文字”Tokyo”が 表示されます。この時のPIC側液晶画面の写真を右側に示します
<PCのWindows画面> | <PIC側液晶画面> | |
A 同様に PC側より ”America”を送信した時の画像です。
<PCのWindows画面> | <PIC側液晶画面> | |
B 同様に PC側より ”Iraque”を送信した時の画像です。
<PCのWindows画面> | <PIC側液晶画面> | |
(5)文字列の送受信 ( Win32API - PIC間 フロー制御あり、PIC側:LCD付、割込みなし、タイムアウトなし)
RTS/CTSハードウェアフロー制御がある場合のWin32API関数をつかったCOMポートとPIC間の通信例を
紹介します。WindowsアプリはBCB(Borland C++ Buider Ver.6)をつかって作成されています。
尚、COMポート制御に関してはBCB専用のコンポーネント、及び関数がありませんので、すぺてWin32API
関数及び構造体を使用しています。Windowsアプリ側の説明はPC側 RS232Cシリアル通信を参照してください。
<試作品仕様>
PCのCOMポートとPICをつなぎ 自作Windowsアプリを起動する。
★ PC側
・ 送信開始ボタンをおすと 0〜359の整数が COM2ポートのRX端子から9600bpsでPIC側に送信される。
・ 送信後トータルタイムアウト時間 100msecでPICからのデータを待つ
・ PICからのデータを受信したらデータをグラフとして表示する。また受信データは3つのエディットボックスに
以下のように表示する。
@ 全受信データエディットボックス……受信した全データ(文字列)を1行にすぺて表示する。
A 送信データXエディットボックス ……受信した全データ(文字列)の中から送信したデータのみを
整数として摘出して、エコーバック値として表示する。
B 受信データYエディットボックス ……全受信データ(文字列)の中からPIC側で計算したY = Sin Xの
値を浮動少数として抽出して表示する。
尚、次の100msec後のデータは改行して同様に表示すること
・ CTS/RTSハードウェアフロー制御をおこなうこと。
・ 受信データを数値化する場合は例外処理をおこなうこと。また例外処理が発生した回数も表示すること
★ PIC側
・ 返信データは 以下の順番で送信する
@ In=のあとに受信データ
A 制御文字ESC(0x1b)×2
B Out=のあとにsin( 2 × 3.1416 × ( 受信データ ) ÷ 360 )の計算値(浮動少数)
C 最後に制御文字CR(0x0D)
(例) In=261 ESC ESC Out=-0.987690 CR
・ 液晶には以下を表示する
@ 1行目には In=のあとに受信データ
A 2行目にはOut=の後に上記の計算値(浮動少数)
<試作品回路図>(→回路図のPDFファイル)
PIC18F452をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> <PIC側> <CCS編> /* ------------------------------------------------------------------ < 構成> PC(C++ Builder:Win32 API) → RS232C → PIC18F452 + 16文字キャラクタ液晶 正弦関数の引数xをPCから受信 → PIC側で sin x を計算 → 計算結果を受信引数xと共に返信 */ #include "18f452.h" #include "stdlib.h" #include "math.h" #use delay(clock=40000000) // 10MHz(システムクロック周波数) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // TX=RC6,RX=RC7 #define ESC 0x1b // Escape #define CR 0x0D // Carridge Return \r #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> int i = 0; char buf[20]; long int DataIn; float fDataIn; float DataOut; char SendData[30]; char* str; void LCD() { buf[i] = getc(); output_high(PIN_C2);//PC側からの送信を禁止: PIC側ソフト:1(High) をRC2ピンにセット //→ MAX232のT2in出力電圧(=PICのRC2ピン):5V //→ PIC側のRTS信号(MAX232のT2out7番ピン):-8V //→ COMポートCTS(8番ピン); -8V //→ Comstat.fCtsHold(送信禁止) = true if( buf[i] == '\r') // \r: 受信データの最後の文字 { buf[i] = '\0'; fDataIn = atof(buf); // fDataIn = (float)atoi(buf) --> NG DataOut = sin ( 2* 3.1416 * (fDataIn / 360)); sprintf(SendData,"In=%s%c%cOut=%f%c",buf,ESC,ESC,DataOut,CR); //送信文字列 : 送信データbuf,DataOutの前後にデータ抽出用の制御文字を挿入 str = &SendData[0]; // CTS/RTSフロー制御 do { }while(input(PIN_C0)!= 0);//PC側のRTS(送信許可)が出るまで待つ // PIC側ソフト:0(Low) を検出 // ←MAX232出力電圧(=PICのRC0ピン):0V // ←PIC側CTS信号(MAX232入力R1in 13番ピン):10V // ←PC側のCOMポートRTS(7番ピン)出力電圧:10V // ← 関数 EscapeCommFunctionの引数をSETRTSにセット printf("%s",str); // 送信されてきていた文字を 文字列としてPCに一括送信 //液晶に出力 lcd_clear();// 液晶オールクリア printf(lcd_data,"In=%s",buf); // 受信した文字を液晶の1行目に表示 lcd_cmd(0xC0); // 2行目の先頭へ printf(lcd_data,"Out=%f",DataOut); // 送信した文字を液晶の2行目に表示 i = 0; } else //Enter キー以外が押された場合 { i++; } //CTS/RTSフロー制御 output_low(PIN_C2);//PC側からの送信を許可: PIC側ソフト:0(Low) をRC2ピンにセット //→ MAX232のT2in出力電圧(=PICのRC2ピン):0V //→ PIC側のRTS信号(MAX232のT2out7番ピン):+8V //→ COMポートCTS(8番ピン); +8V //→ Comstat.fCtsHold(送信禁止) = false //→ 送信許可 } main(){ set_tris_c(0b10000001);// 必須 in = RC7:RX & RC0:CTS out = RC6 :TX & RC2:RTS lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"Open COM port !!"); delay_ms(1000); output_low(PIN_C2);//PC側からの送信を許可 while(1) { LCD(); } return 0; }
//--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home } /* ************************************************************************* ************************************************************************* < プログラム例 Windows側 > このプログラムは C++ Buider Ver.6 でかかれています。 プログラムのソースコード ************************************************************************* ************************************************************************* */ //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <math.h> #include <stdio.h> //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "MsTimer" #pragma resource "*.dfm" #define ESC 0x1b // Escape #define CR 0x0D // Carridge Return #define DC1 0x11 // Device Control 1 #define DC2 0x12 // Device Control 2 TForm1 *Form1; const double PAI = 3.1416; int gLeft = 30; //グラフの左幅 int gTop = 20; //グラフの上幅 int gWidth = 360; //グラフの横幅 int gHeight = 400; //グラフの縦幅 BOOL ColorFlag = 0; int nErrorIn = 0, //整数に変換できない受信データInを受信した回数 nErrorOut =0; //浮動少数に変換できない受信データOutを受信した回数 int Angle =0; //送信データ: 0〜355までの整数 HANDLE hPort; // ポートハンドル DCB dcb; // DCB構造体 COMMTIMEOUTS timeout; // COMMTIMEOUTS構造体 BOOL Ret; // 関数戻り値 //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { MsTimer1->Enabled = false; } //--------------------------------------------------------------------------- void __fastcall TForm1::FormPaint(TObject *Sender) { LinRePaint(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) //”送信開始ボタン”を押した時の処理 { char* szStr; DWORD nNumberOfBytesToWrite; // 送信データのバイト数 DWORD nNumberOfBytesWritten; // 実際に送信されたデータのバイト数 BYTE bReceiveBuffer[20]; // 受信データ DWORD nNumberOfBytesRead; // 実際に受信されたデータのバイト数 // (COM2ポートの)ポートハンドルを取得する hPort = CreateFile( "COM2", // ポートの名前: どのポートを開くのか GENERIC_READ|GENERIC_WRITE, // アクセスモード: 通常送受信ともするので読書き両方を指定 0, // 共有モード: 通常0に設定 再オープン禁止 NULL, //セキュリティアトリビュート:通信では通常NULLに設定 OPEN_EXISTING, // クリエイトディストリビューション:通常COMポートはすでに存在しているのでOPEN_EXISTINGとします。 FILE_ATTRIBUTE_NORMAL, // 属性:通信の場合属性はないのでFILE_ATTRIBUTE_NORMAL(属性なし)を指定 NULL // テンプレートのハンドル: 通信の場合関係ない 通常NULLを指定 ); if(hPort == INVALID_HANDLE_VALUE) //ハンドル取得に失敗した場合 { MessageBox(NULL , "Port could not open" , "警告" , MB_OK); exit(0); } Ret = SetupComm( //設定 hPort, // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 512, // 受信バッファーサイズ: 受信のバッファーサイズをバイト単位で指定 512 // 送信バッファーサイズ: 送信のバッファーサイズをバイト単位で指定 ); if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetupComm failed" , TEXT("警告") , MB_OK); CloseHandle(hPort); exit(0); } Ret = PurgeComm( //消去 hPort, //通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR // 実行する操作: 上記は未処理の読書きの中止及び送受信のバッファーのクリアを指定 ); if(Ret == FALSE) //失敗した場合 { MessageBox(NULL , "PurgeComm failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } dcb.DCBlength = sizeof(DCB); // DCBのサイズ: //データ dcb.BaudRate = 9600; // 伝送速度: ボーレートをbps単位で指定 dcb.fBinary = TRUE; // バイナリモード: 通常TRUEに設定 dcb.ByteSize = 8; // データサイズ : 通常 8 ビット dcb.fParity = NOPARITY; // パリティ有無種類 : パリティなしの場合はNOPARITYを指定 // 奇数パリティの場合は ODDPARITY 他 dcb.StopBits = ONESTOPBIT; // ストップビットの数: 通常1ビット→ ONESTOPBIT; // CTS/RTS ハードウェアフロー制御 //CTS/RTSフロー制御実施 dcb.fOutxCtsFlow = true; // CTSハードウェアフロー制御:CTS制御を使用しない場合はFLASEを指定 // CTS制御をする場合はTRUEを指定してCTS信号を監視します。 dcb.fOutxDsrFlow = FALSE; // DSRハードウェアフロー制御:使用しない場合はFALSEを指定 dcb.fDtrControl = DTR_CONTROL_DISABLE;// DTR有効/無効: 無効なら DTR_CONTROL_DISABLE;ISABLE //CTS/RTSフロー制御実施 dcb.fRtsControl = RTS_CONTROL_ENABLE; // RTS制御: RTS制御をしない場合はRTS_CONTROL_DISABLEを指定 // RTS制御をする場合はRTS_CONTROL_ENABLEを指定 // ソフトウェアフロー制御 dcb.fOutX = FALSE; // 送信時XON/OFF制御の有無: なし→FLALSE dcb.fInX = FALSE; // 受信時XON/XOFF制御の有無:なし→FALSE dcb.fTXContinueOnXoff = TRUE; // 受信バッファー満杯&XOFF受信後の継続送信可否:送信可→TRUE dcb.XonLim = 512; // XONが送られるまでに格納できる最小バイト数: dcb.XoffLim = 512; // XOFFが送られるまでに格納できる最小バイト数: dcb.XonChar = 0x11; // 送信時XON文字 ( 送信可:ビジィ解除 ) の指定: // 一般に、XON文字として11H ( デバイス制御1:DC1 )がよく使われます dcb.XoffChar = 0x13; // XOFF文字(送信不可:ビジー通告)の指定:なし→FALSE // 一般に、XOFF文字として13H ( デバイス制御3:DC3 )がよく使われます //その他 dcb.fNull = TRUE; // NULLバイトの破棄: 破棄する→TRUE dcb.fAbortOnError = TRUE; // エラー時の読み書き操作終了: 終了する→TRUE dcb.fErrorChar = FALSE; // パリティエラー発生時のキャラクタ(ErrorChar)置換: なし→FLALSE dcb.ErrorChar = 0x00; // パリティエラー発生時の置換キャラクタ dcb.EofChar = 0x03; // データ終了通知キャラクタ : 一般に0x03(ETX)がよく使われます。 dcb.EvtChar = 0x02; // イベント通知キャラクタ : 一般に0x02(STX)がよく使われます Ret = SetCommState(hPort, &dcb); //SetCommState()関数にポートハンドルおよびdcb構造体のアドレスを代入する if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetCommState failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } timeout.ReadIntervalTimeout = 5; // 文字読込時の1文字あたりのタイムアウトまでの待ち時間(msec) timeout.ReadTotalTimeoutMultiplier = 0; //読込の1文字あたりの時間 timeout.ReadTotalTimeoutConstant = 100; //読込エラー検出用のタイムアウト時間 //(受信トータルタイムアウト) = ReadTotalTimeoutMultiplier * (受信予定バイト数) + ReadTotalTimeoutConstant timeout.WriteTotalTimeoutMultiplier = 5; //書き込み1文字あたりのタイムアウトまでの待ち時間 timeout.WriteTotalTimeoutConstant = 100;//書き込みエラー検出用のタイムアウト時間 //(送信トータルタイムアウト) = WriteTotalTimeoutMultiplier * (送信予定バイト数) + WriteTotalTimeoutConstant Ret = SetCommTimeouts(hPort, &timeout);//SetCommTimeOut()関数にポートハンドルおよびCOMMTIMEOUTS構造体の //アドレスを代入します。 if(Ret == FALSE) //失敗した場合 { MessageBox(NULL,"SetCommTimeouts failed","警告", MB_OK); CloseHandle(hPort); exit(0); } MsTimer1->Enabled = true; Canvas->Pen->Color = clRed; } //--------------------------------------------------------------------------- void __fastcall TForm1::MsTimer1Timer(TObject *Sender) //100msec インターバルタイマ動作時 { char SendData[10]; // 送信データ char* lpszStr; //文字列のポインタ AnsiString strReceive,str; int InData; int nOffset;// 先頭アドレスから検出文字列までのオフセット(整数) double OutData; //受信データ:PICが計算したsin(x)の値(浮動少数) int x,y; DWORD nNumberOfBytesToWrite; // 送信データのバイト数 DWORD nNumberOfBytesWritten; // 実際に送信されたデータのバイト数 BYTE bReceiveBuffer[30]; // 受信データ DWORD nNumberOfBytesRead; // 実際に受信されたデータのバイト数 COMSTAT Comstat; // 通信デバイス情報構造体 DWORD dwErrorMask; // エラーコードを受け取る変数 sprintf(SendData,"%d\r",Angle); // 送信文字列: 終端にデータの終端を通知する\rを追加 nNumberOfBytesToWrite = strlen(SendData); //送信データの長さ計算 //CTS/RTSフロー制御 //送信禁止が解除されるまで待つ(送信許可が出るまで待つ) do { ClearCommError( // ポートの状態を取得してエラーをクリアする hPort , // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 &dwErrorMask ,//下記のエラーコードのポインタを取得→エラーの判別 // CD_BREAK(フレーミングエラー)、 // CE_RXPARITY(パリティエラー)、 // CE_RXOVER(入力バッファーオーバーフロー)他 &Comstat//COMSTAT構造体へのポインタを取得 // Comstat.cbOutQue 送信バッファーの中に残っているデータ数 ); Application->ProcessMessages(); }while( Comstat.fCtsHold == true ); // COMポートのCTSが+8Vになるまで待つ // Comstat.fCtsHold(送信禁止) != true // Comstat.fCtsHold(送信禁止) = false // ← COMポートCTS(8番ピン); +8V // ← PIC側のRTS信号(MAX232のT2out7番ピン):+8V // ← MAX232のT2in出力電圧(=PICのRC2ピン):0V // ← PIC側ソフト:0(Low) をRC2ピンにセット Ret = WriteFile( //データの送信 hPort, // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 SendData,// 送信データのポインタを指定 nNumberOfBytesToWrite, // 送信するデータのバイト数を指定 &nNumberOfBytesWritten, // 実際に送信されたバイト数が格納されるポインタを指定 NULL // 通信とは関係ない引数なのでNULLを指定 ); if(Ret == FALSE) //失敗した場合 { MessageBox(NULL,"WriteFile failed","警告", MB_OK); CloseHandle(hPort); exit(0); } //CTS/RTSフロー制御 // フロー制御関係の信号を送信 //RTS(送信許可)信号をPIC側に送る。 // 関数 EscapeCommFunctionの引数をSETRTSにセット // →PC側のCOMポートRTS(7番ピン)出力電圧:10V // →PIC側CTS信号(MAX232入力R1in 13番ピン):10V // → MAX232出力電圧(=PICのRC0ピン):0V // → PIC側ソフト:0(Low) を検出 Ret = EscapeCommFunction( hPort, // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 SETRTS // 受信可能であることを相手側に示す:RTSをアクティブにする→SETRTS // (参考) RTSを非アクティブにする→CLRRTS ); if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL,"EscapeCommFunction failed.\n","警告",MB_OK); CloseHandle(hPort); exit(0); } Sleep(40); //40msec ウェイト Ret = ReadFile( // データの受信 hPort, // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 &bReceiveBuffer, // 受信バッファーのポインタを指定: 受信データがここに格納されます。 sizeof(bReceiveBuffer), // 受信するバイト数を指定: ここで指定するバイト数を受信するかまたはタイムアウト時間がくるまで // ReadFile()関数は( getc()のように )待ちます &nNumberOfBytesRead, // 実際に受信したバイト数が格納されるDWORD値のポインタを指定 NULL // 通信とは関係ない引数なのでNULLを指定 ); if(Ret == FALSE) //失敗した場合 { Application->MessageBox("データの読み出しでエラーが発生", "警告", MB_OK ) ; CloseHandle(hPort); exit(0); } //CTS/RTSフロー制御 EscapeCommFunction( hPort, // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 CLRRTS // 受信可能であることを相手側に示す:RTSをアクティブにする→SETRTS // (参考) RTSを非アクティブにする→CLRRTS ); bReceiveBuffer[nNumberOfBytesRead] = '\0'; //受信データの最後尾に\0を追加→文字列化 lpszStr = &bReceiveBuffer[0]; //受信データの先頭アドレスを文字列ポインタに代入 strReceive =(AnsiString)lpszStr;//C言語の文字列をAnsiString文字列にキャストで変換 nOffset = AnsiPos("In=",strReceive);//"In="のある位置(オフセットバイト)検出 この場合は1で固定 lpszStr = &bReceiveBuffer[0] + nOffset +2; //受信データの先頭アドレスを文字列ポインタに代入 str =(AnsiString)lpszStr;//C言語の文字列をAnsiString文字列にキャストで変換 str = str.SubString(1,3); //"In="のあとの3文字を摘出 str = str.Trim();//制御文字(ESC)がある場合はこれを削除 try //例外処理 { InData = str.ToInt();//整数に変換 } catch (EConvertError &e) // catch (...) { nErrorIn++; InData = 400; } nOffset = AnsiPos("Out=",strReceive);//"Out="のある位置(オフセットバイト)検出 InDataの値によって変化 lpszStr = &bReceiveBuffer[0] + nOffset + 3; //受信データの先頭アドレスを文字列ポインタに代入 str =(AnsiString)lpszStr;//C言語の文字列をAnsiString文字列にキャストで変換 str = str.SubString(1,9); //"Out="のあとの6文字を摘出 str = str.Trim();//制御文字(ESC CR)がある場合はこれを削除 try //例外処理 { OutData = str.ToDouble();//浮動少数に変換 } catch (EConvertError &e) // catch (...) { nErrorOut++; OutData = 1.2; } RichEdit1->SelText = strReceive; //全受信データを表示 RichEdit1->SelText = ""; str.sprintf("%d",InData); //送信データX(エコーバック値)を表示 RichEditX->SelText = str; RichEditX->SelText = "\n"; str.sprintf("%f",OutData); // 受信データ(PICが計算した値)を表示 RichEditY->SelText = str; RichEditY->SelText = "\n"; Memo1->Text = str.sprintf("%d",nErrorIn); Memo2->Text = str.sprintf("%d",nErrorOut); x = InData; y = (int)( -gHeight/2*OutData ); if(ColorFlag == 0) { Canvas->Pixels[x + gLeft][y + gHeight/2 + gTop] = clRed; Canvas->Pixels[x+1 + gLeft][y + gHeight/2 + gTop] = clRed; Canvas->Pixels[x-1 + gLeft][y + gHeight/2 + gTop] = clRed; Canvas->Pixels[x + gLeft][y+1 + gHeight/2 + gTop] = clRed; Canvas->Pixels[x + gLeft][y-1 + gHeight/2 + gTop] = clRed; } else { Canvas->Pixels[x + gLeft][y + gHeight/2 + gTop] = clBlue; Canvas->Pixels[x+1 + gLeft][y + gHeight/2 + gTop] = clBlue; Canvas->Pixels[x-1 + gLeft][y + gHeight/2 + gTop] = clBlue; Canvas->Pixels[x + gLeft][y+1 + gHeight/2 + gTop] = clBlue; Canvas->Pixels[x + gLeft][y-1 + gHeight/2 + gTop] = clBlue; } Angle++; if( Angle >= gWidth ) { Angle = 0; if(ColorFlag == 0)ColorFlag = 1 ; else ColorFlag = 0; } } //--------------------------------------------------------------------------- void __fastcall TForm1::LinRePaint() { int i,x,y; Canvas->MoveTo(gLeft,gTop); //グラフ罫線外枠描画 Canvas->LineTo(gLeft + gWidth,gTop); Canvas->LineTo(gLeft + gWidth,gTop + gHeight); Canvas->LineTo(gLeft , gTop + gHeight); Canvas->LineTo(gLeft,gTop); for(i=1;i<8;i++) //グラフ横罫線描画 { Canvas->MoveTo(gLeft , gTop + gHeight/8*i); Canvas->LineTo(gLeft + gWidth ,gTop+ gHeight/8*i); } for(i =1; i < 4; i++) { Canvas->MoveTo(gLeft + gWidth/4*i,gTop); //グラフ縦罫線描画 Canvas->LineTo(gLeft + gWidth/4*i,gTop + gHeight); } Label0->Left =gLeft - 20; Label0->Top = gTop + gHeight /2; Labelx -> Left = gLeft + gWidth + 10; Labelx -> Top = gTop + gHeight /2; Label360 -> Left = gLeft + gWidth + 10 -50; Label360 -> Top = gTop + gHeight /2 +10; Label180 -> Left = gLeft + gWidth + 10 -180 -50; Label180 -> Top = gTop + gHeight /2 + 10; Labely -> Left = gLeft -20 ; Labely -> Top = gTop -20 ; Label10 -> Left = gLeft -30 ; Label10 -> Top = gTop ; Label05 -> Left = gLeft -30; Label05 -> Top = gTop -20 + 110; } //-------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { CloseHandle( hPort // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 ); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { RichEdit1->Lines->Clear(); RichEditX->Lines-> Clear(); RichEditY->Lines-> Clear(); } //---------------------------------------------------------------------------
<動作結果>
・ 以下のようなPCウィンドウ画面に受信データをグラフ化しました。画面は0〜318までの送信データが送られた直後の
ものです。送信データXは100msec毎に送られています。
・画面は送信データX=0〜359(度)の値に対して、PIC側で計算した
Y=sin( 2 × 3.1416 × ( 送信データ ) ÷ 360 )
を受信してグラフにするようになっています。
尚、Yは全受信データの中に文字列として送信されてきます。
・X(整数)、Y(浮動少数)の値は全受信データ(文字列)から摘出されています。
・受信エラー累計X(整数)、Y(浮動少数)には受信データ(文字列)を数値化する際に発生した例外処理の累計が表示
されるようになっています。
・液晶画面を示します。1行目が受信データで2行目が計算(結果)値です。
(6)文字列の送受信 ( Win32API − PIC間 マルチスレッド 受信スレッド: 非イベント動作型 )
<CCS編>
(4)、(5)ではPC側で同期をとって書き込むタイミングでPIC側からの読込処理もおこなっています。アプリケーションに
よってはPC側とPIC側が非同期で動作しなければならないものもあります。以下にスレッドをつかったPC側、PIC側非同期
制御の例を紹介します。(→PCのスレッドプログラム)
<試作品の仕様>
★ PC側
・メインスレッドから受信スレッドを生成しイベント動作はおこなわず、常時ループでPIC側からの送信データを監視する。
・PIC側からデータを受信したら、速やかにメインウィンドウ(メインスレッド)の”PICからの受信エディタ”に表示する。
・PIC側からのデータ受信タイミングとは非同期で、100msec毎にPCの時刻を表示する。
・時刻は SYSTEMTIME構造体から取得する。
★ PIC側
・50msec毎に整数をインクリメントして 19200bps でPC側に送信する。
<試作品回路図>(→回路図のPDFファイル)
PIC18F452をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> <CCS編>
// <PIC側> //***************************************************************************** //マルチスレッド送受信用 // プログラム PIC18F452 //***************************************************************************** #include "18f452.h" #include "string.h" #include "stdio.h" #use delay(clock=40000000) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=19200,XMIT=PIN_C6,RCV=PIN_C7) // ボーレート = 19200bps TX=RC6,RX=RC7 #define ETX 0x03 // ETX #define ESC 0x1b // ESC #define NAK 0x15 // タイムアウトした場合の送信文字としてNAKを使用 long int Count_25msec = 0; unsigned long int data1 = 0; #int_timer0 //タイマ1割込み(25msec毎に割込み発生) interval() { set_timer0(34286); // 0.025μsec× 4 × 8 × 31250 = 25000usec = 25msec (st システムクロック40MHz) // 256×256 - 31250 = 34286 Count_25msec++; if(Count_25msec >=2) { Count_25msec = 0; data1++; if(data1 >= 65535)data1 = 0; // printf("%lu\r\n",data1); printf("%lu",data1); } return 0; } main() { setup_timer_0(RTCC_INTERNAL |RTCC_DIV_8); set_timer0(34286); set_tris_b(0xFF); // RCON = (RCON | 0b10000000); //リセット制御レジスタのb7 = 1 → 割込み優先順位制御有 //タイマ0優先 // INTCON2 = (INTCON2 | 0b00001000);//割込み制御レジスタ2のb3 = 1 → タイマ0割込みを高位レベル割込みにセット // IPR1 = (IPR1 & 0b11001111); //割込み優先順位レジスタ1のb4=0 b5=0 → UARTの送受信割込みを低位レベル割込みにセット delay_ms(1000); output_low(PIN_E2); enable_interrupts(INT_TIMER0); //T0の割込み解除 enable_interrupts(GLOBAL); //全割込み解除 while(1) // 割込みを待つ { } return 0; } //*************************************************************************************************** //*************************************************************************************************** //*************************************************************************************************** // <PC 側> // このプログラムは C++ Builder Ver.6 で作成されています。 プログラムのソースコード //**************************************************************************************************** //**************************************************************************************************** //--------------------------------------------------------------------------- // Unit1.cpp ファイル(メインスレッド) #include <vcl.h> #pragma hdrstop #include <stdio.h> #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "MsTimer" #pragma resource "*.dfm" TForm1 *Form1; SYSTEMTIME stTime; //システムタイム構造体 int ix = 0; extern HANDLE hPort; // ポートハンドル //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { receiveThread = new TReceiveThread(true); //__fastcall TReceiveThread(bool CreateSuspended); //引数:CreateSuspendedがtrueの場合、Execute 関数が実行可能な状態で待機している //Execute 関数が実行可能な状態で待機している } //--------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { CloseHandle( hPort // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 ); if(receiveThread)receiveThread->Terminate();// } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { RichEdit1->Lines->Clear(); RichEdit2->Lines->Clear(); } //--------------------------------------------------------------------------- void __fastcall TForm1::MsTimer1Timer(TObject *Sender) { char strTime[128]; const char* KanjiWeek[7] = {"(日)","(月)","(火)","(水)","(木)","(金)","(土)"}; AnsiString ansiStr; GetLocalTime(&stTime); sprintf(strTime , "%4d年 %2d月 %2d日 %s %2d時 %2d分 %2d秒" , stTime.wYear , stTime.wMonth , stTime.wDay , KanjiWeek[stTime.wDayOfWeek], stTime.wHour , stTime.wMinute , stTime.wSecond ); PcTimeMemo->Text = strTime; sprintf(strTime,"%03d",stTime.wMilliseconds); RichEdit2->SelText = (AnsiString)strTime; RichEdit2->SelText = " "; ix++; if(ix >= 10) { ix = 0; RichEdit2->SelText = "\n"; RichEdit2->SelText = "\n"; } } //--------------------------------------------------------------------------- //************************************************************************************************* //Unit2.cpp ファイル(受信スレッド) //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "mem.h" #include "Unit2.h" #pragma package(smart_init) HANDLE hPort; // ポートハンドル DCB dcb; // DCB構造体 COMMTIMEOUTS timeout; // COMMTIMEOUTS構造体 BOOL Ret; // 関数戻り値 char* szStr; DWORD nNumberOfBytesToWrite; // 送信データのバイト数 DWORD nNumberOfBytesWritten; // 実際に送信されたデータのバイト数 BYTE bReceiveBuffer[10]; // 受信データ DWORD nNumberOfBytesRead; // 実際に受信されたデータのバイト数 int iy = 0; __fastcall TReceiveThread::TReceiveThread(bool CreateSuspended) : TThread(CreateSuspended) { // (COM2ポートの)ポートハンドルを取得する hPort = CreateFile( "COM2", // ポートの名前: どのポートを開くのか GENERIC_READ|GENERIC_WRITE, // アクセスモード: 通常送受信ともするので読書き両方を指定 0, // 共有モード: 通常0に設定 再オープン禁止 NULL, //セキュリティアトリビュート:通信では通常NULLに設定 OPEN_EXISTING, // クリエイトディストリビューション:通常COMポートはすでに存在しているのでOPEN_EXISTINGとします。 FILE_ATTRIBUTE_NORMAL, // 属性:通信の場合属性はないのでFILE_ATTRIBUTE_NORMAL(属性なし)を指定 NULL // テンプレートのハンドル: 通信の場合関係ない 通常NULLを指定 ); if(hPort == INVALID_HANDLE_VALUE) //ハンドル取得に失敗した場合 { MessageBox(NULL , "Port could not open" , "警告" , MB_OK); exit(0); } Ret = SetupComm( //設定 hPort, // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 512, // 受信バッファーサイズ: 受信のバッファーサイズをバイト単位で指定 512 // 送信バッファーサイズ: 送信のバッファーサイズをバイト単位で指定 ); if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetupComm failed" , TEXT("警告") , MB_OK); CloseHandle(hPort); exit(0); } Ret = PurgeComm( //消去 hPort, //通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR // 実行する操作: 上記は未処理の読書きの中止及び送受信のバッファーのクリアを指定 ); if(Ret == FALSE) //失敗した場合 { MessageBox(NULL , "PurgeComm failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } dcb.DCBlength = sizeof(DCB); // DCBのサイズ: //データ dcb.BaudRate = 19200; // 伝送速度: ボーレートをbps単位で指定 dcb.fBinary = TRUE; // バイナリモード: 通常TRUEに設定 dcb.ByteSize = 8; // データサイズ : 通常 8 ビット dcb.fParity = NOPARITY; // パリティ有無種類 : パリティなしの場合はNOPARITYを指定 // 奇数パリティの場合は ODDPARITY 他 dcb.StopBits = ONESTOPBIT; // ストップビットの数: 通常1ビット→ ONESTOPBIT; //ハードウェアフロー制御 dcb.fOutxCtsFlow = FALSE; // CTSハードウェアフロー制御:CTS制御を使用しない場合はFLASEを指定 // CTS制御をする場合はTRUEを指定してCTS信号を監視します。 dcb.fOutxDsrFlow = FALSE; // DSRハードウェアフロー制御:使用しない場合はFALSEを指定 dcb.fDtrControl = DTR_CONTROL_DISABLE;// DTR有効/無効: 無効なら DTR_CONTROL_DISABLE;ISABLE dcb.fRtsControl = RTS_CONTROL_DISABLE; // RTS制御: RTS制御をしない場合はRTS_CONTROL_DISABLEを指定 // RTS制御をする場合はRTS_CONTROL_ENABLEを指定 他 // ソフトウェアフロー制御 dcb.fOutX = FALSE; // 送信時XON/OFF制御の有無: なし→FLALSE dcb.fInX = FALSE; // 受信時XON/XOFF制御の有無:なし→FALSE dcb.fTXContinueOnXoff = TRUE; // 受信バッファー満杯&XOFF受信後の継続送信可否:送信可→TRUE dcb.XonLim = 512; // XONが送られるまでに格納できる最小バイト数: dcb.XoffLim = 512; // XOFFが送られるまでに格納できる最小バイト数: dcb.XonChar = 0x11; // 送信時XON文字 ( 送信可:ビジィ解除 ) の指定: // 一般に、XON文字として11H ( デバイス制御1:DC1 )がよく使われます dcb.XoffChar = 0x13; // XOFF文字(送信不可:ビジー通告)の指定:なし→FALSE // 一般に、XOFF文字として13H ( デバイス制御3:DC3 )がよく使われます //その他 dcb.fNull = TRUE; // NULLバイトの破棄: 破棄する→TRUE dcb.fAbortOnError = TRUE; // エラー時の読み書き操作終了: 終了する→TRUE dcb.fErrorChar = FALSE; // パリティエラー発生時のキャラクタ(ErrorChar)置換: なし→FLALSE dcb.ErrorChar = 0x00; // パリティエラー発生時の置換キャラクタ dcb.EofChar = 0x03; // データ終了通知キャラクタ : 一般に0x03(ETX)がよく使われます。 dcb.EvtChar = 0x02; // イベント通知キャラクタ : 一般に0x02(STX)がよく使われます Ret = SetCommState(hPort, &dcb); //SetCommState()関数にポートハンドルおよびdcb構造体のアドレスを代入する if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetCommState failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } timeout.ReadIntervalTimeout = 5; // 文字読込時の1文字あたりのタイムアウトまでの待ち時間(msec) timeout.ReadTotalTimeoutMultiplier = 0; //読込の1文字あたりの時間 timeout.ReadTotalTimeoutConstant = 100; //読込エラー検出用のタイムアウト時間 //(受信トータルタイムアウト) = ReadTotalTimeoutMultiplier * (受信予定バイト数) + ReadTotalTimeoutConstant timeout.WriteTotalTimeoutMultiplier = 5; //書き込み1文字あたりのタイムアウトまでの待ち時間 timeout.WriteTotalTimeoutConstant = 100;//書き込みエラー検出用のタイムアウト時間 //(送信トータルタイムアウト) = WriteTotalTimeoutMultiplier * (送信予定バイト数) + WriteTotalTimeoutConstant Ret = SetCommTimeouts(hPort, &timeout);//SetCommTimeOut()関数にポートハンドルおよびCOMMTIMEOUTS構造体の //アドレスを代入します。 if(Ret == FALSE) //失敗した場合 { MessageBox(NULL,"SetCommTimeouts failed","警告", MB_OK); CloseHandle(hPort); exit(0); } FreeOnTerminate = true; //スレッド終了後にオブジェクト(メモリ)を自動的に開放する //delete receiveThread; は不要 Resume(); } //--------------------------------------------------------------------------- void __fastcall TReceiveThread::Execute() { // TODO : スレッドとして実行したいコードを以下に記述 */ while(!Terminated) { memset(&bReceiveBuffer,0,sizeof(&bReceiveBuffer)); Ret = ReadFile( // データの受信 hPort, // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 &bReceiveBuffer, // 受信バッファーのポインタを指定: 受信データがここに格納されます。 5, // 受信するバイト数を指定: ここで指定するバイト数を受信するかまたはタイムアウト時間がくるまで // ReadFile()関数は( getc()のように )待ちます &nNumberOfBytesRead, // 実際に受信したバイト数が格納されるDWORD値のポインタを指定 NULL // 通信とは関係ない引数なのでNULLを指定 ); if(Ret == FALSE) //失敗した場合 { Application->MessageBox("データの読み出しでエラーが発生", "警告", MB_OK ) ; CloseHandle(hPort); exit(0); } bReceiveBuffer[nNumberOfBytesRead] = '\0'; szStr = &bReceiveBuffer[0]; Synchronize(UpdateReceiveEdit); } } //--------------------------------------------------------------------------- void __fastcall TReceiveThread::UpdateReceiveEdit(void) { AnsiString str; str.sprintf("%s",szStr); // 受信データ(PICが計算した値)を表示 Form1->RichEdit1->SelText = str; Form1->RichEdit1->SelText = " "; iy++; if(iy >= 10) { iy = 0; Form1->RichEdit1->SelText = "\n"; } }
<動作結果>
・下記にWindowsの画面を示します。
・PICからのデータとして50msec毎にインクリメントされた整数が送られてきています。エディットボックスの1行にデータが
10個になる500msec毎に改行されています。
・右の欄にはPCのシステム時刻が表示さています。”PC時刻”エディットボックスにはPICからのデータとは非同期で、
マルチメディアタイマによる正確な100msec毎のSTSTEMTIMEのmsecの時刻が表示されていくようになっています。
表示データが10個になる1000msec毎に2行改行されています。
・クリアボタンをクリックすると両方のエディットボックスが同時にクリアされて左上隅から表示が始まるようにプログラムは
できています。
(7)文字列の送受信 ( Win32API - PIC間 マルチスレッド 受信スレッド: イベント動作型 ) <CCS編>
CPUの時間を浪費しない、イベントが発生するまでスレッドを待機させた”イベント動作型受信スレッド”の例を紹介し
ます。ハード及びPICのソフトは(6)と同じです。(→PCスレッドプログラムの説明)
<試作品の仕様>
★ PC側
・メインスレッドから受信スレッドを生成し、イベントが発生(PICからのデータが受信バッファーに受信完了)した時に
スレッドの動作を開始する。
・PIC側からデータを受信したら、速やかにメインウィンドウ(メインスレッド)の”PICからの受信エディタ”に表示する。
・PIC側からのデータ受信タイミングとは非同期で、100msec毎にPCの時刻を表示する。
・時刻は SYSTEMTIME構造体から取得する。
★ PIC側
・50msec毎に整数をインクリメントして 19200bps でPC側に送信する。
<試作品回路図>(→回路図のPDFファイル)
PIC18F452をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> <CCS編>
// <PIC側> //***************************************************************************** //マルチスレッド送受信用 // プログラム PIC18F452 //***************************************************************************** #include "18f452.h" #include "string.h" #include "stdio.h" #use delay(clock=40000000) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=19200,XMIT=PIN_C6,RCV=PIN_C7) // ボーレート = 19200bps TX=RC6,RX=RC7 #define ETX 0x03 // ETX #define ESC 0x1b // ESC #define NAK 0x15 // タイムアウトした場合の送信文字としてNAKを使用 long int Count_25msec = 0; unsigned long int data1 = 0; #int_timer0 //タイマ1割込み(25msec毎に割込み発生) interval() { set_timer0(34286); // 0.025μsec× 4 × 8 × 31250 = 25000usec = 25msec (st システムクロック40MHz) // 256×256 - 31250 = 34286 Count_25msec++; if(Count_25msec >=2) { Count_25msec = 0; data1++; if(data1 >= 65535)data1 = 0; // printf("%lu\r\n",data1); printf("%lu",data1); } return 0; } main() { setup_timer_0(RTCC_INTERNAL |RTCC_DIV_8); set_timer0(34286); set_tris_b(0xFF); // RCON = (RCON | 0b10000000); //リセット制御レジスタのb7 = 1 → 割込み優先順位制御有 //タイマ0優先 // INTCON2 = (INTCON2 | 0b00001000);//割込み制御レジスタ2のb3 = 1 → タイマ0割込みを高位レベル割込みにセット // IPR1 = (IPR1 & 0b11001111); //割込み優先順位レジスタ1のb4=0 b5=0 → UARTの送受信割込みを低位レベル割込みにセット delay_ms(1000); output_low(PIN_E2); enable_interrupts(INT_TIMER0); //T0の割込み解除 enable_interrupts(GLOBAL); //全割込み解除 while(1) // 割込みを待つ { } return 0; } //*************************************************************************************************** //*************************************************************************************************** //*************************************************************************************************** // <PC 側> // このプログラムは C++ Builder Ver.6 で作成されています。 プログラムのソースコード //**************************************************************************************************** //**************************************************************************************************** //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <stdio.h> //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "MsTimer" #pragma resource "*.dfm" TForm1 *Form1; SYSTEMTIME stTime; //システムタイム構造体 int ix = 0; extern HANDLE hPort; // ポートハンドル extern HANDLE hReceive; //イベントハンドル //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { receiveThread = new TReceiveThread(true); //受信スレッドのメモリを実装 //CreateSuspendedがtrueの場合、Execute 関数が実行可能な状態で待機している //Execute 関数が実行可能な状態で待機している //// イベントをオートリセット、シグナル状態で作成する //→RS232C受信バッファがデータを受信したらイベントを発生させる hReceive = CreateEvent(NULL, false, true, NULL); //自動リセット、初期状態シグナル(待ち状態) } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { RichEdit2->Lines->Clear(); RichEdit1->Lines->Clear(); } //--------------------------------------------------------------------------- void __fastcall TForm1::MsTimer1Timer(TObject *Sender) { char strTime[128]; const char* KanjiWeek[7] = {"(日)","(月)","(火)","(水)","(木)","(金)","(土)"}; AnsiString ansiStr; GetLocalTime(&stTime); sprintf(strTime , "%4d年 %2d月 %2d日 %s %2d時 %2d分 %2d秒" , stTime.wYear , stTime.wMonth , stTime.wDay , KanjiWeek[stTime.wDayOfWeek], stTime.wHour , stTime.wMinute , stTime.wSecond ); PcTimeMemo->Text = strTime; sprintf(strTime,"%03d",stTime.wMilliseconds); RichEdit2->SelText = (AnsiString)strTime; RichEdit2->SelText = " "; ix++; if(ix >= 10) { ix = 0; RichEdit2->SelText = "\n"; RichEdit2->SelText = "\n"; } } //--------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { CloseHandle( hPort // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 ); if(receiveThread)receiveThread->Terminate();// } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit2.h" #include "Unit1.h" #include "mem.h" #pragma package(smart_init) HANDLE hPort; // ポートハンドル DCB dcb; // DCB構造体 COMMTIMEOUTS timeout; // COMMTIMEOUTS構造体 BOOL Ret; // 関数戻り値 char* szStr; // BYTE bSendBuffer[10]; // 送信データ DWORD nNumberOfBytesToWrite; // 送信データのバイト数 DWORD nNumberOfBytesWritten; // 実際に送信されたデータのバイト数 BYTE bReceiveBuffer[10]; // 受信データ DWORD nNumberOfBytesRead; // 実際に受信されたデータのバイト数 HANDLE hReceive; int iy; __fastcall TReceiveThread::TReceiveThread(bool CreateSuspended) : TThread(CreateSuspended) { // (COM2ポートの)ポートハンドルを取得する hPort = CreateFile( "COM2", // ポートの名前: どのポートを開くのか GENERIC_READ|GENERIC_WRITE, // アクセスモード: 通常送受信ともするので読書き両方を指定 0, // 共有モード: 通常0に設定 再オープン禁止 NULL, //セキュリティアトリビュート:通信では通常NULLに設定 OPEN_EXISTING, // クリエイトディストリビューション:通常COMポートはすでに存在しているのでOPEN_EXISTINGとします。 FILE_ATTRIBUTE_NORMAL, // 属性:通信の場合属性はないのでFILE_ATTRIBUTE_NORMAL(属性なし)を指定 NULL // テンプレートのハンドル: 通信の場合関係ない 通常NULLを指定 ); if(hPort == INVALID_HANDLE_VALUE) //ハンドル取得に失敗した場合 { MessageBox(NULL , "Port could not open" , "警告" , MB_OK); exit(0); } Ret = SetupComm( //設定 hPort, // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 512, // 受信バッファーサイズ: 受信のバッファーサイズをバイト単位で指定 512 // 送信バッファーサイズ: 送信のバッファーサイズをバイト単位で指定 ); if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetupComm failed" , TEXT("警告") , MB_OK); CloseHandle(hPort); exit(0); } Ret = PurgeComm( //消去 hPort, //通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR // 実行する操作: 上記は未処理の読書きの中止及び送受信のバッファーのクリアを指定 ); if(Ret == FALSE) //失敗した場合 { MessageBox(NULL , "PurgeComm failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } dcb.DCBlength = sizeof(DCB); // DCBのサイズ: //データ dcb.BaudRate = 19200; // 伝送速度: ボーレートをbps単位で指定 dcb.fBinary = TRUE; // バイナリモード: 通常TRUEに設定 dcb.ByteSize = 8; // データサイズ : 通常 8 ビット dcb.fParity = NOPARITY; // パリティ有無種類 : パリティなしの場合はNOPARITYを指定 // 奇数パリティの場合は ODDPARITY 他 dcb.StopBits = ONESTOPBIT; // ストップビットの数: 通常1ビット→ ONESTOPBIT; //ハードウェアフロー制御 dcb.fOutxCtsFlow = FALSE; // CTSハードウェアフロー制御:CTS制御を使用しない場合はFLASEを指定 // CTS制御をする場合はTRUEを指定してCTS信号を監視します。 dcb.fOutxDsrFlow = FALSE; // DSRハードウェアフロー制御:使用しない場合はFALSEを指定 dcb.fDtrControl = DTR_CONTROL_DISABLE;// DTR有効/無効: 無効なら DTR_CONTROL_DISABLE;ISABLE dcb.fRtsControl = RTS_CONTROL_DISABLE; // RTS制御: RTS制御をしない場合はRTS_CONTROL_DISABLEを指定 // RTS制御をする場合はRTS_CONTROL_ENABLEを指定 他 // ソフトウェアフロー制御 dcb.fOutX = FALSE; // 送信時XON/OFF制御の有無: なし→FLALSE dcb.fInX = FALSE; // 受信時XON/XOFF制御の有無:なし→FALSE dcb.fTXContinueOnXoff = TRUE; // 受信バッファー満杯&XOFF受信後の継続送信可否:送信可→TRUE dcb.XonLim = 512; // XONが送られるまでに格納できる最小バイト数: dcb.XoffLim = 512; // XOFFが送られるまでに格納できる最小バイト数: dcb.XonChar = 0x11; // 送信時XON文字 ( 送信可:ビジィ解除 ) の指定: // 一般に、XON文字として11H ( デバイス制御1:DC1 )がよく使われます dcb.XoffChar = 0x13; // XOFF文字(送信不可:ビジー通告)の指定:なし→FALSE // 一般に、XOFF文字として13H ( デバイス制御3:DC3 )がよく使われます //その他 dcb.fNull = TRUE; // NULLバイトの破棄: 破棄する→TRUE dcb.fAbortOnError = TRUE; // エラー時の読み書き操作終了: 終了する→TRUE dcb.fErrorChar = FALSE; // パリティエラー発生時のキャラクタ(ErrorChar)置換: なし→FLALSE dcb.ErrorChar = 0x00; // パリティエラー発生時の置換キャラクタ dcb.EofChar = 0x03; // データ終了通知キャラクタ : 一般に0x03(ETX)がよく使われます。 dcb.EvtChar = 0x02; // イベント通知キャラクタ : 一般に0x02(STX)がよく使われます Ret = SetCommState(hPort, &dcb); //SetCommState()関数にポートハンドルおよびdcb構造体のアドレスを代入する if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetCommState failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } timeout.ReadIntervalTimeout = 5; // 文字読込時の1文字あたりのタイムアウトまでの待ち時間(msec) timeout.ReadTotalTimeoutMultiplier = 0; //読込の1文字あたりの時間 timeout.ReadTotalTimeoutConstant = 100; //読込エラー検出用のタイムアウト時間 //(受信トータルタイムアウト) = ReadTotalTimeoutMultiplier * (受信予定バイト数) + ReadTotalTimeoutConstant timeout.WriteTotalTimeoutMultiplier = 5; //書き込み1文字あたりのタイムアウトまでの待ち時間 timeout.WriteTotalTimeoutConstant = 100;//書き込みエラー検出用のタイムアウト時間 //(送信トータルタイムアウト) = WriteTotalTimeoutMultiplier * (送信予定バイト数) + WriteTotalTimeoutConstant Ret = SetCommTimeouts(hPort, &timeout);//SetCommTimeOut()関数にポートハンドルおよびCOMMTIMEOUTS構造体の //アドレスを代入します。 if(Ret == FALSE) //失敗した場合 { MessageBox(NULL,"SetCommTimeouts failed","警告", MB_OK); CloseHandle(hPort); exit(0); } FreeOnTerminate = true; //スレッド終了後にオブジェクト(メモリ)を自動的に開放する //delete receiveThread; は不要 Resume(); //スタート } //--------------------------------------------------------------------------- void __fastcall TReceiveThread::Execute() { // TODO : スレッドとして実行したいコードを以下に記述 */ while(!Terminated) { //// 読込イベントが発生するまでTCounterThreadはsuspend状態になって待機する WaitForSingleObject(hReceive, INFINITE); memset(&bReceiveBuffer,0,sizeof(&bReceiveBuffer)); Ret = ReadFile( // データの受信 hPort, // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 &bReceiveBuffer, // 受信バッファーのポインタを指定: 受信データがここに格納されます。 5, // 受信するバイト数を指定: ここで指定するバイト数を受信するかまたはタイムアウト時間がくるまで // ReadFile()関数は( getc()のように )待ちます &nNumberOfBytesRead, // 実際に受信したバイト数が格納されるDWORD値のポインタを指定 NULL // 通信とは関係ない引数なのでNULLを指定 ); if(Ret == FALSE) //失敗した場合 { Application->MessageBox("データの読み出しでエラーが発生", "警告", MB_OK ) ; CloseHandle(hPort); exit(0); } bReceiveBuffer[nNumberOfBytesRead] = '\0'; szStr = &bReceiveBuffer[0]; Synchronize(UpdateReceiveEdit); //Windowsで同期をとってメインスレッドで実行 //// イベント発生をセット SetEvent(hReceive); } } //--------------------------------------------------------------------------- void __fastcall TReceiveThread::UpdateReceiveEdit(void) { AnsiString str; str.sprintf("%s",szStr); // 受信データ(PICが計算した値)を表示 Form1->RichEdit1->SelText = str; Form1->RichEdit1->SelText = " "; iy++; if(iy >= 10) { iy = 0; Form1->RichEdit1->SelText = "\n"; } }
<動作結果>
・下記にWindowsの画面を示します。 結果は(6)の非イベント動作型受信スレッドの場合と全く同じです。 CPUパワーが
必要なアプリを平行して動作させた場合は明確な違いを感じることでしょう。
・PICからのデータとして50msec毎にインクリメントされた整数が送られてきています。エディットボックスの1行にデータが
10個になる500msec毎に改行されています。
・右の欄にはPCのシステム時刻が表示さています。”PC時刻”エディットボックスにはPICからのデータとは非同期で、
マルチメディアタイマによる正確な100msec毎のSTSTEMTIMEのmsecの時刻が表示されていくようになっています。
表示データが10個になる1000msec毎に2行改行されています。
・クリアボタンをクリックすると両方のエディットボックスが同時にクリアされて左上隅から表示が始まるようにプログラムは
できています。
(8)文字列の送受信 (Win32API - PIC間 マルチスレッド クリティカルセクション ) <CCS編>
2つのスレッドが1つの共有するデータにアクセスすると問題が発生します。データベースのひとつのデータを2人が
同時に書き込みをおこなった場合を考えれば問題の重大さがわかります。2つのスレッドが同時にアクセスする可能性が
ある部分をクリティカルセクションと云います。 Win32APIにはクリティカルセクションへの同時アクセスをブロックする
関数が用意されています。以下に使用例を紹介します。(→PCスレッドプログラムの説明)
<試作品の仕様>
★ PC側
・メインスレッドから受信スレッドを生成しでPIC側からの送信データを監視する。
・PIC側から100msec毎に送られてくるデータを受信スレッドで受信したら、30msecのスレッドスリープ後メインウィン
ドウ(メインスレッド)の”PICからの受信エディタ”に表示する。
・一方、PICから送られてきた表示前の受信データを50msec毎にメインスレッドで”00000”に書き換える。
・同じ変数(受信データ)を書き込む下記部分をクリティカルセクションにする。
@受信スレッド上でPIC側からの受信データを処理して表示するSynchronize( )関数部分
Aメインスレッド上で受信データを”00000”に書き換える部分
・クリティカルセクション有無をメインウィンドウのチェックボックスで切り替えられるようにする。
★ PIC側
・100msec毎に整数をインクリメントして 19200bps でPC側に送信する。
<試作品回路図>(→回路図のPDFファイル)
PIC18F452をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> <CCS編> //***************************************************************************** //マルチスレッド送受信用 // プログラム PIC18F452 //***************************************************************************** #include "18f452.h" #include "string.h" #include "stdio.h" #use delay(clock=40000000) #FUSES H4,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=19200,XMIT=PIN_C6,RCV=PIN_C7) // ボーレート = 19200bps TX=RC6,RX=RC7 #define ETX 0x03 // ETX #define ESC 0x1b // ESC #define NAK 0x15 // タイムアウトした場合の送信文字としてNAKを使用 long int Count_25msec = 0; unsigned long int data1 = 0; #int_timer0 //タイマ1割込み(25msec毎に割込み発生) interval() { set_timer0(34286); // 0.025μsec× 4 × 8 × 31250 = 25000usec = 25msec (st システムクロック40MHz) // 256×256 - 31250 = 34286 Count_25msec++; if(Count_25msec >=4) { Count_25msec = 0; data1++; if(data1 >= 65535)data1 = 0; // printf("%lu\r\n",data1); printf("%lu",data1); } return 0; } main() { setup_timer_0(RTCC_INTERNAL |RTCC_DIV_8); set_timer0(34286); set_tris_b(0xFF); // RCON = (RCON | 0b10000000); //リセット制御レジスタのb7 = 1 → 割込み優先順位制御有 //タイマ0優先 // INTCON2 = (INTCON2 | 0b00001000);//割込み制御レジスタ2のb3 = 1 → タイマ0割込みを高位レベル割込みにセット // IPR1 = (IPR1 & 0b11001111); //割込み優先順位レジスタ1のb4=0 b5=0 → UARTの送受信割込みを低位レベル割込みにセット delay_ms(1000); output_low(PIN_E2); enable_interrupts(INT_TIMER0); //T0の割込み解除 enable_interrupts(GLOBAL); //全割込み解除 while(1) // 割込みを待つ { } return 0; } //*************************************************************************************************** //*************************************************************************************************** // <PC 側> // このプログラムは C++ Builder Ver.6 で作成されています。 プログラムのソースコード //**************************************************************************************************** //**************************************************************************************************** //Unit1.cpp //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include <stdio.h> #include "Unit1.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "MsTimer" #pragma resource "*.dfm" TForm1 *Form1; int ix = 0; extern AnsiString str; extern HANDLE hPort; // ポートハンドル extern CRITICAL_SECTION CriticalSection; //クリティカルセクション構造体 extern bool CS_Mode; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { receiveThread = new TReceiveThread(true); //__fastcall TReceiveThread(bool CreateSuspended); //引数:CreateSuspendedがtrueの場合、Execute 関数が実行可能な状態で待機している //Execute 関数が実行可能な状態で待機している // クリティカルセクションを初期化する InitializeCriticalSection(&CriticalSection); } //--------------------------------------------------------------------------- void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action) { CloseHandle( hPort // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 ); if(receiveThread)receiveThread->Terminate();// // クリティカルセクションを削除する DeleteCriticalSection(&CriticalSection); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { RichEdit1->Lines->Clear(); } //--------------------------------------------------------------------------- void __fastcall TForm1::MsTimer1Timer(TObject *Sender) { if(CS_Mode)//クリティカルセクションモードの場合 { EnterCriticalSection(&CriticalSection); //クリティカルセクションモードへ str.sprintf("0000"); // PICからの受信データを表示 LeaveCriticalSection(&CriticalSection); //クリティカルセクションモード終了 } else str.sprintf("00000"); // PICからの受信データを表示 } //--------------------------------------------------------------------------- //Unit2.cpp //--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include "mem.h" #include "Unit2.h" #pragma package(smart_init) HANDLE hPort; // ポートハンドル DCB dcb; // DCB構造体 COMMTIMEOUTS timeout; // COMMTIMEOUTS構造体 BOOL Ret; // 関数戻り値 char* szStr; DWORD nNumberOfBytesToWrite; // 送信データのバイト数 DWORD nNumberOfBytesWritten; // 実際に送信されたデータのバイト数 BYTE bReceiveBuffer[10]; // 受信データ DWORD nNumberOfBytesRead; // 実際に受信されたデータのバイト数 int iy = 0; AnsiString str; CRITICAL_SECTION CriticalSection; //クリティカルセクション構造体 bool CS_Mode; //-------------------------------------------------------------------------- __fastcall TReceiveThread::TReceiveThread(bool CreateSuspended) : TThread(CreateSuspended) { // (COM2ポートの)ポートハンドルを取得する hPort = CreateFile( "COM2", // ポートの名前: どのポートを開くのか GENERIC_READ|GENERIC_WRITE, // アクセスモード: 通常送受信ともするので読書き両方を指定 0, // 共有モード: 通常0に設定 再オープン禁止 NULL, //セキュリティアトリビュート:通信では通常NULLに設定 OPEN_EXISTING, // クリエイトディストリビューション:通常COMポートはすでに存在しているのでOPEN_EXISTINGとします。 FILE_ATTRIBUTE_NORMAL, // 属性:通信の場合属性はないのでFILE_ATTRIBUTE_NORMAL(属性なし)を指定 NULL // テンプレートのハンドル: 通信の場合関係ない 通常NULLを指定 ); if(hPort == INVALID_HANDLE_VALUE) //ハンドル取得に失敗した場合 { MessageBox(NULL , "Port could not open" , "警告" , MB_OK); exit(0); } Ret = SetupComm( //設定 hPort, // 通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 512, // 受信バッファーサイズ: 受信のバッファーサイズをバイト単位で指定 512 // 送信バッファーサイズ: 送信のバッファーサイズをバイト単位で指定 ); if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetupComm failed" , TEXT("警告") , MB_OK); CloseHandle(hPort); exit(0); } Ret = PurgeComm( //消去 hPort, //通信デバイスのハンドル:CreateFile()で取得したハンドルを指定 PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR // 実行する操作: 上記は未処理の読書きの中止及び送受信のバッファーのクリアを指定 ); if(Ret == FALSE) //失敗した場合 { MessageBox(NULL , "PurgeComm failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } dcb.DCBlength = sizeof(DCB); // DCBのサイズ: //データ dcb.BaudRate = 19200; // 伝送速度: ボーレートをbps単位で指定 dcb.fBinary = TRUE; // バイナリモード: 通常TRUEに設定 dcb.ByteSize = 8; // データサイズ : 通常 8 ビット dcb.fParity = NOPARITY; // パリティ有無種類 : パリティなしの場合はNOPARITYを指定 // 奇数パリティの場合は ODDPARITY 他 dcb.StopBits = ONESTOPBIT; // ストップビットの数: 通常1ビット→ ONESTOPBIT; //ハードウェアフロー制御 dcb.fOutxCtsFlow = FALSE; // CTSハードウェアフロー制御:CTS制御を使用しない場合はFLASEを指定 // CTS制御をする場合はTRUEを指定してCTS信号を監視します。 dcb.fOutxDsrFlow = FALSE; // DSRハードウェアフロー制御:使用しない場合はFALSEを指定 dcb.fDtrControl = DTR_CONTROL_DISABLE;// DTR有効/無効: 無効なら DTR_CONTROL_DISABLE;ISABLE dcb.fRtsControl = RTS_CONTROL_DISABLE; // RTS制御: RTS制御をしない場合はRTS_CONTROL_DISABLEを指定 // RTS制御をする場合はRTS_CONTROL_ENABLEを指定 他 // ソフトウェアフロー制御 dcb.fOutX = FALSE; // 送信時XON/OFF制御の有無: なし→FLALSE dcb.fInX = FALSE; // 受信時XON/XOFF制御の有無:なし→FALSE dcb.fTXContinueOnXoff = TRUE; // 受信バッファー満杯&XOFF受信後の継続送信可否:送信可→TRUE dcb.XonLim = 512; // XONが送られるまでに格納できる最小バイト数: dcb.XoffLim = 512; // XOFFが送られるまでに格納できる最小バイト数: dcb.XonChar = 0x11; // 送信時XON文字 ( 送信可:ビジィ解除 ) の指定: // 一般に、XON文字として11H ( デバイス制御1:DC1 )がよく使われます dcb.XoffChar = 0x13; // XOFF文字(送信不可:ビジー通告)の指定:なし→FALSE // 一般に、XOFF文字として13H ( デバイス制御3:DC3 )がよく使われます //その他 dcb.fNull = TRUE; // NULLバイトの破棄: 破棄する→TRUE dcb.fAbortOnError = TRUE; // エラー時の読み書き操作終了: 終了する→TRUE dcb.fErrorChar = FALSE; // パリティエラー発生時のキャラクタ(ErrorChar)置換: なし→FLALSE dcb.ErrorChar = 0x00; // パリティエラー発生時の置換キャラクタ dcb.EofChar = 0x03; // データ終了通知キャラクタ : 一般に0x03(ETX)がよく使われます。 dcb.EvtChar = 0x02; // イベント通知キャラクタ : 一般に0x02(STX)がよく使われます Ret = SetCommState(hPort, &dcb); //SetCommState()関数にポートハンドルおよびdcb構造体のアドレスを代入する if(Ret == FALSE) // 失敗した場合 { MessageBox(NULL , "SetCommState failed" , "警告" , MB_OK); CloseHandle(hPort); exit(0); } timeout.ReadIntervalTimeout = 5; // 文字読込時の1文字あたりのタイムアウトまでの待ち時間(msec) timeout.ReadTotalTimeoutMultiplier = 0; //読込の1文字あたりの時間 timeout.ReadTotalTimeoutConstant = 100; //読込エラー検出用のタイムアウト時間 //(受信トータルタイムアウト) = ReadTotalTimeoutMultiplier * (受信予定バイト数) + ReadTotalTimeoutConstant timeout.WriteTotalTimeoutMultiplier = 5; //書き込み1文字あたりのタイムアウトまでの待ち時間 timeout.WriteTotalTimeoutConstant = 100;//書き込みエラー検出用のタイムアウト時間 //(送信トータルタイムアウト) = WriteTotalTimeoutMultiplier * (送信予定バイト数) + WriteTotalTimeoutConstant Ret = SetCommTimeouts(hPort, &timeout);//SetCommTimeOut()関数にポートハンドルおよびCOMMTIMEOUTS構造体の //アドレスを代入します。 if(Ret == FALSE) //失敗した場合 { MessageBox(NULL,"SetCommTimeouts failed","警告", MB_OK); CloseHandle(hPort); exit(0); } FreeOnTerminate = true; //スレッド終了後にオブジェクト(メモリ)を自動的に開放する //delete receiveThread; は不要 Resume(); } //--------------------------------------------------------------------------- void __fastcall TReceiveThread::Execute() { // TODO : スレッドとして実行したいコードを以下に記述 */ while(!Terminated) { memset(&bReceiveBuffer,0,sizeof(&bReceiveBuffer)); Ret = ReadFile( // データの受信 hPort, // 通信デバイスのハンドル: CreateFile()で取得したハンドルを指定 &bReceiveBuffer, // 受信バッファーのポインタを指定: 受信データがここに格納されます。 5, // 受信するバイト数を指定: ここで指定するバイト数を受信するかまたはタイムアウト時間がくるまで // ReadFile()関数は( getc()のように )待ちます &nNumberOfBytesRead, // 実際に受信したバイト数が格納されるDWORD値のポインタを指定 NULL // 通信とは関係ない引数なのでNULLを指定 ); if(Ret == FALSE) //失敗した場合 { Application->MessageBox("データの読み出しでエラーが発生", "警告", MB_OK ) ; CloseHandle(hPort); exit(0); } bReceiveBuffer[nNumberOfBytesRead] = '\0'; szStr = &bReceiveBuffer[0]; Synchronize(UpdateReceiveEdit); } } //--------------------------------------------------------------------------- void __fastcall TReceiveThread::UpdateReceiveEdit(void) { CS_Mode = Form1->CheckBox1->Checked; if(CS_Mode)//クリティカルセクションモードの場合 { EnterCriticalSection(&CriticalSection); //クリティカルセクションモードへ str.sprintf("%s",szStr); // 受信データ(PICが計算した値)を表示 Sleep(30); Form1->RichEdit1->SelText = str; Form1->RichEdit1->SelText = " "; iy++; if(iy >= 10) { iy = 0; Form1->RichEdit1->SelText = "\n"; } LeaveCriticalSection(&CriticalSection); //クリティカルセクションモード終了 } else { str.sprintf("%s",szStr); // 受信データ(PICが計算した値)を表示 Sleep(30); Form1->RichEdit1->SelText = str; Form1->RichEdit1->SelText = " "; iy++; if(iy >= 10) { iy = 0; Form1->RichEdit1->SelText = "\n"; } } }
<動作結果>
・動作結果のPC画面を以下に示します
・10行目まではクリティカルセクションのチェックボックスをはずしてPICからのデータを受信しています。50msec毎に
受信データが”00000”に書き換えられているのがわかります。
・10行目に表示が移動したタイミングでマウスでクリティカルセクションのチェックをONにしました。クリティカルセクション
制御がONになったため受信データの書き換えがおこらなくなりすべての受信データが正常に表示されるようになって
います。
(9) 文字の送受信 ( .NET − PIC 間 ) <CCS編><C18編>
PC側を C#によるMicrosoft .NET Framework 3.0のアプリとした場合のPICとの通信例を紹介します。
( .NET側については .NET側プログラムを参照願います)
PIC側は、割込み制御レジスタのUSART受信完了フラグがたった時、割込みを発生させています。
<試作品仕様>
・ PCのCOMポートとPICをつなぎ PC(Microsoft .NET Framework 3.0)とPIC間の通信をおこなう。
送受信は1バイトのASCIIコードとする。(Shift JIS とする。 16バイトのUnicodeではない)
・ PCの画面上の”A”、”B”、”C”ボタンをマウスでクリックすると A、B、C が送信される。
・ PIC側でこれを受信し、液晶にそれぞれ以下のように表示する。
(例) 2番目にクリックしたボタンが”B”の場合 …… buf[1]=B
・ ”Enter”ボタンをボタンをクリックすると ”\r”が送信され、それまでに送信されてきた文字すべてをまとめて1行で 液晶に表示する。
(例) ”A” ”B” ”C” とクリックしたあとに”Enter”がクリックされた場合 …… ABC
・また ”Enter”ボタンがクリックされた時にはそれまでに送信されてきた文字をまとめてPC側に送信する。
・PC側ではおくられてきた文字をテキストボックスに表示する
<試作品回路図>(→回路図のPDFファイル)
PIC18F4550をつかった場合の回路図を以下に示します。
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
★ <CCS編>
PIC側のプログラムを以下に示します。PC側のプログラムは PC側プログラムを参照願います <プログラム例>
// PC側 (.NET Flamework) → RS232C → PIC18F4550 + LCD // RDA割込みによる受信 /* PCモニタ出力 buf[0]=a buf[1]=b buf[2]=c abc buf[0]=1 buf[1]=2 buf[2]=3 buf[3]=4 buf[4]=5 12345 */ #include "18f4550.h" #use delay(clock=20000000) // 20MHz(システムクロック周波数) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7,stream=PC) // ボーレート = 9600bps TX=RC6,RX=RC7 #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //rs #define stb PIN_D0 //strobe #include <1lcd_lib.c> char buf[20]; int i =0; #INT_RDA void rs232c() { buf[i] = getc(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; printf(buf); // 送信されてきていた文字を 文字列としてPCに一括送信 putc('\r');putc('\n');putc('\r');putc('\n'); //1行あける //液晶に出力 lcd_clear();// 液晶オールクリア lcd_cmd(0xC0);//2行目の先頭へ printf(lcd_data,buf); // 送信されてきていた文字を液晶の2行目に一括表示 i = 0; } else //Enter キー以外が押された場合 { printf("buf[%d]=%c\r\n",i,buf[i]); // PCへエコーバック → ハイパーターミナルに表示 //液晶に出力 lcd_clear();// 液晶オールクリア printf(lcd_data,"buf[%d]=%c",i,buf[i]);// PICに接続してある液晶に受信文字を表示 i++; } } main(){ set_tris_c(0b10000000);// 必須 in = RC7 & RC4 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"start!!"); enable_interrupts(INT_RDA); enable_interrupts(GLOBAL); while(1) { } return 0; }
//--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
<C18編>
<プログラム例> /* PC-PIC間 RS232C通信 <C18コンパイラ> 受信 : 受信時割込み方式 PC : N.NET PIC : PIC18F4550 液晶付 */ #include <p18f4550.h> #include <usart.h> #include <stdio.h> #include "1lcd_lib_C18.h" #include "1lcd_lib_C18.c" #pragma config FOSC = HS // f=20MHz #pragma config WDT = OFF #pragma config LVP = OFF char buf[20]; // タイプした文字用のレジスタ int i = 0; void RS232(void); #pragma code low_vector=0x18 //低位レベル割込み void low_interrupt (void) { _asm GOTO RS232 _endasm } #pragma code #pragma interruptlow RS232 void RS232() // 受信割込み関数 { char Buffer[17]; //液晶表示データの一時保存レジスタ char* str; PIR1bits.RCIF = 0; //PIR1 レジスタのRCIFビット(受信フラグ)をクリア buf[i] = getcUSART(); //受信データを読み込む if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; str = &buf[0]; // ポインタにアドレスを代入 printf("%s",str); // 送信されてきていた文字を 文字列としてPCに一括送信 printf("\n\r\n\r"); //液晶に出力 lcd_clear();// 液晶オールクリア lcd_cmd(0xC0);//2行目の先頭へ while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; } i = 0; } else //Enter キー以外が押された場合 { printf("buf[%d]=%c\r\n",i,buf[i]); // PCへエコーバック → ハイパーターミナルに表示 //液晶に出力 lcd_clear();// 液晶オールクリア sprintf(Buffer,"buf[%d]=%c",i,buf[i]);// PICに接続してある液晶に受信文字を表示 str = &Buffer[0]; // ポインタにアドレスを代入 while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; } i++; } } void main (void) { char tempBuf[17]; //液晶表示データの一時保存レジスタ char* tempStr; TRISC = 0b10111111; //RC7(RX): input mode RC6(TX): output mode OpenUSART( USART_TX_INT_OFF & //送信割込み送信:OFF USART_RX_INT_ON & //割込み受信:ON USART_ASYNCH_MODE & //調歩同期通信モード USART_EIGHT_BIT & //データ長:8ビット USART_CONT_RX & //連続受信モード USART_BRGH_HIGH, //ボーレート:HIGH伝送速度モード spbrg=129 //bau rate = Fosc/(128*(spbrg + 1)) 129 ); // = 20000000/(16*(129 + 1)) = 9615.4 bps // error rate = (9615.4-9600)/9600 = 0.0016 lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF sprintf(tempBuf,"Start2 !!"); //文字列としてバッファーに収納 tempStr = &tempBuf[0]; // ポインタにアドレスを代入 while(*tempStr) //文字列終端の '\0'を検出するまで { lcd_data(*tempStr); // 1文字表示 tempStr++; } RCONbits.IPEN = 0; //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0) INTCONbits.GIE = 1; //全割込み許可 INTCONbits.PEIE = 1; //周辺機能の割込み有効 while (1) { } CloseUSART(); } //************************************************ //インクルードファイル 1lcd_lib_C18.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //************************************************ #define lcd_port LATD //DataOutPort pin : 上位4bit #define lcd_stb LATDbits.LATD0 //stb OutPort #define lcd_rs LATDbits.LATD2 // rs OutPort #define port_Mode TRISD // Port Mode set void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_out(char code, char flag);
//*********************************************** //インクルードファイル 1lcd_lib_C18.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //*********************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C18コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 ////////////////////////////////////////////// #include "delays.h" #include "1lcd_lib_C18.h" //////// データ出力サブ関数 void lcd_out(char code, char flag) { port_Mode = 0; // PIC側の DataPort、stbPort、 rsPort を出力モードに設定 lcd_port = code & 0xF0; if (flag == 0) lcd_rs = 1; //表示データの場合 else lcd_rs = 0; //コマンドデータの場合 Delay10TCYx(1); //10NOP lcd_stb = 1; //strobe out Delay10TCYx(1); //10NOP lcd_stb = 0; //reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 Delay10TCYx(50); //500NOP (50μsec待ち at 40MHz) } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 if((cmd & 0x03) != 0) Delay10KTCYx(2); //2msec待ち at 40MHz else Delay10TCYx(50); //50usec待ち at 40MHz } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); //初期化コマンド出力 // Delay10KTCYx(15); //15msec待ち at 40MHz } /////// 初期化関数 void lcd_init(void) { lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(5); //5msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x20, 1); //4bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x01); //all clear }
<動作結果>
PC画面上で”A”ボタンをクリックした場合 | PC画面上で”A”、”B”、”C”、”C”、”B”、”A”を クリック後 ”Enter”をクリックした場合 |
||
液晶表示 | |||
PCのWindow画面 |
(10)文字列の送受信(.NET 〜 PIC間 マルチスレッド編 英数字の送受信 )<CCS編> <C18編>
.NETのC#、またはC++を使い英数字文字列の送受信をおこなう。
<試作品の仕様> → PC側ソフト(VC#)
→ PC側ソフト(VC++)
・パソコン側は.NETのC#、またはC++とし、RS232Cシリアル通信を用いPIC18F4550と文字列の送受信をおこなう。
・PIC側のコンボボックスにあらかじめ下記の文字をセットしておきボタンをクリックすると選択されていた文字列を送信する。
送信される文字の最後尾には’¥r’付加する。
PIC側ではこれらの文字列を受信したら所定の文字列をPC側に返信する。
Oda → Nobunaga
Toyotomi → Hideyoshi
Tokugawa → Ieyasu
Tanaka → Pardon?
・ PIC側では受信文字、送信文字を液晶に表示する。
・ PC側でも受信文字をテキストボックスに表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC18F4550をつかった場合の回路図を以下に示します
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
★ <CCS編>
PIC側のプログラムを以下に示します。PC側のプログラムは PC側プログラム(C#の場合)、PC側プログラム(C++の場合)を 参照願います <プログラム例> /* ------------------------------------------------------------------ < 構成> PC(C# .NET ) → RS232C → PIC18F4550 + 16文字キャラクタ液晶 -------------------------------------------------------------------- */ #include "18f4550.h" #include "string.h" #use delay(clock=20000000) // 20MHz(システムクロック周波数) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // TX=RC6,RX=RC7 #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> int i = 0; char buf[20]; char Oda[] = "Oda"; char Nobunaga[] = "Nobunaga"; char Toyotomi[] = "Toyotomi"; char Hideyoshi[] = "Hideyoshi"; char Tokugawa[] = "Tokugawa"; char Ieyasu[] = "Ieyasu"; char Tanaka[] = "Tanaka"; char Pardon[] = "Pardon?"; char* str; void LCD() { buf[i] = getc(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Oda) == 0)str = Nobunaga; else if(strcmp(buf,Toyotomi) == 0) str = Hideyoshi; else if(strcmp(buf,Tokugawa) == 0) str = Ieyasu; else str = Pardon; printf(str); // 送信されてきていた文字を 文字列としてPCに一括送信 //液晶に出力 lcd_clear();// 液晶オールクリア printf(lcd_data,buf); // 送信されてきていた文字を液晶の1行目に一括表示 lcd_cmd(0xC0); // 2行目の先頭へ printf(lcd_data,str); // 送信されてきていた文字を液晶の2行目に一括表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } main(){ set_tris_c(0b10010000);// 必須 in = RC7 & RC4 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"Open COM port !!"); delay_ms(1000); // while(1) { LCD(); } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home }
//************************************************************************************************************** //************************************************************************************************************** //以下 C18コンパイラ編 /* PC-PIC間 RS232C通信 受信 : 受信時割込み方式 PC : N.NET PIC : PIC18F4550 液晶付 */ #include <p18f4550.h> #include <stdlib.h> #include "string.h" #include <usart.h> #include <stdio.h> #include "1lcd_lib_C18.h" #include "1lcd_lib_C18.c" #pragma config FOSC = HS // f=20MHz #pragma config WDT = OFF #pragma config LVP = OFF char buf[20]; // タイプした文字用のレジスタ int i = 0; char buf[20]; char buf2[20]; char Oda[] = "Oda"; char Nobunaga[] = "Nobunaga"; char Toyotomi[] = "Toyotomi"; char Hideyoshi[] = "Hideyoshi"; char Tokugawa[] = "Tokugawa"; char Ieyasu[] = "Ieyasu"; char Tanaka[] = "Tanaka"; char Pardon[] = "Pardon?"; char* str; void RS232(void); void lcd_printf(char* strx) //液晶表示補助関数 { while(*strx) //文字列終端の '\0'を検出するまで { lcd_data(*strx); // 1文字表示 strx++; } } #pragma code low_vector=0x18 //低位レベル割込み void low_interrupt (void) { _asm GOTO RS232 _endasm } #pragma code #pragma interruptlow RS232 void RS232() // 受信割込み関数 { char Buffer[17]; //液晶表示データの一時保存レジスタ char* str; PIR1bits.RCIF = 0; //PIR1 レジスタのRCIFビット(受信フラグ)をクリア buf[i] = getcUSART(); //受信データを読み込む if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Oda) == 0)str = Nobunaga; else if(strcmp(buf,Toyotomi) == 0) str = Hideyoshi; else if(strcmp(buf,Tokugawa) == 0) str = Ieyasu; else str = Pardon; printf("%s",str); // 送信されてきていた文字を 文字列としてPCに一括送信 //液晶に出力 lcd_clear();// 液晶オールクリア lcd_printf(&buf[0]); //1行目に受信文字を表示 lcd_cmd(0xC0); // 2行目の先頭へ lcd_printf(&str[0]); // 送信されてきていた文字を液晶の2行目に一括表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } main() { char tempBuf[17]; //液晶表示データの一時保存レジスタ TRISC = 0b10111111; //RC7(RX): input mode RC6(TX): output mode OpenUSART( USART_TX_INT_OFF & //送信割込み送信:OFF USART_RX_INT_ON & //割込み受信:ON USART_ASYNCH_MODE & //調歩同期通信モード USART_EIGHT_BIT & //データ長:8ビット USART_CONT_RX & //連続受信モード USART_BRGH_HIGH, //ボーレート:HIGH伝送速度モード spbrg=129 //bau rate = Fosc/(128*(spbrg + 1)) 129 ); // = 20000000/(16*(129 + 1)) = 9615.4 bps // error rate = (9615.4-9600)/9600 = 0.0016 Delay10KTCYx(25);//50msec液晶立ち上がりを待つ 10KT:0.05μsec×4×10000=2000μsec=2msec lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); sprintf(&tempBuf[0],"Com Port"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); lcd_cmd(0xC0);//2行目の先頭へ sprintf(&tempBuf[0]," Start !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); RCONbits.IPEN = 0; //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0) INTCONbits.GIE = 1; //全割込み許可 INTCONbits.PEIE = 1; //周辺機能の割込み有効 while(1) { } CloseUSART(); return 0; } //************************************************ //インクルードファイル 1lcd_lib_C18.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //************************************************ #define lcd_port LATD //DataOutPort pin : 上位4bit #define lcd_stb LATDbits.LATD0 //stb OutPort #define lcd_rs LATDbits.LATD2 // rs OutPort #define port_Mode TRISD // Port Mode set void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_out(char code, char flag);
//*********************************************** //インクルードファイル 1lcd_lib_C18.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //*********************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C18コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 ////////////////////////////////////////////// #include "delays.h" #include "1lcd_lib_C18.h" //////// データ出力サブ関数 void lcd_out(char code, char flag) { port_Mode = 0; // PIC側の DataPort、stbPort、 rsPort を出力モードに設定 lcd_port = code & 0xF0; if (flag == 0) lcd_rs = 1; //表示データの場合 else lcd_rs = 0; //コマンドデータの場合 Delay10TCYx(1); //10NOP lcd_stb = 1; //strobe out Delay10TCYx(1); //10NOP lcd_stb = 0; //reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 Delay10TCYx(50); //500NOP (50μsec待ち at 40MHz) } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 if((cmd & 0x03) != 0) Delay10KTCYx(2); //2msec待ち at 40MHz else Delay10TCYx(50); //50usec待ち at 40MHz } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); //初期化コマンド出力 // Delay10KTCYx(15); //15msec待ち at 40MHz } /////// 初期化関数 void lcd_init(void) { lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(5); //5msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x20, 1); //4bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x01); //all clear }
<実行結果>
PC側 | 液晶表示 | |
★ 文字列の送受信(.NET 〜 PIC間 英数字送受信) <C30編 PIC24F>
.NETのVC++を使い英数字文字列の送受信をおこなう。
<試作品の仕様> → PC側ソフト(VC++)
・パソコン側は.NETのVC++とし、RS232Cシリアル通信を用いPIC24Fと英数字文字列の送受信をおこなう。
・PC側のコンボボックスにあらかじめ下記の文字をセットしておきボタンをクリックすると選択されていた文字列を送信する。
送信される文字の最後尾には’¥r’付加する。
PIC側ではこれらの文字列を受信したら以下の文字列をPC側に返信する。
Sakamoto → Ryouma
Saigou → Takamori
Katsura → Kogorou
その他 → Pardon?
・ PIC側では受信文字、送信文字を液晶に表示する。
・ PC側でも受信文字をテキストボックス 及びリストに表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC18F4550をつかった場合の回路図を以下に示します
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> //RS232C 送受信(割り込みなし) // PC−PIC 間 PIC24FJ64GA002 #include "p24FJ64GA002.h" #include <stdio.h> #include <uart.h> #include "1lcd_lib_C30.h" #include "1lcd_lib_c30.c" /// コンフィギュレーション ビットの設定 _CONFIG1 ( JTAGEN_OFF & //JTAGポート: OFF GCP_OFF & //コードプロテクト: OFF GWRP_OFF & //書き込みプロテクト: OFF BKBUG_OFF & //バックグランドデバック: OFF COE_OFF & //クリップオン エミュレーション: OFF ICS_PGx1& //ICDピンの選択: EMUC/EMUDをPGC1/PGD1と共用 FWDTEN_OFF //ウォッチドックタイマ: OFF ) _CONFIG2 ( FNOSC_PRI & //外付け発振子20MHZ PLLなし → システムクロック:20MHZ POSCMOD_HS //発振回路モード Oscillator Selection: HS (外付け発振回路 発振周波数レベル:HS) ) int i = 0; char buf[20]; char Buf[20]; char Saigou[] = "Saigou"; char Takamori[] = "Takamori"; char Katsura[] = "Katsura"; char Kogorou[] = "Kogorou"; char Sakamoto[] = "Sakamoto"; char Ryouma[] = "Ryouma"; char Pardon[] = "Pardon?"; char* str; char Space = ' '; void delay_ms(unsigned int N) //ウェイト関数 { __delay32(Clock/2000*N); } void LCD() //受信&液晶表示 { while(!DataRdyUART1()); //UARTバッファーにデータがくるまでまつ buf[i] = getcUART1(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Sakamoto) == 0)str = Ryouma; else if(strcmp(buf,Saigou) == 0) str = Takamori; else if(strcmp(buf,Katsura) == 0) str = Kogorou; else str = Pardon; printf(str); // 返信を 文字列としてPCに一括送信 //液晶に出力 lcd_clear(); //全消去 lcd_str(&buf[0]); // 開始メッセージ1行目表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"%s%c",str,Space); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ2行目表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } main() { CLKDIV = 0; // set 1:1 AD1PCFG = 0xFFFF; // ポートA全ディジタルに指定//ANxのポートすべてに対して必須 TRISB = 0b0000000000001000; // ポートB RB3:RXは入力に 、その他RB5:SDA、RB6:SCL等は出力に設定 // UART1ピン割付 リマッピング RPINR18bits.U1RXR = 3; // UART1 RX to RP3 RPOR1bits.RP2R = 3; // UART1 TX to RP2 /// UART1初期設定 9600bps 8ビット パリティなし、フロー制御なし U1BRG = 64; // 9600bps at システムクロック20MHz //U1BRG = (Fosc(Hz)/2/16/baud(bps) - 1 // = 20000000/2/16/9600 - 1 = 64.1 → 64) U1MODE = 0b1000100000000000; // UART1初期設定 //U1MODEレジスタ設定 U1STA = 0b0000010000000000; // UART1初期設定 //U1STAレジスタ設定 lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"RS232C Start !!%c",Space);//arguementがないと遅い C30のバグ? lcd_str(Buf); //液晶表示 delay_ms(1000); while(1) { LCD(); } return 0; } //************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等でに変更したものです。 //************************************************************************* #include "p24FJ64GA002.h" #define Clock 20000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB15 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB14 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB13 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB12 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATBbits.LATB1 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATBbits.LATB0 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 2000000); // 1μsecに要するウェイト回数 _50usec = (unsigned int)(Clock / 2000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 2000); // 1msecに要するウェイト回数 // = Clock / 2000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home } //---------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- //RS232C 送受信(割り込み有り) // PC−PIC 間 PIC24FJ64GA002 #include "p24FJ64GA002.h" #include <stdio.h> #include <uart.h> #include "1lcd_lib_C30.h" #include "1lcd_lib_c30.c" /// コンフィギュレーション ビットの設定 _CONFIG1 ( JTAGEN_OFF & //JTAGポート: OFF GCP_OFF & //コードプロテクト: OFF GWRP_OFF & //書き込みプロテクト: OFF BKBUG_OFF & //バックグランドデバック: OFF COE_OFF & //クリップオン エミュレーション: OFF ICS_PGx1& //ICDピンの選択: EMUC/EMUDをPGC1/PGD1と共用 FWDTEN_OFF //ウォッチドックタイマ: OFF ) _CONFIG2 ( FNOSC_PRI & //外付け発振子20MHZ PLLなし → システムクロック:20MHZ POSCMOD_HS //発振回路モード Oscillator Selection: HS (外付け発振回路 発振周波数レベル:HS) ) int i = 0; char buf[20]; char Buf[20]; char Saigou[] = "Saigou"; char Takamori[] = "Takamori"; char Katsura[] = "Katsura"; char Kogorou[] = "Kogorou"; char Sakamoto[] = "Sakamoto"; char Ryouma[] = "Ryouma"; char Pardon[] = "Pardon?"; char* str; char Space = ' '; void delay_ms(unsigned int N) //ウェイト関数 { __delay32(Clock/2000*N); } void _ISR _U1RXInterrupt(void) //RS232C 受信割込み { IFS0bits.U1RXIF = 0; //受信割込みフラグクリア while(!DataRdyUART1()); //UARTバッファーにデータがくるまでまつ buf[i] = getcUART1(); if(buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Sakamoto) == 0)str = Ryouma; else if(strcmp(buf,Saigou) == 0) str = Takamori; else if(strcmp(buf,Katsura) == 0) str = Kogorou; else str = Pardon; printf(str); // 返信を 文字列としてPCに一括送信 //液晶に出力 lcd_clear(); //全消去 lcd_str(&buf[0]); // 開始メッセージ1行目表示 lcd_cmd(0xC0); //2行目の先頭へ sprintf(Buf,"%s%c",str,Space); //文字列としてバッファーに収納 lcd_str(Buf); // 開始メッセージ2行目表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } main() { CLKDIV = 0; // set 1:1 AD1PCFG = 0xFFFF; // ポートA全ディジタルに指定//ANxのポートすべてに対して必須 TRISB = 0b0000000000001000; // ポートB RB3:RXは入力に 、その他RB5:SDA、RB6:SCL等は出力に設定 // UART1ピン割付 リマッピング RPINR18bits.U1RXR = 3; // UART1 RX to RP3 RPOR1bits.RP2R = 3; // UART1 TX to RP2 /// UART1初期設定 9600bps 8ビット パリティなし、フロー制御なし U1BRG = 64; // 9600bps at システムクロック20MHz //U1BRG = (Fosc(Hz)/2/16/baud(bps) - 1 // = 20000000/2/16/9600 - 1 = 64.1 → 64) U1MODE = 0b1000100000000000; // UART1初期設定 //U1MODEレジスタ設定 U1STA = 0b0000010000000000; // UART1初期設定 //U1STAレジスタ設定 lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); // 全消去 sprintf(Buf,"RS232C Start !!%c",Space);//arguementがないと遅い C30のバグ? lcd_str(Buf); //液晶表示 delay_ms(1000); SetPriorityIntU1RX(5);//RS232C受信割込みON レベル5 //数字が大きい方が割込み優先度高 EnableIntU1RX; //受信割込み許可 while(1) { if(U1STAbits.OERR || U1STAbits.FERR) { U1STA &= 0xFFF0; //オーバーランエラー、フレーミングエラー、パリティエラークリア U1MODEbits.UARTEN = 0; //UARAT初期化 U1MODEbits.UARTEN = 1; } } return 0; } //************************************************************************* //インクルードファイル 1lcd_lib_C30.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等でに変更したものです。 //************************************************************************* #include "p24FJ64GA002.h" #define Clock 20000000 // 単位はHzで指定 // LCDポート設定 #define lcd_port_DB7 LATBbits.LATB15 //LCDのDB7(14番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB6 LATBbits.LATB14 //LCDのDB6(13番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB5 LATBbits.LATB13 //LCDのDB5(12番ピン)に接続されるPIC側ポート番号設定 #define lcd_port_DB4 LATBbits.LATB12 //LCDのDB4(11番ピン)に接続されつPIC側ポート番号設定 #define lcd_stb LATBbits.LATB1 //LCDのstb(6番ピン)に接続されるPIC側ポート番号設定 #define lcd_rs LATBbits.LATB0 //LCDのrs(4番ピン)に接続されるPIC側ポート番号設定 void lcd_out(char code, char flag); void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_str(char *str); //************************************************************************** //インクルードファイル 1lcd_lib_C30.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリ 1lcd_lib.cをもとに、 //C30コンパイラ対応等で変更したものです。 //************************************************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C30コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 // lcd_str(str*) ----- 文字列表示 ////////////////////////////////////////////// #include "1lcd_lib_C30.h" unsigned int _1usec; // 1μsec待つに必要なウェイト回数 unsigned int _50usec; //50μsec待つに必要なウェイト回数 unsigned long N_msec; // 1msec待つに必要なウェイト回数 //////// データ出力サブ関数 void lcd_out(char code, char flag) { if(code & 0b10000000)lcd_port_DB7 = 1; //LCDのDB7への出力セット else lcd_port_DB7 = 0; if(code & 0b01000000)lcd_port_DB6 = 1; //LCDのDB6への出力セット else lcd_port_DB6 = 0; if(code & 0b00100000)lcd_port_DB5 = 1; //LCDのDB5への出力セット else lcd_port_DB5 = 0; if(code & 0b00010000)lcd_port_DB4 = 1; //LCDのDB4への出力セット else lcd_port_DB4 = 0; if (flag == 0) lcd_rs = 1; // 表示データの場合 else lcd_rs = 0; // コマンドデータの場合 __delay32(_1usec); //1μsecウェイト lcd_stb = 1; // strobe(E) ON (Enable) __delay32(_1usec); // 1μsec : strobe信号の幅 lcd_stb = 0; // reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); // 上位4ビット出力 lcd_out(asci<<4, 0); // 下位4ビット出力 __delay32(_50usec); //50μsecウェイト } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); // 上位4ビット出力 lcd_out(cmd<<4, 1); // 下位4ビット出力 if((cmd & 0x03) != 0) // clear Homeの場合 __delay32(2*N_msec); // 2msec待ち else __delay32(_50usec); //50μsecウェイト } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); // 初期化コマンド出力 // __delay32(15*N_msec); //15msecウェイト } /////// 文字列出力関数 void lcd_str(char* str) { while(*str) //文字列終端の '\0'を検出するまで { lcd_data(*str); // 1文字表示 str++; //ポインタをインクリメント } } /////// 初期化関数 void lcd_init(void) { _1usec =(unsigned int)( Clock / 2000000); // 1μsecに要するウェイト回数 _50usec = (unsigned int)(Clock / 2000000 * 50); //50μescに要するウェイト回数 N_msec = (unsigned long int)(Clock / 2000); // 1msecに要するウェイト回数 // = Clock / 2000000*1000 __delay32(20*N_msec); //20msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(5*N_msec); //5msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x30, 1); // 8bit mode set __delay32(N_msec); //1msecウェイト lcd_out(0x20, 1); // 4bit mode set __delay32(N_msec); //1msecウェイト lcd_cmd(0x2E); // DL=0 4bit mode lcd_cmd(0x08); // display off C=D=B=0 lcd_cmd(0x0D); // display on C=D=1 B=0 lcd_cmd(0x06); // entry I/D=1 S=0 lcd_cmd(0x02); // cursor home }
<実行結果>
PC側画面 | PIC側液晶画面 1行目: 受信文字 2行目: 返信文字 |
|
@ | 上記ダイアログは以下の順番でコンボボックスの送信データを 順次選択して、送信した時のものです。 @ Sakamoto A Saigou B katusra C Hellow !! |
|
A | ||
B | ||
C |
(11)文字列の送受信(.NET 〜 PIC間 マルチスレッド編 漢字の送受信 )<CCS編> <C18編>
.NETのC#、またはC++を使い漢字(シフトJIS)文字列の送受信をおこなう。
<試作品の仕様> → PC側ソフト(VC#)
→ PC側ソフト(VC++)
・パソコン側は.NETのC#、またはC++とし、RS232Cシリアル通信を用いPIC18F4550と文字列の送受信をおこなう。
・PC側のコンボボックスにあらかじめ下記の文字をセットしておく。送信ボタンをクリックして選択されていた文字列を送信する。
送信される文字の最後尾には’¥r’付加する。
PIC側ではこれらの文字列を受信したら、以下に定めた文字列をPC側に返信する。
織田(織:0x9044 田:0x9363) → 0x904D(信) 0x92B7(長)
豊臣(豊:0x964C 臣:0x9062) → 0x8F47(秀) 0x8B67(吉)
徳川(徳:0x93BF 川:0x90EC) → 0x89C6(家) 0x8D4E(康)
田中 → Pardon?
・ PIC側では受信文字を16進数表示で受信文字 及び送信文字を液晶に表示する。
・ PC側では、受信文字を漢字でテキストボックスに表示する。
<試作品回路図>(→回路図のPDFファイル)
PIC18F4550をつかった場合の回路図を以下に示します
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例> CCS編 /* ------------------------------------------------------------------ < 構成> PC(C# .NET ) → RS232C → PIC18F4550 + 16文字キャラクタ液晶 -------------------------------------------------------------------- */ #include "18f4550.h" #include "string.h" #use delay(clock=20000000) // 20MHz(システムクロック周波数) #FUSES HS,NOWDT,NOPROTECT,PUT,BROWNOUT,NOLVP #use RS232(BAUD=9600,XMIT=PIN_C6,RCV=PIN_C7) // TX=RC6,RX=RC7 #use fast_io(D) //////// Port define and link LCD library #define mode 0 // 液晶 #define input_x input_D #define output_x output_D #define set_tris_x set_tris_D #define rs PIN_D2 //chip select #define stb PIN_D0 //strobe #include <1lcd_lib.c> int i = 0; char buf[20]; char Oda[10]; //織田 : 織[シフトJIS]9044 田[シフトJIS]9363 char Nobunaga[10]; //信長 : 信[シフトJIS]904D 長[シフトJIS]92B7 char Toyotomi[10]; //豊臣 : 豊[シフトJIS]964C 臣[シフトJIS]9062 char Hideyoshi[10]; //秀吉 : 秀[シフトJIS]8F47 吉[シフトJIS]8B67 char Tokugawa[10]; //徳川 : 徳[シフトJIS]93BF 川[シフトJIS]90EC char Ieyasu[10]; //家康 : 家[シフトJIS]89C6 康[シフトJIS]8D4E char Tanaka[10]; //田中 char Pardon[10]; char Hellow[] = "Hellow"; char* str; void LCD() { buf[i] = getc(); if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Oda) == 0)str = Nobunaga; else if(strcmp(buf,Toyotomi) == 0) str = Hideyoshi; else if(strcmp(buf,Tokugawa) == 0) str = Ieyasu; else str = Pardon; printf(str); // 送信されてきていた文字を 文字列としてPCに一括送信 //液晶に出力 lcd_clear();// 液晶オールクリア printf(lcd_data,"%x%x %x%x",buf[0],buf[1],buf[2],buf[3]); // 受信文字を液晶の1行目に一括表示 lcd_cmd(0xC0); // 2行目の先頭へ printf(lcd_data,"%x%x %x%x",str[0],str[1],str[2],str[3]); // 送信文字を液晶の2行目に一括表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } main(){ set_tris_c(0b10010000);// 必須 in = RC7 & RC4 lcd_init(); lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); printf(lcd_data,"Open COM port !!"); //織田 : 織[シフトJIS]9044 田[シフトJIS]9363 Oda[0] = 0x90; //織[シフトJIS]9044 Oda[1] = 0x44; Oda[2] = 0x93; //田[シフトJIS]9363 Oda[3] = 0x63; Oda[4] = 0x00; //信長 : 信[シフトJIS]904D 長[シフトJIS]92B7 Nobunaga[0] = 0x90; //信[シフトJIS]904D Nobunaga[1] = 0x4D; // Nobunaga[2] = 0x92; //長[シフトJIS]92B7 Nobunaga[3] = 0xB7; // Nobunaga[4] = 0x00; //豊臣 : 豊[シフトJIS]964C 臣[シフトJIS]9062 Toyotomi[0] = 0x96; //豊[シフトJIS]964C Toyotomi[1] = 0x4C; Toyotomi[2] = 0x90; //臣[シフトJIS]9062 Toyotomi[3] = 0x62; Toyotomi[4] = 0x00; //秀吉 : 秀[シフトJIS]8F47 吉[シフトJIS]8B67 Hideyoshi[0] = 0x8F; // 秀[シフトJIS]8F47 Hideyoshi[1] = 0x47; Hideyoshi[2] = 0x8B; //吉[シフトJIS]8B67 Hideyoshi[3] = 0x67; Hideyoshi[4] = 0x00; //徳川 : 徳[シフトJIS]93BF 川[シフトJIS]90EC Tokugawa[0] = 0x93; //徳[シフトJIS]93BF Tokugawa[1] = 0xBF; // Tokugawa[2] = 0x90; //川[シフトJIS]90EC Tokugawa[3] = 0xEC; Tokugawa[4] = 0x00; //家康 : 家[シフトJIS]89C6 康[シフトJIS]8D4E Ieyasu[0] = 0x89; //家[シフトJIS]89C6 Ieyasu[1] = 0xC6; Ieyasu[2] = 0x8D; //康[シフトJIS]8D4E Ieyasu[3] = 0x4E; Ieyasu[4] = 0x00; Pardon[0] = 'P'; Pardon[1] = 'a'; Pardon[2] = 'r'; Pardon[3] = 'd'; Pardon[4] = 'o'; Pardon[5] = 'n'; Pardon[6] = ' '; Pardon[7] = '?'; Pardon[8] = '\0'; delay_ms(1000); // while(1) { LCD(); } return 0; } //--------------------------------------------------------------------------- //************************************** //インクルードファイル 1lcd_lib.c //このファイルは後閑哲也さんが設計されたものです //************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 //////// データ出力サブ関数 void lcd_out(int code, int flag) { output_x((code & 0xF0) | (input_x() & 0x0F)); if (flag == 0) output_high(rs); //表示データの場合 else output_low(rs); //コマンドデータの場合 delay_cycles(4); //NOP 1 output_high(stb); //strobe out delay_cycles(8); //NOP 2 output_low(stb); //reset strobe } //////// 1文字表示関数 void lcd_data(int asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 delay_us(50); //50μsec待ち } /////// コマンド出力関数 void lcd_cmd(int cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 delay_ms(2); //2msec待ち } /////// 全消去関数 void lcd_clear() { lcd_cmd(0x01); //初期化コマンド出力 delay_ms(15); //15msec待ち } /////// 初期化関数 void lcd_init() { set_tris_x(mode); //モードセット delay_ms(15); lcd_out(0x30, 1); //8bit mode set delay_ms(5); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x30, 1); //8bit mode set delay_ms(1); lcd_out(0x20, 1); //4bit mode set delay_ms(1); lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x02); //cursor home } //----------------------------------------------------------------------------------------------------------
// C18編 /* PC-PIC間 RS232C通信 受信 : 受信時割込み方式 PC : N.NET PIC : PIC18F4550 液晶付 */ #include <p18f4550.h> #include <stdlib.h> #include "string.h" #include <usart.h> #include <stdio.h> #include "1lcd_lib_C18.h" #include "1lcd_lib_C18.c" #pragma config FOSC = HS // f=20MHz #pragma config WDT = OFF #pragma config LVP = OFF char buf[20]; // タイプした文字用のレジスタ int i = 0; char buf[20]; char buf2[20]; char Oda[10]; //織田 : 織[シフトJIS]9044 田[シフトJIS]9363 char Nobunaga[10]; //信長 : 信[シフトJIS]904D 長[シフトJIS]92B7 char Toyotomi[10]; //豊臣 : 豊[シフトJIS]964C 臣[シフトJIS]9062 char Hideyoshi[10]; //秀吉 : 秀[シフトJIS]8F47 吉[シフトJIS]8B67 char Tokugawa[10]; //徳川 : 徳[シフトJIS]93BF 川[シフトJIS]90EC char Ieyasu[10]; //家康 : 家[シフトJIS]89C6 康[シフトJIS]8D4E char Tanaka[10]; //田中 char Pardon[10]; char Hellow[] = "Hellow"; char* str; void RS232(void); void lcd_printf(char* strx) //液晶表示補助関数 { while(*strx) //文字列終端の '\0'を検出するまで { lcd_data(*strx); // 1文字表示 strx++; } } #pragma code low_vector=0x18 //低位レベル割込み void low_interrupt (void) { _asm GOTO RS232 _endasm } #pragma code #pragma interruptlow RS232 void RS232() // 受信割込み関数 { char Buffer[17]; //液晶表示データの一時保存レジスタ char* str; char strTemp[20]; PIR1bits.RCIF = 0; //PIR1 レジスタのRCIFビット(受信フラグ)をクリア buf[i] = getcUSART(); //受信データを読み込む if( buf[i] == '\r') // Enter キーが押された場合 { buf[i] = '\0'; if(strcmp(buf,Oda) == 0)str = Nobunaga; else if(strcmp(buf,Toyotomi) == 0) str = Hideyoshi; else if(strcmp(buf,Tokugawa) == 0) str = Ieyasu; else str = Pardon; printf("%s",str); // 送信されてきていた文字を 文字列としてPCに一括送信 //液晶に出力 lcd_clear();// 液晶オールクリア sprintf(&strTemp,"%x%x %x%x",buf[0],buf[1],buf[2],buf[3]);//sprintfのバグあり ffが文字の前にに表示される lcd_printf(&strTemp[0]);// 受信文字を液晶の1行目に表示 lcd_cmd(0xC0); // 2行目の先頭へ sprintf(&strTemp,"%x%x %x%x",str[0],str[1],str[2],str[3]);//sprintfのバグあり ffが文字の前にに表示される lcd_printf(&strTemp[0]); // 送信文字を液晶の2行目に一括表示 i = 0; } else //Enter キー以外が押された場合 { i++; } } main() { char tempBuf[17]; //液晶表示データの一時保存レジスタ TRISC = 0b10111111; //RC7(RX): input mode RC6(TX): output mode OpenUSART( USART_TX_INT_OFF & //送信割込み送信:OFF USART_RX_INT_ON & //割込み受信:ON USART_ASYNCH_MODE & //調歩同期通信モード USART_EIGHT_BIT & //データ長:8ビット USART_CONT_RX & //連続受信モード USART_BRGH_HIGH, //ボーレート:HIGH伝送速度モード spbrg=129 //bau rate = Fosc/(128*(spbrg + 1)) 129 ); // = 20000000/(16*(129 + 1)) = 9615.4 bps // error rate = (9615.4-9600)/9600 = 0.0016 Delay10KTCYx(25);//50msec液晶立ち上がりを待つ 10KT:0.05μsec×4×10000=2000μsec=2msec lcd_init(); // LCD初期化 lcd_cmd(0b00001100); // カーソル:OFF ブリンク:OFF lcd_clear(); sprintf(&tempBuf[0],"Com Port"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); lcd_cmd(0xC0);//2行目の先頭へ sprintf(&tempBuf[0]," Start !!"); //文字列としてバッファーに収納 lcd_printf(&tempBuf[0]); //織田 : 織[シフトJIS]9044 田[シフトJIS]9363 Oda[0] = 0x90; //織[シフトJIS]9044 Oda[1] = 0x44; Oda[2] = 0x93; //田[シフトJIS]9363 Oda[3] = 0x63; Oda[4] = 0x00; //信長 : 信[シフトJIS]904D 長[シフトJIS]92B7 Nobunaga[0] = 0x90; //信[シフトJIS]904D Nobunaga[1] = 0x4D; // Nobunaga[2] = 0x92; //長[シフトJIS]92B7 Nobunaga[3] = 0xB7; // Nobunaga[4] = 0x00; //豊臣 : 豊[シフトJIS]964C 臣[シフトJIS]9062 Toyotomi[0] = 0x96; //豊[シフトJIS]964C Toyotomi[1] = 0x4C; Toyotomi[2] = 0x90; //臣[シフトJIS]9062 Toyotomi[3] = 0x62; Toyotomi[4] = 0x00; //秀吉 : 秀[シフトJIS]8F47 吉[シフトJIS]8B67 Hideyoshi[0] = 0x8F; // 秀[シフトJIS]8F47 Hideyoshi[1] = 0x47; Hideyoshi[2] = 0x8B; //吉[シフトJIS]8B67 Hideyoshi[3] = 0x67; Hideyoshi[4] = 0x00; //徳川 : 徳[シフトJIS]93BF 川[シフトJIS]90EC Tokugawa[0] = 0x93; //徳[シフトJIS]93BF Tokugawa[1] = 0xBF; // Tokugawa[2] = 0x90; //川[シフトJIS]90EC Tokugawa[3] = 0xEC; Tokugawa[4] = 0x00; //家康 : 家[シフトJIS]89C6 康[シフトJIS]8D4E Ieyasu[0] = 0x89; //家[シフトJIS]89C6 Ieyasu[1] = 0xC6; Ieyasu[2] = 0x8D; //康[シフトJIS]8D4E Ieyasu[3] = 0x4E; Ieyasu[4] = 0x00; Pardon[0] = 'P'; Pardon[1] = 'a'; Pardon[2] = 'r'; Pardon[3] = 'd'; Pardon[4] = 'o'; Pardon[5] = 'n'; Pardon[6] = ' '; Pardon[7] = '?'; Pardon[8] = '\0'; RCONbits.IPEN = 0; //割込み優先順位制御:OFF (RCON レジスタのIPENビット = 0) INTCONbits.GIE = 1; //全割込み許可 INTCONbits.PEIE = 1; //周辺機能の割込み有効 while(1) { } CloseUSART(); return 0; } //************************************************ //インクルードファイル 1lcd_lib_C18.h //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //************************************************ #define lcd_port LATD //DataOutPort pin : 上位4bit #define lcd_stb LATDbits.LATD0 //stb OutPort #define lcd_rs LATDbits.LATD2 // rs OutPort #define port_Mode TRISD // Port Mode set void lcd_data(char asci); void lcd_cmd(char cmd); void lcd_clear(void); void lcd_init(void); void lcd_out(char code, char flag);
//*********************************************** //インクルードファイル 1lcd_lib_C18.c //このファイルは後閑哲也さんが設計されたCCSコンパイラ用液晶表示ライブラリを //C18コンパイラ用に変更したものです。 //*********************************************** /////////////////////////////////////////////// // 液晶表示器制御ライブラリ for C18コンパイラー // 内蔵関数は以下 // lcd_init() ----- 初期化 // lcd_cmd(cmd) ----- コマンド出力 // lcd_data(chr) ----- 1文字表示出力 // lcd_clear() ----- 全消去 ////////////////////////////////////////////// #include "delays.h" #include "1lcd_lib_C18.h" //////// データ出力サブ関数 void lcd_out(char code, char flag) { port_Mode = 0; // PIC側の DataPort、stbPort、 rsPort を出力モードに設定 lcd_port = code & 0xF0; if (flag == 0) lcd_rs = 1; //表示データの場合 else lcd_rs = 0; //コマンドデータの場合 Delay10TCYx(1); //10NOP lcd_stb = 1; //strobe out Delay10TCYx(1); //10NOP lcd_stb = 0; //reset strobe } //////// 1文字表示関数 void lcd_data(char asci) { lcd_out(asci, 0); //上位4ビット出力 lcd_out(asci<<4, 0); //下位4ビット出力 Delay10TCYx(50); //500NOP (50μsec待ち at 40MHz) } /////// コマンド出力関数 void lcd_cmd(char cmd) { lcd_out(cmd, 1); //上位4ビット出力 lcd_out(cmd<<4, 1); //下位4ビット出力 if((cmd & 0x03) != 0) Delay10KTCYx(2); //2msec待ち at 40MHz else Delay10TCYx(50); //50usec待ち at 40MHz } /////// 全消去関数 void lcd_clear(void) { lcd_cmd(0x01); //初期化コマンド出力 // Delay10KTCYx(15); //15msec待ち at 40MHz } /////// 初期化関数 void lcd_init(void) { lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(5); //5msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x30, 1); //8bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_out(0x20, 1); //4bit mode set Delay10KTCYx(1); //1msec待ち at 40MHz lcd_cmd(0x2E); //DL=0 4bit mode lcd_cmd(0x08); //display off C=D=B=0 lcd_cmd(0x0D); //display on C=D=1 B=0 lcd_cmd(0x06); //entry I/D=1 S=0 lcd_cmd(0x01); //all clear }
<動作結果>
送受信文字 (シフトJIS) |
PC側 | PIC側 (上段:受信データ 下段:送信データ) |
||
織田信長 織:0x9044 田:0x9363 信:0x904D 長:0x92B7 |
||||
豊臣秀吉 豊:0x964C 臣:0x9062 秀:0x8F47 吉:0x8B67 |
||||
徳川家康 徳:0x93BF 川:0x90EC 家:0x89C6 康:0x8D4E |
(注) 液晶表示で1、2バイト目と3、4バイト目の間に1文字分の空白がありますが、これは液晶表示する際漢字(2バイト)データをわかりやすく
するために表示制御で挿入した空白です。実際の送受信においては、4バイトデータの中間に空白データ(0x00など)はありません
(12) RS232C送受信データ波形観測( .NET − PIC間通信)
PCとPIC間で実際に送受信されるRS232Cの信号をビットレベルで観測した結果を紹介します。 受信したPICはPIC24FJ64GA002ですが
受信なので どのPICでもよく、あるいは10KΩ程度の抵抗を受信波形観測の負荷としてでも観測はOKです。
送信側のPCのプログラムは →送信側のPCプログラム を参照願います
<試作品の仕様>
・ PCからPICに文字データをおくり、PCのTX 及びPICのRXの波形を観測する
・ 送信データは下記とする
@ A
A B
B C
C AA
・ データの形式は以下のとする
@ スタートビット : 1ビット固定
A データビット : 8ビット固定
B ストップビット : 1ビット固定
C パリティ : なし
<試作品の回路図> ( → 回路図のPDFファイル)
<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<結果>
<PC側送信画面>
A、B、C、AA の各文字 及び文字列をRS232Cで送信したPCの画面です。
<測定結果>
測定結果を以下に示します
受信文字 (16進数表示) (2進数表示) |
受信パルス実測波形(パリティなし) 上側:PICのRX端子波形 下側:PCのTX端子波形 |
A (0x41) (0b01000001) |
|
B (0x42) (0b01000010) |
|
C (0x43) (0b01000011) |
|
AA (0x41 + 0x41) (0b01000001+ 0b01000001) |
デジタルオシロ:岩通 DS-5102