0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PIC18F27Q43 ADコンバータ BasicMode(legacyMode)

Last updated at Posted at 2024-05-25

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

Basic Mode 初期化

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

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

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

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

1.ポート設定

RA2をAD変換に使用。

//port設定
TRISA|=0x04;            //RA2:input 
ANSELA|=0x04;           //RA2:ANA2;    

2.ADCリファレンス電圧設定

Vref-は、グランドに接続
Vref+は、VDDに接続。
ADREF(0x3F8).png

//参照電圧設定
    ADREFbits.NREF=0;       //Negative Voltage: Vss
    ADREFbits.PREF=0b00;    //Positive Voltage: Vdd

3.ADC変換クロック設定

ADC用のクロックに、Foscシステムクロックを選びます。
ADCON0レジスタのCSビットを0にします。
ADC変換クロック.png

 //ADC変換クロック設定 1us    
    ADCON0bits.CS=0;         

Q43の電気特性の章にADコンバータのクロック周期の定格が掲載されています。
ADCのクロック周期の最長が9us、最短が0.5usになっています。
これに合わせて今回は、ADCクロック周期Tadを1usに設定しています。
TAD.png
Foscを32で割ると、Tad周期が1usになります。
ADCクロック.png

//ADC変換クロック設定 1us    
    ADCON0bits.CS=0;        //ConversionClockSource:Fosc=32Mhz
    ADCLK=15;               //Fosc/(2*(n+1)):n=15 Tad=1us 

ADCLK.png
ADCLKレジスタに15をセットして、Tadを1usにします。

4.チャンネル指定

RA2(ANA2)をAD端子に設定しています。この端子のチャンネル番号は、2になります。 ADPCH.png

//チャンネル指定
    ADPCH=2;                //Channel Select RA2 ANA2

5.AD変換のフォーマット

AD変換の結果を右詰めにします。 ADCON0_FM.png

 //フォーマット
    ADCON0bits.FM=1;        //Right justified

6.AD変換のモードを"Basic"に設定

ADCON2_MD.png

//mode
    ADCON2bits.MD = 0b000;  //Basic mode

7.自動トリガーの設定

タイマー2をでトリガーとして使用します。インターバル時間は1msに設定しています。
ADACT.png

//Auto Conversion Trigger Source
    ADACTbits.ACT=0b00100;  //TMR2 postscaled.

8. prechargeTimeとacquisition time

・prechargeTimeは0に設定。
・acquisition Timeはデータシートの例の値をそのまま使用しました。
acquisitonTime.png
温度50度、インピーダンス10kΩ、Vdd=5vで計算した値、Tacq=7.79usを用いて、acquisitionTimeの計算をして、ADACQレジスタに値をセットします。
ADACQ.png
Fosc = 32Mhz
Tosc = 1/Fosc = 1/32 us = 0.03125us
Tacq=7.79の小数点以下を切り捨てて、
7us/0.03125us = 224

//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 コード

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 */
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();
}

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 *
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を使用できない。                  
}
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;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?