● CDC(Communication Device Class)のデバイスを開発します。
使用するハードウエアは、おなじみの 秋月電子の超小型切手サイズPIC18F14K50マイコンボードAE-PIC18F14K50 です。
CDCなのでPCとは仮想COMポート接続します。Tera Termなどのターミナルで動作確認できます。
AE-PIC18F14K50
回路の追加
動作確認用に、可変抵抗器、スイッチ、LED、電流制限抵抗を付けます。
確認用なので適当な部品で問題ありません。
回路図
MPLAB X プロジェクトの作成
MPLAB X のインストール、使い方については MPLAB X IDE で PIC18F14K50 にサンプルプロジェクトを書き込む を参照して下さい。
MPLAB X IDE を起動し「File」→「New Project」をクリックします。
「Standalone Project」を選択し「Next >」をクリックします。
「Advanced 8-bit MCUs (PIC 18)」を選択→「PIC18F14K50」を選択→「Show All」をチェックし「PICkit3」を選択し「Next >」をクリックします。
「None」のまま「Next >」をクリックします。
「XC8」を選択し「Next >」をクリックします。
Project Name、Project Locationを入力→「Set as main project」をチェック→「UTF-8」を選択し「Finsh」をクリックします。
新しいプロジェクトができました。
「Projects」ウインドウのプロジェクト名を右クリックして「Properties」をクリックします。
「Show All」をチェックし「PICkit3」を選択し「OK」をクリックします。
「OK」をクリックできない場合はMPLAB X を再起動して下さい。
もう一度「Projects」ウインドウのプロジェクト名を右クリックし「Properties」を表示して「Categories」から「PICkit 3」を選択し、「Option Categories」を「Power」にして、「Power target circuit from PICkit3」のチェックボックスをチェックし「OK」をクリックします。「Voltage Level」は3.25のままで問題ありません。
もう一度「Projects」ウインドウのプロジェクト名を右クリックし「Properties」を表示して「Categories」から「XC8 Compiler」を選択し、「Include directories」の横の「…」をクリックします
「Browse」をクリックします。
「ファイル名」に「.」(ドット)を入力し「開く」をクリックします。
「OK」をクリックします。
「OK」をクリックします。
これで、プロジェクト名フォルダ内のファイルをインクルードできるようになります。
「Projects」ウインドウの「Source files」を右クリック→「New」→「main.c」をクリックします。
「File Name」を「main」に修正して「Finish」をクリックします。
「main.c」ができました。中身は空っぽです。
一度ビルドしてみましょう。「Build Main Project」をクリックします。
「Output」ウインドウに「BUILD SUCCESSFUL」が出ればOKです。
Microchip Libraries for Applications(MLA)から必要なファイルをコピーします。
Microchip Libraries for Applications(MLA)のインストールについては MPLAB X IDE で PIC18F14K50 にサンプルプロジェクトを書き込む を参照してください。
以下12個のファイルを「プロジェクト名.x」フォルダにコピーしてください。
「プロジェクト名.x」フォルダは、先ほど「main.c」を作ったフォルダです。
C:\microchip\mla\v2018_11_26\apps\usb\device\cdc_basic\firmware\demo_src フォルダから
「usb_config.h」
「usb_descriptors.c」
C:\microchip\mla\v2018_11_26\framework\usb\inc フォルダから
「usb.h」
「usb_ch9.h」
「usb_common.h」
「usb_device.h」
「usb_device_cdc.h」
「usb_hal.h」
「usb_hal_pic18.h」
C:\microchip\mla\v2018_11_26\framework\usb\src フォルダから
「usb_device.c」
「usb_device_cdc.c」
「usb_device_local.h」
コピーしたファイルをプロジェクトに追加します。
「Projects」ウインドウの「Header Files」を右クリックして「Add Exist Item」をクリックします。
9個の「.h」ファイルを選択し「Select」をクリックします。
同様に、3個の「.c」ファイルを「Source Files」に追加します。
ファイルの準備ができました。
「usb_device_cdc.c」のソースコードの48行目をコメント化して、54行目以降に以下の5行を追加します。
//5行追加する
#define FIXED_ADDRESS_MEMORY
#define IN_DATA_BUFFER_ADDRESS_TAG __at(0x240)
#define OUT_DATA_BUFFER_ADDRESS_TAG __at(0x280)
#define CONTROL_BUFFER_ADDRESS_TAG __at(0x2C0)
#define DRIVER_DATA_ADDRESS_TAG __at(0x2C8)
「main.c」を開きソースコードを以下に書き換えます。
#include "usb_device_cdc.h"
/** CONFIGURATION Bits **********************************************/
#pragma config CPUDIV = NOCLKDIV
#pragma config USBDIV = OFF
#pragma config FOSC = HS
#pragma config PLLEN = ON
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRTEN = OFF
#pragma config BOREN = OFF
#pragma config BORV = 30
#pragma config WDTEN = OFF
#pragma config WDTPS = 32768
#pragma config MCLRE = OFF
#pragma config HFOFST = OFF
#pragma config STVREN = ON
#pragma config LVP = OFF
#pragma config XINST = OFF
#pragma config BBSIZ = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CPB = OFF
#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRTB = OFF
#pragma config WRTC = OFF
#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTRB = OFF
#define SYSTEM_Tasks()
#define INTERRUPT __interrupt()
#define _XTAL_FREQ 48000000 //__delay_ms()で使う
static bool buttonPressed;
static char buttonMessage[] = "Button pressed.\r\n";
static uint8_t readBuffer[CDC_DATA_OUT_EP_SIZE];
static uint8_t writeBuffer[CDC_DATA_IN_EP_SIZE];
void INTERRUPT SYS_InterruptHigh(void)
{
USBDeviceTasks(); //usb_device.c
}
void Blink_LED(void)
{
static uint16_t ledCount = 0;
if(USBIsDeviceSuspended() == true)
{
PORTC = 0x00; //ポートC全部オフ LED
return;
}
switch(USBGetDeviceState())
{
case CONFIGURED_STATE: // Blink fast.
if(ledCount == 1)
{
PORTC = 0xFF; //ポートC全部オン LED
}
else if(ledCount == 75)
{
PORTC = 0x00; //ポートC全部オフ LED
}
else if(ledCount > 150)
{
ledCount = 0;
}
break;
default: //blink with a slow pulse.
if(ledCount == 1)
{
PORTC = 0xFF; //ポートC全部オン LED
}
else if(ledCount == 50)
{
PORTC = 0x00; //ポートC全部オフ LED
}
else if(ledCount > 950)
{
ledCount = 0;
}
break;
}
ledCount++; //ms counter
}
void Init_UART()
{
line_coding.bCharFormat = 0;
line_coding.bDataBits = 8;
line_coding.bParityType = 0;
line_coding.dwDTERate = 9600;
buttonPressed = false;
}
void Read_Write_USB()
{
if( USBGetDeviceState() < CONFIGURED_STATE ) //USB device isn't configured yet. So jump back to the top of the while loop.
{
return;
}
if( USBIsDeviceSuspended() == true ) //suspended. just continue back to the start of the while loop.
{
return;
}
if(PORTBbits.RB7 == 0) //the user has pressed the button
{
if(buttonPressed == false)
{
if(mUSBUSARTIsTxTrfReady() == true) // Make sure that the CDC driver is ready for a transmission.
{
putrsUSBUSART(buttonMessage); //メッセージ送信 usb_device_cdc.c
buttonPressed = true;
__delay_ms(100); //チャタリング除去
}
}
}
else
{
if(buttonPressed)
{
if(mUSBUSARTIsTxTrfReady() == true) // Make sure that the CDC driver is ready for a transmission.
{
putrsUSBUSART("Button released.\r\n");
buttonPressed = false;
__delay_ms(100); //チャタリング除去
}
}
}
if( USBUSARTIsTxTrfReady() == true) //transmission is not in progress. perform an echo response to data received.
{
uint8_t i;
uint8_t numBytesRead;
numBytesRead = getsUSBUSART(readBuffer, sizeof(readBuffer));
for(i=0; i<numBytesRead; i++) // For every byte that was read
{
switch(readBuffer[i])
{
case 0x0A: //LF If we receive new line or line feed commands,
case 0x0D: //CR
writeBuffer[i] = readBuffer[i]; //just echo them direct. CRとLFはエコーが返される
break;
default:
writeBuffer[i] = readBuffer[i] + 1; //echo it plus one
break;
}
}
if(numBytesRead > 0)
{
putUSBUSART(writeBuffer,numBytesRead); //文字列送信 usb_device_cdc.c
}
}
CDCTxService(); //受信
}
void SYSTEM_Init(void) //ポート設定
{
//LED
TRISC = 0x00; //1で入力 0で出力 ポートCは全部出力
//Button
TRISBbits.TRISB7 = 1; //1で入力 0で出力 RB7は入力
WPUBbits.WPUB7 = 1; //RB7をプルアップ
INTCON2bits.RABPU = 0; //プルアップ有効
}
bool USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void *pdata, uint16_t size)
{
switch( (int) event )
{
case EVENT_TRANSFER:
break;
case EVENT_SOF: //We are using the SOF as a timer to time the LED indicator.
Blink_LED();
break;
case EVENT_SUSPEND: // Update the LED status for the suspend event.
Blink_LED();
break;
case EVENT_RESUME: //Update the LED status for the resume event.
Blink_LED();
break;
case EVENT_CONFIGURED: //When the device is configured, we can (re)initialize the demo code.
CDCInitEP(); //usb_device_cdc.c
Init_UART();
break;
case EVENT_SET_DESCRIPTOR:
break;
case EVENT_EP0_REQUEST: //We have received a non-standard USB request. The CDC driver needs to check to see if the request was for it.
USBCheckCDCRequest(); //usb_device_cdc.c
break;
case EVENT_BUS_ERROR:
break;
case EVENT_TRANSFER_TERMINATED:
break;
default:
break;
}
return true;
}
void main(void)
{
SYSTEM_Init();
USBDeviceInit(); //usb_device.c
USBDeviceAttach(); //usb_device.c
while(1)
{
SYSTEM_Tasks();
Read_Write_USB();
}//end while
}//end main
「Build Main Project」をクリックして正しくビルドできることを確認します。
書き込みと動作確認
書き込みについては MPLAB X IDE で PIC18F14K50 にサンプルプロジェクトを書き込む を参照してください。
AE-PIC18F14K50をPCとUSB接続するとPIC18F14K50はCOMポートとして認識されます。
Tera Term を起動しシリアル接続します。
シリアルポートの設定は、以下のとおりです。
Tera Term にメッセージが返ってきます。
ポートRB7に接続したスイッチを
オンすると「Button pressed」が返ってきます。
オフすると「Button released」が返ってきます。
「1」を送信すると「2」が返ってきます。
「a」を送信すると「b」が返ってきます。
以上です。