PIC18F27Q43 ADコンバータ BasicMode(legacyMode)

# Q43 Analog-to-Digital Converter with Computation Module(ADCC)

# Basic Mode 初期化
**Q43に、従来のピックマイコンの標準的なADコンバータの動作をさせます。**

最も簡単にADコンバータが使えるまでの設定です。

※設定値は、あくまで一例で、読者様の環境に合わせて変更してください。

**オシレータスピードFosc=32Mhzで設定していきます。**

# 1.ポート設定
RA2をAD変換に使用。
```C:
//port設定
TRISA|=0x04;            //RA2:input 
ANSELA|=0x04;           //RA2:ANA2;    
```
# 2.ADCリファレンス電圧設定
Vref-は、グランドに接続
Vref+は、VDDに接続。
![ADREF(0x3F8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/e18abd4b-b05c-1a3b-ef9a-02f2308edb4a.png)
```C:
//参照電圧設定
    ADREFbits.NREF=0;       //Negative Voltage: Vss
    ADREFbits.PREF=0b00;    //Positive Voltage: Vdd
```

# 3.ADC変換クロック設定
ADC用のクロックに、Foscシステムクロックを選びます。
ADCON０レジスタのCSビットを０にします。
![ADC変換クロック.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/3654255e-5d8d-30e6-f464-a986a1af8f79.png)
```C
 //ADC変換クロック設定 1us    
    ADCON0bits.CS=0;         
```
Q43の電気特性の章にADコンバータのクロック周期の定格が掲載されています。
ADCのクロック周期の最長が**9us**、最短が**0.5us**になっています。
これに合わせて**今回は、ADCクロック周期Tadを１us**に設定しています。
![TAD.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/224293ca-14c6-a333-97ff-e64eea447f64.png)
Foscを32で割ると、Tad周期が1usになります。
![ADCクロック.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/f53598a3-626c-7f6f-fd3c-bd8eac131b5c.png)

```C
//ADC変換クロック設定 1us    
    ADCON0bits.CS=0;        //ConversionClockSource:Fosc=32Mhz
    ADCLK=15;               //Fosc/(2*(n+1)):n=15 Tad=1us 
```
![ADCLK.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/213b6222-cf90-dd7d-38ee-ee6d967ba89a.png)
ADCLKレジスタに１５をセットして、Tadを1usにします。

# 4.チャンネル指定
RA2(ANA2）をAD端子に設定しています。この端子のチャンネル番号は、2になります。　![ADPCH.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/946953c6-afa9-2831-91a7-02056a1d40be.png)
```C
//チャンネル指定
    ADPCH=2;                //Channel Select RA2 ANA2
```
# 5.AD変換のフォーマット
AD変換の結果を右詰めにします。　![ADCON0_FM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/95da3ede-8c78-e5aa-42a6-c50988e90686.png)
```C
 //フォーマット
    ADCON0bits.FM=1;        //Right justified
```
# 6.AD変換のモードを"Basic"に設定
![ADCON2_MD.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/9b47be2d-4918-409c-c9a1-21ead88efefc.png)
```C
//mode
    ADCON2bits.MD = 0b000;  //Basic mode
```
# 7.自動トリガーの設定
タイマー２をでトリガーとして使用します。インターバル時間は1msに設定しています。
![ADACT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/2f58f72f-2172-af80-9b4d-c15d5d8106ee.png)
```C
//Auto Conversion Trigger Source
    ADACTbits.ACT=0b00100;  //TMR2 postscaled.
```
# 8. prechargeTimeとacquisition time
・prechargeTimeは０に設定。
・acquisition Timeはデータシートの例の値をそのまま使用しました。
![acquisitonTime.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/b32be5c2-74fd-af8b-65f3-c60ab1daa189.png)
温度５０度、インピーダンス10kΩ、Vdd=5vで計算した値、Tacq=7.79usを用いて、acquisitionTimeの計算をして、ADACQレジスタに値をセットします。
![ADACQ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/534756a5-f621-2166-3c21-fa77d03440cf.png)
Fosc = 32Mhz
Tosc = 1/Fosc = 1/32 us = 0.03125us
Tacq=7.79の小数点以下を切り捨てて、
7us/0.03125us = 224
```C
//acquisition time Tacq=7us(50度、10kΩ、5v)
    ADACQ = 224;            //Tosc=1/32Mhz = 1/32 us =0.03125us
                            //7us/0.03125us = 224
```


# PIC18F27Q43 ADC Basic mode コード

```C:Q_Peripheral.h

#ifndef Q_PERIPHERAL27Q43_H
#define	Q_PERIPHERAL27Q43_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
    
#define Low 0
#define High 1
   
#define _XTAL_FREQ 32000000
#define BAUDRATE 115200
#define SET_SPBRG_DATA  (((unsigned int)((_XTAL_FREQ/4)/BAUDRATE))-1)
#define SET_SPBRG_DATA1 (((unsigned int)((_XTAL_FREQ/16)/BAUDRATE))-1)   
//USART---------------------------------------
#define RXUSART_BUFFER_SIZE 20
typedef struct
{
    uint8_t buf[RXUSART_BUFFER_SIZE];
    uint8_t length;
    uint8_t completed;
}_rxUsart;
extern _rxUsart rxUsart;
extern void usartInit(void);
extern void putch(uint8_t);
extern uint8_t getch(void);
//Timer--------------------------------------
typedef struct
{
    uint16_t cnt;
    bool fg;
}_tm;
extern _tm tm0,tm2;
extern void timer0Init(void);    
extern void timer2Init(void);
//IOC------------------------------------------
extern void iocInit(void);
typedef struct
{
    bool fg;
}_ioc;
extern _ioc ioc;  
//--------------------------------------//
//ADC 12bits
//--------------------------------------//
#define ADC_SamplingNum 8
typedef struct{
    uint16_t val[6];
    uint32_t sum[6];
    uint16_t avr[6];
    uint8_t ch;
    uint8_t cnt;
    bool completed;
}_adc;
extern _adc adcInfo;
extern void adcInit(void);    

#ifdef	__cplusplus
}
#endif

#endif	/* Q_PERIPHERAL27Q43_H */
```

```C:Q_Peripheral.c

#include <pic18f27q43.h>
#include "Q_peripheral27Q43.h"

//*****************************************************//
//Timer0初期化
//*****************************************************//
_rxUsart rxUsart;
void usartInit(void)
{
    //1.ボーレート設定115200
    U1BRG=SET_SPBRG_DATA1;
    //2.モード　非同期
    U1CON0bits.MODE=0b0000; //Asynchronous 8-bit USART mode
    //4.Serial port enabled
    U1CON1bits.ON=1;
    //5.Transmit is enabled.
    U1CON0bits.TXEN=1;
    U1CON0bits.RXEN=1;
    //6.PPS
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;//Unlock.
    U1RXPPS=0b010111;//RC7:rx
    RC6PPS=0x20;//RC6:tx
    TRISC|=0x80;
    PPSLOCK = 0x55; 
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;//lock.
    //7.interrupt
    PIR4bits.U1RXIF=0;
    PIE4bits.U1RXIE=1; 
}

void putch(uint8_t _txData)
{
    if(U1ERRIRbits.TXMTIF==High)//ｼﾌﾄﾚｼﾞｽﾀ空?
    {
        do{
            U1TXB=_txData;
            while(U1ERRIRbits.TXMTIF==Low);
        }while(U1FIFObits.TXBF);//TXﾊﾞｯﾌｧ空になるまで送信。
    }else{
        //error operation
    }
}

uint8_t getch(void)
{
    while(PIR4bits.U1RXIF==Low);//受信完了
    return U1RXB;
}

//*****************************************************//
//Timer0初期化
//*****************************************************//
_tm tm0;
void timer0Init(void)
{
//Timer0初期化--------------------------------------------------
    T0CON1bits.CS=0b010;//クロックソースFosc/4
    T0CON1bits.CKPS=0b0011;//プリスケ1:8
    T0CON0bits.MD16=1;//16bitsタイマー
    T0CON0bits.OUTPS=0b0000;//ﾎﾟｽﾄｽｹｰﾗ1:1
    TMR0H=0xD8;//10ms Fosc=32Mhz
    TMR0L=0xF0;//10ms 
    T0CON0bits.EN=1;
    PIE3bits.TMR0IE=1;
    PIR3bits.TMR0IF=0;
}

/*---------------------------------------------------
 Timer2
 ---------------------------------------------------*/
_tm tm2;
void timer2Init(void)
{
    TMR2=0x00;
    T2CONbits.OUTPS=0b1111;//postScaler 1:16
    T2CONbits.T2CKPS=0b100;//prescle1:16
    T2HLTbits.MODE=0b00000;//softwareGateMode(従来のTimer)
    T2HLTbits.PSYNC=1;//synchoronized to Fosc/4
    T2CLKCONbits.CS=0b00001;//Fosc/4
    PR2=0x1F;//Fosc=32Mhz 1ms
    //PR2=0x9C;//Fosc=32Mhz 5ms
    tm2.cnt=0;
    tm2.fg=false;        
    PIR3bits.TMR2IF=0;
    PIE3bits.TMR2IE=1;
    T2CONbits.TMR2ON=1;
}


//*****************************************************//
//ioc初期化
//*****************************************************//
_ioc ioc;
void iocInit(void)
{
    IOCCNbits.IOCCN0=1;//RC0
    TRISC|=0x01;//RC0
    PIE0bits.IOCIE=1;
    PIR0bits.IOCIF=0;
}

//******************************************************//
// * ADC初期化 Basic Mode
// *****************************************************//
_adc adcInfo;
void adcInit(void)
{
    //port設定
    TRISA|=0x04;            //RA2:input 
    ANSELA|=0x04;           //RA2:ANA4;   
    //参照電圧設定
    ADREFbits.NREF=0;       //Negative Voltage: Vss
    ADREFbits.PREF=0b00;    //Positive Voltage: Vdd
    //ADC変換クロック設定 1us    
    ADCON0bits.CS=0;        //ConversionClockSource:Fosc=32Mhz
    ADCLK=15;               //Fosc/(2*(n+1)):n=15 Tad=1us                           
    //チャンネル指定
    ADPCH=2;                //Channel Select RA2 ANA2
    adcInfo.ch=2;   
    //フォーマット
    ADCON0bits.FM=1;        //Right justified
    //mode
    ADCON2bits.MD = 0b000;  //Basic mode
    //Auto Conversion Trigger Source
    ADACTbits.ACT=0b00100;  //TMR2 postscaled.
    //Precharge Time 0;
    ADPRE = 0;
    //acquisition time Tacq=7us(50度、10kΩ、5v)
    ADACQ = 224;            //Tosc=1/32Mhz = 1/32 us =0.03125us
                            //7us/0.03125us = 224
    //割込み許可
    PIR1bits.ADIF=0;
    PIE1bits.ADIE=1;
    ADCON0bits.ON=1;//注：以降、OFFにしないこと。
    //Trigger Timer begins
    timer2Init();
}

```
```C:Q_interrupt.h
#ifndef Q_INTERRUPT_H
#define	Q_INTERRUPT_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"
  
extern void __interrupt(irq(IRQ_U1RX)) USART1RX_ISR(void);    
extern void __interrupt(irq(IRQ_TMR0)) Timer0_ISR(void); 
extern extern void __interrupt(irq(IRQ_TMR2)) Timer2_ISR(void); 
extern void __interrupt(irq(IRQ_IOC)) IOC_ISR(void);

#ifdef	__cplusplus
}
#endif

#endif	/* Q_INTERRUPT_H *
```
```C:Q_interrupt.c
#include "Q_interrupt27Q43.h"

//****************割り込み関数***********************//
// USART1割込み
//**************************************************//
void __interrupt(irq(IRQ_U1RX)) USART1RX_ISR(void)
{
    uint8_t ch;
    PIR4bits.U1RXIF=0;
    ch=getch();
    rxUsart.buf[rxUsart.length++]=ch;
    if(rxUsart.length>RXUSART_BUFFER_SIZE)
    {
        rxUsart.length=0;
    }
    if(ch==0x0a)
    {
        rxUsart.buf[rxUsart.length-2]=0x00;
        PIE4bits.U1RXIE=0;
        rxUsart.completed=1;
    }
}

//****************割り込み関数***********************//
// Timer0割込み
//**************************************************//
void __interrupt(irq(IRQ_TMR0)) Timer0_ISR(void)
{
    PIR3bits.TMR0IF=0;
    tm0.cnt++;
    if(tm0.cnt==50)
    {
        tm0.cnt=0;
        tm0.fg=true;
        T0CON0bits.EN=0;
        PIE3bits.TMR0IE=0;
    }
    
    TMR0L=0xF0;//10ms
}
//****************割り込み関数***********************//
// Timer2割込み
//**************************************************//
void __interrupt(irq(IRQ_TMR2)) Timer2_ISR(void)
{
    PIR3bits.TMR2IF=0;
    //ADCON0bits.GO = 1; //Start conversion
    //while (ADCON0bits.GO); //Wait for conversion done
}

//****************割り込み関数***********************//
// IOC割込み
// ※印は、割り込み関数実行中の変化を取りこぼさないためのコード。
//**************************************************//
void __interrupt(irq(IRQ_IOC)) IOC_ISR(void)
{
    uint8_t val,mask;
    
    PIR0bits.IOCIF=0;
    val=IOCCF;  //※IOCフラグレジスタ読み出し
    mask=0xFF;  //※ゼロクリアマスク
    mask=mask^val;//現状を記録
    printf("IOCCF:%02X mask:%02X\n", IOCCF, mask);
    if(IOCCNbits.IOCCN0==1 && val==0x01)
    {
        ioc.fg=true; //main関数で実処理開始
        PIE0bits.IOCIE=0;//一時割り込み停止
    }
    //zero clear--------------    
    IOCCF&=mask;   //※状態変化の取りこぼしをしない。
    printf("IOCCF:%02X\n",IOCCF);
}

//****************割り込み関数***********************//
// ADC割込み
//**************************************************//
void __interrupt(irq(IRQ_AD)) ADC_ISR(void)
{
    PIR1bits.ADIF=0;
    adcInfo.val[0]=ADRES;
    adcInfo.completed=true;//mainで処理
    //main関数で復帰
    PIE3bits.TMR2IE=0;
    T2CONbits.TMR2ON=0;
    PIE1bits.ADIE=0;
    //ADCON0bits.ON=0;これを有効にすると
    //acquisitonTime, pretimeを使用できない。                  
}
```
```C:main.c
// PIC18F27Q43 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
#pragma config FEXTOSC = OFF    // External Oscillator Selection (Oscillator not enabled)
#pragma config RSTOSC = HFINTOSC_64MHZ// Reset Oscillator Selection (HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1)

// CONFIG2
#pragma config CLKOUTEN = OFF   // Clock out Enable bit (CLKOUT function is disabled)
#pragma config PR1WAY = OFF     // PRLOCKED One-Way Set Enable bit (PRLOCKED bit can be set and cleared repeatedly)
#pragma config CSWEN = ON       // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)

// CONFIG3
#pragma config MCLRE = EXTMCLR  // MCLR Enable bit (If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR )
#pragma config PWRTS = PWRT_OFF // Power-up timer selection bits (PWRT is disabled)
#pragma config MVECEN = ON      // Multi-vector enable bit (Multi-vector enabled, Vector table used for interrupts)
#pragma config IVT1WAY = ON     // IVTLOCK bit One-way set enable bit (IVTLOCKED bit can be cleared and set only once)
#pragma config LPBOREN = OFF    // Low Power BOR Enable bit (Low-Power BOR disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled , SBOREN bit is ignored)

// CONFIG4
#pragma config BORV = VBOR_1P9  // Brown-out Reset Voltage Selection bits (Brown-out Reset Voltage (VBOR) set to 1.9V)
#pragma config ZCD = OFF        // ZCD Disable bit (ZCD module is disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
#pragma config PPS1WAY = OFF     // PPSLOCK bit One-Way Set Enable bit (PPSLOCKED bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle)
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = ON         // Low Voltage Programming Enable bit (Low voltage programming enabled. MCLR/VPP pin function is MCLR. MCLRE configuration bit is ignored)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Extended Instruction Set and Indexed Addressing Mode disabled)

// CONFIG5
#pragma config WDTCPS = WDTCPS_31// WDT Period selection bits (Divider ratio 1:65536; software control of WDTPS)
#pragma config WDTE = OFF       // WDT operating mode (WDT Disabled; SWDTEN is ignored)

// CONFIG6
#pragma config WDTCWS = WDTCWS_7// WDT Window Select bits (window always open (100%); software control; keyed access not required)
#pragma config WDTCCS = SC      // WDT input clock selector (Software Control)

// CONFIG7
#pragma config BBSIZE = BBSIZE_512// Boot Block Size selection bits (Boot Block size is 512 words)
#pragma config BBEN = OFF       // Boot Block enable bit (Boot block disabled)
#pragma config SAFEN = OFF      // Storage Area Flash enable bit (SAF disabled)
#pragma config DEBUG = OFF      // Background Debugger (Background Debugger disabled)

// CONFIG8
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block not Write protected)
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers not Write protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not Write protected)
#pragma config WRTSAF = OFF     // SAF Write protection bit (SAF not Write Protected)
#pragma config WRTAPP = OFF     // Application Block write protection bit (Application Block not write protected)

// CONFIG10
#pragma config CP = OFF         // PFM and Data EEPROM Code Protection bit (PFM and Data EEPROM code protection disabled)

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

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Q_peripheral27Q43.h"
#include "Q_interrupt27Q43.h"
#include "Q_initialize.h"
#include "Q_I2C1.h"
#include "I2C_LCD.h"
#include "stringFormat.h"

void portInit(void);
void oscillatorInit(void);
void vicInit(void);

void main(void)
{
    uint8_t counter=0;
    //CPUハード初期化-----------------------
    portInit();
    oscillatorInit();
    vicInit();
    
    //周辺機能初期化--------------------------------
    timer0Init();
    iocInit();
    usartInit();
    adcInit();
    printf("START\n");    
    I2C1_Init();    
    
    INTCON0bits.GIE=1;//Enable all masked interrupts
    
    while(1)
    {
        //Timer0 interrupt process-------
        if(tm0.fg)
        {
            tm0.fg=false;
            //Interrupt ADCC process----------
            if(adcInfo.completed)
            {
                adcInfo.completed=false;
                printf("ANA2:%4d\n",adcInfo.val[0]);
                //ADCC復帰処理
                PIE1bits.ADIE=1;
                PIE3bits.TMR2IE=1;
                T2CONbits.TMR2ON=1;
            }
            T0CON0bits.EN=1;
            PIE3bits.TMR0IE=1;
        } 
        
        //Usart interrupt process--------
        if(rxUsart.completed)
        {
            rxUsart.completed=false;
            printf("echo:%s\n",rxUsart.buf);
            rxUsart.length=0;
            PIE4bits.U1RXIE=1;
        }
        
        //Interrupt On Change process--------
        if(ioc.fg)
        {
            ioc.fg=false;
            printf("Switch ON:%d\n",counter);
            PORTBbits.RB1=~PORTBbits.RB1;
            counter++;
            PIE0bits.IOCIE=1;
        }
        
        
        
    }
    return;
}

void oscillatorInit(void)
{
    //オシレータ設定----------------
    OSCCON3bits.CSWHOLD=1;//Hold
    OSCCON1bits.NDIV=1;//64Mhz/2=32Mhz;
    while(!OSCCON3bits.NOSCR);
    while(!PIR0bits.CSWIF);//ready state
    PIR0bits.CSWIF=0;
    OSCCON3bits.CSWHOLD=0;
    while(!OSCCON3bits.ORDY);
}

void portInit(void)
{
    //ポート設定----------------------    
    PORTA=0x00;
    LATA=0x00;
    ANSELA=0x00;
    TRISA=0x00;
    
    PORTB=0x00;
    LATB=0x00;
    ANSELB=0x00;
    TRISB=0x00;
    
    PORTC=0x00;
    LATC=0x00;
    ANSELC=0x00;
    TRISC=0x00;
    
     //PPS---------------------
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 0;
    
    //I2C1-------------------------
    //RC4 for SDA
    RC4PPS=0x38;
    I2C1SDAPPS=0x14;
    //RC3 for SCL
    RC3PPS = 0x37;
    I2C1SCLPPS=0x13;
    
    PPSLOCK = 0x55;
    PPSLOCK = 0xAA;
    PPSLOCKbits.PPSLOCKED = 1;
    
    ODCONCbits.ODCC3=1;
    ODCONCbits.ODCC4=1;
    
    RC3I2Cbits.TH=1;
    RC4I2Cbits.TH=1;
    
}

void vicInit(void)
{
 //割り込みテーブルaddress設定----------------------------------
    INTCON0bits.GIE=0;//Enable all masked interrupts
    IVTLOCK=0x55;
    IVTLOCK=0xAA;
    IVTLOCKbits.IVTLOCKED=0;
    IVTBASE = 0x000008;
    IVTLOCK=0x55;
    IVTLOCK=0xAA;
    IVTLOCKbits.IVTLOCKED=1;
}
```