前回 APDS-9960 のジェスチャーセンサーを使用しました。今回はジェスチャーに加えて近接センサーも使用してみたいと思います。
前回の記事はこちら
さて、近接センサーですが、前回ジェスチャーセンサーを使用するときに既に動作しています。近接センサーの値によってジェスチャーセンサーを ON/OFF させていました。
というわけで今回すべきことは近接センサーの調整ぐらいになりそうです。
データシートを確認すると近接センサーの測定値は PDATA(0x9C) に格納されているようです。なので早速このレジスタの値を読み取って LCD に表示させてみました。
・・あれ?なぜ11までしか値が増加しないのだ?
しかし、すぐにピンときました。前回ジェスチャーエンジンを起動する閾値を10と設定したせいでしょう。
試しに閾値を20にしてみると今度は21まで値が増加しました。どうやら閾値を超えるとそれ以上は測定しないようですね。
そこで、近接センサーの測定値を読む間だけジェスチャーエンジンを OFF にしておくことにしました。これで255まで測定することができます。
その後スケールなどを試行錯誤した結果、LED電流 100mA, ブースト 300% にすることにしました。
電流はジェスチャーエンジンと近接エンジンで個別に設定できますが、ブーストは共通なので、ジェスチャーエンジンの電流を 25mA → 12.5mA に変更しました。
また、近接センサーの電流を増やしたのでジェスチャーエンジンの閾値を GPENTH = 20, GEXTH = 10 としました。2つの閾値が異なっているのは閾値付近での動作を安定化させるためです。
では実際に動作テストしてみます。0.1s 毎に近接センサーの値を読み取ります。このとき、タイマ割り込みで直接読み取りしようとすると、メインループでのジェスチャーの処理に重なってしまうので、読み取りフラグを立てるだけにしてメインループでフラグを確認します。
今回は近接センサーの測定値を PWM で出力してレベルメーターで確認できるようにしてみました。レベルメーターは秋月電子のこちらのキットを使用しました。
以下テスト動画、ソースコード、回路図です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
#pragma config FEXTOSC = OFF // FEXTOSC External Oscillator mode Selection bits (Oscillator not enabled) #pragma config RSTOSC = HFINT1 // Power-up default value for COSC bits (HFINTOSC (1MHz)) #pragma config CLKOUTEN = OFF // Clock Out Enable bit (CLKOUT function is disabled; I/O or oscillator function on OSC2) #pragma config CSWEN = ON // Clock Switch Enable bit (Writing to NOSC and NDIV is allowed) #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled) #pragma config MCLRE = ON // Master Clear Enable bit (MCLR/VPP pin function is MCLR; Weak pull-up enabled) #pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled) #pragma config WDTE = OFF // Watchdog Timer Enable bits (WDT disabled; SWDTEN is ignored) #pragma config LPBOREN = OFF // Low-power BOR enable bit (ULPBOR disabled) #pragma config BOREN = OFF // Brown-out Reset Enable bits (Brown-out Reset disabled) #pragma config BORV = LOW // Brown-out Reset Voltage selection bit (Brown-out voltage (Vbor) set to 2.45V) #pragma config PPS1WAY = ON // PPSLOCK bit One-Way Set Enable bit (The PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable bit (Stack Overflow or Underflow will cause a Reset) #pragma config DEBUG = OFF // Debugger enable bit (Background debugger disabled) #pragma config WRT = OFF // User NVM self-write protection bits (Write protection off) #pragma config LVP = OFF // Low Voltage Programming Enable bit (High Voltage on MCLR/VPP must be used for programming.) #pragma config CP = OFF // User NVM Program Memory Code Protection bit (User NVM code protection disabled) #pragma config CPD = OFF // Data NVM Memory Code Protection bit (Data NVM code protection disabled) #include <xc.h> #include <stdio.h> #include "i2c.h" #include "apds.h" #define _XTAL_FREQ 16000000 bit ProxFlag; void init(){ OSCFRQ = 0x06; //3 : 4MHz/ 4 : 8MHz/ 6 : 16MHz/ 7 : 32MHz OSCCON1bits.NDIV = 0x0; //Clock Divider 1/1 TRISA = 0b00001000; TRISC = 0b00110000; ANSELA = 0b00000000; ANSELC = 0b00000000; WPUA = 0b00000000; WPUC = 0b00000000; PORTA = 0b00000000; PORTC = 0b00000000; } void SetPWMDuty(int i){ CCPR1H = (i&0x0300) >> 8; CCPR1L = i&0x00ff; } void interrupt isr(){ if(TMR0IF == 1){ TMR0IF = 0; ProxFlag = 1; } } int main() { init(); GIE = 1; PEIE = 1; TMR0IE = 1; T0CON0 = 0b10010101; //Timer 0 T0CON1 = 0b01000000; //0.1s T2CON = 0b00000100; //Timer 2 PR2 = 0xFF; //for CCP module CCP1CON = 0b10001111; //CCP as PWM CCPTMRS = 0b00000000; // RC2PPS = 12; //PPS Setting I2C_Master_Init(100000); APDS_Init(); while(1){ APDS_Main(); //Gesture if(ProxFlag == 1){ //Proximity ProxFlag = 0; SetPWMDuty(APDS_ReadProx()*4); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
#include<xc.h> #include"i2c.h" bit Gesture_End = 0; char UDLR[4]; char UDLR_Old[4]; char UDLR_Peak[4]; char PhaseCounter; char Direction; char UDLR_PeakEndFlag; void APDS_Send(char address, char data){ I2C_Master_Start(); I2C_Master_Write(0x72); //SlaveAdress + Write I2C_Master_Write(address); //RegisterAdress I2C_Master_Write(data); I2C_Master_Stop(); } void APDS_ReadGesture(){ I2C_Master_Start(); I2C_Master_Write(0x72); //SlaveAdress + Write I2C_Master_Write(0xFC); //Adress I2C_Master_RepeatedStart(); I2C_Master_Write(0x73); //SlaveAdress + Read UDLR[0] = I2C_Master_Read(0); UDLR[1] = I2C_Master_Read(0); UDLR[2] = I2C_Master_Read(0); UDLR[3] = I2C_Master_Read(1); I2C_Master_Stop(); } char APDS_FIFOCheck(){ char check = 0; I2C_Master_Start(); I2C_Master_Write(0x72); //SlaveAdress + Write I2C_Master_Write(0xAE); //Adress I2C_Master_RepeatedStart(); I2C_Master_Write(0x73); //SlaveAdress + Read check = I2C_Master_Read(1); I2C_Master_Stop(); return check; } char APDS_GMODECheck(){ char check = 0; I2C_Master_Start(); I2C_Master_Write(0x72); //SlaveAdress + Write I2C_Master_Write(0xAB); //Adress I2C_Master_RepeatedStart(); I2C_Master_Write(0x73); //SlaveAdress + Read check = I2C_Master_Read(1); I2C_Master_Stop(); return check & 0x01; } void APDS_ResetVariable(){ for(char i=0; i<4; i++) UDLR_Old[i] = 0; UDLR_PeakEndFlag = 0; PhaseCounter = 0; } void APDS_Init(){ APDS_Send(0x80,0x45); //POWER ON, GESTURE ENABLE, PROXIMITY DETECT ENALBE,AEN=0 APDS_Send(0xA3,0x79); //Gain x8, LED Drive 12.5mA, Wait Time 2.8ms for Gesture Engine APDS_Send(0xAB,0x00); //GIEN off(INTERRUPT DISABLE), GMODE OFF APDS_Send(0x90,0x31); //LED Boost 300% APDS_Send(0xA0,20); // Enter Threshold APDS_Send(0xA1,10); // Exit Threshold APDS_ResetVariable(); } char APDS_Process(){ for(char i=0; i<4; i++){ if(UDLR[i] > UDLR_Old[i]){ // Aproaching to Peak UDLR_Old[i] = UDLR[i]; UDLR_Peak[i] = PhaseCounter; } else{ // Peak Was Gone UDLR_PeakEndFlag = (UDLR_PeakEndFlag & ~(1 << i)) + (1 << i); } } if(UDLR_PeakEndFlag == 0b1111){ // All Peak Was Gone /* Find Last Peak */ if((UDLR_Peak[0] > UDLR_Peak[1]) && (UDLR_Peak[0] >= UDLR_Peak[2]) && (UDLR_Peak[0] >= UDLR_Peak[3])) Direction = 0; else if((UDLR_Peak[1] > UDLR_Peak[0]) && (UDLR_Peak[1] >= UDLR_Peak[2]) && (UDLR_Peak[1] >= UDLR_Peak[3])) Direction = 1; else if((UDLR_Peak[2] > UDLR_Peak[3]) && (UDLR_Peak[2] >= UDLR_Peak[0]) && (UDLR_Peak[2] >= UDLR_Peak[1])) Direction = 2; else if((UDLR_Peak[3] > UDLR_Peak[2]) && (UDLR_Peak[3] >= UDLR_Peak[0]) && (UDLR_Peak[3] >= UDLR_Peak[1])) Direction = 3; else Direction = 4; return 0; // Process Complete } return 1; // Still Processing } void APDS_Main(){ if(APDS_FIFOCheck() != 0){ // Data Exist APDS_ReadGesture(); if(Gesture_End == 0){ // Before Gesture End PhaseCounter++; if(APDS_Process() == 0){ // Processs & If Complete switch(Direction){ case 0: // Up PORTA = 0b00010000; break; case 1: // Down PORTA = 0b00000001; break; case 2: // Left PORTA = 0b00000010; break; case 3: // Right PORTA = 0b00100000; break; default: // Error PORTA = 0b00000000; break; } APDS_ResetVariable(); Gesture_End = 1; } } } else if((APDS_GMODECheck() == 0) && (Gesture_End == 1)) // Reset Gesture_End Gesture_End = 0; } char APDS_ReadProx(){ char pdata = 0; APDS_Send(0x80,0x05); //Gesture disable I2C_Master_Start(); I2C_Master_Write(0x72); //SlaveAdress + Write I2C_Master_Write(0x9C); //Adress I2C_Master_RepeatedStart(); I2C_Master_Write(0x73); //SlaveAdress + Read pdata = I2C_Master_Read(1); I2C_Master_Stop(); APDS_Send(0x80,0x45); //Gesture Enable return pdata; } |
1 2 3 4 5 6 7 8 9 |
void APDS_Send(char address, char data); void APDS_Read(); char APDS_FIFOCheck(); char APDS_GMODECheck(); void APDS_ResetVariable(); void APDS_Init(); char APDS_Process(); void APDS_Main(); char APDS_ReadProx(); |
I2Cライブラリ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include<xc.h> #define _XTAL_FREQ 16000000 void I2C_Master_Init(const unsigned long c){ SSP2CON1 = 0x28; //SSP2 Module as Master SSP2CON2 = 0x00; SSP2CON3 = 0x00; SSP2ADD = (_XTAL_FREQ/(4*c))-1; //Setting Clock Speed SSP2STAT = 0x80; SSP2CLKPPS = 0x14; //PPS Settings SSP2DATPPS = 0x15; // SCL : RC4 RC4PPS = 0x1a; // SDA : RC5 RC5PPS = 0x1b; } void I2C_Master_Wait(){ while ((SSP2STAT & 0x04) || (SSP2CON2 & 0x1F)); //Transmit is in progress } void I2C_Master_Start(){ I2C_Master_Wait(); SSP2CON2bits.SEN = 1; //Initiate start condition } void I2C_Master_RepeatedStart(){ I2C_Master_Wait(); SSP2CON2bits.RSEN = 1; //Initiate repeated start condition } void I2C_Master_Stop(){ I2C_Master_Wait(); SSP2CON2bits.PEN = 1; //Initiate stop condition } void I2C_Master_Write(unsigned d){ I2C_Master_Wait(); SSP2BUF = d; //Write data to SSP2BUF } unsigned short I2C_Master_Read(unsigned short a){ unsigned short temp; I2C_Master_Wait(); SSP2CON2bits.RCEN = 1; I2C_Master_Wait(); temp = SSP2BUF; //Read data from SSP2BUF I2C_Master_Wait(); SSP2CON2bits.ACKDT = a; //Acknowledge bit SSP2CON2bits.ACKEN = 1; //Acknowledge sequence return temp; }</xc.h> |
1 2 3 4 5 6 7 |
void I2C_Master_Init(const unsigned long c); void I2C_Master_Wait(); void I2C_Master_Start(); void I2C_Master_RepeatedStart(); void I2C_Master_Stop(); void I2C_Master_Write(unsigned d); unsigned short I2C_Master_Read(unsigned short a); |
次回はこのセンサーのもう一つの機能である RGBセンサーを使ってみたいと思います。
次回 ↓