ULPWU 超低電流SLEEPモードを使う PIC12F683
先日、友人との会話の中で、所有する車に警報機が実装されて居ない
という事で、購入しようと思えば星の数ほどピンからキリまで様々な
警報機が在るのですが「ダミーでも構わない」という事で製作する
ことに成りまして超単純なLチカを造ろうと、色々と考えて居たのです
至った結論として・・・・
・電池が矢鱈に長持ちする
・三回点滅にする
・警報機らしく見せかける
・・・・などを考慮して取り敢えずPIC12F683を使う事にしました
理由は・・・・
・8ピンと小さい
・ULPWU 超低電流SLEEPモードを持って居る
・・・・からです。
データシートに依れば下記の様に謳われています
Low-Power Features:
• Standby Current:
- 50 nA @ 2.0V, typical
• Operating Current:
- 11μA @ 32 kHz, 2.0V, typical
- 220μA @ 4 MHz, 2.0V, typical
• Watchdog Timer Current:
- 1μA @ 2.0V, typical
• Standby Current:
- 50 nA @ 2.0V, typical
• Operating Current:
- 11μA @ 32 kHz, 2.0V, typical
- 220μA @ 4 MHz, 2.0V, typical
• Watchdog Timer Current:
- 1μA @ 2.0V, typical
最低電流値が50nAとはなかなかの実力だと思います
電源電圧で変わる数値ですから額面通りに受け取れませんがそれでも
それ成りに極小電流値で動いて呉れることでしょう。
という訳で又々他力本願のC言語探しをしていたところ記事が見つか
りまして早速、コピペ致しました PIC マイコンを便利に使うページ
部分的なコピペですが難なくアッサリと動いて呉れました感謝です。
動画は未だブレッドボード試作ですが何か探してそれらしく見せかけ
る為に組み込む予定です。
LEDは三回点滅します
ON = 10ms
インターバル = 200ms
周期 = 3.28秒
ザックリ計算して92.3uA/h、エボルタUM-3 で1,000mA/hですから
1.23年ぐらい持つだろうという捕らぬ狸の皮算用中です
電池は三本、4.5Vで動かします。
写真は
黄色 LEDオン波形
青 ULPWU コンデンサ放電波形
ピンク CPUクロック出力波形、sleep したかの確認の為に出力して居ます
追記2019/01/30(水)
動画の周期は正確ではない事が発覚致しました
理由は何かですが、オシロスコープのプローブのインピーダンスですプローブ
を除去することで周期が9.2秒まで広がりました、現在ULPWU コンデンサは
積層セラミックコンデンサー104を二個パラレルに接続して居ますが一個に
減らしました、それでも周期は4.6秒ですからもっと少ない容量でも良いかも
知れません、要はお好み次第って事ですね。
回路図です
ソースファイル、部分コピペにLEDの点滅を割り込ませただけです
/* * File: main.c * Author: maru Jan,29,2019 */ // インクルードファイル #include#include #include // PIC12F683コンフィグレーションビット設定 // PIC12F683 Configuration Bit Settings // 'C' source line config statements // CONFIG #pragma config FOSC = INTOSCCLK // Oscillator Selection bits 自己発信、1/4周波数出力 3pin出力 #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config MCLRE = OFF // MCLR Pin Function Select bit (MCLR pin function is digital input, MCLR internally tied to VDD) #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #pragma config BOREN = ON // Brown Out Detect (BOR enabled) #pragma config IESO = OFF // Internal External Switchover bit (Internal External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. #include // クロック周波数指定 // (__delay_ms()関数が必要としているため) #define _XTAL_FREQ 1000000 /****************************** LowPowerSleep *******************************/ void LowPowerSleep(void) { #ifndef DEBUG for (int i = 0; i < 3; i++) { GP5 = 1; __delay_ms(10); GP5 = 0; __delay_ms(200); } GP0 = 1; TRISIO0 = 0; //charge start __delay_us(650); //2*PI*C*R*10 GPIF = 0; ULPWUE = 1; //enable ULPWU IOC0 = 1; #endif GPIE = 1; GIE = 1; TRISIO0 = 1; //discharge start #ifdef DEBUG TMR0 = 0; T0IF = 0; while (!T0IF); #else SLEEP(); NOP(); #endif } /* * main()関数 */ int main(int argc, char** argv) { // PICマイコン初期化 OSCCON = 0x40; //クロック周波数を1MHzに設定 ANSEL = 0x00; //すべてのピンをデジタルモードに設定 TRISIO = 0x00; //すべてのピンを出力に設定 // LEDのピンを0にして、LEDを消灯する GP5 = 0; // 点滅を永遠繰り返す while (1) { LowPowerSleep(); NOP(); } // ここには到達しない return (EXIT_SUCCESS); }
I2C Color Sensor S11059 02DT
他力本願C言語シリーズ、カラーセンサ
CPU = PIC16F886
LCD = AQM1602XA スレーブアドレス 0x7C(W) READ不可
カラーセンサ = S-5851A スレーブアドレス 0x90(W) 0x91(R)
以前の記事で製作したものはアセンブラでしたので今回はC言語での制御です
正直言うとアセンブラの方が楽で確実でした、なにせど素人プログラムなので
C言語で制御すると文字化けが止まりません、5桁書くと6桁表示されて最後の
数字が6桁目にコピーされる、や、ちょっと長い文字列を書くと全部文字化け
するなど悪戦苦闘しました、結果的に出来た物は R / G / B / IR の表示が出来ず
得られたデータの羅列と成っています。
勉強に成ったのは1バイトが二個のデータをどうやって1つの固まりにするのか
全く概念が掴めなかったのですが、何の事は無い、上位バイトを八回左シフト
して下位バイトとの論理和にすれば良いんですね、まぁその程度なんですよ
だからど素人なのです。
動画の数字ですが・・・・
RED GREEN
BLUE IR
・・・・という並びに成っています。
ソースファイルです、相変わらず他のデバイスの関数がありまして何でもアリ
のプログラムです、そういうゴミは消せば良いのですが何でLCDが文字化けを
起こすのか未だに原因不明です、うーーん、気持ちがスッキリしない・・・
/* * File: main.c * Author: maru * I2C_Color Sensor_S11059-02DT_v000 * Created on 2019/01/22(火) * */ //****************************************************************************** //コンフィギュレーション // CONFIG1 MPLAB XIDEの Production -> Set Configration bits で設定してもこのプログラムでの宣言が優先される //#pragma config FOSC = INTRC_NOCLKOUT //RA6 = I/O //デフォルトではRA6 = fosc/4 output // CONFIG1 #pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT disabled) #pragma config MCLRE = ON // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)電源オン時、要リセット、しないとBootしない #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #pragma config BOREN = ON // Brown Out Reset Selection bits (BOR enabled) #pragma config IESO = ON // Internal External Switchover bit (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) #pragma config LVP = ON // Low Voltage Programming Enable bit (RB3/PGM pin has PGM function, low voltage programming enabled) // CONFIG2 #pragma config BOR4V = BOR40V // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V) #pragma config WRT = OFF // Flash Program Memory Self Write Enable bits (Write protection off) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. //****************************************************************************** //コンパイラ #include#include #include #include //****************************************************************************** //外部自作ファイル //****************************************************************************** //マクロ #define _XTAL_FREQ 8000000 //PIC16F886はINTOSC時最高8MHzまでしか出ない下のOSCCON = 0x70;と矛盾しては成らない #define LCD_ADD 0x7C //LCDスレーブアドレス W #define S5851A_ADR 0x90 //温度センサースレーブアドレス W #define PCF8574AN_ADR 0x70 //Extentioned IO スレーブアドレス W #define PCF8574AN_ADR_R 0x73 //Extentioned IO スレーブアドレス W #define ToHome 0b00000010 #define shiftLeft 0b00011000 #define shiftRight 0b00011100 #define clear 0b00000001 //-------------------------- //****************************************************************************** static unsigned char I2C_rcv(); static void I2C_nacksnd(); static unsigned char I2C_ackchk(); char moji[] = " "; char moji2[] = "Celsius "; char moji3[] = "Thermal S-5851A SII"; //この文字列を長くするとカウントアップがバグる、原因不明 char moji4[] = " "; //空白を書く、前の文字が残って邪魔をするから char moji5[] = "."; // char moji6[] = "C"; char moji10[] = "0000"; //温度計少数以下 char moji11[] = "0625"; //温度計少数以下 char moji12[] = "1250"; //温度計少数以下 char moji13[] = "1875"; //温度計少数以下 char moji14[] = "2500"; //温度計少数以下 char moji15[] = "3125"; //温度計少数以下 char moji16[] = "3750"; //温度計少数以下 char moji17[] = "4375"; //温度計少数以下 char moji18[] = "5000"; //温度計少数以下 char moji19[] = "5625"; //温度計少数以下 char moji20[] = "6250"; //温度計少数以下 char moji21[] = "6875"; //温度計少数以下 char moji22[] = "7500"; //温度計少数以下 char moji23[] = "8125"; //温度計少数以下 char moji24[] = "8750"; //温度計少数以下 char moji25[] = "9375"; //温度計少数以下 char moji30[] = "EEPROM bank="; //EEPROM char moji31[] = "W="; //EEPROM char moji32[] = "R="; //EEPROM unsigned char k; // k = PCF8574ANから読み込んだデータ、char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char k2; // k2 = MCP23017から読み込んだデータ、char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char k3; // k3 = 温度センサーから読み込んだデータ、MSB char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char k4; // k4 = 温度センサーから読み込んだデータ、LSB 但し上位4bitのみ、下位4bitはゼロ、char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char k5; unsigned char LED; //--------------------------------- //for EEPROM int HADR; //EEPROM High address int LADR; //EEPROM Low address int ROMDATA_W; //EEPROM write data int ROMDATA_R; //EEPROM read data //--------------------------------- //for cplor sensor S11059-02DT int RGB_R_MSB; //RGB int RGB_R_LSB; //RGB int RGB_G_MSB; //RGB int RGB_G_LSB; //RGB int RGB_B_MSB; //RGB int RGB_B_LSB; //RGB int IR_MSB; //IR int IR_LSB; //IR int RGB_R; //RED int RGB_G; //GREEN int RGB_B; //BLUE int IR; //Infra red //****************************************************************************** void TRIGGER() { PORTAbits.RA0 = 1; //for debug オシロスコープ・トリガ用 PORTA-RA0 __delay_us(10); PORTAbits.RA0 = 0; } //------------------------------- void I2C_Master_Init(const unsigned long c) { SSPCON = 0b00101000; //RC3/SCK/SCL RC4/SDI/SDA として使用宣言 SSPCON2 = 0; SSPADD = (_XTAL_FREQ / (4 * c)) - 1; SSPSTAT = 0b00000000; // 標準速度モードに設定する(100kHz) } //------------------------------- void I2C_Init() { SSPCON = 0x28; //RC3/SCK/SCL RC4/SDI/SDA として使用宣言 SMP = 1; CKE = 0; SSPADD = 0x13; // } //------------------------------- void I2C_Master_Wait() { while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); } //------------------------------- void I2C_Master_Start() { I2C_Master_Wait(); SEN = 1; } //------------------------------- void I2C_Master_RepeatedStart() { I2C_Master_Wait(); RSEN = 1; } //------------------------------- // void I2C_Master_Stop() // { // I2C_Master_Wait(); // PEN = 1; // } // ストップコンディション生成 ↑代替 maru void I2C_Master_Stop() { // SSP1CON2レジスタのPENビットを1に設定すると // ストップコンディションが生成される // 発行が完了するとSSP1IFが1になるのでwhile文で待つ SSPIF = 0; SSPCON2bits.PEN = 1; while (SSPIF == 0) { } SSPIF = 0; return; } //------------------------------- // void I2C_Master_Write(unsigned d) // { // I2C_Master_Wait(); // SSPBUF = d; // } //代替↑ void I2C_Master_Write(unsigned d) // SSP1BUFに送信したいデータをセットすると、そのデータが送信される // 発行が完了するとSSP1IFが1になるのでwhile文で待つ // ACK 待ちは無い、https://tool-lab.com/make/pic-practice-40/ { I2C_Master_Wait(); //これが無いと全く出鱈目に成る __delay_us(10); //add maru 20190125 18:15 SSPIF = 0; SSPBUF = d; while (SSPIF == 0) { } SSPIF = 0; // return; } //------------------------------- // I2C ACK check static unsigned char I2C_ackchk() { unsigned char i2c_data; if (ACKSTAT) { i2c_data = 0xFF; } else { i2c_data = 0x00; } return (i2c_data); } //------------------------------- // I2C Recive //static unsigned char I2C_rcv() { // SSPIF = 0; // RCEN = 1; // while (RCEN) {} // return(SSPBUF); //} static unsigned char I2C_rcv() { SSPIF = 0; SSPCON2bits.RCEN = 1; while (SSPIF == 0) { } SSPIF = 0; return SSPBUF; } //------------------------------- // I2C NACK send //static void I2C_nacksnd() { // ACKDT = 1; // ACKEN = 1; // while (ACKEN) {} // return; //} //------------------------------- static void I2C_nacksnd() { // ACKDTにNACKをセット(負論理なので1を設定) SSPCON2bits.ACKDT = 1; // NACK信号生成 SSPCON2bits.ACKEN = 1; while (SSPCON2bits.ACKEN) { } return; } //------------------------------- static void I2C_acksnd() { // ACKDTにACKをセット SSPCON2bits.ACKDT = 0; // NACK信号生成 SSPCON2bits.ACKEN = 1; while (SSPCON2bits.ACKEN) { } return; } //------------------------------- void writeData(char t_data) { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(LCD_ADD); //0x7C スレーブアドレス I2C_Master_Write(0x40); //0x40 キャラクタを書くよって宣言 I2C_Master_Write(t_data); //キャラクタの送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //------------------------------- void writeCommand(char t_command) { I2C_Master_Start(); I2C_Master_Write(LCD_ADD); I2C_Master_Write(0x00); I2C_Master_Write(t_command); I2C_Master_Stop(); __delay_ms(10); } //------------------------------- void PICinit() { OSCCON = 0x70; //0x70=8MHz PIC16F886はINTOSC時最高8MHzまでしか出ない上の#define _XTAL_FREQ 8000000;と矛盾しては成らない ANSEL = 0b00000000; ANSELH = 0b00000000; TRISA = 0b00000000; TRISB = 0b00000000; TRISC = 0b00011000; PORTA = 0b00000000; //2進数で書いた場合 PORTB = 0x00; //16進数で書いた場合 } //****************************************************************************** void LCD_Init() { //LCDの初期化、秋月のマニュアル通り //TRIGGER(); //for debug オシロスコープ・トリガ用 PORTA-RA0 I2C_Master_Init(100000); __delay_ms(400); //TRIGGER(); //for debug オシロスコープ・トリガ用 PORTA-RA0 writeCommand(0x38); //このプロトコルは S 0x7C 0x00 0x38 A P と成っているから下のプロトコルも全部一個ずつ送信している __delay_ms(20); writeCommand(0x39); __delay_ms(20); writeCommand(0x14); __delay_ms(20); writeCommand(0x73); __delay_ms(20); writeCommand(0x52); __delay_ms(20); writeCommand(0x6C); __delay_ms(250); writeCommand(0x38); __delay_ms(20); writeCommand(0x01); __delay_ms(20); writeCommand(0x0C); __delay_ms(20); } //------------------------------- void LCD_str2(char *c) { //LCDに配列の文字を表示 unsigned char i, wk; for (i = 0; i < 5; i++) { wk = c[i]; //__delay_us(30); if (wk == 0x00) { break; } writeData(wk); } } void LCD_str(char *c) { //LCDに配列の文字を表示 unsigned char i, wk; for (i = 0;; i++) { wk = c[i]; if (wk == 0x00) { break; } writeData(wk); } } //****************************************************************************** //S5851A_ADR 温度センサー部分 void S5851A_W(char t_data) { I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(S5851A_ADR); //スレーブアドレス I2C_Master_Write(0x01); // I2C_Master_Write(t_data); //キャラクタの送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //****************************************************************************** //PCF8574AN Extentioned IO 部分 void PCF8574AN_W() { //PCF8574AN Extentioned IO WRITE I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR); //スレーブアドレス I2C_Master_Write(0xAA); //データ送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } void PCF8574AN_W2(char LED) { //PCF8574AN Extentioned IO WRITE I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR); //スレーブアドレス I2C_Master_Write(LED); //データ送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } void PCF8574AN_R() { //PCF8574AN Extentioned IO READ // I2C_Master_Init(100000); //これだと遅い I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR_R); //スレーブアドレス read I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする k = I2C_rcv(); //スレーブアドレス側からのデータを受信する // I2C_rcv(k); //この文法では読めない // PORTA = (k); //ここに入れるのもOK I2C_nacksnd(); //NACk送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //****************************************************************************** // MCP23017 16bit IO 部分 int GPA_LED; int GPB_IN_DATA; void MCP23017_GPA_INIT() { //MCP23017_GPAイニシャライズ I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //全入力設定 write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void MCP23017_GPB_INIT() { //MCP23017_GPイニシャライズ I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x01); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0xFF); //全出力設定 write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void MCP23017_GPA_OUT(GPA_LED) { //MCP23017_GPAにデータ出力させる、Lチカ I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x14); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(GPA_LED); //LED表示 write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void MCP23017_GPB_IN() { //MCP23017_GPBのデータを読み込む、ディップスイッチ8bit I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x13); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_RepeatedStart(); //SR = RepeatedStart I2C_Master_Write(0x41); //スレーブアドレス READ I2C_Master_Wait(); I2C_ackchk(); k2 = I2C_rcv(); //スレーブアドレス側からのデータを受信する = k2 I2C_nacksnd(); //NACk送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //****************************************************************************** //I2C 温度センサー SII S-5851A 部分 void s5851a_init() //温度センサー初期化 { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x90); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x01); //コンフィギュレーション・レジスタ I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //常温設定 I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void s5851a_me1() //温度測定一回目のみ、二回目からはカレントリードと云う簡略化したプロトコルで良い { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x90); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //ダミー I2C_Master_Wait(); I2C_ackchk(); I2C_Master_RepeatedStart(); //リスタート I2C_Master_Write(0x91); //スレーブアドレス Read I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする k3 = I2C_rcv(); //スレーブアドレス側からのデータを受信するMSB I2C_acksnd(); //ACK送信 k4 = I2C_rcv(); //スレーブアドレス側からのデータを受信するLSB 但し上位4bitのみ下位4bitはゼロ I2C_nacksnd(); //NACK送信 I2C_Master_Stop(); //ストップ・コンディション } void s5851a_me2() //温度測定一回目のみ、二回目からはカレントリードと云う簡略化したプロトコルで良い { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x91); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする k3 = I2C_rcv(); //スレーブアドレス側からのデータを受信するMSB I2C_acksnd(); //ACK送信 k4 = I2C_rcv(); //スレーブアドレス側からのデータを受信するLSB 但し上位4bitのみ下位4bitはゼロ I2C_nacksnd(); //NACK送信 I2C_Master_Stop(); //ストップ・コンディション } void hairetsu() { if (k4 == 0) { LCD_str(moji10); } else if (k4 == 1) { LCD_str(moji11); } else if (k4 == 2) { LCD_str(moji12); } else if (k4 == 3) { LCD_str(moji13); } else if (k4 == 4) { LCD_str(moji14); } else if (k4 == 5) { LCD_str(moji15); } else if (k4 == 6) { LCD_str(moji16); } else if (k4 == 7) { LCD_str(moji17); } else if (k4 == 8) { LCD_str(moji18); } else if (k4 == 9) { LCD_str(moji19); } else if (k4 == 0x0A) { LCD_str(moji20); } else if (k4 == 0x0B) { LCD_str(moji21); } else if (k4 == 0x0C) { LCD_str(moji22); } else if (k4 == 0x0D) { LCD_str(moji23); } else if (k4 == 0x0E) { LCD_str(moji24); } else if (k4 == 0x0F) { LCD_str(moji25); } return; } //****************************************************************************** //I2C EEPROM 24LC64 部分 void EEPROM_W() //EEPROM 1 byte write routin 2019/01/22 { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0xA0); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(HADR); //EEPROM High address I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(LADR); //EEPROM Low address I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(ROMDATA_W); //EEPROM Low address I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void EEPROM_R() //温度測定一回目のみ、二回目からはカレントリードと云う簡略化したプロトコルで良い { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0xA0); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(HADR); //EEPROM High address I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(LADR); //EEPROM Low address I2C_Master_Wait(); I2C_ackchk(); I2C_Master_RepeatedStart(); //リスタート I2C_Master_Write(0xA1); //スレーブアドレス Read I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする ROMDATA_R = I2C_rcv(); //スレーブアドレス側からのデータを受信するMSB I2C_nacksnd(); //NACK送信 I2C_Master_Stop(); //ストップ・コンディション } //****************************************************************************** //I2C color srnsor S11059-02DT 部分 void COLOR_S() //I2C color srnsor S11059-02DT読み出し、イニシャライズは無い { //TRIGGER(); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x54); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x89); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_RepeatedStart(); //リスタート I2C_Master_Write(0x54); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x09); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする __delay_ms(10); //TRIGGER(); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x54); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x03); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_RepeatedStart(); //リスタート I2C_Master_Write(0x55); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする RGB_R_MSB = I2C_rcv(); //スレーブアドレス側からのデータを受信する I2C_acksnd(); //マスターから送信するack RGB_R_LSB = I2C_rcv(); //スレーブアドレス側からのデータを受信する I2C_acksnd(); //マスターから送信するack RGB_G_MSB = I2C_rcv(); //スレーブアドレス側からのデータを受信する I2C_acksnd(); //マスターから送信するack RGB_G_LSB = I2C_rcv(); //スレーブアドレス側からのデータを受信する I2C_acksnd(); //マスターから送信するack RGB_B_MSB = I2C_rcv(); //スレーブアドレス側からのデータを受信する I2C_acksnd(); //マスターから送信するack RGB_B_LSB = I2C_rcv(); //スレーブアドレス側からのデータを受信する I2C_acksnd(); //マスターから送信するack IR_MSB = I2C_rcv(); //スレーブアドレス側からのデータを受信する I2C_acksnd(); //マスターから送信するack IR_LSB = I2C_rcv(); //スレーブアドレス側からのデータを受信する I2C_nacksnd(); //NACK送信 I2C_Master_Stop(); //ストップ・コンディション } //****************************************************************************** int main(void) { PICinit(); //PICを初期化 //----------- I2C_Init(); //これだと速い //----------- LCD_Init(); //LCD初期化 __delay_ms(2); //----------- writeCommand(0x01); //画面をクリア __delay_ms(10); writeCommand(0x02); //ホームへカーソル移動 __delay_ms(2); // LCD側の処理待ち、LCDは全く読み込めないので見込み時間 //------------------------------- /* writeCommand(0x85); //2列目へ移動 LCD_str2(moji32); writeCommand(0x8D); //2列目へ移動 LCD_str2(moji32); writeCommand(0x85 + 0x40); //2列目へ移動 LCD_str2(moji32); writeCommand(0x8D + 0x40); //2列目へ移動 LCD_str2(moji32); __delay_ms(10); */ //------------------------------- while (1) //Loop { COLOR_S(); //I2C color srnsor S11059-02DT読み出し //------------------------------- RGB_R_MSB = RGB_R_MSB << 8; //shift 8bit to left RGB_R = RGB_R_MSB | RGB_R_LSB; // make 2 byte RGB_G_MSB = RGB_G_MSB << 8; //shift 8bit to left RGB_G = RGB_G_MSB | RGB_G_LSB; // make 2 byte RGB_B_MSB = RGB_B_MSB << 8; //shift 8bit to left RGB_B = RGB_B_MSB | RGB_B_LSB; // make 2 byte IR_MSB = IR_MSB << 8; //shift 8bit to left IR = IR_MSB | IR_LSB; // make 2 byte writeCommand(0x80); //1列目へ移動 __delay_ms(10); sprintf(moji, "%05d", RGB_R); //左寄せしない5桁 LCD_str2(moji); __delay_ms(10); writeCommand(0x88); //1列目へ移動 __delay_ms(10); sprintf(moji, "%05d", RGB_G); //左寄せしない5桁 LCD_str2(moji); __delay_ms(10); writeCommand(0x80 + 0x40); //2列目へ移動 __delay_ms(10); sprintf(moji, "%05d", RGB_B); //左寄せしない5桁 LCD_str2(moji); __delay_ms(10); writeCommand(0x88 + 0x40); //2列目へ移動 __delay_ms(10); sprintf(moji, "%05d", IR); //左寄せしない5桁 TRIGGER(); LCD_str2(moji); __delay_ms(3); //------------------------------- __delay_ms(333); } return 0; //Loop //------------------------------- }
I2C CPU= pic16f886 EEPROM=24LC64 c
他力本願C言語シリーズ
以前、アセンブラで行ったI2C通信に依るEEPROM 24LC64です
書き込みと読み出しのデータをLCD表示しています
CPU = PIC16F886 マスター
LCD = AQX1602XA スレーブアドレス=0x7C
EEPROM = 24LC64 スレーブアドレス=0xA0
動作は単純です
EEPROMのメモリーアドレス 0x00~0xFFに対して
データ 0x00~0xFF を書いて読み出す、という動作です
LCDの表示は・・・
W=xx が書き込みデータ
R=xx が読み出しデータ
・・・と成っています、いつもの様に単純な動作確認です
ちゃんと書かれているかも確認しました
↓
ソースファイルです、無関係のデバイスの関数も書かれていて
相変わらずど素人のソースです、多方面からコピーしてペタペタ
貼って書いて居ますので無理無駄、煩雑、理解不能、苛々など
在りますが責任も含めて全て放棄します、ご容赦下さい。
/* * File: main.c * Author: maru * pic16f886_24LC64_v003 * Created on 2019/01/22(火) * 0 -> 1 -> 2...32768 -> -32768 -> -32767...-3 -> -2 -> -1 -> 0 の繰り返し */ //****************************************************************************** //コンフィギュレーション // CONFIG1 MPLAB XIDEの Production -> Set Configration bits で設定してもこのプログラムでの宣言が優先される //#pragma config FOSC = INTRC_NOCLKOUT //RA6 = I/O //デフォルトではRA6 = fosc/4 output // CONFIG1 #pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT disabled) #pragma config MCLRE = ON // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)電源オン時、要リセット、しないとBootしない #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #pragma config BOREN = ON // Brown Out Reset Selection bits (BOR enabled) #pragma config IESO = ON // Internal External Switchover bit (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) #pragma config LVP = ON // Low Voltage Programming Enable bit (RB3/PGM pin has PGM function, low voltage programming enabled) // CONFIG2 #pragma config BOR4V = BOR40V // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V) #pragma config WRT = OFF // Flash Program Memory Self Write Enable bits (Write protection off) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. //****************************************************************************** //コンパイラ #include#include #include #include //****************************************************************************** //外部自作ファイル //****************************************************************************** //マクロ #define _XTAL_FREQ 8000000 //PIC16F886はINTOSC時最高8MHzまでしか出ない下のOSCCON = 0x70;と矛盾しては成らない #define LCD_ADD 0x7C //LCDスレーブアドレス W #define S5851A_ADR 0x90 //温度センサースレーブアドレス W #define PCF8574AN_ADR 0x70 //Extentioned IO スレーブアドレス W #define PCF8574AN_ADR_R 0x73 //Extentioned IO スレーブアドレス W #define ToHome 0b00000010 #define shiftLeft 0b00011000 #define shiftRight 0b00011100 #define clear 0b00000001 //-------------------------- //****************************************************************************** static unsigned char I2C_rcv(); static void I2C_nacksnd() ; static unsigned char I2C_ackchk(); char moji[] = " "; char moji2[] = "Celsius "; char moji3[] = "Thermal S-5851A SII"; //この文字列を長くするとカウントアップがバグる、原因不明 char moji4[] = " "; //空白を書く、前の文字が残って邪魔をするから char moji5[] = "."; // char moji6[] = "C"; char moji10[] = "0000"; //温度計少数以下 char moji11[] = "0625"; //温度計少数以下 char moji12[] = "1250"; //温度計少数以下 char moji13[] = "1875"; //温度計少数以下 char moji14[] = "2500"; //温度計少数以下 char moji15[] = "3125"; //温度計少数以下 char moji16[] = "3750"; //温度計少数以下 char moji17[] = "4375"; //温度計少数以下 char moji18[] = "5000"; //温度計少数以下 char moji19[] = "5625"; //温度計少数以下 char moji20[] = "6250"; //温度計少数以下 char moji21[] = "6875"; //温度計少数以下 char moji22[] = "7500"; //温度計少数以下 char moji23[] = "8125"; //温度計少数以下 char moji24[] = "8750"; //温度計少数以下 char moji25[] = "9375"; //温度計少数以下 char moji30[] = "EEPROM 24LC64"; //EEPROM char moji31[] = "W="; //EEPROM char moji32[] = "R="; //EEPROM unsigned char k; // k = PCF8574ANから読み込んだデータ、char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char k2; // k2 = MCP23017から読み込んだデータ、char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char k3; // k3 = 温度センサーから読み込んだデータ、MSB char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char k4; // k4 = 温度センサーから読み込んだデータ、LSB 但し上位4bitのみ、下位4bitはゼロ、char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char k5; unsigned char LED; //--------------------------------- //for EEPROM int HADR; //EEPROM High address int LADR; //EEPROM Low address int ROMDATA_W; //EEPROM write data int ROMDATA_R; //EEPROM read data //****************************************************************************** void TRIGGER(){ PORTAbits.RA0 = 1; //for debug オシロスコープ・トリガ用 PORTA-RA0 __delay_us(10); PORTAbits.RA0 = 0; } //------------------------------- void I2C_Master_Init(const unsigned long c) { SSPCON = 0b00101000; //RC3/SCK/SCL RC4/SDI/SDA として使用宣言 SSPCON2 = 0; SSPADD = (_XTAL_FREQ/(4*c))-1; SSPSTAT = 0b00000000 ; // 標準速度モードに設定する(100kHz) } //------------------------------- void I2C_Init() { SSPCON = 0x28; //RC3/SCK/SCL RC4/SDI/SDA として使用宣言 SMP = 1; CKE = 0; SSPADD = 0x13; // } //------------------------------- void I2C_Master_Wait() { while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); } //------------------------------- void I2C_Master_Start() { I2C_Master_Wait(); SEN = 1; } //------------------------------- void I2C_Master_RepeatedStart() { I2C_Master_Wait(); RSEN = 1; } //------------------------------- // void I2C_Master_Stop() // { // I2C_Master_Wait(); // PEN = 1; // } // ストップコンディション生成 ↑代替 maru void I2C_Master_Stop() { // SSP1CON2レジスタのPENビットを1に設定すると // ストップコンディションが生成される // 発行が完了するとSSP1IFが1になるのでwhile文で待つ SSPIF = 0; SSPCON2bits.PEN = 1; while (SSPIF == 0) {} SSPIF = 0; return; } //------------------------------- // void I2C_Master_Write(unsigned d) // { // I2C_Master_Wait(); // SSPBUF = d; // } //代替↑ void I2C_Master_Write(unsigned d) // SSP1BUFに送信したいデータをセットすると、そのデータが送信される // 発行が完了するとSSP1IFが1になるのでwhile文で待つ // ACK 待ちは無い、https://tool-lab.com/make/pic-practice-40/ { I2C_Master_Wait(); //これが無いと全く出鱈目に成る SSPIF = 0; SSPBUF = d; while (SSPIF == 0) {} SSPIF = 0; // return; } //------------------------------- // I2C ACK check static unsigned char I2C_ackchk() { unsigned char i2c_data; if (ACKSTAT) { i2c_data = 0xFF; } else { i2c_data = 0x00; } return(i2c_data); } //------------------------------- // I2C Recive //static unsigned char I2C_rcv() { // SSPIF = 0; // RCEN = 1; // while (RCEN) {} // return(SSPBUF); //} static unsigned char I2C_rcv() { SSPIF = 0; SSPCON2bits.RCEN = 1; while (SSPIF == 0) {} SSPIF = 0; return SSPBUF; } //------------------------------- // I2C NACK send //static void I2C_nacksnd() { // ACKDT = 1; // ACKEN = 1; // while (ACKEN) {} // return; //} //------------------------------- static void I2C_nacksnd() { // ACKDTにNACKをセット(負論理なので1を設定) SSPCON2bits.ACKDT = 1; // NACK信号生成 SSPCON2bits.ACKEN = 1; while (SSPCON2bits.ACKEN) {} return; } //------------------------------- static void I2C_acksnd() { // ACKDTにACKをセット SSPCON2bits.ACKDT = 0; // NACK信号生成 SSPCON2bits.ACKEN = 1; while (SSPCON2bits.ACKEN) {} return; } //------------------------------- void writeData(char t_data){ I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(LCD_ADD); //0x7C スレーブアドレス I2C_Master_Write(0x40); //0x40 キャラクタを書くよって宣言 I2C_Master_Write(t_data); //キャラクタの送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //------------------------------- void writeCommand(char t_command){ I2C_Master_Start(); I2C_Master_Write(LCD_ADD); I2C_Master_Write(0x00); I2C_Master_Write(t_command); I2C_Master_Stop(); __delay_ms(10); } //------------------------------- void PICinit(){ OSCCON = 0x70; //0x70=8MHz PIC16F886はINTOSC時最高8MHzまでしか出ない上の#define _XTAL_FREQ 8000000;と矛盾しては成らない ANSEL = 0b00000000; ANSELH = 0b00000000; TRISA = 0b00000000; TRISB = 0b00000000; TRISC = 0b00011000; PORTA = 0b00000000; //2進数で書いた場合 PORTB = 0x00; //16進数で書いた場合 } //****************************************************************************** void LCD_Init(){ //LCDの初期化、秋月のマニュアル通り //TRIGGER(); //for debug オシロスコープ・トリガ用 PORTA-RA0 I2C_Master_Init(100000); __delay_ms(400); //TRIGGER(); //for debug オシロスコープ・トリガ用 PORTA-RA0 writeCommand(0x38); //このプロトコルは S 0x7C 0x00 0x38 A P と成っているから下のプロトコルも全部一個ずつ送信している __delay_ms(20); writeCommand(0x39); __delay_ms(20); writeCommand(0x14); __delay_ms(20); writeCommand(0x73); __delay_ms(20); writeCommand(0x52); __delay_ms(20); writeCommand(0x6C); __delay_ms(250); writeCommand(0x38); __delay_ms(20); writeCommand(0x01); __delay_ms(20); writeCommand(0x0C); __delay_ms(20); } //------------------------------- void LCD_str(char *c) { //LCDに配列の文字を表示 unsigned char i,wk; for (i=0 ; ; i++) { wk = c[i]; if (wk == 0x00) {break;} writeData(wk); } } //****************************************************************************** //S5851A_ADR 温度センサー部分 void S5851A_W(char t_data){ I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(S5851A_ADR); //スレーブアドレス I2C_Master_Write(0x01); // I2C_Master_Write(t_data); //キャラクタの送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //****************************************************************************** //PCF8574AN Extentioned IO 部分 void PCF8574AN_W(){ //PCF8574AN Extentioned IO WRITE I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR); //スレーブアドレス I2C_Master_Write(0xAA); //データ送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } void PCF8574AN_W2(char LED){ //PCF8574AN Extentioned IO WRITE I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR); //スレーブアドレス I2C_Master_Write(LED); //データ送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } void PCF8574AN_R(){ //PCF8574AN Extentioned IO READ // I2C_Master_Init(100000); //これだと遅い I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR_R); //スレーブアドレス read I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする k = I2C_rcv(); //スレーブアドレス側からのデータを受信する // I2C_rcv(k); //この文法では読めない // PORTA = (k); //ここに入れるのもOK I2C_nacksnd(); //NACk送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //****************************************************************************** // MCP23017 16bit IO 部分 int GPA_LED; int GPB_IN_DATA; void MCP23017_GPA_INIT(){ //MCP23017_GPAイニシャライズ I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //全入力設定 write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void MCP23017_GPB_INIT(){ //MCP23017_GPイニシャライズ I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x01); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0xFF); //全出力設定 write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void MCP23017_GPA_OUT(GPA_LED){ //MCP23017_GPAにデータ出力させる、Lチカ I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x14); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(GPA_LED); //LED表示 write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void MCP23017_GPB_IN(){ //MCP23017_GPBのデータを読み込む、ディップスイッチ8bit I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x13); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_RepeatedStart(); //SR = RepeatedStart I2C_Master_Write(0x41); //スレーブアドレス READ I2C_Master_Wait(); I2C_ackchk(); k2 = I2C_rcv(); //スレーブアドレス側からのデータを受信する = k2 I2C_nacksnd(); //NACk送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //****************************************************************************** //I2C 温度センサー SII S-5851A 部分 void s5851a_init() //温度センサー初期化 { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x90); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x01); //コンフィギュレーション・レジスタ I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //常温設定 I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void s5851a_me1() //温度測定一回目のみ、二回目からはカレントリードと云う簡略化したプロトコルで良い { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x90); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //ダミー I2C_Master_Wait(); I2C_ackchk(); I2C_Master_RepeatedStart(); //リスタート I2C_Master_Write(0x91); //スレーブアドレス Read I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする k3 = I2C_rcv(); //スレーブアドレス側からのデータを受信するMSB I2C_acksnd(); //ACK送信 k4 = I2C_rcv(); //スレーブアドレス側からのデータを受信するLSB 但し上位4bitのみ下位4bitはゼロ I2C_nacksnd(); //NACK送信 I2C_Master_Stop(); //ストップ・コンディション } void s5851a_me2() //温度測定一回目のみ、二回目からはカレントリードと云う簡略化したプロトコルで良い { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x91); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする k3 = I2C_rcv(); //スレーブアドレス側からのデータを受信するMSB I2C_acksnd(); //ACK送信 k4 = I2C_rcv(); //スレーブアドレス側からのデータを受信するLSB 但し上位4bitのみ下位4bitはゼロ I2C_nacksnd(); //NACK送信 I2C_Master_Stop(); //ストップ・コンディション } void hairetsu() { if (k4 == 0) { LCD_str(moji10); }else if (k4 == 1){ LCD_str(moji11); }else if (k4 == 2){ LCD_str(moji12); }else if (k4 == 3){ LCD_str(moji13); }else if (k4 == 4){ LCD_str(moji14); }else if (k4 == 5){ LCD_str(moji15); }else if (k4 == 6){ LCD_str(moji16); }else if (k4 == 7){ LCD_str(moji17); }else if (k4 == 8){ LCD_str(moji18); }else if (k4 == 9){ LCD_str(moji19); }else if (k4 == 0x0A){ LCD_str(moji20); }else if (k4 == 0x0B){ LCD_str(moji21); }else if (k4 == 0x0C){ LCD_str(moji22); }else if (k4 == 0x0D){ LCD_str(moji23); }else if (k4 == 0x0E){ LCD_str(moji24); }else if (k4 == 0x0F){ LCD_str(moji25); } return; } //****************************************************************************** //I2C EEPROM 24LC64 部分 void EEPROM_W () //EEPROM 1 byte write routin 2019/01/22 { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0xA0); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(HADR); //EEPROM High address I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(LADR); //EEPROM Low address I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(ROMDATA_W); //EEPROM Low address I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void EEPROM_R() //温度測定一回目のみ、二回目からはカレントリードと云う簡略化したプロトコルで良い { I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0xA0); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(HADR); //EEPROM High address I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(LADR); //EEPROM Low address I2C_Master_Wait(); I2C_ackchk(); I2C_Master_RepeatedStart(); //リスタート I2C_Master_Write(0xA1); //スレーブアドレス Read I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする ROMDATA_R = I2C_rcv(); //スレーブアドレス側からのデータを受信するMSB I2C_nacksnd(); //NACK送信 I2C_Master_Stop(); //ストップ・コンディション } //****************************************************************************** int main(void) { PICinit(); //PICを初期化 //----------- I2C_Init(); //これだと速い //----------- LCD_Init(); //LCD初期化 __delay_ms(2); //----------- writeCommand(0x01); //画面をクリア __delay_ms(10); writeCommand(0x02); //ホームへカーソル移動 __delay_ms(2); // LCD側の処理待ち、LCDは全く読み込めないので見込み時間 writeCommand(0x80); //1列目へ移動 LCD_str(moji30); //EEPROM __delay_ms(10); writeCommand(0x80+0x40); //2列目へ移動 LCD_str(moji31); //EEPROM __delay_ms(10); writeCommand(0x88+0x40); //2列目へ移動 LCD_str(moji32); //EEPROM __delay_ms(10); //------------------------------- HADR = 0x00; LADR = 0x00; ROMDATA_W = 0x00; while(1) { //------------------------------- //write //TRIGGER(); EEPROM_W (); //EEPROM DATA WRITE writeCommand(0x82+0x40); //2列目へ移動 sprintf(moji,"%02X",ROMDATA_W); //左寄せしない2桁表示 LCD_str(moji); //--------------------------- //更新 ROMDATA_W = ROMDATA_W ++; //DATA inc+1 if(ROMDATA_W == 0x100){ //FF -> 100 と成らない様にする ROMDATA_W = 0x00; } LADR = LADR ++; //Low address inc+1 if(LADR== 0x100){ //FF -> 100 と成らない様にする LADR = 0x00; } __delay_ms(100); //遅延 //--------------------------- //read TRIGGER(); EEPROM_R(); //EEPROM DATA READ writeCommand(0x8A+0x40); //2列目へ移動 sprintf(moji,"%02X",ROMDATA_R); //左寄せしない2桁表示 LCD_str(moji); //------------------------------- __delay_ms(100); //遅延 } return 0; //------------------------------- }
I2C & PIC16F886 & LCD/AQM1602AXA & IO/PCF8574AN & IO/MCP23017
他力本願C言語第三弾
I2C制御
CPU=PIC16F886
LCD=AQM1602AXA
IO=PCF8574AN 8bit
IO=MCP23017 16bit
IO=PCF8574AN 8bit の入力データを IO=MCP23017 16bit のGPA のLEDとLCDに表示
IO=MCP23017 16bit の入力データを LCDに表示
という単純な動作です、仕事として無意味ですが単なるプログラミングの勉強です
参考にしたホームページは下記の通り、御礼申し上げます
苦しんで覚えるC言語 さん
Wak-techさん
また、パクッたプログラムをコピペしたばかりで無く一貫性の無いボロボロの
プログラムにしてしまい申し訳御座いません、素人なのでご容赦下さい。<(__)>
ソース、そろそろファイル分割したほうが良いと考えていますがその方法もこれからです。
/* * File: main.c * Author: maru * pic16f886_pcf8574an_mcp23017_v000 * Created on 2019/01/09, 8:57 * 0 -> 1 -> 2...32768 -> -32768 -> -32767...-3 -> -2 -> -1 -> 0 の繰り返し */ //****************************************************************************** //コンフィギュレーション // CONFIG1 MPLAB XIDEの Production -> Set Configration bits で設定してもこのプログラムでの宣言が優先される //#pragma config FOSC = INTRC_NOCLKOUT //RA6 = I/O //デフォルトではRA6 = fosc/4 output // CONFIG1 #pragma config FOSC = INTRC_NOCLKOUT// Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT disabled) #pragma config MCLRE = ON // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)電源オン時、要リセット、しないとBootしない #pragma config CP = OFF // Code Protection bit (Program memory code protection is disabled) #pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled) #pragma config BOREN = ON // Brown Out Reset Selection bits (BOR enabled) #pragma config IESO = ON // Internal External Switchover bit (Internal/External Switchover mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is disabled) #pragma config LVP = ON // Low Voltage Programming Enable bit (RB3/PGM pin has PGM function, low voltage programming enabled) // CONFIG2 #pragma config BOR4V = BOR40V // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V) #pragma config WRT = OFF // Flash Program Memory Self Write Enable bits (Write protection off) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. //****************************************************************************** //コンパイラ #include#include #include #include //****************************************************************************** //外部自作ファイル //****************************************************************************** //マクロ #define _XTAL_FREQ 8000000 //PIC16F886はINTOSC時最高8MHzまでしか出ない下のOSCCON = 0x70;と矛盾しては成らない #define LCD_ADD 0x7C //LCDスレーブアドレス W #define S5851A_ADR 0x90 //温度センサースレーブアドレス W #define PCF8574AN_ADR 0x70 //Extentioned IO スレーブアドレス W #define PCF8574AN_ADR_R 0x73 //Extentioned IO スレーブアドレス W #define ToHome 0b00000010 #define shiftLeft 0b00011000 #define shiftRight 0b00011100 #define clear 0b00000001 //****************************************************************************** static unsigned char I2C_rcv(); static void I2C_nacksnd() ; static unsigned char I2C_ackchk(); char moji[] = " "; char moji2[] = "MCP23017=0x "; char moji3[] = "PCF8574AN=0x"; //この文字列を長くするとカウントアップがバグる、原因不明 char moji4[] = " "; //空白を書く、前の文字が残って邪魔をするから unsigned char k; // k = PCF8574ANから読み込んだデータ、char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char k2; // k2 = MCP23017から読み込んだデータ、char型 保存できる値は-127?127 //unsigned char型 保存できる値は 0-255です unsigned char LED; //****************************************************************************** void TRIGGER(){ PORTAbits.RA0 = 1; //for debug オシロスコープ・トリガ用 PORTA-RA0 __delay_us(10); PORTAbits.RA0 = 0; } //------------------------------- void I2C_Master_Init(const unsigned long c) { SSPCON = 0b00101000; //RC3/SCK/SCL RC4/SDI/SDA として使用宣言 SSPCON2 = 0; SSPADD = (_XTAL_FREQ/(4*c))-1; SSPSTAT = 0b00000000 ; // 標準速度モードに設定する(100kHz) } //------------------------------- void I2C_Init() { SSPCON = 0x28; //RC3/SCK/SCL RC4/SDI/SDA として使用宣言 SMP = 1; CKE = 0; SSPADD = 0x21; //PICがスレーブの時の自分のスレーブアドレス、使わない } //------------------------------- void I2C_Master_Wait() { while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); } //------------------------------- void I2C_Master_Start() { I2C_Master_Wait(); SEN = 1; } //------------------------------- void I2C_Master_RepeatedStart() { I2C_Master_Wait(); RSEN = 1; } //------------------------------- // void I2C_Master_Stop() // { // I2C_Master_Wait(); // PEN = 1; // } // ストップコンディション生成 ↑代替 maru void I2C_Master_Stop() { // SSP1CON2レジスタのPENビットを1に設定すると // ストップコンディションが生成される // 発行が完了するとSSP1IFが1になるのでwhile文で待つ SSPIF = 0; SSPCON2bits.PEN = 1; while (SSPIF == 0) {} SSPIF = 0; return; } //------------------------------- // void I2C_Master_Write(unsigned d) // { // I2C_Master_Wait(); // SSPBUF = d; // } //代替↑ void I2C_Master_Write(unsigned d) // SSP1BUFに送信したいデータをセットすると、そのデータが送信される // 発行が完了するとSSP1IFが1になるのでwhile文で待つ // ACK 待ちは無い、https://tool-lab.com/make/pic-practice-40/ { I2C_Master_Wait(); //これが無いと全く出鱈目に成る SSPIF = 0; SSPBUF = d; while (SSPIF == 0) {} SSPIF = 0; // return; } //------------------------------- // I2C ACK check static unsigned char I2C_ackchk() { unsigned char i2c_data; if (ACKSTAT) { i2c_data = 0xFF; } else { i2c_data = 0x00; } return(i2c_data); } //------------------------------- // I2C Recive //static unsigned char I2C_rcv() { // SSPIF = 0; // RCEN = 1; // while (RCEN) {} // return(SSPBUF); //} static unsigned char I2C_rcv() { SSPIF = 0; SSPCON2bits.RCEN = 1; while (SSPIF == 0) {} SSPIF = 0; return SSPBUF; } //------------------------------- // I2C NACK send //static void I2C_nacksnd() { // ACKDT = 1; // ACKEN = 1; // while (ACKEN) {} // return; //} static void I2C_nacksnd() { // ACKDTにNACKをセット(負論理なので1を設定) SSPCON2bits.ACKDT = 1; // NACK信号生成 SSPCON2bits.ACKEN = 1; while (SSPCON2bits.ACKEN) {} return; } //------------------------------- void writeData(char t_data){ I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(LCD_ADD); //0x7C スレーブアドレス I2C_Master_Write(0x40); //0x40 キャラクタを書くよって宣言 I2C_Master_Write(t_data); //キャラクタの送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //------------------------------- void writeCommand(char t_command){ I2C_Master_Start(); I2C_Master_Write(LCD_ADD); I2C_Master_Write(0x00); I2C_Master_Write(t_command); I2C_Master_Stop(); __delay_ms(10); } //------------------------------- void PICinit(){ OSCCON = 0x70; //0x70=8MHz PIC16F886はINTOSC時最高8MHzまでしか出ない上の#define _XTAL_FREQ 8000000;と矛盾しては成らない ANSEL = 0b00000000; ANSELH = 0b00000000; TRISA = 0b00000000; TRISB = 0b00000000; TRISC = 0b00011000; PORTA = 0b00000000; //2進数で書いた場合 PORTB = 0x00; //16進数で書いた場合 } //****************************************************************************** void LCD_Init(){ //LCDの初期化、秋月のマニュアル通り //TRIGGER(); //for debug オシロスコープ・トリガ用 PORTA-RA0 I2C_Master_Init(100000); __delay_ms(400); //TRIGGER(); //for debug オシロスコープ・トリガ用 PORTA-RA0 writeCommand(0x38); //このプロトコルは S 0x7C 0x00 0x38 A P と成っているから下のプロトコルも全部一個ずつ送信している __delay_ms(20); writeCommand(0x39); __delay_ms(20); writeCommand(0x14); __delay_ms(20); writeCommand(0x73); __delay_ms(20); writeCommand(0x52); __delay_ms(20); writeCommand(0x6C); __delay_ms(250); writeCommand(0x38); __delay_ms(20); writeCommand(0x01); __delay_ms(20); writeCommand(0x0C); __delay_ms(20); } //------------------------------- void LCD_str(char *c) { //LCDに配列の文字を表示 unsigned char i,wk; for (i=0 ; ; i++) { wk = c[i]; if (wk == 0x00) {break;} writeData(wk); } } //****************************************************************************** //S5851A_ADR 温度センサー部分 void S5851A_W(char t_data){ I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(S5851A_ADR); //スレーブアドレス I2C_Master_Write(0x01); // I2C_Master_Write(t_data); //キャラクタの送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //****************************************************************************** //PCF8574AN Extentioned IO 部分 void PCF8574AN_W(){ //PCF8574AN Extentioned IO WRITE I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR); //スレーブアドレス I2C_Master_Write(0xAA); //データ送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } void PCF8574AN_W2(char LED){ //PCF8574AN Extentioned IO WRITE I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR); //スレーブアドレス I2C_Master_Write(LED); //データ送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } void PCF8574AN_R(){ //PCF8574AN Extentioned IO READ // I2C_Master_Init(100000); //これだと遅い I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR_R); //スレーブアドレス read I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする k = I2C_rcv(); //スレーブアドレス側からのデータを受信する // I2C_rcv(k); //この文法では読めない // PORTA = (k); //ここに入れるのもOK I2C_nacksnd(); //NACk送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //****************************************************************************** // MCP23017 16bit IO 部分 int GPA_LED; int GPB_IN_DATA; void MCP23017_GPA_INIT(){ //MCP23017_GPAイニシャライズ I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x00); //全入力設定 write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void MCP23017_GPB_INIT(){ //MCP23017_GPイニシャライズ I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x01); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0xFF); //全出力設定 write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void MCP23017_GPA_OUT(GPA_LED){ //MCP23017_GPAにデータ出力させる、Lチカ I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x14); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(GPA_LED); //LED表示 write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Stop(); //ストップ・コンディション } void MCP23017_GPB_IN(){ //MCP23017_GPBのデータを読み込む、ディップスイッチ8bit I2C_Init(); //これだと速い I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(0x40); //スレーブアドレス write I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_Write(0x13); //レジスタ・ナンバー I2C_Master_Wait(); I2C_ackchk(); //ACKチェック、無くても普通に動く、スレーブアドレス違ってもスルーする I2C_Master_RepeatedStart(); //SR = RepeatedStart I2C_Master_Write(0x41); //スレーブアドレス READ I2C_Master_Wait(); I2C_ackchk(); k2 = I2C_rcv(); //スレーブアドレス側からのデータを受信する = k2 I2C_nacksnd(); //NACk送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //****************************************************************************** //****************************************************************************** int main(void) { PICinit(); //PICを初期化 __delay_ms(2); LCD_Init(); //LCD初期化 __delay_ms(2); MCP23017_GPA_INIT(); __delay_ms(2); //TRIGGER(); MCP23017_GPB_INIT(); __delay_ms(2); writeCommand(0x01); //画面をクリア __delay_ms(20); writeCommand(0x02); //ホームへカーソル移動 __delay_ms(2); // LCD側の処理待ち、LCDは全く読み込めないので見込み時間 int count = 0; //カウント初期値 int count2 = 0; //カウント初期値 __delay_ms(333); writeCommand(0x80); //1列目へ移動 LCD_str(moji3); // __delay_ms(100); writeCommand(0x80+0x40); //2列目へ移動 LCD_str(moji2); //毎回「counter」と書き込むのは無駄なのでループ外へ出した __delay_ms(100); //------------------------------- while(1) { //------------------------------- //データ受信 //TRIGGER(); //オシロスコープ用 PCF8574AN_R(); // k に受信データを持って来る //k = k & 0xFE; // RA0 はTRIGGER()で使用中だからマスクを掛ける PORTA = (k); //LED出力、PORTBだとフリーズする原因不明 //---------------- TRIGGER(); MCP23017_GPB_IN(); //MCP GPB IN data read = k2 //------------------------------- // writeCommand(ToHome); //画面左上へカーソルを移動 writeCommand(0x8B+0x40); //カーソル移動 // count++; //カウントアップ // PCF8574AN入力で得られたデータをLCDに出力表示する sprintf(moji,"%02X",k2); //LCD %=16進表示、02=2桁表示で左寄せしない、X=大文字表示(x=小文字)。MSBがゼロでも文字無しとしないでゼロ表示させる。ex) NG = 0x 1 Good = 0x01 %=文字変換 0=左寄せしないでゼロ表示、2=2桁表示 LCD_str(moji); //mojiを表示 //---------------- // writeCommand(ToHome); //画面左上へカーソルを移動 writeCommand(0x8C); //カーソル移動 // count++; //カウントアップ // PCF8574AN入力で得られたデータをLCDに出力表示する sprintf(moji,"%02X",k); //LCD 16進表示、2桁表示、左寄せしない、MSBがゼロでも文字無しとしないでゼロ表示させる。ex) NG = 0x 1 Good = 0x01 %=文字変換 0=左寄せしないでゼロ表示、2=2桁表示 LCD_str(moji); //mojiを表示 //------------------------------- //TRIGGER(); MCP23017_GPA_OUT(k); __delay_ms(2); //------------------------------- // count2++; // PCF8574AN_W2(count2); //インクリメントした数値をPCF8574AN Extentioned IO に I2C送信 //------------------------------- // PCF8574AN入力で得られたデータを別のPCF8574ANに出力、LED表示する k = ~k; //LEDが逆論理で発光するので逆論理に変更 PCF8574AN_W2(k); // //------------------------------- __delay_ms(10); //遅延 } return 0; //------------------------------- }
I2C PIC16F886 LCD AQM1602XA EX_IO_PCF8574AN_c
他力本願のC言語入門で下記の制御です
・CPU PIC16F886
・LCD AQM1602XA
・I/O PCF8574AN
アセンブラでも記事がありますのでご参考まで
動作は下記の様に成って居ます
・LCD AQM1602XA
0 -> 1 -> 2...32768 -> -32768 -> -32767...-3 -> -2 -> -1 -> 0 の繰り返し
・I/O PCF8574AN
0 -> 1 -> 2・・・255 -> 0 -> 1・・・の繰り返し
データは出しっ放しでスレーブアドレス側からのデータ読み込みは有りません
参考にしたと申しますか殆どパクッたプログラムです
出典元はWak-techさんです、とても丁寧で判りやすいブログです
この場を借りて御礼申し上げます。
ソースです、なにぶんど素人なのでへたくそです笑って下さい
/* * File: main.c * Author: maru * PCF8574AN_pic16f886_v001 * Created on 2019/01/09, 8:57 * 0 -> 1 -> 2...32768 -> -32768 -> -32767...-3 -> -2 -> -1 -> 0 の繰り返し */ // CONFIG1 MPLAB XIDEの Production -> Set Configration bits で設定してもこのプログラムでの宣言が優先される //#pragma config FOSC = INTRC_NOCLKOUT //RA6 = I/O //デフォルトではRA6 = fosc/4 output #pragma config FOSC = INTRC_CLKOUT //RA6 = fosc/4 output #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config MCLRE = ON #pragma config CP = OFF #pragma config CPD = OFF #pragma config BOREN = OFF //#pragma config CLKOUTEN = OFF //#pragma config IESO = OFF #pragma config FCMEN = OFF // CONFIG2 #pragma config WRT = OFF //#pragma config VCAPEN = OFF //#pragma config PLLEN = ON //#pragma config STVREN = ON #pragma config BOR4V = BOR40V #pragma config LVP = ON #include#include #include #include #define _XTAL_FREQ 8000000 //PIC16F886はINTOSC時最高8MHzまでしか出ない下のOSCCON = 0x70;と矛盾しては成らない #define LCD_ADD 0x7C //LCDスレーブアドレス W #define S5851A_ADR 0x90 //温度センサースレーブアドレス W #define PCF8574AN_ADR 0x70 //Extentioned IO スレーブアドレス W #define ToHome 0b00000010 #define shiftLeft 0b00011000 #define shiftRight 0b00011100 #define clear 0b00000001 char moji[] = " "; char moji2[] = "counter= "; char moji3[] = "v001"; //この文字列を長くするとカウントアップがバグる、原因不明 void TRIGGER(){ PORTAbits.RA0 = 1; //for debug オシロスコープ・トリガ用 PORTA-RA0 __delay_us(10); PORTAbits.RA0 = 0; } void I2C_Master_Init(const unsigned long c) { SSPCON = 0b00101000; //RC3/SCK/SCL RC4/SDI/SDA として使用宣言 SSPCON2 = 0; SSPADD = (_XTAL_FREQ/(4*c))-1; SSPSTAT = 0b00000000 ; // 標準速度モードに設定する(100kHz) } void I2C_Master_Wait() { while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F)); } void I2C_Master_Start() { I2C_Master_Wait(); SEN = 1; } void I2C_Master_RepeatedStart() { I2C_Master_Wait(); RSEN = 1; } void I2C_Master_Stop() { I2C_Master_Wait(); PEN = 1; } void I2C_Master_Write(unsigned d) { I2C_Master_Wait(); SSPBUF = d; } void writeData(char t_data){ I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(LCD_ADD); //0x7C スレーブアドレス I2C_Master_Write(0x40); //0x40 キャラクタを書くよって宣言 I2C_Master_Write(t_data); //キャラクタの送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } void writeCommand(char t_command){ I2C_Master_Start(); I2C_Master_Write(LCD_ADD); I2C_Master_Write(0x00); I2C_Master_Write(t_command); I2C_Master_Stop(); __delay_ms(10); } void PICinit(){ OSCCON = 0x70; //0x70=8MHz PIC16F886はINTOSC時最高8MHzまでしか出ない上の#define _XTAL_FREQ 8000000;と矛盾しては成らない ANSEL = 0b00000000; ANSELH = 0b00000000; TRISA = 0b00000000; TRISB = 0b00000000; TRISC = 0b00011000; PORTA = 0b00000000; //2進数で書いた場合 PORTB = 0x00; //16進数で書いた場合 } void LCD_Init(){ //LCDの初期化、秋月のマニュアル通り //TRIGGER(); //for debug オシロスコープ・トリガ用 PORTA-RA0 I2C_Master_Init(100000); __delay_ms(400); //TRIGGER(); //for debug オシロスコープ・トリガ用 PORTA-RA0 writeCommand(0x38); //このプロトコルは S 0x7C 0x00 0x38 A P と成っているから下のプロトコルも全部一個ずつ送信している __delay_ms(20); writeCommand(0x39); __delay_ms(20); writeCommand(0x14); __delay_ms(20); writeCommand(0x73); __delay_ms(20); writeCommand(0x52); __delay_ms(20); writeCommand(0x6C); __delay_ms(250); writeCommand(0x38); __delay_ms(20); writeCommand(0x01); __delay_ms(20); writeCommand(0x0C); __delay_ms(20); } void LCD_str(char *c) { //LCDに配列の文字を表示 unsigned char i,wk; for (i=0 ; ; i++) { wk = c[i]; if (wk == 0x00) {break;} writeData(wk); } } //S5851A_ADR 温度センサー部分========================================================================================= void S5851A_W(char t_data){ I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(S5851A_ADR); //スレーブアドレス I2C_Master_Write(0x01); // I2C_Master_Write(t_data); //キャラクタの送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //S5851A_ADR 温度センサー部分========================================================================================= //PCF8574AN Extentioned IO 部分========================================================================================= void PCF8574AN_W(){ I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR); //スレーブアドレス I2C_Master_Write(0xAA); //データ送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } void PCF8574AN_W2(char LED){ I2C_Master_Init(100000); I2C_Master_Start(); //スタート・コンディション I2C_Master_Write(PCF8574AN_ADR); //スレーブアドレス I2C_Master_Write(LED); //データ送信 I2C_Master_Stop(); //ストップ・コンディション __delay_ms(10); } //PCF8574AN Extentioned IO 部分========================================================================================= int main(void){ PICinit(); //PICを初期化 // TRIGGER(); PCF8574AN_W(); // S5851A_W(0x00); //温度センサー、コンフィギュレーションレジスタ書き込みプロトコル LCD_Init(); writeCommand(0x01); //画面をクリア __delay_ms(20); writeCommand(0x02); //ホームへカーソル移動 __delay_ms(2); // LCD側の処理待ち int count = 0; //カウント初期値 int count2 = 0; //カウント初期値 __delay_ms(1000); writeCommand(0x80); //1列目へ移動 LCD_str(moji3); // __delay_ms(100); writeCommand(0x80+0x40); //2列目へ移動 LCD_str(moji2); //毎回「counter」と書き込むのは無駄なのでループ外へ出した __delay_ms(100); //------------------------------------------------------ while(1){ //writeCommand(ToHome); //画面左上へカーソルを移動 writeCommand(0x88+0x40); //カーソル移動 count++; //カウントアップ //----------------------- sprintf(moji,"%d",count); //mojiにcounter:countを代入 LCD_str(moji); //mojiを表示 //----------------------- TRIGGER(); count2++; PCF8574AN_W2(count2); //インクリメントした数値をPCF8574AN Extentioned IO に I2C送信 //----------------------- __delay_ms(1); //1ms遅延 } return 0; //------------------------------------------------------ }
I2C デジタル・カラーセンサS11059-02DT & PIC16F886 & LCD アセンブラ
下記の制御です
カラーセンサ / S11059-02DT
CPU / PIC16F886
LCD / AQM1602XA
I2C制御アセンブラ
世の中、Arduino や Raspberry Pi だのという時代に
時代遅れのアセンブラです、ただ、アセンブラの利点は
ハードウェアが良く理解出来るということでしょうか
部品は全て秋月でお安く手に入る物ばかりです
カラーセンサで得られた赤、緑、青、赤外、の各データ
をLCDに表示しています、ただ、問題が在ってLCDが
しょっちゅうフリーズします原因不明です。
写真手前がカラーセンサ、奥はI2Cレベルシフトです
5V /3.3V のバッファーと成ります
↓
回路図、センサー基板
↓
回路図、CPU
↓
センサー基板をビニル袋に入れている理由ですが、手で触れて
いる内にそれが原因かは不明ですがI2Cレベルシフトが完全に
壊れてしまったからです。
↓
動画のソースファイルです
素人プログラムです、不備、バグ、無理、無駄、プロの皆様から
見れば児戯レベルですので全責任と共にご容赦下さい。
I2Cフォーマット
スレーブアドレスはArduino や Raspberry Piですと 0x2Aですが
アセンブラですと 0x54(W) / 0x55(R) と成りますのでご注意下さい。
AQM1602 LCD / I2C / PIC16F886 / 温度計S-5851 アセンブラ
温度計です。
何もデジタルで無くても昔乍らのガラスの温度計の方が
趣もあり無電源で絶対良いと思うのですがまぁ遊びという
ことでご容赦下さい。
CPU PIC16F886
LCD AQM1602XA
温度センサー S5851A
これらをI2Cで繋いで制御します
動画です、四秒に一回ぐらいの更新です、分解能は 0.0625℃
って、どこまで正確なのか疑問ですが・・・
ブリンクは何だか動きが寂しいので表示しましたが要りません
作っていて思った事ですが、温度計の表示って数秒に一度あれば
充分ですよね、なので本気で作るなら sleep させて置いて
タイマー割り込み掛けて表示するのが現実的と思います
最近の電波時計は気温湿度が表示されますよね、あれは完璧に
sleepさせて必要な時だけ測定表示していると思います
でなければ乾電池が忽ち消耗してしまいます。
動画のソースファイル。