2024年4月24日水曜日

PIC16f1827 and aqm1602 success code

AQM1602_rev2.pdf (akizukidenshi.com) にて半田するのでモシニャガ本のpullup不要

> コピペで超簡単!PICマイコンでI2C接続のLCD(AQM1602)を使う【PIC16F1938】 | Wak-tech のコードをみているとsda,sclをプルアップしていません 同サイトの回路をみてもプルアップ抵抗が使われていません これでうごくのでしょうか?
<私もこのサイトを参考にさせていただきました。秋月の付属データシートには「基板上のプルアップ抵抗(10KΩ)」をはんだするか、別途プルアップ抵抗を接続するように書いています。私ははんだして同サイトのようにしました
> (ちなみにモシニャガ先生はソフト的にsda,sclをweak pullupする方法をとっていました) それとsda,sclをinputにしておくのはackを受け取るためでしょうか sda/sclをinputにしておいてもPICからLCDに命令がだせるのはなぜでしょうか?
<先にお送りしたAQM1602のライブラリではハードでプルアップしていますのでこのコードはありません。ソフトプルアップするにはポートをINPUTにする必要があり、OUTPUTではプルアップできません。ACM1602NIの回路図ではSDA,SCLをプルアップするように指定されていますので、このようなコードになっているのではないでしょうか。
よろしくお願いします。

//コピペで超簡単!PICマイコンでI2C接続のLCD(AQM1602)を使う【PIC16F1938】 | Wak-tech を参考にしているとのこと

 /* from yosino san

 *  AQM1602 【16F1827】

 *   AQM1602/main.c   Created on 2024/04/20, 21:48

 */

// config1

#pragma config FOSC = INTOSC , WDTE = OFF , PWRTE = ON , MCLRE = ON , CP = OFF , CPD = OFF

#pragma config BOREN = OFF , CLKOUTEN = OFF , IESO = OFF , FCMEN = OFF

// config2

#pragma config WRT = OFF , PLLEN = OFF , STVREN = ON , LVP = OFF 

#include <xc.h>

#define _XTAL_FREQ 8000000

#define LCD_ADD 0x7C // 下記参照

char moji[] = "Hello,World!";

char moji2[] = "PIC16F1827";

void I2C_Master_Init(const unsigned long c){

 // OPTION_REGbits.nWPUEN = 0; // この2行はプルアップ半田したので不要

   // WPUB    |= 0b00010010;

    SSP1CON1 = 0b00101000;

    SSP1CON2 = 0; 

    SSPADD = (_XTAL_FREQ/(4*c))-1; // これでcに1000000 つまり100khZを入れる

   // つまり SSP1ADD = 19;                 // (_XTAL_FREQ / (4*c))-1;

    SSP1STAT = 0b00000000 ;    // 標準速度モードに設定する(100kHz)

}

void I2C_Master_Wait(){

    while ((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F));

// start sequence 検出 または acken=1 & rcen=1 & pen=1 & rsen=1 & sen=1

// https://nukomabo.work/post-528/ ssp1stat == 0x04 は送信中

// 【PIC】I2C通信のやり方 | 理系男子の電子工作 (rikeden.net) では後半も含めて

//  trasnmission is in progresと表現

// cf I2C温度センサーLM75ADをPIC12F1822で使う (r271-635) (netlog.jpn.org)

}

void I2C_Master_Start(){

    I2C_Master_Wait();

    SSP1CON2bits.SEN = 1;

}

void I2C_Master_Stop(){

    I2C_Master_Wait();

    SSP1CON2bits.PEN = 1;

}

void I2C_Master_Write(unsigned char d){

    I2C_Master_Wait();

    SSP1BUF = d;

}

void writeData(char t_data){

    I2C_Master_Start();

    I2C_Master_Write(LCD_ADD);

    I2C_Master_Write(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 LCD_Init(){            //LCDの初期化

    I2C_Master_Init(100000);

    __delay_ms(400);

    writeCommand(0x38);

    __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);

    }

}


int main(void){

 OSCCON=0x72;            // 8MHz

    ANSELA=0x00;

    ANSELB=0x00;

    TRISA=0x00;

    TRISB=0x12;             // 0b00010010 for sda and scl

    PORTB=0x00;

    LCD_Init();

    writeCommand(0x01); //画面をクリア

    __delay_ms(20);

    writeCommand(0x02); //ホームへカーソル移動

    __delay_ms(2);                  // LCD側の処理待ち


    while(1){

        writeCommand(0x02);         //ホームへカーソル移動

        LCD_str(moji);

        writeCommand(0x40+0x80);    //2列目へ移動

        __delay_ms(200);

        LCD_str(moji2);

        __delay_ms(1000);

        writeCommand(0x01); //画面をクリア

        __delay_ms(200);

    }

    return 0;

}

--------------------------------------------------------------------

I2C接続AQMシリーズのキャラクタ表示LCDをArduinoで使う (2) AQM1602 | 電子工作の環境向上 (denshi.club) より 上記0x7cはwriteの0を含んでいる!

※ライブラリFaBoLCDmini_AQM0802Aのヘッダ・ファイルには、スレーブ・アドレスが、0x3eと固定されています。AQM1602のデータシートには0x7cと書かれています。マスタがスレーブのLCDに対してスレーブ・アドレスを指定するとき、最後にRead/Writeビットを追加します。LCDはライト・オンリなので、8ビットの0x7c(01111100)の最後のwriteビット0を取り去ると0111110=0x3eになります。

ーーーーーーーーーーー以下をheader,lib,mainにわけたーーーーーーーーーーーーーーーーーーー

/* 

 *   AQM1602 ライブラリ用 ヘッダファイル aqm1602.h

 */


#include <xc.h> 


#ifndef AQM1602_H

#define AQM1602_H


void I2C_Master_Init(const unsigned long c);

void I2C_Master_Wait(void);

void I2C_Master_Start(void);

void I2C_Master_Stop(void);

void I2C_Master_Write(unsigned char d);

void writeData(unsigned char t_data);

void writeCommand(unsigned char t_command);

void LCD_Init(void);                                    // LCDの初期化

void LCD_str(char *c);                                  // LCDに配列の文字を表示

void LCD_clear(void);                                   // LCDの画面をクリア

void LCD_home(void);                                    // LCDのカーソルをホームへ

void LCD_locate(unsigned char row, unsigned char col);  

// LCDのカーソル位置を指定(行,列))

// 行:1,2 列:1~16

#endif

ーーーーーーーーーーーーーーーーーーーーーーーーーー

/*
 *   AQM1602用 ライブラリ関数 aqm1602.c
 */

#include <xc.h>
#include "aqm1602.h"

#define _XTAL_FREQ 8000000
#define LCD_ADD 0x7C

void I2C_Master_Init(const unsigned long c){
    SSP1CON1 = 0b00101000;
    SSP1CON2 = 0;
    SSPADD = (_XTAL_FREQ/(4*c))-1; // これでcに1000000 つまり100khZを入れる
   // SSP1ADD = 19;                 // (_XTAL_FREQ / (4*c))-1;
    SSP1STAT = 0b00000000 ;       // 標準速度モードに設定する(100kHz)
}
void I2C_Master_Wait(void){
    while ((SSP1STAT & 0x04) || (SSP1CON2 & 0x1F));
}
void I2C_Master_Start(void){
    I2C_Master_Wait();
    SSP1CON2bits.SEN = 1;
}
void I2C_Master_Stop(void){
    I2C_Master_Wait();
    SSP1CON2bits.PEN = 1;
}
void I2C_Master_Write(unsigned char d){
    I2C_Master_Wait();
    SSP1BUF = d;
}
void writeData(unsigned char t_data){
    I2C_Master_Start();
    I2C_Master_Write(LCD_ADD);
    I2C_Master_Write(0x40);
    I2C_Master_Write(t_data);
    I2C_Master_Stop();
    __delay_ms(10);
}
void writeCommand(unsigned 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 LCD_Init(void){           
    I2C_Master_Init(100000);
    __delay_ms(400);
    writeCommand(0x38);
    __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) {     
    unsigned char i,wk;
    for (i=0 ; ; i++) {
      wk = c[i];
      if  (wk == 0x00) {break;}
      writeData(wk);
    }
}
void LCD_clear(void){
    writeCommand(0x01);
    __delay_ms(5);
}
void LCD_home(void){
    writeCommand(0x02);
    __delay_ms(5);
}
void LCD_locate(unsigned char row, unsigned char col){
    char addr;
    switch(row){
        case 1: addr = 0x00; break;
        case 2: addr = 0x40; break;
    }
    if (col > 0x15)
        col = -1;
    addr += col - 1;
    addr |= 0x80;
    writeCommand(addr);
    __delay_ms(5);
}
ーーーーーーーーーーーーーーー
// config1
#pragma config FOSC = INTOSC , WDTE = OFF , PWRTE = ON , MCLRE = ON , CP = OFF , CPD = OFF
#pragma config BOREN = OFF , CLKOUTEN = OFF , IESO = OFF , FCMEN = OFF
// config2
#pragma config WRT = OFF , PLLEN = OFF , STVREN = ON , LVP = OFF 

#include <xc.h>
#include <stdio.h>
#include "aqm1602.h"
#define _XTAL_FREQ 8000000
#define LCD_ADD 0x7C

char moji[] = "Hello, PIC World!";
char moji2[] = "Wak-tech";
int main(void){
      
OSCCON = 0x72; // 8MHZ
ANSELA = 0x00; // RA DIGITAL
ANSELB = 0x00; // RB DIGITAL
TRISA = 0b00000000;
TRISB = 0x12; // pulluped input for sda scl
PORTA = 0;
PORTB = 0;
 // OPTION_REGbits.nWPUEN = 0; // この2行はプルアップ半田したので不要
 // WPUB    |= 0b00010010;   
  LCD_Init();
  writeCommand(0x01); //画面をクリア
  __delay_ms(20);
 writeCommand(0x02); //ホームへカーソル移動
 __delay_ms(2); // LCD側の処理待ち

   while(1){
          writeCommand(0x02);   //ホームへカーソル移動
          LCD_str(moji);
          writeCommand(0x40+0x80); //2列目へ移動
          __delay_ms(200);
          LCD_str(moji2);
          __delay_ms(1000);
          writeCommand(0x01); //画面をクリア
          __delay_ms(200);
  }
  return 0;
}

0 件のコメント:

コメントを投稿