« 自記温度計、自記気圧計 - 複数のSPIデバイスがいっしょに使えなかった話 | トップページ | 交流電圧計(ミリバル)を作る - 高周波電圧計 - 1 »

2015年2月13日 (金)

PIC+SPI+I2C 自記温湿度計+気圧計+8ch電圧計のソース - main()

参考になるかどうかわかりませんが.....

今回はmain()です。

装置の全体像とブロックダイヤグラムや関連記事(回路、ソース)へのリンクが
  「PIC+SPI+I2C 自記温湿度計+気圧計+8ch電圧計+周波数カウンタ(技術要素一覧表)
にあります。
Imgp87021200


MCP3208はRTCのバックアップ用電池の隣のソケットにいれました。

PICでSPI - 超高精度SPIバスRTC(リアルタイムクロック)DS3234Sの使い方(ソース付き)
PICでI2C - 大気圧・温度センサーLPS331APの使い方
I2C/SPI大気圧センサーLPS25Hの使い方 - 1 - 実装
意外に正確そうなI2C大気圧センサーMPL115A2の測定値
温度センサー3種の精度比較(摂氏0度~40度編)
PICで作るお手軽サーミスタ温度計 (2) - ソース付き
(趣味の)白金抵抗温度計の製作 - 準備編
PICでI2C - ADコンバーター・MCP3425の使い方
PIC18F26K22でSPI - 8ch/ADコンバータ MCP3208の使い方(ソース付き)
PICでSPI SDカードを読み書きする

  趣味の電子工作
    PIC
  趣味の気象観測
  趣味の実験

========

// xc8コンパイラー  foat=24bit double=32bit でコンパイルすること
// 各種センサーのデータを取得し、それらをLCDに表示するとともにSDカードに記録します。
// どういうデータを表示するかとかどういうふうにデータを取得するかも指定できるようにしたいけれど未実装です。
// SDカードに記録する間隔だけは設定できるようになっています。
// タクトスイッチ2個で設定画面呼び出し、設定値保存、測定値手動記録、測定値保存終了などを制御します。
// 記録時間間隔は可変抵抗で選択します。
// 1,2,3,4,5,6,10,15,20,30,60,120,180,240,300,600秒から選べます。
// ただし1秒は特殊でこれが選択されると測定値の記録は行わずタクトスイッチが押されたときだけ記録されます。
// 1秒じゃなくて0秒の選択肢にするんでした (^^;;
// 測定とその記録は1秒では時間が足りません。またSDカードへの記録量が増えて行くと書き込みが遅くなるようです。
// つまり長時間記録をとるときは記録間隔は長めにしておいた方が無難です。
// 例えば2秒間隔で記録をとると、毎分0,2,4,6,8,...秒に記録されるはずが0,2,4,6,10,14,20,...秒に記録されるみたいになります。
// (これはわかりやすいようにデフォルメした表現です)
// 時刻合わせの機能もつくるつもりだったのですがRTC(DS3234S)があまりにも正確なので作成意欲を失いました。
// このRTCは秒を設定したらその0.5秒後から1PPSが出るらしいのでGPSの1PPSと同期するようにしたいものです。
// PIC18F26K22
// 01 RE3/VPP/MCLR .....(1) .... 10kでプルアップ
// 02 RA0/C12IN0-/AN0 ..... 可変抵抗の中点(?)へ、電源電圧(3.3V)の分圧を測定、設定値選択用
// 03 RA1/C12IN1-/AN1 /..... タクトスイッチ、メニューボタン
// 04 RA2/C2IN+/AN2/DACOUT/VREF .... タクトスイッチ、決定・終了ボタン
// 05 RA3/C1IN+/AN3/VREF+ .... 未使用
// 06 RA4/CCP5/C1OUT/SRQ/T0CKI ..... 未使用
// 07 RA5/C2OUT/SRNQ/SS1/HLVDIN/AN4 .... 未使用
// 08 VSS
// 09 RA7/CLKI/OSC1 .... RTC・DS3234Sの/CS
// 10 RA6/CLKO/OSC2 ..... ADコンバータのMCP3208の/CS
// 11 RC0/P2B/T3CKI/T3G/T1CKI/SOSCO ..... Reserved アナログ・スイッチの制御(I2Cバスラインの選択)
// 12 RC1/P2A/CCP2/SOSCI ..... Reserved アナログ・スイッチの制御(I2Cバスラインの選択)
// 13 RC2/CTPLS/P1A/CCP1/T5CKI/AN14 ..... アナログ・スイッチの制御(I2Cバスラインの選択)
// 14 RC3/SCK1/SCL1/AN15 ..... I2C/SCL ..... MCP3425、LPS331AP、LPS25H、AM2321、MLP115A2、AM3201
// 15 RC4/SDI1/SDA1/AN16 ..... I2C/SDA
// 16 RC5/SDO1/AN17 .... つかっちゃまずい?
// 17 RC6/P3A/CCP3/TX1/CK1/AN18 ..... Reserved TX1
// 18 RC7/P3B/RX1/DT1/AN19 ..... Reserved RX1
// 19 VSS .....(3)
// 20 VDD .....(2)
// 21 RB0/INT0/CCP4/FLT0/SRI/SS2/AN12 ..... INT0 ..... RTC/1PPS出力へ
// 22 RB1/INT1/P1C/SCK2/SCL2/C12IN3-/AN10 ...... SPI/SCK .... SDカード、DS3234S、MCP3208
// 23 RB2/INT2/CTED1/P1B/SDI2/SDA2/AN8 ..... SPI/SDI
// 24 RB3/CTED2/P2A/CCP2/SDO2/C12IN2-/AN9 ..... SPI/SDO
// 25 RB4/IOC0/P1D/T5G/AN11 .... SDカードの/CS
// 26 RB5/IOC1/P2B/P3A/CCP3/T3CKI/T1G/AN13 ..... 未使用
// 27 RB6/IOC2/TX2/CK2/PGC .....(5) ..... 未使用
// 28 RB7/IOC3/RX2/DT2/PGD .....(4) ..... 未使用
// SPI MODE 0 DS3234S(モード1/3とあるけれどこれで動いています)、MCP3208
// SSP2STAT &= 0xBF;
// SSP2CON1 &= 0xEF;
// SPI MODE 1
// SSP2STAT |= 0x40;
// SSP2CON1 &= 0xEF;
// SPI MODE 2 SDカード
// SSP2STAT &= 0xBF;
// SSP2CON1 |= 0x10;
// SPI MODE 3
// SSP2STAT |= 0x40;
// SSP2CON1 |= 0x10;
#include <xc.h>
#include <stdio.h>
#include <string.h>
#include "..\..\include\common\MyDef.h"
#include "..\..\include\common\I2CLib.h"
#include "..\..\include\common\ACM1602lib.h"
#include "..\..\include\common\lps331ap.h"
#include "..\..\include\common\MCP3425lib.h"
#include "..\..\include\common\AM2321lib.h"
#include "..\..\include\common\MPL115A2lib.h"
#include "..\..\include\common\SPILib.h"
#include "..\..\include\common\SDlib.h"
// C:\Program Files (x86)\Microchip\xc8\v1.32\docs\chips\18f26k22.html
#ifdef _18F26K22
#pragma config FOSC = INTIO67
#pragma config WDTEN = OFF
#pragma config MCLRE = INTMCLR
#endif
// 割込みがあったかどうか確認するためのフラグです。
static int Interrupt=0;
// センサーから読み込んだデータをLCDに16進表示するため
// sprintf()を使いたくないとき用
void putLCDhex(unsigned char ch)
{
    char hex[]="0123456789ABCDEF";
    LCD_Putc(hex[ch>>4]) ;
    LCD_Putc(hex[ch & 0x0f]) ;
}
// 可変抵抗(アナログ端子の電圧)で記録時間間隔をコントロールします。
// エンコーダーやDIPスイッチを使うより簡単で応用がききます。
// RTCの時刻設定もこれにするつもりです。
int getValOfVR(void)
{
    int val;
    static int vtint[]={1,2,3,4,5,6,10,15,20,30,60,120,180,240,300,600};
    ADCON0 = 0b00000011 ;             // AN0のAD変換開始
    while(ADCON0 & 0b00000010) ;          // ADC変換終了待ち
    val = ADRESH * 256 + ADRESL;
    return vtint[val/64];
}
// 割込みがあったときはフラグを立てます。
// 割込みルーチンの中では何もしません。
void interrupt InterFunction( void )
{
    // INT0割込み
    if( INT0IF == 1 ) {
        Interrupt = 1;
        INT0IF = 0;
    // I2C関連の割り込み処理
    } else {
        InterI2C() ;
    }
}
void main()
{
    unsigned char ct[8];
    unsigned char d1,d2,d3;
    char filename[16];
    union {
        char c[2] ;
        int  i ;
    } ans ;
    char    dt_w[128] ="LPS331-T,LPS331-P,LPS25H-T,LPS25H-P,3425-V,3425-T\r\n";
    char    dt_m[128];
    int     j,k,sec,min;
    int     status=0;
    unsigned char   menu = 4;
    int   tint = 300,tint_t;
    double   val_LPS331[2];
    double   val_LPS25H[2];
// 白金薄膜抵抗の抵抗値を求めたり、それから温度を求めるための定数
// MCP3425 & Pt
    unsigned char ip_MCP3425[4]={0,0,0,0};
    float vlt_MCP3425;
    float tmp_MCP3425;
    float R1;
    float V_cmp= 1.002965;      // MCP3425の電圧補正値
    float Offset = 0.00000;
    float Vin=4.094;            // 基準電圧
    float Rin= 4980.0;          // 直列抵抗(金属皮膜抵抗 0.5%)
    float R0 = 100.00;           // 白金薄膜抵抗の273.15Kでの抵抗値
    float C_a= 0.0039083;       // 白金薄膜抵抗の補間式係数
    float C_b= -0.0000005775;   // 白金薄膜抵抗の補間式係数
// MCP3208(ADコンバータ)で電圧を求めるための定数
    float value[8];
    float Vref=3.3;
    float val_AM2321[2];
    float prs_MPL115;
   
    OSCCON = MyOSCCON ;
// 入力ピンは一般的に電源を含めどこに接続してもたいていヘーキですが
// 出力ピンが電源や他の出力ピンに接続されるは避けた方がいいと思います。
// だから事故防止のため出力として使わないピンは入力のままにしてあります。
// for I2C
    ANSELCbits.ANSC3 = 0;
    ANSELCbits.ANSC4 = 0;
// Select bus for I2C
// 同じアドレスのI2Cデバイスを使うのにSCLをアナログ・スイッチで切り替えるため
    TRISC2 = 0;
    PORTCbits.RC2 = 1;
// for SPI
    ANSELBbits.ANSB2 = 0;
    ANSELBbits.ANSB1 = 0;
    TRISB1 = 0;
    TRISB3 = 0;
// OUTPUT
// SDカードの/CS
    TRISB4 = 0;
    CS_SD = 1;
// RTC DS3234Sの/CS
    TRISA7 = 0;
    CS_RTC = 1;
// RTC DS3234Sの/CS
    TRISA6 = 0;
    CS_ADC = 1;
// INT0 RB0
    ANSELBbits.ANSB0 = 0;
// INPUT RA1 メニューボタン
    ANSELAbits.ANSA1 = 0;
// メニューボタンの機能
// 1. 測定値を記録する間隔を設定する画面に入ります
// 2. 設定画面を終了する
// ※ 起動した直後は設定画面になります。
// INPUT RA2 決定、終了ボタン
    ANSELAbits.ANSA2 = 0;
// 決定・終了ボタンの機能
// 設定画面のとき
// 1. 画面に表示されている値を保存します。
// 設定画面でないとき
//  測点間隔が1秒以外に設定されているとき
//   測定値の記録を終了し、表示のみのモードに移行します。
//  測定間隔が1秒に設定されているとき
//  (測定間隔1秒の場合は測定値の自動記録はしません)
//   測定値を記録します。
// ADC AN0 設定切替用可変抵抗
    ADCON2 = 0b10101111 ;
    ADCON1 = 0b00000000 ;
// SPIはひとまずmode 2として初期化します。
    SPI_Init(SPI_MODE2,SPI_CLOCK_DIV16) ;
    InitI2C_Master() ;
    LCD_Init() ;
    LCD_Clear();
    LCD_Puts("Start!");
    // これが重要みたいです。
    for(j=0; j < 300; j++ ) __delay_ms(10);
    // MCP3208のデータを読み込みます
    // SDカードの初期化でエラーが起きることの対策として入れたがたぶん不要
    for( k=0; k < 8; k++ ) {
        // SPI MODE 0
        SSP2STAT &= 0xBF;
        SSP2CON1 &= 0xEF;
        CS_ADC = 0;
        d1=SPI_transfer(0x06 | ((k >> 2) & 0x01) ) ;
        d2=SPI_transfer( k << 6 );
        d3=SPI_transfer(0x00);
        CS_ADC = 1;
        value[k] = (float)(d2 & 0x0F)*256.0 + (float)d3;
        value[k] = Vref * value[k]/4096.0;
    }
    // DS3234Sから時刻を取得します。
    // この処理はどうして必要か不明
    // なくても動きそうだが....
    // SPI MODE 0
    SSP2STAT &= 0xBF;
    SSP2CON1 &= 0xEF;
    CS_RTC = 0;
    for( j=0; j < 25; j++ ) __delay_ms(20);
    ct[0]=SPI_transfer(0x00) ;
    for( j =0; j < 7; j++ ) {
    ct[6-j]=SPI_transfer(0x00) ;
    }
    CS_RTC = 1;
    // 時刻を取得します。
    // SPI MODE 0
    SSP2STAT &= 0xBF;
    SSP2CON1 &= 0xEF;
    CS_RTC = 0;
    d1=SPI_transfer(0x00) ;
    for( j =0; j < 7; j++ ) {
        ct[6-j]=SPI_transfer(0x00) ;
    }
    CS_RTC = 1;
    LCD_SetCursor(0,0);
    for( j=0; j < 7; j++ ) {
        putLCDhex(ct[j]);
    }
    LCD_SetCursor(0,1);
    // ファイル名は8.3形式である必要があります。
    sprintf(filename,"%02x%02x%02x%02x.TXT",ct[1],ct[2],ct[4],ct[5]);
    // SDカードの初期化とファイルのオープン
    // SPI MODE 2
    SSP2STAT &= 0xBF;
    SSP2CON1 |= 0x10;
    ans.i = SD_Init() ;
    if (ans.i != 0) {
        LCD_Puts("Error-Init ") ;            // 初期化エラー
        putLCDhex(ans.c[1]) ;
        putLCDhex(ans.c[0]) ;
        while( PORTAbits.RA1 == 1 );
        status = 0x01;
    } else {
        ans.i = SD_Open(filename,O_RDWR) ;
        if (ans.i != 0) {
            LCD_Puts("Error-Open ") ;      // オープンエラー
            while( PORTAbits.RA1 == 1 );
            status = 0x02;
        } else {
            ans.i = SD_Write(dt_w,strlen(dt_w)) ;
            if( ans.i == -1 ) {
                LCD_Puts("Error-Write  ") ;      // オープンエラー
                while( PORTAbits.RA1 == 1 );
                status = 0x04;
            }
        }
    }
    // RTCの1PPSでINT0から割込みをかけます。
    INT0IE = 1;
    k = 0;
    LCD_SetCursor(0,0);
    while( status == 0 ) {
        // いろいろ面倒くさいことをしていますがチャタリングやスイッチが押しっぱなしにされたときの対策です。
        if( PORTAbits.RA1 == 0 ) {
            if( menu == 4 ) menu = 5;
        } else {
            if( menu == 3 ) menu = 4;
            else if( menu == 5 ) menu = 0;
        }
        if( menu < 3 ){
            // 1PPSの割込みがなかったときは何もしない
            if( Interrupt == 0 ) continue;
   // データの取得、SDカード書き込み中は割込み禁止です。
            INT0IE = 0;
            if( PORTAbits.RA1 == 0 ) menu++;
            else menu = 0;
            // データ表示中にRA2がLowに落ちたら測定終了です。
            // ただしデータ記録間隔が1秒のときは除きます
            // RA2をHighにしたら再測定、ということにはなっていません。
            if( PORTAbits.RA2 == 0 && tint != 1 ) break;
            // DS3234Sから時刻を取得します。
            // SPI MODE 0
            SSP2STAT &= 0xBF;
            SSP2CON1 &= 0xEF;
            CS_RTC = 0;
            d1 = SPI_transfer(0x00) ;
            for( j =0; j < 7; j++ ) {
                ct[6-j]=SPI_transfer(0x00) ;
            }
            CS_RTC = 1;
            // 時刻をLCDに表示します。
            LCD_SetCursor(0,0);
            for( j=0; j < 7; j++ ) {
                if( j == 3 || j == 4 ) LCD_Putc('-');
                putLCDhex(ct[j]);
            }
            LCD_SetCursor(0,1);
            // 白金薄膜抵抗の抵抗値から温度を求めます。
            getDataMCP3425(0x07, ip_MCP3425);
            LCD_SetCursor(0,0);
//            for(j=0; j < 4; j++ ) putLCDhex(ip_MCP3425[j]);
            vlt_MCP3425 = getVltMCP3425(0x07,V_cmp,Offset,ip_MCP3425);
            R1 = getRegPt(Vin,Rin,0.0,vlt_MCP3425);
            tmp_MCP3425 = getTmpPt(R0,C_a,C_b,R1);
//            sprintf(dt_w,"%7.3f %7.3f",vlt_MCP3425,tmp_MCP3425);
//            LCD_SetCursor(0,1);
//            LCD_Puts(dt_w);
            // LPS331APから気圧と温度を取得します。
            lps331ap(LPS331AP, val_LPS331);
            // LPS25Hから気圧と温度を取得します。
            lps331ap(LPS25H, val_LPS25H);
            // MCP3208のデータを読み込みます
            for( k=0; k < 8; k++ ) {
                // SPI MODE 0
                SSP2STAT &= 0xBF;
                SSP2CON1 &= 0xEF;
                CS_ADC = 0;
                d1=SPI_transfer(0x06 | ((k >> 2) & 0x01) ) ;
                d2=SPI_transfer( k << 6 );
                d3=SPI_transfer(0x00);
                CS_ADC = 1;
                value[k] = (float)(d2 & 0x0F)*256.0 + (float)d3;
                value[k] = Vref * value[k]/4096.0;
            }
            // AM2321から温度と湿度を取得します。
            AM2321(val_AM2321);
            //
            MPL115A2(&prs_MPL115);
            // 温度と気圧をLCDに表示します。
//            sprintf(dt_m,"%4.1f,%4.1f,%6.1f",
//                    tmp_MCP3425,val_LPS331[0],val_LPS331[1]);
//            sprintf(dt_m,"%7.2f%7.2f",
//                    val_LPS331[1],val_LPS25H[1]);
            sprintf(dt_m,"%6.3f%6.3f",
                    value[0],value[1]);
            LCD_SetCursor(0,1);
            LCD_Puts(dt_m) ;
            // インターバル設定値ごとに測定結果をSDカードに書き込みます。
            sec = ((ct[6] & 0xF0) >> 1) + ((ct[6] & 0xF0) >> 3) + (ct[6] & 0x0F);
            min = ((ct[5] & 0xF0) >> 1) + ((ct[5] & 0xF0) >> 3) + (ct[5] & 0x0F);
            sec = min * 60 + sec;
            if( (sec % tint ) == 0 ) {
                if( tint == 1 && PORTAbits.RA2 != 0 ) {
                    LCD_Puts("  ") ;
                    continue;
                }
                // 時刻をSDカードに記録します。
                // SPI MODE 2
                SSP2STAT &= 0xBF;
                SSP2CON1 |= 0x10;
                sprintf(dt_w,"%02x/%02x/%02x,%02x:%02x:%02x,",
                        ct[0],ct[1],ct[2],ct[4],ct[5],ct[6]);
                ans.i = SD_Write(dt_w,strlen(dt_w)) ;
                // 温度と気圧をSDカードに記録します。
                sprintf(dt_m,"%6.2f,%7.2f,%6.2f,%7.2f,%9.6f,%7.2f,",
                    val_LPS331[0],val_LPS331[1],val_LPS25H[0],val_LPS25H[1],vlt_MCP3425,tmp_MCP3425);
                ans.i = SD_Write(dt_m,strlen(dt_m)) ;
                sprintf(dt_m,"%6.2f,%6.2f,", val_AM2321[0], val_AM2321[1]);
                ans.i = SD_Write(dt_m,strlen(dt_m)) ;
   
                sprintf(dt_m,"%8.2f,", prs_MPL115);
                ans.i = SD_Write(dt_m,strlen(dt_m)) ;
                for( k=0; k < 8; k++ ) {
                    sprintf(dt_m,"%6.3f,",value[k]);
                    ans.i = SD_Write(dt_m,strlen(dt_m)) ;
                }
                sprintf(dt_w,"\r\n");
                ans.i = SD_Write(dt_w,strlen(dt_w)) ;
               
                // 測定結果をSDカードに書き込んだことをLCDに表示します。
                LCD_Puts(" R") ;
            } else {
                // SDカードへの書き込みをしないとき
                LCD_Puts("  ") ;
            }
            LCD_SetCursor(0,0);
            // 次の割込みを待ちます。
            Interrupt = 0;
    INT0IE = 1;
        // メニューボタンが押されたときは記録間隔の設定します。
        } else {
            tint_t = getValOfVR();
            sprintf(dt_w,"%4d            ",tint_t);
            LCD_SetCursor(0,0);
            LCD_Puts(dt_w);
            // 決定ボタンが押されている
            if( PORTAbits.RA2 == 0 ) {
                tint = tint_t;
                LCD_SetCursor(6,0);
                LCD_Puts("Set");
                for(j=0; j < 50; j++ ) __delay_ms(10);
            // 決定ボタンが押されていない
            } else {
                LCD_SetCursor(6,0);
                LCD_Puts("   ");
            }
            for(j=0; j < 10; j++ ) __delay_ms(10);
        }
    }
    // SDカードをクローズします。
    if( status == 0 ){
    INT0IE = 0;
        // SPI MODE 2
        SSP2STAT &= 0xBF;
        SSP2CON1 |= 0x10;
        SD_Close() ;
        LCD_SetCursor(0,1);
        LCD_Puts("End.            ") ;
    INT0IE = 1;
    }
    // 測定の記録が終わっても時刻の表示は続けます。
    LCD_SetCursor(0,0);
    while( 1 ) {
        if( Interrupt == 0 ) continue;
  // データの取得中は割込み禁止です。
     INT0IE = 0;
        // DS3234Sから時刻を取得します。
        // SPI MODE 0
        SSP2STAT &= 0xBF;
        SSP2CON1 &= 0xEF;
        CS_RTC = 0;
        for( j=0; j < 25; j++ ) __delay_ms(20);
        ct[0]=SPI_transfer(0x00) ;
        for( j =0; j < 7; j++ ) {
        ct[6-j]=SPI_transfer(0x00) ;
        }
        CS_RTC = 1;
        for( j=0; j < 7; j++ ) {
            if( j == 3 || j == 4 ) LCD_Putc(' ');
            putLCDhex(ct[j]);
        }
        // LPS331APから気圧と温度を取得します。
        // lps331ap(val_LPS331);
        // 温度と気圧をLCDに表示します。
        // sprintf(dt_m,"%5.1f %8.1f *",val_LPS331[0],val_LPS331[1]);
        // LPS331APから気圧と温度を取得します。
        lps331ap(LPS331AP, val_LPS331);
        // LPS25Hから気圧と温度を取得します。
        lps331ap(LPS25H, val_LPS25H);
        AM2321(val_AM2321);
        // 温度と気圧をLCDに表示します。
        sprintf(dt_m,"%7.2f,%7.2f",
                val_AM2321[0],val_AM2321[1]);
        LCD_SetCursor(0,1);
        LCD_Puts(dt_m) ;
        LCD_SetCursor(0,0);
        Interrupt = 0;
    INT0IE = 1;
    }
}


« 自記温度計、自記気圧計 - 複数のSPIデバイスがいっしょに使えなかった話 | トップページ | 交流電圧計(ミリバル)を作る - 高周波電圧計 - 1 »

趣味の電子工作」カテゴリの記事

コメント

こんにちは。こんな話題の時にしか出て来れなくてすいません(天体写真は趣味で撮っているのですが)。

SDカードに記録するとの事ですが、あまり頻繁に記録を重ねるとすぐに寿命になってしまいます。私は1秒に1回データを書き込むような事をやっていて、数か月で中身が読めなくなってしまいました。そんな失敗がありましたので、お知らせに及んだ次第です。

あれ、そういうものなんですか。
データが消えるのが嫌なのでできるだけファイルを分割して1日に一度はPCに移すようにしているのですが、毎回SDカードを入れ替えるくらいしておいた方がよさそうですね。
ありがとうございます m(._.)m

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: PIC+SPI+I2C 自記温湿度計+気圧計+8ch電圧計のソース - main():

« 自記温度計、自記気圧計 - 複数のSPIデバイスがいっしょに使えなかった話 | トップページ | 交流電圧計(ミリバル)を作る - 高周波電圧計 - 1 »

フォト

サイト内検索

  • 記事を探されるんでしたらこれがいちばん早くて確実です。私も使ってます (^^;; 検索窓が表示されるのにちょっと時間がかかるのはどうにかしてほしいです。

新着記事

リンク元別アクセス数

  • (アクセス元≒リンク元、原則PCのみ・ドメイン別、サイト内等除く)

人気記事ランキング

  • (原則PCのみ、直近2週間)
無料ブログはココログ