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

最低電流値が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秒ですからもっと少ない容量でも良いかも
知れません、要はお好み次第って事ですね。
DSCN0562

回路図です
bandicam 2019-01-29 21-55-26-894

ソースファイル、部分コピペに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);
}

“ULPWU 超低電流SLEEPモードを使う PIC12F683” の続きを読む

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 Color Sensor S11059 02DT” の続きを読む

I2C S-5851A thermal sensor LCD PIC16F886

他力本願C言語シリーズ 温度計
CPU = PIC16F886
温度センサー = SII S-5851A  スレーブアドレス 0x90(W) / 0x91(R)
LCD = AQM1602XA  スレーブアドレス 0x7C READ不可

前回アセンブラで作った同一品をC言語化したものです
正直言うと一体何日間掛かったことか・・・何十回となく
書いては直し、壊しては書き直し、訳が判らなく成って
振り出しに戻り、また書いて失敗し失望しての繰り返しでした。

結果的に言えることは
・コピペばっかりやって来た事で一貫性が無く関数にバグが入ったこと
・ひらがなモードのスペースとか入るともうズタズタに成りました、視えないんだもん
・C言語のシミュレーションを別のコンパイラで行って初めて「ダメだこりゃ」だったこと
・LCDが曲者で長い文字列を書くと他の文字が文字化けすること、特にこの問題が
 異常に時間が掛かった主な理由です、従って原因不明の儘となっています
 四文字ならOKで12文字ぐらいだと文字化けする、ってなに?

ともあれ何とか形に成りました

ソースファイルです、参考に成らないと思いますが素人の極みと言うことで
ご容赦下さい。
/*
* File:   main.c
* Author: maru
* I2C_S5851A_thermal_sensor_c_v005
* Created on 2019/01/09, 8:57
*
*/
// 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 ToHome 0b00000010
#define shiftLeft 0b00011000
#define shiftRight 0b00011100
#define clear 0b00000001
char moji[] = " ";
char moji2[] = ".";
char moji3[] = "C S5851A"; //この文字列を長くするとカウントアップがバグる、原因不明
char moji4[] = "v005";//この文字列を長くするとカウントアップがバグる、原因不明
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です
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;
}
//-------------------------------
// I2C ACK check
static unsigned char I2C_ackchk() {
unsigned char i2c_data;
if (ACKSTAT) {
i2c_data = 0xFF;
} else {
i2c_data = 0x00;
}
return (i2c_data);
}
static unsigned char I2C_rcv() {
SSPIF = 0;
SSPCON2bits.RCEN = 1;
while (SSPIF == 0) {
}
SSPIF = 0;
return SSPBUF;
}
//-------------------------------
static void I2C_acksnd() {
// ACKDTにACKをセット
SSPCON2bits.ACKDT = 0;
// NACK信号生成
SSPCON2bits.ACKEN = 1;
while (SSPCON2bits.ACKEN) {
}
return;
}
//-------------------------------
static void I2C_nacksnd() {
// ACKDTにNACKをセット(負論理なので1を設定)
SSPCON2bits.ACKDT = 1;
// NACK信号生成
SSPCON2bits.ACKEN = 1;
while (SSPCON2bits.ACKEN) {
}
return;
}
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);
}
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(); //ストップ・コンディション
}
//=========================================================================================
int main(void) {
PICinit(); //PICを初期化
LCD_Init();
writeCommand(0x01); //画面をクリア
__delay_ms(10);
writeCommand(0x82); //一行目
__delay_ms(10);
LCD_str(moji2); //mojiを表示
__delay_ms(10); //遅延
writeCommand(0x87); //一行目
__delay_ms(10);
writeData(0xF2);//文字表示
__delay_ms(10); //遅延
writeCommand(0x88); //2行目
__delay_ms(10);
LCD_str(moji3); //mojiを表示
__delay_ms(10); //遅延
writeCommand(0x80 + 0x40); //2行目
__delay_ms(10);
LCD_str(moji4); //mojiを表示
__delay_ms(10); //遅延
//S5851A_ADR 温度センサー測定
s5851a_init();
__delay_ms(10); //遅延
s5851a_me1(); //一回目はダミー
__delay_ms(10); //遅延
while (1) {
//------------------------------------------------
//温度測定
TRIGGER();
s5851a_me2(); //2回目は本測定 この時点で k3 = MSB 8bit と k4 = LSB 但し上位4ビット
__delay_ms(10); //遅延
//------------------------------------------------
//温度下位8ビットの表示、詰まり0℃以下の部分のみで上位4ビットだけ有効
writeCommand(0x83); //一行目
__delay_ms(10); //遅延
k4 = k4 >> 4;
sprintf(moji, "%04d", k4 * 625); //mojiにcounter:countを代入
LCD_str(moji); //mojiを表示
__delay_ms(10); //遅延
//------------------------------------------------
//温度上位8ビットの表示、詰まり0℃以上の部分のみ
s5851a_me2(); //2回目は本測定 この時点で k3 = MSB 8bit と k4 = LSB 但し上位4ビット、ここで二度目の二度目をやっている理由はk3が化けるから原因不明
__delay_ms(10); //遅延
writeCommand(0x80); //一行目
__delay_ms(10); //遅延
sprintf(moji, "%02u", k3); //mojiにcounter:countを代入
LCD_str(moji); //mojiを表示
__delay_ms(10); //遅延
}
return 0;
}