2016年6月5日日曜日

PIC32MX120F032Bで液晶(ACM0802C-NLW-BBH)が動かしたかった。。

動かなかった。。
取りあえず勉強になったのでメモ。



まず、今回やりたかったことをやっていたサイトから。(ソースコードも大体書いてある)
ACM0802C-NLW-BBHを使ってみる ハード編
LCDモニターについて

簡単そうに書いてあるんだけど出来ない!!

今回調べて知ったこと

PIC32MXについて

delayっていうユーティリティメソッドが無い!32bitのpicではdelayが無いのでタイマーを利用したロジックを書かないといけない。
まず、これがすごい面倒くさいんですよ。
液晶の制御で○○㎲以内とか、○○㎲以上のウェイトするとか、指定あるから。

今回、こうしてみたけど多分、間違ってる。

まず、コンフィグで80MHzで動作してるはず。
次に、レジスタ設定でタイマーを有効化して、1/256を設定。
    T1CON = 0x8030; // TMR1 on, prescale 1:256 PB
こうすると、タイマーのカウンタが80MHzの1/256でカウントアップされるのではなかろうか?(推測)
それなので、waitの関数をこうやって定義してみた。

void wait_us(unsigned int us){

    // 今回のタイマー設定なら、80MHzの256分の1の割り込みで3usになるはず。

    unsigned int val = us / 3 + 1;

    TMR1 =  0;

    while ( TMR1 < val){}

}

(この考え方が本当にあってるのか、今度、LEDチカチカでざっくり測定してみよう)

2016/6/10 追記:

上の考え方間違ってる。ブログ記事書いた。


液晶(ACM0802C-NLW-BBH)について

どうやって制御するのか全く知らなかったのでとっつき方が分からなくて大変だった。
まず、データシート開いて、全14ピンの機能を確認。


4bitモードで利用するときは、DB0~3は未使用なのでGND。
また、R/Wピンは、今回writeしかしないのでGNDでOK。(そのため、ソースコードに書かなくてよい)

初めてタイミングチャートなるものを見た。書き込みの場合のタイミングチャートが次のもの。



この図があらわしているのは、RSピンを1or0にして、R/Wピンを0にして、Eピンを1にして、DBピンでデータ書き込むということ。
へぇ、なるほどねぇ。

液晶のピンとPICのピン(BRとか)を1つずつ接続してあげれば、PICから命令できるようになるようだ。(出来なかったけど!)

一応、ソース。

Lib_LCD.h
================
#ifndef LIB_LCD_H
#define LIB_LCD_H

#include <xc.h>

// 参考1: http://amahime.main.jp/lcd/main.php?name=lcd
// 参考2 : http://minkara.carview.co.jp/userid/1540421/blog/27503415/

/********************************************
 * 液晶表示器用ライブラリ ACM0802C-NLW-BBH専用
 ********************************************/
#define LCD_PORT    PORTB   // DBピンの出力ポート(RB0~RB3を使う)
#define LCD_RS      PORTBbits.RB5     // RSピンの接続ポート
#define LCD_E       PORTBbits.RB6     // E(STB)信号
// LCDのデータシートに書いてあるタイムチャートには次の4つが書いてある
// 1. レジスタ選択信号(RS)
// 2. 読み出し/書き込みの選択信号(R/W)
// 3. 動作起動信号(E)端子
// 4. 入出力データ信号(DB0~DB7)

#define RS_CMD  0
#define RS_DATA 1


void lcd_send(char code, int rs);
void lcd_str(char *str);
void lcd_data(char data, int);
void wait_us(unsigned int);
void wait_ms(unsigned int);


void lcd_init(void){
    wait_ms(30);

    // Function set
    lcd_send(0x02, RS_CMD);
    lcd_send(0x02, RS_CMD);
    lcd_send(0x08, RS_CMD);
    wait_us(50);

    // Display ON/OFF control
    lcd_send(0x00, RS_CMD);
    lcd_send(0x0C, RS_CMD);
    wait_us(50);
 
    // Display Clear
    lcd_send(0x00, RS_CMD);
    lcd_send(0x01, RS_CMD);
    wait_ms(2);
 
    // Entry Mode Set
    lcd_send(0x00, RS_CMD);
    lcd_send(0x06, RS_CMD);
    wait_ms(5);
 
}

// ビットチェンジ及び信号制御
void lcd_send(char code, int rs){
    // 4bit命令用のマスク(RB0~RB3までを使い、他のbitは状態を残す。)
    LCD_PORT = (LCD_PORT & 0xF0) | (code & 0x0F);
 
    LCD_RS = rs;     // 0: コマンド、1: データ
    wait_us(40);
    LCD_E = 1;
    wait_us(1);
    LCD_E = 0;
}

// 文字列を出力する
void lcd_str(char *str){
    while(*str != 0x00){
        lcd_data(*str, RS_DATA);
        str++;
    }
}

void lcd_data(char data, int rs){
    lcd_send(data >> 4, rs);
    lcd_send(data, rs);
    wait_us(50);
}

// 指定した時間だけ待機する(ただし、正確ではない。)
void wait_us(unsigned int us){
    // 今回のタイマー設定なら、80MHzの256分の1の割り込みで3usになるはず。
    unsigned int val = us / 3 + 1;
    TMR1 = 0;
    while ( TMR1 < val){}
}

void wait_ms(unsigned int ms){
    int i;
    for(i=0; i<ms; i++){
        wait_us(1000);
    }
}

#endif /* LIB_LCD_H */
================


main.c
================
#include <xc.h>
#include "Lib_LCD.h"

// Config settings
// POSCMOD = HS, FNOSC = PRIPLL, FWDTEN = OFF
// PLLIDIV = DIV_2, PLLMUL = MUL_16
// PBDIV = 8 (default)
// Main clock = 8MHz /2 * 16    = 80MHz
// Peripheral clock = 80MHz /8  =  10MHz

// Configuration Bit settings
// SYSCLK = 80 MHz (8MHz Crystal/ FPLLIDIV * FPLLMUL / FPLLODIV)
// PBCLK = 10 MHz
// Primary Osc w/PLL (XT+,HS+,EC+PLL)
// WDT OFF
// Other options are don't care
//
#pragma config FPLLMUL = MUL_20, FPLLIDIV = DIV_2, FPLLODIV = DIV_1, FWDTEN = OFF
#pragma config POSCMOD = HS, FNOSC = PRIPLL, FPBDIV = DIV_8

char dispText[] = "HELLO";

void init_pic(){
    // disable JTAG port
    DDPCONbits.JTAGEN = 0;

    TRISA = 0;      // all PORTA as output
    TRISB = 0;

    // wait関数のためにタイマ設定
    T1CON = 0x8030; // TMR1 on, prescale 1:256 PB
}

void main(void) {
    init_pic();
    lcd_init();
    
    //lcd_data(0x81, RS_CMD);
    //lcd_data(0x30, RS_DATA);    // 0
    
    // 液晶に表示
    lcd_send(0xC0, RS_CMD);
    lcd_str(dispText);
     
    while(1){
    }
    return;
}
================


まとめ


今回、まずPICの回路で電解コンデンサ付ける場所間違えてて、
Failed to program device
Selected device and target: memory mismatch.
ってエラー出たのでハマってた。(19,20で繋がないといけないのに、18,19で繋いでた)

今回失敗した原因と思わしき場所
・waitの時間が正しくない
・回路でLCDが5V(アダプタから供給)、PICが3V(PICKITから供給)と2つ使ってるからダメ
・回路間違ってる?

次の装置は動くようにお祈りしましょう。