PIC18F47Q43　光透過型センサーを用いたものさし


<iframe width="560" height="315" src="https://www.youtube.com/embed/ve0RH4eqmA4?si=yHr_hH_TlJ6HvXz7" 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 info
光透過型センサーを用いたものさしを作りました。
センサーの立ち上がりエッジ検出で、長さがプラス。
センサーの立ち下がりエッジ検出で、長さがマイナス。


※IOC(Interrupt On Change)をつかってセンサー位置で、長さを図ります。
※ポートB、RB0からRB5にセンサーを接続しています。
:::
```C:Q_peripheral.c
//*****************************************************//
//ioc初期化
//*****************************************************//
 _ioc ioc;
void iocInit(void)
{
    //RB0
    IOCBPbits.IOCBP0=1;//Positive Edge
    IOCBNbits.IOCBN0=0;//Negative Edge
    //RB1
    IOCBPbits.IOCBP1=1;//Positive Edge
    IOCBNbits.IOCBN1=0;//Negative Edge
    //RB2
    IOCBPbits.IOCBP2=1;//Positive Edge
    IOCBNbits.IOCBN2=0;//Negative Edge
    //RB3
    IOCBPbits.IOCBP3=1;//Positive Edge
    IOCBNbits.IOCBN3=0;//Negative Edge
    //RB4
    IOCBPbits.IOCBP4=1;//Positive Edge
    IOCBNbits.IOCBN4=0;//Negative Edge
    //RB5
    IOCBPbits.IOCBP5=1;//Positive Edge
    IOCBNbits.IOCBN5=0;//Negative Edge
    
    
    TRISB|=0x3F;//RB0,RB1,RB2,RB3, RB4, RB5
    PIE0bits.IOCIE=1;
    PIR0bits.IOCIF=0;
}

```

```C:Q_interrupt.c
//****************割り込み関数***********************//
// IOC割込み
//**************************************************//
void __interrupt(irq(IRQ_IOC)) IOC_ISR(void)
{
   uint8_t val,mask;
    
    val=IOCBF;  //※IOCフラグレジスタ読み出し
    mask=0xFF;  //※ゼロクリアマスク
    mask=mask^val;//※現状を記録
    
    //RB0 input
    if(IOCBFbits.IOCBF0)
    {
        IOCBFbits.IOCBF0=0;
        ioc.fg=true; //main関数で実処理開始
        
        LATDbits.LATD0=PORTBbits.RB0;
        if(IOCBPbits.IOCBP0==1)
        {
            ioc.num = 1;
            IOCBPbits.IOCBP0=0;
            IOCBNbits.IOCBN0=1;
        }else
            if(IOCBNbits.IOCBN0==1)
            {
                ioc.num = 0;
                IOCBPbits.IOCBP0=1;
                IOCBNbits.IOCBN0=0;
            }
        
        PIE0bits.IOCIE=0;//一時割り込み停止
    }
    
    //RB1 input
    if(IOCBFbits.IOCBF1)
    {
        IOCBFbits.IOCBF1=0;
        ioc.fg=true; //main関数で実処理開始
        
        LATDbits.LATD1=PORTBbits.RB1;
        if(IOCBPbits.IOCBP1==1)
        {
            ioc.num = 2;
            IOCBPbits.IOCBP1=0;
            IOCBNbits.IOCBN1=1;
        }else
            if(IOCBNbits.IOCBN1==1)
            {
                ioc.num = 1;
                IOCBPbits.IOCBP1=1;
                IOCBNbits.IOCBN1=0;
            }        
        PIE0bits.IOCIE=0;//一時割り込み停止
    }
    
    //RB2 input
    if(IOCBFbits.IOCBF2)
    {
        IOCBFbits.IOCBF2=0;
        ioc.fg=true; //main関数で実処理開始
        
        LATDbits.LATD2=PORTBbits.RB2;
        if(IOCBPbits.IOCBP2==1)
        {
            ioc.num = 3;
            IOCBPbits.IOCBP2=0;
            IOCBNbits.IOCBN2=1;
        }else
            if(IOCBNbits.IOCBN2==1)
            {
                ioc.num = 2;
                IOCBPbits.IOCBP2=1;
                IOCBNbits.IOCBN2=0;
            }        
        PIE0bits.IOCIE=0;//一時割り込み停止
    }
    
    //RB3 input
    if(IOCBFbits.IOCBF3)
    {
        IOCBFbits.IOCBF3=0;
        ioc.fg=true; //main関数で実処理開始
        
        LATDbits.LATD3=PORTBbits.RB3;
        if(IOCBPbits.IOCBP3==1)
        {
            ioc.num = 4;
            IOCBPbits.IOCBP3=0;
            IOCBNbits.IOCBN3=1;
        }else
            if(IOCBNbits.IOCBN3==1)
            {
                ioc.num = 3;
                IOCBPbits.IOCBP3=1;
                IOCBNbits.IOCBN3=0;
            }        
        PIE0bits.IOCIE=0;//一時割り込み停止
    }
    
    //RB4 input
    if(IOCBFbits.IOCBF4)
    {
        IOCBFbits.IOCBF4=0;
        ioc.fg=true; //main関数で実処理開始
        
        LATDbits.LATD4=PORTBbits.RB4;
        if(IOCBPbits.IOCBP4==1)
        {
            ioc.num = 5;
            IOCBPbits.IOCBP4=0;
            IOCBNbits.IOCBN4=1;
        }else
            if(IOCBNbits.IOCBN4==1)
            {
                ioc.num = 4;
                IOCBPbits.IOCBP4=1;
                IOCBNbits.IOCBN4=0;
            }        
        PIE0bits.IOCIE=0;//一時割り込み停止
    }
    
    //RB5 input
    if(IOCBFbits.IOCBF5)
    {
        IOCBFbits.IOCBF5=0;
        ioc.fg=true; //main関数で実処理開始
        
        LATDbits.LATD5=PORTBbits.RB5;
        if(IOCBPbits.IOCBP5==1)
        {
            ioc.num = 6;
            IOCBPbits.IOCBP5=0;
            IOCBNbits.IOCBN5=1;
        }else
            if(IOCBNbits.IOCBN5==1)
            {
                ioc.num = 5;
                IOCBPbits.IOCBP5=1;
                IOCBNbits.IOCBN5=0;
            }        
        PIE0bits.IOCIE=0;//一時割り込み停止
    }
    //zero clear--------------    
    IOCCF&=mask;   //※状態変化の取りこぼしをしない。
}
```

```C:main.c

/*
 * File:   main.c
 * Author: yutak
 *
 * Created on 2022/12/29, 18:47
 */



// 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"
#include  "MCP23017.h"
#include "I2C_LCD.h"
#include "I2C_LCD_BarMeter.h"
#include "RTC_DS3231.h"
#include "EEPROM_24LCxxx.h"
#include "Q_SPI2.h"
#include "MCP23Sxx.h"
#include "DFMRW.h"
#include "ds_ST7735S.h"
#include "ST7735_BarMeter.h"

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

uint16_t tone[8]={261,293,330,347,391,440,495,522};
uint16_t ans[10];
uint8_t txt[20];

void main(void)
{
    int8_t  num,sign;
    uint8_t length,i,strlen;
    int16_t val16;
    uint16_t buttonState;
    bool flag;
    uint8_t keyState,keyNote;
    
    
    i=0;
    val16=0;
    //CPUハード初期化-----------------------
    portInit();
    oscillatorInit();
    vicInit();
    __delay_ms(100);
   
     
    //周辺機能初期化--------------------------------
    timer0Init();//LED表示
    timer1Init();//表示
    //timer2Init();//ADC trigger
    //timer3Init();//CCP capture
    //timer4Init();//I2C　timeOut
    //timer6Init();//CCP1 PWM
    //timer6Init();
    usartInit();
    iocInit();//RC0:input
    I2C1_Init();//I2C初期化
    
    //LCD初期化
    LCD_Init(LcdDeviceAdd);//LCD初期化(PCD8574駆動)
    //Lcd_Mem_Char_Set(LcdDeviceAdd);//LCD CGRAMデータセット
    LCD_Printf(LcdDeviceAdd,"18F27Q43",8,0x80);
    
    //ｸﾞﾛｰﾊﾞﾙ割り込み許可------------------------------------------
    IPR3bits.TMR2IP=1;
    INTCON0bits.IPEN=1;//プライオリティ無し
    INTCON0bits.GIE=1;//Enable all masked interrupts
     
   
    while(1)
    {
     
        //Timer0割込み処理-------------------------------------
        if(tm0.fg==true)
        {
            tm0.fg=false;                        
                                               
            T0CON0bits.EN=1;
            PIE3bits.TMR0IE=1;
        }
        
               
        //Timer1割込み-----------------------------------------
        if(tm1.fg==true)
        {
            tm1.fg=false;
            T1CONbits.ON=1;
            PIE3bits.TMR1IE=1;
        }
        
        if(ioc.fg)
        {
            ioc.fg=false;
            length=ioc.num*3;
            strlen = sprintf(txt,"%4dcm",length);
            LCD_Printf(LcdDeviceAdd,txt,6,0xC0);
            printf("%4dcm\n",length);
            PIE0bits.IOCIE=1;
        }else
        {
            
        }
        
        
    }
    
    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;
   
    PORTD=0x00;
    LATD=0x00;
    ANSELD=0x00;
    TRISD=0x00;
    
    
    PORTE=0x00;
    LATE=0x00;
    ANSELE=0x00;
    TRISE=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;
}
```