一人もくもく会 α verでサービス開始しました。

8ピンPIC用のデバッグモニタ作成

キャラクタLCDを購入していたのだがずっと触らずに放置していた。
色々調べてみるときむ茶さんのところに
デバッグモニターの作成
という記事があったのだが、面倒くさそうだし
LCDの操作自体はシンプルそうなので必要な時に
ピン数の多いICで直接操作すればいいかな、くらいの感じで考えていた。

別でmTouchというタッチセンサっぽいものが気になったので
PIC12F1822を購入していたのだがずっと手を付けずにいた。
ようやくやってみようという気になって色々調べてみたところ、
どうも離している時と触っている時の充電、放電の回数をカウントする必要があるらしく、
ちゃんと大きな数値をデバッグできないと作成が出来ないっぽいことがわかった。

なるほど、だからデバッグモニタを作成する必要があったのか…と理解。
この方法なら1ピンでモニタを操作できることになる。

さて、やってみようと思いきや記事に書かれている
モニタを直接操作するためのICがない。
手元にある8ビットの安いICはPIC18F14K50くらい。
20ピンもあるのでなんとなくもったいない気がしたが
とりあえずブレッドボードで仮に作成してみることにした。

でよくよく記事を見ると、どうもソフトウェアでシリアル通信をしているらしい。
でもちょっとまてよ、PIC18F14K50は普通にシリアル通信に対応してたはず。
もしかするとこのシリアル通信とソフトウェアシリアルで通信できるんだろうか?
そう思いPIC18F14K50は普通にシリアル通信の機能を使ってやってみることにした。

下記がPIC18F14K50側のプログラム。

#include <xc.h>
#include <stdlib.h>
#include "skUARTlib.h"

#if defined _18F14K50

#pragma config FOSC   = IRC,  PLLEN  = ON,  FCMEN  = OFF
#pragma config IESO   = OFF, USBDIV = OFF, CPUDIV = NOCLKDIV
#pragma config PWRTEN = ON, BOREN  = ON, WDTEN  = OFF
#pragma config HFOFST = OFF, MCLRE  = OFF
#pragma config STVREN = ON,  BBSIZ  = OFF, LVP    = OFF
#pragma config XINST  = OFF
#pragma config CP0    = OFF, CP1    = OFF, CPB    = OFF
#pragma config WRT0   = OFF, WRT1   = OFF, WRTB   = OFF, WRTC   = OFF
#pragma config EBTR0  = OFF, EBTR1  = OFF, EBTRB  = OFF

#define _XTAL_FREQ 8000000         // CLK 12MHz (use from __delay_ms)

#define LCD_RS    PORTCbits.RC0
#define LCD_EN    PORTCbits.RC1
#define LCD_D4    PORTCbits.RC3
#define LCD_D5    PORTCbits.RC4
#define LCD_D6    PORTCbits.RC5
#define LCD_D7    PORTCbits.RC6

#endif

#define	LCD_STROBE()	((LCD_EN=1),(LCD_EN=0))

void Wait(unsigned int num)
{
     int i ;

     // numで指定した回数だけ繰り返す
     for (i=0 ; i<num ; i++) {
          __delay_ms(10) ;     // 10msプログラムの一時停止
     }
}

void lcd_write(unsigned char c)
{
     // 送信データのバイト列上位4ビットを処理
     LCD_D4 = ( ( c >> 4 ) & 0x01 ) ;
     LCD_D5 = ( ( c >> 5 ) & 0x01 ) ;
     LCD_D6 = ( ( c >> 6 ) & 0x01 ) ;
     LCD_D7 = ( ( c >> 7 ) & 0x01 ) ;
     LCD_STROBE() ;
     // 送信データのバイト列下位4ビットを処理
     LCD_D4 = ( ( c ) & 0x01 ) ;
     LCD_D5 = ( ( c >> 1 ) & 0x01 ) ;
     LCD_D6 = ( ( c >> 2 ) & 0x01 ) ;
     LCD_D7 = ( ( c >> 3 ) & 0x01 ) ;
     LCD_STROBE() ;
}

void command(unsigned char c)
{
     LCD_RS = 0 ;
     LCD_D4 = ( ( c ) & 0x01 ) ;
     LCD_D5 = ( ( c >> 1 ) & 0x01 ) ;
     LCD_D6 = ( ( c >> 2 ) & 0x01 ) ;
     LCD_D7 = ( ( c >> 3 ) & 0x01 ) ;
     LCD_STROBE() ;
}

/*******************************************************************************
*    lcd_clear - LCDモジュールの画面を消す処理                              *
*******************************************************************************/
void lcd_clear(void)
{
     LCD_RS = 0 ;
     lcd_write(0x01) ; // Clear Display : 画面全体に20Hのスペースで表示、カーソルはcol=0,row=0に移動
     __delay_ms(2) ;   // LCDが処理(1.53ms)するのを待ちます
}
/*******************************************************************************
*    lcd_setCursor - LCDモジュール画面内のカーソル位置を移動する処理        *
*      col : 横(列)方向のカーソル位置(0-15)                                    *
*      row : 縦(行)方向のカーソル位置(0-1)                                     *
********************************************************************************/
void lcd_setCursor(int col, int row)
{
     int row_offsets[] = { 0x00, 0x40 } ;

     LCD_RS = 0 ;
     lcd_write(0x80 | (col + row_offsets[row])) ; // Set DDRAM Adddress : 00H-0FH,40H-4FH
}
/*******************************************************************************
*  lcd_putc - LCDにデータを1バイト出力する処理                             *
*    c : 出力する文字データ                                                    *
*******************************************************************************/
void lcd_putc(char c)
{
     LCD_RS = 1 ;        // RSの制御信号線をセットします
     lcd_write( c ) ;    // LCDにデータの送信
}
/*******************************************************************************
*  lcd_puts - LCDに文字列データを出力する処理(文字列をNULL(0x00)まで繰返し出力)*
*    s : 出力する文字列のデータ                                                *
*******************************************************************************/
void lcd_puts(const char * s)
{
	LCD_RS = 1 ;        // RSの制御信号線をセットします
	while(*s) lcd_write(*s++) ;
}
/*******************************************************************************
*  lcd_init - LCDの初期化処理                                               *
*******************************************************************************/
void lcd_init()
{
     LCD_RS = 0 ;
     LCD_EN = 0 ;

     __delay_ms(15) ;    // 電源ON後15msまで待ってから初期化

     // LCDの立上げ時のチェックデータ(イニシャライズ処理用)を設定
     command(0x03) ;
     __delay_ms(5) ;
     command(0x02) ;
     // LCDにコマンドを発行します
     lcd_write(0x28) ;   // function set   : データ線は4本・表示は2行・フォントは5x8ドット
     lcd_write(0x0c) ;   // display control: 画面表示はON・カーソル表示はOFF・カーソル点滅はOFF
     lcd_clear() ;       // Clear Display  : 画面をクリアし、カーソル位置はcol=0,row=0
     lcd_write(0x06) ;   // entry mode set : 文字を表示した次にカーソルを移動するを指示
}

void interrupt inter(void) {
    InterUART();
}

void main(void)
{
    int i = 0;
    char s[17];
//    char debug[2] = "a";

    OSCCON = 0b01100010;
    TRISC  = 0b00000000;
    ANSEL  = 0b00000000;
    ANSELH = 0b00000000;
    PORTC = 0;
    InitUART(12, 10, 51);

    lcd_init();
    lcd_setCursor(0, 0);
    lcd_puts(" Monitor  Start ");

    while(1) {
        if (UART_Available() != 0) {
            char c = UART_Read();
            if (c == '\n' || c == '\r') {
                c = 0;
            }
//            debug[0] = c;
//            UART_Send(debug, 2);
            if (i < 16 || c == 0) {
                s[i++] = c;
                if (c == 0) {
                    lcd_setCursor(0, 1);
                    lcd_puts("                ");
                    lcd_setCursor(0, 1);
                    lcd_puts(s);
                    i = 0;
                }
            }
        }
    }

    return;
}

skUARTlib.hはこれまたきむ茶さんのところで手に入れたUARTプログラム。
FT232RLとつないでteratermから文字を送ってみたら
とくにつまづくことなくモニタに文字を表示することが出来た。感動。
(ヌル文字の送り方が分からなかったので改行もヌル文字として扱っている)

引き続きPIC12F1822側の送信プログラムを試してみた。
…が、動かない。
どうも厳密なソフトウェアシリアルではなく、
ソフトウェアシリアル同士でのみ通信できるシリアル通信もどきのようだ。

困った…、どう調整すればいいのかも分からない…。

PIC12F1822 シリアル通信
で検索してみたところ、またもやきむ茶さんのサイトに辿り着いた。
ぼーっと眺めていると、なんかUARTが使えるとか書いてある。
え…?

データシートを見てみたら確かにRX, TXのピンがある。
何だそりゃと思いつつskUARTlib.hを使ったプログラムに書き換えてみたら
普通に動いた。
こっちのほうが簡単じゃないか。

// 12F1822によるLCDモニターのサンプルプログラム
#include <xc.h>
#include <string.h>
#include <stdlib.h>
#include "skUARTlib.h"

#define _XTAL_FREQ 8000000

// コンフィギュレーション1の設定
// CLKOUTピンをRA4ピンで使用する(CLKOUTEN_OFF):内部クロック使用する(FOSC_INTOSC)
// 外部クロック監視しない(FCMEN_OFF):外部・内部クロックの切替えでの起動はなし(IESO_OFF)
// 電源電圧降下常時監視機能ON(BOREN_ON):電源ONから64ms後にプログラムを開始する(PWRTEN_ON)
// ウオッチドッグタイマー無し(WDTE_OFF):
// 外部リセット信号は使用せずにデジタル入力(RA3)ピンとする(MCLRE_OFF)
// プログラムメモリーを保護しない(CP_OFF):データメモリーを保護しない(CPD_OFF)
__CONFIG(CLKOUTEN_OFF & FOSC_INTOSC & FCMEN_OFF & IESO_OFF & BOREN_ON &
         PWRTE_ON & WDTE_OFF & MCLRE_OFF & CP_OFF & CPD_OFF) ;
// コンフィギュレーション2の設定
// 動作クロックを32MHzでは動作させない(PLLEN_OFF)
// スタックがオーバフローやアンダーフローしたらリセットをする(STVREN_ON)
// 低電圧プログラミング機能使用しない(LVP_OFF)
// Flashメモリーを保護しない(WRT_OFF):電源電圧降下常時監視電圧(2.5V)設定(BORV_25)
__CONFIG(PLLEN_OFF & STVREN_ON & WRT_OFF & BORV_HI & LVP_OFF);


/*******************************************************************************
*  メインの処理                                                                *
*******************************************************************************/
void main()
{
     int  i ;
     char s[17] ;

     OSCCON  = 0b01110010 ;   // 内部クロックは8MHzとする
     ANSELA  = 0b00000000 ;   // アナログは使用しない(すべてデジタルI/Oに割当てる)
     TRISA   = 0b00000000 ;   // ピンはRA1(SCL)/RA2(SDA)のみ入力(RA3は入力専用)
     PORTA   = 0b00000000 ;   // 出力ピンの初期化(全てLOWにする)

     // LCDモニターを使用する為の初期化処理
     InitUART(2, 3, 51);

     i = 0 ;
     while(1) {
          itoa(s,i,10) ;
          UART_Send(s, strlen(s) + 1);
          i++ ;
          __delay_ms(1000) ;  // 1秒後に繰り返す
     }
}

画像をつけようと思ったが
輝度調整を省いたのでLCDが明るすぎてLCDしか映らなかったので省略。

さてこれでmTouchが試せそうだ。