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?

PIC16F1827 ブレッドボード配線7 DCモータの回転数を計測。

Last updated at Posted at 2024-09-25

CCP2モジュールで、DCモータの回転数を計測します。

IMG_4989.JPG

前回は、ccp1モジュールのRB3(9番ピン)からPWM信号を出力し、オープンドレインでDCモータを回転させました。

今回は、そのDCモータの回転数を、CCP2モジュール(RA7)を使って計測します。

これで、回転数を用いた、簡単なフィードバック処理ができそうですが、フリーのコンパイラから出力される実行ファイルは、フラッシュメモリを95%使用しているので、16F1827では、PID制御などを実装するには、スペックが足りそうにありません。

PIC18F26K22、Qシリーズなどを使えば、回転数を一定に保つような制御を行えると、思います。

その基礎固めに、とりあえず、回転数の計測まで行いました。

コードのアルゴリズムは、18Fになっても基本的には同じ動作で、微妙にレジスタ名とビット名が違うだけで、動作仕様に大差はないはずです。

回転数を計測する回路。

キャプチャー回路図.jpg
赤外線LEDと、フォトトランジスタを組み合わせた回路からの出力を、CCP2キャプチャー端子(RA7)で捉え、DCモータに取り付けた回転歯の1枚の通過時間を計測します。
IMG_4991.JPG

回転数を計測するアルゴリズム

CCPキャプチャーデータシート.jpg

まず、CCP2モジュール端子をオルタナティブピンセレクトで、RA7に設定します。

CCP2の専用端子をRA7にする
    TRISA7=1;
    APFCON0bits.CCP2SEL=1;//RA7

この端子に、赤外線受光素子フォトトランジスタの出力を接続して、その信号の立ち上がりをキャプチャーのトリガーに設定します。

信号が立ち上がるたびに、割り込みが発生します。

その割込み処理関数の中で、CCP2に連動しているTimer1の16ビットカウンタの値を記録します。

2つの立ち上がり信号をキャプチャーしたら、その時間差が1枚の回転歯の通過時間になっているので、それをもとに、1分間の回転数、RPMを求めます。

CCP2割り込み処理
//CCP2 Capture Mode
    if(PIE2bits.CCP2IE==1 && PIR2bits.CCP2IF)
    {
        PIR2bits.CCP2IF = 0;
        ccp2.data[ccp2.index]=CCPR2H;
        ccp2.data[ccp2.index]<<=8;
        ccp2.data[ccp2.index++]|=CCPR2L;
        if(ccp2.index==2)
        {
            ccp2.index=0;
            ccp2.finished=true;
            PIE2bits.CCP2IE=0;
            T1CONbits.TMR1ON = 0;
            TMR1H=0x00;
            TMR1L=0x00;
        }
    }

2回の立ち上がりエッジの時間差から、1枚の回転翼の通過時間がわかります。その時間を6倍すれば、1回転の時間がわかります。

RPM計算
if(ccp2.finished)//CCP2モジュールで2つの立ち上がりエッジの時刻を取得ずみなら、
{
    ccp2.finished=false;
    if(ccp2.data[1]>ccp2.data[0])//2つ目の時刻のほうが1つ目より後なら、RPMを計算。
    {
        rpm = (ccp2.data[1]-ccp2.data[0]);
        rpm*=6;
        rpm = 500000/rpm * 60;
        //printf("%u %u\n",ccp2.data[1],ccp2.data[0]);//デバッグで値を確かめる。
        //printf("%u\n",rpm);
    }
    else
    {//回転が遅い場合。
        rpm=0;
    } 

    //LCDバーメーター表示
    Lcd_BarMeter(LcdDeviceAdd,rpm);
    //LCD数値表示
    length=sprintf(txt,"RPM:%4d",rpm);
    LCD_Printf(LcdDeviceAdd,txt,length,0xC0);
    //割込み復帰処理
    ccp2.data[1]=0x0000;
    ccp2.data[0]=0x0000;
    PIR2bits.CCP2IF=0;
    PIE2bits.CCP2IE=1;                
    T1CONbits.TMR1ON = 1;
}

Timer1の1msはシステムクロック16Mhzの時、500カウント。1秒間では、500,000カウント。
1秒間の回転数を求めた後、60を掛けて、RPMをもとめています。
オシロ波形1.jpg
オシロで計測して183ヘルツの場合、6枚歯のエンコーダなので、183÷6×60=1830RPMとなります。
1827で計算した値は、LCDに表示されます。
動画で確認していただけると、オシロの周波数と、LCDの回転数表示が一致しているので、正しく計測できていることが確認できるはずです。

回転数をLCDにバーメータとして表示させています。
LCD液晶には、ユーザー登録メモリエリアが存在しています。そこにバーメータの表示図形を登録します。

I2C_LCD_BarMeter.h
#ifndef I2C_LCD_BARMETER_H
#define	I2C_LCD_BARMETER_H

#ifdef	__cplusplus
extern "C" {
#endif
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Peripheral.h"
#include "LCDdriver.h"
    
extern uint8_t LcdMemoryData[5];
extern void Lcd_Mem_Char_Set(uint8_t deviceAdd);
extern void Lcd_BarMeter(uint8_t deviceAdd, int32_t val32);



#ifdef	__cplusplus
}
#endif

#endif	/* I2C_LCD_BARMETER_H */
I2C_BarMeter.c
#include "I2C_LCD_BarMeter.h"

//バーメータのLCD登録図形
uint8_t LcdMemoryData[5]={0x00,0x10,0x18,0x1C,0x1E};


//*******************************************************//
// LCD ユーザーRAMデータセット バーメーター
// Ldc_Mem_Char_Set
// 引数:deviceAdd I2Cデバイスアドレス
// 
//*******************************************************//
void Lcd_Mem_Char_Set(uint8_t deviceAdd)
{
    int i,j,cgram,num;
    
    num=0;
    for(i=0x00; i<=0x20; i+=0x08)
    {
        cgram=0x40|i;//CGRAM address set Command = 0x40
        LCD_Command(deviceAdd,cgram);
        for(j=0x00; j<=0x7; j++)
        {
            LCD_WriteData(deviceAdd,LcdMemoryData[num]);
            __delay_ms(10);
        }
        num++;
    }
}

//*******************************************************//
// LCDバーメーター表示
// Ldc_BarMeter
// 100(RPM/縦列)
//*******************************************************//
void Lcd_BarMeter(uint8_t deviceAdd, int32_t val32)
{
    uint8_t A,B,C,adram;
    
    A=val32/100;
    B=A/5;
    C=A%5;

    LCD_Command(deviceAdd,0x80);//DDRAM開始アドレスセット
    for(adram=0; adram<B; adram++)
    {
        LCD_WriteData(deviceAdd,0xFF);//塗りつぶし
    }

    LCD_WriteData(deviceAdd,C);//Bar先頭 0?4列表示
    for(adram=B+1; adram<16; adram++)
    {
        LCD_WriteData(deviceAdd,' ');
    }  
}

コード

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,tm4;

//************************************************//
//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;

//***************************************************//
//CCP Capture
//***************************************************//
typedef struct{
    uint16_t data[3];
    uint8_t index;
    bool finished;
}_CCP_CAP;
extern _CCP_CAP ccp2;

extern void Timer0_INIT(void);
extern void Timer1_INIT(void);
extern void Timer2_INIT(void);
extern void Timer4_INIT(void);
extern void Interrupt_START(void);
extern void ADC_INIT(void);
extern void CCP1_PWM_Init(void);
extern void CCP2_Capture_Init(void);

#ifdef	__cplusplus
}
#endif

#endif	/* MYLIB_H */

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
 ---------------------------------------------------*/
_tm tm4;
void Timer4_INIT(void)
{
    T4CONbits.T4OUTPS=0b1111;   //1:16 Postscaler
    TMR4=0;
    T4CONbits.T4CKPS=0b11;  //prescle1:64
    PR4=0x27;   //Fosc=16Mhz 10ms
    PIE3bits.TMR4IE=1;
    PIR3bits.TMR4IF=0;
    T4CONbits.TMR4ON=1;
    tm4.up=false;
    tm4.cnt=0;
}

/*---------------------------------------------------
 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 PWM mode
void CCP1_PWM_Init(void)
{
    CCP1CONbits.CCP1M=0b1100;//PWM mode
    CCPTMRSbits.C1TSEL0=0b00;//Timer2 in PWM mode
    CCPR1L=0x00;
    TRISB3=0;
    //APFCON0bits.CCP1SEL=1;//RB0
    APFCON0bits.CCP1SEL=0;//RB3
}

 _CCP_CAP ccp2;
//RA7 Capture mode
void CCP2_Capture_Init(void)
{
    CCP2CONbits.CCP2M=0b0101;//Capture mode rising edge
    CCPR2H=0x00;
    CCPR2L=0x00;
    TRISA7=1;
    APFCON0bits.CCP2SEL=1;//RA7
    //interrupt enable
    PIE2bits.CCP2IE=1;
    PIR2bits.CCP2IF=0;
    //user variant
    ccp2.data[0]=0x0000;
    ccp2.data[1]=0x0000;
    ccp2.finished=false;
}

//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;
}

Interrupt.h

#ifndef INTERRUPT_H
#define	INTERRUPT_H

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



#ifdef	__cplusplus
}
#endif

#endif	/* INTERRUPT_H */
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 <stdint.h>
#include "Interrupt.h"
#include "Peripheral.h"
#include "I2C_MSSP1.h"
#include "LCDdriver.h"
#include "I2C_LCD_BarMeter.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;
    uint32_t rpm;
            
    unsigned int t=5000;
    //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();        //CCP1 PWM1初期化
    Timer1_INIT();
    CCP2_Capture_Init();    //CCP2 capture mode 初期化
    Timer4_INIT();
    
    //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_Mem_Char_Set(LcdDeviceAdd);
    //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;
            
            
         
            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;
        }
        
        if(tm4.up)
        {
            tm4.up=false;
            if(ccp2.finished)
            {
                ccp2.finished=false;
                if(ccp2.data[1]>ccp2.data[0])
                {
                    rpm = (ccp2.data[1]-ccp2.data[0]);
                    rpm*=6;
                    rpm = 500000/rpm * 60;
                    //printf("%u %u\n",ccp2.data[1],ccp2.data[0]);
                    //printf("%u\n",rpm);
                }
                else
                {
                    rpm=0;
                } 
                Lcd_BarMeter(LcdDeviceAdd,rpm);
                
                length=sprintf(txt,"RPM:%4d",rpm);
                LCD_Printf(LcdDeviceAdd,txt,length,0xC0);
                
                ccp2.data[1]=0x0000;
                ccp2.data[0]=0x0000;
                PIR2bits.CCP2IF=0;
                PIE2bits.CCP2IE=1;                
                T1CONbits.TMR1ON = 1;
            }
            PIR3bits.TMR4IF=0;
            PIE3bits.TMR4IE=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
}

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 */
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 1バイト受信
//_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:送信データ
//戻り値:2バイトデータ
//----------------------------------------------------
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;
}
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 */


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
//機能:データ送信
//引数1:_device_add スレーブアドレス(8bits)
//引数2:_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); //上位4ビット
    __delay_us(40);
}

//----------------------------------------------//
//関数名:LCD_Command
//機能:コマンド送信
//引数1:_device_add スレーブアドレス(8bits)
//引数2:_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初期化
//引数1:_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
//機能:文字列表示
//引数1:_device_add スレーブアドレス(8bits)
//引数2:*string 文字列先頭アドレス
//引数3:文字列長
//引数4:表示位置アドレス
//----------------------------------------------//
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バックライト点灯
//引数1:_device_add スレーブアドレス(8bits)
//引数2:_led 0:消灯 1:点灯
//------------------------------------------------//
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);
    
}

I2C_LCD_BarMeter.h

#ifndef I2C_LCD_BARMETER_H
#define	I2C_LCD_BARMETER_H

#ifdef	__cplusplus
extern "C" {
#endif
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "Peripheral.h"
#include "LCDdriver.h"
    
extern uint8_t LcdMemoryData[5];
extern void Lcd_Mem_Char_Set(uint8_t deviceAdd);
extern void Lcd_BarMeter(uint8_t deviceAdd, int32_t val32);
I2C_LCD_BarMeter.c
#include "I2C_LCD_BarMeter.h"

uint8_t LcdMemoryData[5]={0x00,0x10,0x18,0x1C,0x1E};


//*******************************************************//
// LCD ユーザーRAMデータセット バーメーター
// Ldc_Mem_Char_Set
// 引数:deviceAdd I2Cデバイスアドレス
// 
//*******************************************************//
void Lcd_Mem_Char_Set(uint8_t deviceAdd)
{
    int i,j,cgram,num;
    
    num=0;
    for(i=0x00; i<=0x20; i+=0x08)
    {
        cgram=0x40|i;//CGRAM address set Command = 0x40
        LCD_Command(deviceAdd,cgram);
        for(j=0x00; j<=0x7; j++)
        {
            LCD_WriteData(deviceAdd,LcdMemoryData[num]);
            __delay_ms(10);
        }
        num++;
    }
}

//*******************************************************//
// LCDバーメーター表示
// Ldc_BarMeter
// 100(RPM/縦列)
//*******************************************************//
void Lcd_BarMeter(uint8_t deviceAdd, int32_t val32)
{
    uint8_t A,B,C,adram;
    
    A=val32/100;
    B=A/5;
    C=A%5;

    LCD_Command(deviceAdd,0x80);//DDRAM開始アドレスセット
    for(adram=0; adram<B; adram++)
    {
        LCD_WriteData(deviceAdd,0xFF);//塗りつぶし
    }

    LCD_WriteData(deviceAdd,C);//Bar先頭 0?4列表示
    for(adram=B+1; adram<16; adram++)
    {
        LCD_WriteData(deviceAdd,' ');
    }  
}
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?