PIC18F14K50 で USB CDC デバイスを作る

PIC18F14K50

● CDC(Communication Device Class)のデバイスを開発します。
使用するハードウエアは、おなじみの 秋月電子の超小型切手サイズPIC18F14K50マイコンボードAE-PIC18F14K50 です。
CDCなのでPCとは仮想COMポート接続します。Tera Termなどのターミナルで動作確認できます。
AE-PIC18F14K50

PIC18F14K50
IC18F14K50、水晶振動子、USB周辺回路実装済みで1個800円。
  1. 回路の追加
  2. MPLAB X プロジェクトの作成
  3. 書き込みと動作確認

回路の追加

動作確認用に、可変抵抗器、スイッチ、LED、電流制限抵抗を付けます。
確認用なので適当な部品で問題ありません。
回路図

回路図

MPLAB X プロジェクトの作成

MPLAB X のインストール、使い方については MPLAB X IDE で PIC18F14K50 にサンプルプロジェクトを書き込む を参照して下さい。
MPLAB X IDE を起動し「File」→「New Project」をクリックします。

MPLAB X

「Standalone Project」を選択し「Next >」をクリックします。

MPLAB X

「Advanced 8-bit MCUs (PIC 18)」を選択→「PIC18F14K50」を選択→「Show All」をチェックし「PICkit3」を選択し「Next >」をクリックします。

MPLAB X

「None」のまま「Next >」をクリックします。

MPLAB X

「XC8」を選択し「Next >」をクリックします。

MPLAB X

Project Name、Project Locationを入力→「Set as main project」をチェック→「UTF-8」を選択し「Finsh」をクリックします。

MPLAB X

新しいプロジェクトができました。

MPLAB X

「Projects」ウインドウのプロジェクト名を右クリックして「Properties」をクリックします。

MPLAB X

「Show All」をチェックし「PICkit3」を選択し「OK」をクリックします。
「OK」をクリックできない場合はMPLAB X を再起動して下さい。

MPLAB X

もう一度「Projects」ウインドウのプロジェクト名を右クリックし「Properties」を表示して「Categories」から「PICkit 3」を選択し、「Option Categories」を「Power」にして、「Power target circuit from PICkit3」のチェックボックスをチェックし「OK」をクリックします。「Voltage Level」は3.25のままで問題ありません。

MPLAB X

もう一度「Projects」ウインドウのプロジェクト名を右クリックし「Properties」を表示して「Categories」から「XC8 Compiler」を選択し、「Include directories」の横の「…」をクリックします

MPLAB X

「Browse」をクリックします。

MPLAB X

「ファイル名」に「.」(ドット)を入力し「開く」をクリックします。

MPLAB X

「OK」をクリックします。

MPLAB X

「OK」をクリックします。
これで、プロジェクト名フォルダ内のファイルをインクルードできるようになります。

MPLAB X

「Projects」ウインドウの「Source files」を右クリック→「New」→「main.c」をクリックします。

MPLAB X

「File Name」を「main」に修正して「Finish」をクリックします。

MPLAB X

「main.c」ができました。中身は空っぽです。

MPLAB X

一度ビルドしてみましょう。「Build Main Project」をクリックします。

MPLAB X

「Output」ウインドウに「BUILD SUCCESSFUL」が出ればOKです。

MPLAB X

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」をクリックします。

MPLAB X

9個の「.h」ファイルを選択し「Select」をクリックします。

MPLAB X

同様に、3個の「.c」ファイルを「Source Files」に追加します。

MPLAB X

ファイルの準備ができました。

MPLAB X

「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)
MPLAB X

「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 を起動しシリアル接続します。

TeraTerm

シリアルポートの設定は、以下のとおりです。

TeraTerm

Tera Term にメッセージが返ってきます。
ポートRB7に接続したスイッチを
オンすると「Button pressed」が返ってきます。
オフすると「Button released」が返ってきます。
「1」を送信すると「2」が返ってきます。
「a」を送信すると「b」が返ってきます。

TeraTerm

以上です。

コメントを残す