I2C PIC16F886 & LCD=AQM1602XA & 温度センサー=S-5851A c

他力本願C言語シリーズ、温度計です
以前、アセンブラで書いたプログラムをC言語に変えただけです
ハードウェアは全く一緒でプログラムも単純です
未だに上手く出来ないのがC言語での計算で 625 * 0x0F の表示が
文字化けしてしまうのです、仕方無く配列を書いて選んで表示してます
プロの方から視れば児戯に等しいでしょうけどこれが精一杯。

ソースファイル、余計なデバイスのプログラムが混じって居ますので
見辛いところはご容赦下さい。
/*
* File:   main.c
* Author: maru
* pic16f886_pcf8574an_mcp23017_v003
* 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[] = "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";		//温度計少数以下
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;
//******************************************************************************
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;
}
//******************************************************************************
int main(void)
{
PICinit();                        //PICを初期化
__delay_ms(2);
//-----------
I2C_Init();                             //これだと速い
//-----------
LCD_Init();                       //LCD初期化
__delay_ms(2);
//-----------
s5851a_init();                    //温度センサー初期化
//TRIGGER();
s5851a_me1();                     //温度センサー一回目のみの受信プロトコル
__delay_ms(2);
//-----------
writeCommand(0x01);               //画面をクリア
__delay_ms(20);
writeCommand(0x02);               //ホームへカーソル移動
__delay_ms(2);                    // LCD側の処理待ち、LCDは全く読み込めないので見込み時間
__delay_ms(333);
writeCommand(0x80);               //1列目へ移動
LCD_str(moji3);                   //
__delay_ms(100);
//writeCommand(0x80+0x40);          //2列目へ移動
//LCD_str(moji2);                   //文字表示
writeCommand(0x82+0x40);          //2列目へ移動
LCD_str(moji5);                   //文字表示
writeCommand(0x88+0x40);          //2列目へ移動
LCD_str(moji6);                   //文字表示
writeCommand(0x87+0x40);          //2列目へ移動
writeData(0xF2);
__delay_ms(100);
//-------------------------------
while(1)
{
//-------------------------------
TRIGGER();
s5851a_me2();                       //温度センサー測定値受信 k3 & k4
//-------------------------------
writeCommand(0x80+0x40);            //カーソル移動
//  温度センサーで得られたデータをLCDに出力表示する
sprintf(moji,"%02u",k3);            //LCD %=10進表示、02=2桁表示で左寄せしない。MSBがゼロでも文字無しとしないでゼロ表示させる。ex) NG = 0x 1 Good = 0x01 %=文字変換 0=左寄せしないでゼロ表示、2=2桁表示
LCD_str(moji);                      //mojiを表示
writeCommand(0x83+0x40);            //カーソル移動
k4 = k4 >> 4;                       // k4を1ビット右へ4シフト
//k4 = 1 / k4;
hairetsu();
//LCD_str(moji6);
//-------------------------------
//    PCF8574AN_W2(k);                    //
//-------------------------------
__delay_ms(10);                     //遅延
}
return 0;
//-------------------------------
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です