PIC16F1827 ブレッドボード配線６ PWM信号でDCモータを駆動させる。

# アクチュエータの基本のDCモータを、PWM信号で駆動します。

<iframe width="560" height="315" src="https://www.youtube.com/embed/r8ibSXiPtWs?si=2nsyQbAwxYeSJ3is" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

:::note
**前回、VRﾎﾞﾘｭｰﾑをRA0に配線してAD変換ができるようにしました。
これをPWM信号のduty比を変えるコントローラとして使用して、DCモータの回転速度を変化させます。**
![IMG_4980.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/f0d2e093-07e5-20a9-15f3-6b79fb6f963b.jpeg)
:::

# 回路図
![全体回路図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/e4785c5f-75b7-9418-8482-60a17272a865.jpeg)


:::note info
# 今回使用したDCモータドライブ回路
![回路図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/83fc7256-b38c-88d7-30c0-8d6c87dd22b6.jpeg)
上記回路をもとに、ユニバーサル基板で半田付けした基板。
![IMG_4977＿１.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/4cfedb42-69c3-0a2d-8ba7-eb1ae8a48c8b.jpeg)

ブレッドボード側は、3ピンのヘッダーピンでこの基板と接続します。
![ブレッドボード側コネクタ名.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/2a282c8a-3d79-f809-77d5-28c9a80146c0.jpeg)

:::

:::note info
# CCP1モジュールのPWM信号出力ピンの設定
16F1827の9番ピン、RB3をCCP1モジュールの出力端子にします。オルタナティブピンセレクト機能で、指定してあげます。
```C:CCP1の初期化コード
//RB3をCCP1、PWM信号の出力端子として使用。
void CCP1_PWM_Init(void)
{
    CCP1CONbits.CCP1M=0b1100;//PWMmode
    CCPTMRSbits.C1TSEL0=0b00;//Timer2 in PWM mode
    CCPR1L=0x00;
    TRISB3=0;
    //APFCON0bits.CCP1SEL=1;//RB0
    APFCON0bits.CCP1SEL=0;//RB3
}
```
:::

:::note
# CCP1モジュールのPWM信号
![CCP_PWMchart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/ee2df73a-449a-b7af-871b-125976f3b067.png)
PWM全体の周期は、Timer2(Timer4,Timer6でもOK)。
Duty比の調整は、CCPR1Lレジスタで調整。

※今回は、Timer2の周期を1msとし、AD値10ビットを4で割った値をCCPR1Lレジスタに設定して、DCモータの回転速度を制御しています。

:::

:::note 
# PIC16F1827のPWM信号
16F1827にはCCPモジュールが4つ搭載されています。

![datasheet_CCP1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/a64a9f28-713d-fd47-ef60-a201aa9196d1.png)

CCP1,CCP2はエンハンスメントモードを使用するとﾌﾙブリッジで、DCモータを正逆回転させることができます。
CCP2,CCP3は通常のCCPモジュールと同様に、一定方向にDCモータを回転させます。

今回は、CCP1モジュールをエンハンスしないで、反時計周りにDCモータを回転させました。
:::


# 今回のコード
```C:Peripheral.h

#ifndef PERIPHERAL_H
#define	PERIPHERAL_H

#include <xc.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

#define _XTAL_FREQ 16000000

#ifdef	__cplusplus
extern "C" {
#endif

//**************************************************//    
//   USART 
//**************************************************//    
//#define BAUDRATE 19200
#define BAUDRATE 115200  
#define SET_SPBRG_DATA  (((unsigned int)((_XTAL_FREQ/16)/BAUDRATE))-1)
#define SET_SPBRG_DATA1 (((unsigned int)((_XTAL_FREQ/4)/BAUDRATE))-1)    
extern void USART_INIT(void);
extern void putch(uint8_t byte);
extern uint8_t getch(void);
#define rxLength 30
typedef struct {
    uint8_t length;
    uint8_t rxBuf[30];
    bool rxCompleted;
}_usart;    
extern _usart usart;

#define rxBuffer_length 30
typedef struct{
    uint8_t ch;
    uint8_t Buffer[rxBuffer_length];
    uint8_t index;
    uint8_t Completed;
}_rx;
extern _rx rx;

//************************************************//
//Timer0 8bits timer
//************************************************//
#define T0_UP 1
#define T0_STOP 0
typedef struct{
    bool up;
    uint16_t cnt;
}_tm0;    
extern _tm0 tm0;

//************************************************//
//Timer1
//************************************************//
#define T1_UP 1
#define T1_STOP 0
typedef struct{
    bool up;
    uint16_t cnt;
}_tm;    
extern _tm tm1;

//************************************************//
//ADC
//************************************************//
#define ADC_Sampling_Num 10    
typedef struct{
    uint8_t Ch;
    uint16_t val;
    bool    Completed;
    uint16_t data[ADC_Sampling_Num+1];
    uint8_t index;
    uint16_t RMS;
    int32_t cal;
}_ADC;
extern _ADC ADC;

extern void Timer0_INIT(void);
extern void Timer2_INIT(void);
extern void Interrupt_START(void);
extern void ADC_INIT(void);
extern void CCP1_PWM_Init(void);

#ifdef	__cplusplus
}
#endif

#endif	/* MYLIB_H */


```

```C:Peripheral.c
#include <pic16f1827.h>

#include "Peripheral.h"

/*-----------------------------------------
 *USART
 *-----------------------------------------*/
_usart usart;
_rx rx;
void USART_INIT(void)
{
    uint8_t buf;
    unsigned int brg;
    //SPBRG value set
    brg = SET_SPBRG_DATA1;
    SP1BRGL =(unsigned char) brg;
    SP1BRGH =(unsigned char) (brg>>8); 
    //TX-------------------------------------
    TXREG=0x00;
    //TXSTA SYNC:1 BRGH:1 TXEN:1 TX9:0
    buf =TXSTA & 0x83;
    TXSTA = buf | 0x24;
    //RX-------------------------------------
    //RCSTA  SPEN:1 RX9:0 CREN:1
    buf =RCSTA & 0x2F;
    RCSTA =buf | 0x90;
    //BAUR RATE CONTROL REGISTER
    BAUDCON = 0x08;
    //if interrupt is desired, TXIE set(PIE1)
    PIE1bits.TXIE=0;//disable
    //if interrupts are desired, RCIE set(PIE1)
    PIE1bits.RCIE=1;//enable
    
    usart.length=0;
    usart.rxCompleted=false;
}
void putch(uint8_t byte)
{
    while(!PIR1bits.TXIF)continue;
    TXREG=byte;
}

uint8_t getch(void)
{
    while(!PIR1bits.RCIF){};
    return RCREG;
}



/*---------------------------------------------------
 Timer0     8bits　Timer　
 ---------------------------------------------------*/
_tm0 tm0;
void Timer0_INIT(void)
{
    OPTION_REGbits.TMR0CS = 0;  //ClockSource:Fosc/4
    OPTION_REGbits.PSA = 0;     //assingned to the Timer0
    OPTION_REGbits.PS = 0b111;  //1:256
    TMR0=0x63;  //Fosc:32Mhz interval time 10ms
    INTCONbits.T0IE = 1;
    tm0.cnt=0;
}


/*---------------------------------------------------
 Timer1
 ---------------------------------------------------*/
 _tm tm1;
void Timer1_INIT(void)
{
    TMR1L=0x0B;//16MHz 1ms PSC:1:8
    TMR1H=0xFE;
    T1CON=0x31;    
    T1GCON=0x00;
    PIE1bits.TMR1IE=1;
    tm1.up=T0_STOP;
    tm1.cnt=0x0000;
}

/*-------------------------------------------
Timer2
--------------------------------------------*/
void Timer2_INIT(void)
{
    T2CONbits.T2OUTPS=0b0000;//post sc 1:16
    T2CONbits.T2CKPS=0b11;//PSC 1:16
    T2CONbits.TMR2ON=1;
    PR2=0xFA;//1ms matching.
    TMR2=0;
    PIR1bits.TMR2IF=0;
    PIE1bits.TMR2IE=1;
}

/*---------------------------------------------------
 Timer4
 ---------------------------------------------------*/
void Timer4_INIT(void)
{
    T4CONbits.T4OUTPS=0b1111;//1:16 Postscaler
    TMR4=0;
    T4CONbits.T4CKPS=0b01;//prescle1:4
    PR4=0x4B;
    PIE3bits.TMR4IE=1;
    PIR3bits.TMR4IF=0;
    T4CONbits.TMR4ON=1;
}

/*---------------------------------------------------
 Timer6
 ---------------------------------------------------*/
void Timer6_INIT(void)
{
    T6CONbits.T6OUTPS=0b0000;//1:16 Postscaler
    T6CONbits.T6CKPS=0b11;//prescle1:16
    T6CONbits.TMR6ON=1;
    PR6=0xFA;
    TMR6=0;
    PIR3bits.TMR6IF=0;
    PIE3bits.TMR6IE=1;
}
//interrupt start
void Interrupt_START(void)
{
    INTCONbits.PEIE=1;
    INTCONbits.GIE=1;
}
/*---------------------------------------------------
 AD converter
 -------------------------------------------------------*/
_ADC ADC;
void ADC_INIT(void)
{
    uint8_t buf;
    
    //1.Configure PortA
    buf=TRISA;
    TRISA=buf|0x01;
    ANSELA|=0x01;
  
    //2.Configure the ADC module
    ADCON1bits.ADFM=1;      //Right justified.
    ADCON1bits.ADCS=0b101;  //FOSC/16  Select ADC conversion clock
    ADCON1bits.ADNREF=0;    //Vref-:AVss Configure voltage referrence 
    ADCON1bits.ADPREF=0b00; //Vref+ is connected to Vdd.
    ADCON0bits.CHS=0x00;    //RA0:Select ADC input channel
    
    //Turn on ADC module
    ADCON0bits.ADON=1;
    PIR1bits.ADIF=0;
    PIE1bits.ADIE=1;
    
    //ADC struct data initialize
    ADC.index=0;
    ADC.cal=0;
    ADC.Completed=false;
    
  
}

/*----------------------------------------------*/
//PWM
/*-----------------------------------------------*/

//RB3
void CCP1_PWM_Init(void)
{
    CCP1CONbits.CCP1M=0b1100;//PWMmode
    CCPTMRSbits.C1TSEL0=0b00;//Timer2 in PWM mode
    CCPR1L=0x00;
    TRISB3=0;
    //APFCON0bits.CCP1SEL=1;//RB0
    APFCON0bits.CCP1SEL=0;//RB3
}

//RA7
void CCP2_PWM_Init(void)
{
    CCP2CONbits.CCP2M=0b1100;//PWMmode
    CCPTMRSbits.C2TSEL0=0b00;//Timer2 in PWM mode
    CCPR2L=0x00;
    TRISA7=0;
    APFCON0bits.CCP2SEL=1;//RA7
}

//RA3
void CCP3_PWM_Init(void)
{
    CCP3CONbits.CCP3M=0b1100;//PWMmode
    CCPTMRSbits.C3TSEL0=0b00;//Timer2in PWM mode
    CCPR3L=0x00;
    TRISA3=0;
}

//RA4
void CCP4_PWM_Init(void)
{
    CCP4CONbits.CCP4M=0b1100;//PWMmode
    CCPTMRSbits.C4TSEL0=0b00;//Timer2in PWM mode
    CCPR4L=0x00;
    TRISA4=0;
}

```

```C:interrupt.h
#ifndef INTERRUPT_H
#define	INTERRUPT_H

#ifdef	__cplusplus
extern "C" {
#endif
    
    extern void __interrupt()isr();



#ifdef	__cplusplus
}
#endif

#endif	/* INTERRUPT_H */

```

```C:interrupt.c
#include <pic16f1827.h>
#include "Peripheral.h"
#include "Interrupt.h"

void __interrupt()isr()
{
    uint8_t ch;
    
    //USART受信割り込み処理
    if(PIE1bits.RCIE==1 &&  PIR1bits.RCIF)
    {
        PIR1bits.RCIF=0;
        ch = getch();
        usart.rxBuf[usart.length++]=ch;
        if(usart.length>=rxLength)
        {
            usart.length=0;
        }
        if(ch==0x0A)
        {//CR,LF受信
            usart.rxCompleted=true;
            usart.rxBuf[usart.length-2]=0x00;
            PIE1bits.RCIE=0;
        }
    }
    
    //Timer0割り込み処理
    if(INTCONbits.TMR0IE==1 && INTCONbits.TMR0IF )
    {
        INTCONbits.TMR0IF=0;
        tm0.cnt++;
        if(tm0.cnt==50)
        {
            tm0.cnt=0;
            INTCONbits.TMR0IE=0;
            tm0.up=true;
        }
        TMR0=0x63;
    }
    
    //Timer2割り込み処理ADCトリガー
    if(PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF)
    {
        PIR1bits.TMR2IF=0;
        ADCON0bits.ADGO=1;
       // while(ADCON0bits.ADGO);
    }
    
    //AD変換完了割り込み
    if(PIE1bits.ADIE==1 && PIR1bits.ADIF)
    {
        PIR1bits.ADIF = 0;
        ADC.data[0]=ADRESH;
        ADC.data[0]<<=8;
        ADC.data[0]|=ADRESL;
        PIE1bits.ADIE = 0;
        PIE1bits.TMR2IE=0;
        ADC.Completed = true;
    }

}


```

```main.c

// PIC16F1827 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
//#pragma config FOSC = HS      // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP =ON      // Low-Voltage Programming Enable (Low-voltage programming enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdlib.h>
#include <stdio.h>
#include "Interrupt.h"
#include "Peripheral.h"
#include "I2C_MSSP1.h"
#include "LCDdriver.h"

#define _XTAL_FREQ  16000000

void Oscillator_Init(void);
void Port_Init(void);

char txt[20];

void main(void)
{    
    uint8_t val=0x55;
    uint8_t counter=0x00;
    uint8_t length=0;
    //Basic Hard Initialize
    Oscillator_Init();
    Port_Init(); 
    
    //Peripheral初期化
    Timer0_INIT();
    USART_INIT();
    I2C1_Reg_Init();  //I2C初期化
    Timer2_INIT();    //1khzサンプリング
    ADC_INIT();       //ADC初期化
    CCP1_PWM_Init();  //PWM1初期化
    
    //IOex:MCP23017初期化
    I2C1_b2Write(0x4C,0x0A,0x00);//コンフィグ
    I2C1_b2Write(0x4C,0x00,0x00);//PortA IOdirection
    I2C1_b2Write(0x4C,0x01,0x00);//PortB IOdirection
    
    //LCD SC1602　初期化
    LCD_Init(LcdDeviceAdd);//Fclock=100kHzで初期化。
    SSP1ADD=0x09;//Fosc=16MHz Fclock=400kHz
    LCD_Printf(LcdDeviceAdd,"PIC16F1827",10,0x80);
    
    //割り込み許可
    Interrupt_START();
    
    while(1)
    {
        //USART interrupt processing
        if(usart.rxCompleted)
        {
            usart.rxCompleted=false;
            printf("%s\n",usart.rxBuf);
            usart.length=0;
            PIE1bits.RCIE=1;
        }
        
        //Timer0 interrupt processing
        if(tm0.up)
        {
            tm0.up=false;
            LATBbits.LATB0=~LATBbits.LATB0;
            I2C1_b2Write(0x4C,0x14,val);//IOex:PortA
            I2C1_b2Write(0x4C,0x15,val);//IOex:PortB
            
            if(val==0x55)
                val=0xAA;
            else
                val=0x55;
            
            counter++;
            length=sprintf(txt,"Count:%3d",counter);
            LCD_Printf(LcdDeviceAdd,txt,length,0xC0);
            INTCONbits.TMR0IE=1;
        }   
        
        if(ADC.Completed)
        {
            ADC.Completed=false;
            
            length=sprintf(txt,"%4d",ADC.data[0]);
            LCD_Printf(LcdDeviceAdd,txt,length,0xCC);
                        
            CCPR1L=ADC.data[0]/4;
            
            PIE1bits.ADIE = 1;
            PIE1bits.TMR2IE=1;
        }
    }
    return;
}

void Oscillator_Init(void)
{
    OSCCONbits.SPLLEN=0;
    OSCCONbits.IRCF=0b1111;//16Mhz
    OSCCONbits.SCS=0b10;//InternalOscillator
}

void Port_Init(void)
{
    TRISA=0x00;
    ANSELA=0x00;
    TRISB=0x04;     //RX:RB2
    ANSELB=0x00;
    PORTA=0x00;
    PORTB=0x00;  
    //Altanative Pin Selective
    APFCON0bits.RXDTSEL=1;  //RX:RB2
    APFCON1bits.TXCKSEL=1;  //TX:RB5
    //I2Cpin
    TRISBbits.TRISB1=1;
    TRISBbits.TRISB4=1;
    //PWM1pin
    APFCON0bits.CCP1SEL=0; //CCP1:RB3
}

```

```C:I2C_MSSP1.h

#ifndef I2C_MSSP1_H
#define	I2C_MSSP1_H
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

#define _XTAL_FREQ  16000000

#ifdef	__cplusplus
extern "C" {
#endif
//-----------------------------------------------
#define I2C1_Ack   0//SSP1CON2.ACKDT master:receive mode
#define I2C1_NoAck 1//SSP1CON2.ACKDT master:receive mode
extern void I2C1_Reg_Init(void);
extern bool I2C1_Start(void);
extern bool I2C1_ReStart(void);
extern bool I2C1_Stop(void);
extern bool I2C1_Tx_Buffer_Write(uint8_t _byte_data);
extern uint8_t I2C1_Rx_Buffer_Read(void);
extern bool I2C1_Wait_Ack(void);
extern bool I2C1_Send_Ack(uint8_t _Ack_Nack);
extern bool I2C1_CheckIdle(void);
extern bool I2C1_ClearSSPxIF(void);
//------------------------------------------------
//-----------------------------------------------
extern bool I2C1_b1Write(uint8_t _device_add, uint8_t _data);
extern uint8_t I2C1_b2Write(uint8_t _device_add, uint8_t _data1, uint8_t _data2);
extern uint8_t I2C1_DataBuffer[10];
extern bool I2C1_bnWrite(uint8_t _device_add, uint8_t *_data, uint8_t _len);
extern uint8_t I2C1_b1Read(uint8_t _device, uint8_t _data1);
extern uint16_t I2C1_b2Read(uint8_t _device_add, uint8_t _data1);
extern bool I2C1_bnRead(uint8_t _device_add, uint8_t _data1,uint8_t _len);
//-----------------------------------------------
#ifdef	__cplusplus
}
#endif

#endif	/* I2C_MSSP1_H */


```

```C:I2C_MSSP1.c
#include "I2C_MSSP1.h"


uint8_t I2C1_DataBuffer[10];//読取りバッファ

//--------------------------------------------
//I2C1 MSSP1初期化
//--------------------------------------------
void I2C1_Reg_Init(void)
{
    SSP1STAT=0xC0;
    SSP1CON1=0x38;
    SSP1CON3=0x00;
    //SSP1ADD=0x50;//Fosc=16Mhz Fclock=50kHz
    SSP1ADD=0x27;//Fosc=16MHz Fclock=100kHz
    //SSP1ADD=0x09;//Fosc=16MHz Fclock=400kHz
    PIE1bits.SSP1IE=0;
}

//--------------------------------------------
//I2C1 MSSP1スタートコンディション発令
//--------------------------------------------
bool I2C1_Start(void)
{
    if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.SEN=1;
    if(!I2C1_ClearSSPxIF())return false;
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    return true;
}

//--------------------------------------------
//I2C1 MSSP1リスタートコンディション発令
//--------------------------------------------
bool I2C1_ReStart(void)
{
     //restart
    if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.RSEN=1;
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    return true;
    
}

//--------------------------------------------
//I2C1 MSSP1ストップコンディション発令
//--------------------------------------------
bool I2C1_Stop(void)
{
     if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.PEN=1;
    if(!I2C1_ClearSSPxIF())return false;
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    return true;
}

//--------------------------------------------
//I2C1 MSSP1　送信バッファ書込み
//--------------------------------------------
bool I2C1_Tx_Buffer_Write(uint8_t _byte_data)
{
    if(!I2C1_CheckIdle()) return false;
    SSP1BUF=_byte_data;
    if(!I2C1_ClearSSPxIF())return false;
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    return true;
}

//--------------------------------------------
//I2C1 MSSP1 受信バッファ読み出し
//--------------------------------------------
uint8_t I2C1_Rx_Buffer_Read(void)
{
    uint8_t ret, cnt;
    ret=0xFF;
    cnt=0;
    if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.RCEN=1;
    while(!SSP1STATbits.BF){
        __delay_us(3);
        cnt++;
        if(cnt==100)return false;
    }
    if(!I2C1_CheckIdle()) return false;
    ret = SSP1BUF;
    if(!I2C1_ClearSSPxIF())return false;
    return ret;
}

//--------------------------------------------
//I2C1 MSSP1　ACK確認
//--------------------------------------------
bool I2C1_Wait_Ack(void)
{
    //while(SSP1CON2bits.ACKSTAT);
    if(SSP1CON2bits.ACKSTAT)
    {
        return false;//error
        
    }else
    {
        return true;//success
    }
}

//--------------------------------------------
//I2C1 MSSP1　ACK送信
//--------------------------------------------
bool I2C1_Send_Ack(uint8_t _Ack_Nack)
{
    if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.ACKDT=_Ack_Nack;
    SSP1CON2bits.ACKEN=1;   
    if(!I2C1_ClearSSPxIF())return false;
    return true;
}

//--------------------------------------------
//I2C1 MSSP1　アイドリングチェック
//--------------------------------------------
bool I2C1_CheckIdle(void)
{
    uint8_t cnt=0;
    while(SSP1STATbits.R_nW || SSP1CON2 & 0x1F)
    {
    /*    __delay_us(2);
        cnt++;
        if(cnt==100) 
            return false;*/
    };//MSSP1 is idle mode
    return true;
}

//--------------------------------------------
//I2C1 MSSP1 SSP1IFフラグクリア
//--------------------------------------------
bool I2C1_ClearSSPxIF(void)
{
    uint8_t cnt=0;
    while(!PIR1bits.SSP1IF)
    {
    /*    __delay_us(2);
        cnt++;
        if(cnt==100)
            return false;*/
    };
    PIR1bits.SSP1IF=0;
    return true;
}


//-----------------------------------------------------------------


//----------------------------------------------------
//  I2C1 MSSP1 1バイト送信
//_device_add:I2Cスレーブアドレス
//_data:送信データ
//----------------------------------------------------
bool I2C1_b1Write(uint8_t _device_add, uint8_t _data)
{  
    //start condition
    I2C1_Start();
    //send device address
    I2C1_Tx_Buffer_Write(_device_add);
    if(!I2C1_Wait_Ack())
        return false;
    //send data
    I2C1_Tx_Buffer_Write(_data);
    if(!I2C1_Wait_Ack())
        return false;
    //Stop condition
    I2C1_Stop();
    return true;
}

//----------------------------------------------------
//  I2C1 MSSP1 2バイト送信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//_data2:送信データ
//----------------------------------------------------
uint8_t I2C1_b2Write(uint8_t _device_add, uint8_t _data1, uint8_t _data2)
{
    //start condition
    I2C1_Start();
    //send device address
    I2C1_Tx_Buffer_Write(_device_add);
    if(!I2C1_Wait_Ack())
    {
        return 0xF1;
        //return false;
    }
    //send data
    I2C1_Tx_Buffer_Write(_data1);
    if(!I2C1_Wait_Ack())
    {    
        return 0xF2;
        //return false;
    }
        //send data
    I2C1_Tx_Buffer_Write(_data2);
    if(!I2C1_Wait_Ack())
    {
        return 0xF3;
        //return false;
    }
    //Stop condition
    I2C1_Stop();
    return true;
}

//----------------------------------------------------
//  I2C1 MSSP1 nバイト送信
//_device_add:I2Cスレーブアドレス
//_data:送信データ先頭アドレス
//_len:送信長
//----------------------------------------------------
bool I2C1_bnWrite(uint8_t _device_add, uint8_t *_data, uint8_t _len)
{
    //start condition
    I2C1_Start();
    //send device address
    I2C1_Tx_Buffer_Write(_device_add);
     if(!I2C1_Wait_Ack())
        return false;
    //send data
    do{
        I2C1_Tx_Buffer_Write(*_data);
        if(!I2C1_Wait_Ack())
        return false;
        _data++;
    }while(--_len);
    //Stop condition
    I2C1_Stop();
    return true;
}

//----------------------------------------------------
//  I2C1 MSSP1 １バイト受信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//戻り値：受信バイトデータ
//----------------------------------------------------
uint8_t I2C1_b1Read(uint8_t _device_add, uint8_t _data1)
{
    uint8_t ret;
    //Start Condition
    I2C1_Start();
     //send device address
    I2C1_Tx_Buffer_Write(_device_add);
     if(!I2C1_Wait_Ack())
        return false;
    //send data
    I2C1_Tx_Buffer_Write(_data1);
     if(!I2C1_Wait_Ack())
        return false;
    //restart
    I2C1_ReStart();
      //send device address
    I2C1_Tx_Buffer_Write(_device_add|0x01);
     if(!I2C1_Wait_Ack())
        return false;
    //recieve data
    ret=I2C1_Rx_Buffer_Read();
    //send Nack
    I2C1_Send_Ack(I2C1_NoAck);
    //Stop Condition
    I2C1_Stop();
    return ret;
}

//----------------------------------------------------
//  I2C1 MSSP1 2バイト受信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//戻り値：２バイトデータ
//----------------------------------------------------
uint16_t I2C1_b2Read(uint8_t _device_add, uint8_t _data1)
{
    uint16_t ret;
    //Start Condition
    I2C1_Start();
     //send device address
    I2C1_Tx_Buffer_Write(_device_add);
     if(!I2C1_Wait_Ack())
        return false;
    //send data
    I2C1_Tx_Buffer_Write(_data1);
     if(!I2C1_Wait_Ack())
        return false;
    //restart
    I2C1_ReStart();
    //send device address
    I2C1_Tx_Buffer_Write(_device_add|0x01);
     if(!I2C1_Wait_Ack())
        return false;
    //recieve data
    ret=I2C1_Rx_Buffer_Read();
    ret<<=8;
    //send Ack
    I2C1_Send_Ack(I2C1_Ack);
    //recieve data
    ret|=I2C1_Rx_Buffer_Read();
    //send Nack
    I2C1_Send_Ack(I2C1_NoAck);
    //Stop Condition
    I2C1_Stop();
    return ret;
}

//----------------------------------------------------
//  I2C1 MSSP1 nバイト受信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//_len:受信長
//戻り値：受信の成否
//----------------------------------------------------
bool I2C1_bnRead(uint8_t _device_add, uint8_t _data1,uint8_t _len)
{
    uint8_t index=0;
    
    //Start Condition
    I2C1_Start();
     //send device address
    I2C1_Tx_Buffer_Write(_device_add);
     if(!I2C1_Wait_Ack())
        return false;
    //send data
    I2C1_Tx_Buffer_Write(_data1);
     if(!I2C1_Wait_Ack())
        return false;
    //restart
    I2C1_ReStart();
      //send device address
    I2C1_Tx_Buffer_Write(_device_add|0x01);
     if(!I2C1_Wait_Ack())
        return false;
    //recieve data
    do{
        I2C1_DataBuffer[index++]=I2C1_Rx_Buffer_Read();
        if(_len!=1)
        {
            I2C1_Send_Ack(I2C1_Ack);
        }
        _len--;
    }while(_len!=0);
    //send Nack
    I2C1_Send_Ack(I2C1_NoAck);
    //Stop Condition
    I2C1_Stop();
    return true;
}
```

```C:LCDdriver.h

#ifndef LCDDRIVER_H
#define	LCDDRIVER_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>  
#include "I2C_MSSP1.h"

#define _XTAL_FREQ  16000000
    
#define I2C_b1Write I2C1_b1Write    
#define CM	0	//Command Mode
#define DM	1	//Data Mode
#define WM  0	//出力WriteMode
#define RM  1   //入力ReadMode
#define High 1
#define Low  0
#define LcdDeviceAdd 0x4E//FC-113(RCF8574 address)
#define LcdDeviceAdd_AT 0x7E//RCF8574AT address    

#define LcdDDRAMAdd_firstline 0x80
#define LcdDDRAMAdd_secondline 0xC0
#define LcdDDRAMAdd_thirdline 0x94
#define LcdDDRAMAdd_forthline 0xD4
#define LcdCmd_Clear_all 0x01
    
//LCD SC1602構造体宣言
//Optical Device _OD
typedef union {
	uint8_t byt;
	struct{
		uint8_t RS:1;//LSB
		uint8_t RW:1;
		uint8_t EN:1;
		uint8_t LED:1;
		uint8_t D4:1;
		uint8_t D5:1;
		uint8_t D6:1;
		uint8_t D7:1;//MSB
	};
}_LCDdata;


extern _LCDdata LCDdata;
extern void LCD_send( uint8_t _device_add,uint8_t _data, uint8_t _mode);
extern void LCD_WriteData(uint8_t _device_add,uint8_t data);
extern void LCD_Command(uint8_t _device_add,uint8_t cmd);
extern void LCD_Init(uint8_t _device_add);
extern void LCD_Printf(uint8_t _device_add, uint8_t *string, uint8_t _length, uint8_t _DDRAM_Add);
extern void LCD_LED_Pow(uint8_t _device_add,uint8_t _led);
 


#ifdef	__cplusplus
}
#endif

#endif	/* LCDDRIVER_H */


```

```C:LCDdriver.c

#include "LCDdriver.h"

_LCDdata LCDdata;
//-----------------------------------------//
//関数名：LCD_send
//機能：LCDコマンド、データ送信
//data: Upper or Lower 4bits data
//_mode: CM 0 :Command Mode
//		   DM 1 :Data Mode
//_device_add
//-----------------------------------------//
void LCD_send(uint8_t _device_add,uint8_t _data, uint8_t _mode)
{   
    LCDdata.byt=0x00;
    LCDdata.LED=High;//バックライト点灯
    LCDdata.byt = LCDdata.byt|(_data& 0xF0);
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    LCDdata.RS=_mode;
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    LCDdata.EN=High;
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    NOP();
    LCDdata.EN=Low;
    I2C_b1Write(_device_add,LCDdata.byt);
    __delay_us(500);    
}

//----------------------------------------------//
//関数名：LCD_WriteData
//機能：データ送信
//引数１：_device_add スレーブアドレス(8bits)
//引数２：_data 送信データ
//----------------------------------------------//
void LCD_WriteData(uint8_t _device_add,uint8_t _data)
{
    LCD_send(_device_add, _data,DM);    //下位4ビット
    LCD_send(_device_add, _data<<4,DM); //上位４ビット
    __delay_us(40);
}

//----------------------------------------------//
//関数名：LCD_Command
//機能：コマンド送信
//引数１：_device_add スレーブアドレス(8bits)
//引数２：_cmd コマンド(8bits)
//----------------------------------------------//
void LCD_Command(uint8_t _device_add,uint8_t cmd)
{
    LCD_send(_device_add,cmd,CM);
    LCD_send(_device_add,cmd<<4,CM);
    __delay_us(40);
}

//----------------------------------------------//
//関数名：LCD_Init
//機能：LCD初期化
//引数１：_device_add スレーブアドレス
//----------------------------------------------//
void LCD_Init(uint8_t _device_add)
{
    __delay_ms(15);
    LCD_send(_device_add,0x30,CM);//8bits mode
    __delay_ms(5);
    LCD_send(_device_add,0x30,CM);//8bits mode
	__delay_us(100);
	LCD_send(_device_add,0x30,CM);//8bits mode three times setting
	LCD_send(_device_add,0x20,CM);//4bits mode 
	LCD_Command(_device_add,0x28);//Function setting.
	LCD_Command(_device_add,0x08);//display off
	LCD_Command(_device_add,0x01);//display clear
	LCD_Command(_device_add,0x06);//entry
	LCD_Command(_device_add,0x02);//cursor home
	LCD_Command(_device_add,0x0C);//display on
}

//----------------------------------------------//
//関数名：LCD_Printf
//機能：文字列表示
//引数１：_device_add スレーブアドレス(8bits)
//引数２：*string 文字列先頭アドレス
//引数３：文字列長
//引数４：表示位置アドレス
//----------------------------------------------//
void LCD_Printf(uint8_t _device_add, uint8_t *string, uint8_t _length, uint8_t _DDRAM_Add)
{
    LCD_Command(_device_add,_DDRAM_Add);
    do{
        LCD_WriteData(_device_add, *string);
        string++;
    }while(--_length);
}

//------------------------------------------------//
//関数名：LCD_LED_Pow
//機能：LCDバックライト点灯
//引数１：_device_add スレーブアドレス(8bits)
//引数２：_led 0:消灯　１：点灯
//------------------------------------------------//
void LCD_LED_Pow(uint8_t _device_add,uint8_t _led)
{
    uint8_t _data=0x01;
    
    LCDdata.byt=0x00;
    LCDdata.LED=_led;
    LCDdata.byt = LCDdata.byt|(_data& 0xF0);
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    LCDdata.RS=DM;
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    LCDdata.EN=High;
    I2C_b1Write(_device_add,LCDdata.byt);
    NOP();
    NOP();
    NOP();
    LCDdata.EN=Low;
    I2C_b1Write(_device_add,LCDdata.byt);
    __delay_us(500);
    
}



```