趣味のブログ

アクセスカウンタ

zoom RSS 秋月パーツ、AQM1248でグラフィックPLOT,LINE

<<   作成日時 : 2014/01/16 18:44   >>

ナイス ブログ気持玉 1 / トラックバック 0 / コメント 0

AQM1248は、小型ながら128x48ドットの解像度があり、文字などを表示するのに便利だとわかりましたがせっかくグラフィック液晶なのでグラフを表示するようにしてみました。描画するためには最低PLOTルーチンがあればよいことになりますが、便利のためにLINEとBOXルーチンも用意しています。書き込みは1バイト単位なので、1ドットを操作するには一度1バイトを読み出して1ビットを操作する必要があります。しかし、液晶モジュールは読み出しが出来ないためマイコン内にバッファを用意します。

画像AQM1248は小型で信号線も少ないので小さくまとめることが出来ますが、グラフを表示するためには、1ドットを表示するPLOTルーチンを作っておく必要があります。また、直線を引くことが多いのでLINEルーチンも必要でしょう。おまけに枠などを書くためにBOXルーチンも用意しました。PLOTルーチンでは液晶モジュールから読み出すことが出来ないため表示エリアをマイコン内にも持っている必要があります。1ドットを表示するためには、そのドットが属するバイトをマイコン内のメモリから読み出してドット操作した後、メモリと液晶モジュールに送ります。表示メモリには128x6=768バイトが必要になりますが、16F886などでは連続して確保することが出来ないためPIC24FJ64GA002を使用しました。16F886などではRAMが分断されていて連続して確保が出来ないようですが、16F1938などのような新PIC16F1シリーズではRAMを連続して使うことが出来るのでもしかしたら使えるかもしれません。PLOTは表示するドットの液晶メモリのアドレスを計算するだけですが、CLR、SET、XORの3つの演算を用意しました。XORは、グラフを表示するときに使い、もう一度同じ描画を行うと消すことが出来るので動くグラフを速く描画することが出来ます。これはLINEやBOXルーチンでも使うことが出来ます。LINEルーチンは、X軸とY軸を較べて変化の大きい方を1ドットずつ増やすなどの工夫が必要ですが、ちょうど書籍「LCD&タッチパネル活用の素」にあったのでそのまま引用しました。
プログラムの中でサインとコサインを描画するためにMath.hをインクルードしていますが、そのほかの表示だけを行うには浮動小数点は必要ありません。

AQM1248plotline.c
/**********************************************
*
*  PIC24FJ64GA002  family  
*
*  AQM1248  graphic  draw
*
***********************************************/
#include  "p24FJ64GA002.h"
#include  <math.h>
//  コンフィギュレーション  ビットの設定
_CONFIG1(  JTAGEN_OFF  &  GCP_OFF  &  GWRP_OFF  &  BKBUG_OFF
         &  COE_OFF  &  ICS_PGx1&  FWDTEN_OFF  )  
//  外付けセラミック使用  8MHz*PLL4=32MHz  (Full  Speed)
_CONFIG2(  IESO_OFF  &  FNOSC_PRIPLL  &  FCKSM_CSDCMD
         &  OSCIOFNC_OFF  &  IOL1WAY_OFF  &  I2C1SEL_PRI  &  POSCMOD_HS)

#define  CLOCK      16    //  単位はMHzで指定

void  delay_us(int  usec);
void  delay_ms(int  msec);

void  delay_us(int  us){
       us  =  (int)(CLOCK*us)/  10;
       while(us)      {
               asm("NOP");
               asm("NOP");
               asm("NOP");
               asm("NOP");
               asm("NOP");                                  
               us--;
       }
}
void  delay_ms(int  ms){
       int  i;
       for(i=0;  i<  ms;  i++)
               delay_us(1000);
}

#define  CLR  0
#define  SET  1
#define  XOR  2
unsigned  char  lcdbuf[6][128];
unsigned  char  bitmap[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};

typedef  unsigned  char  BYTE;

//  SPIポート
#define  bitSCK    5              //  RB5
#define  bitSDI    6              //  RB6
#define  bitSDO    7              //  RB7
#define  bitCS      9              //  RB9
#define  bitRS      8              //  RB8
#define  CS    LATBbits.LATB9    //  RB9
#define  RS    LATBbits.LATB8    //  RB8

//****************************************
//  SPIマスタ初期化(MSSP使用)
//****************************************
void  SPIMsInit(void)  {
       TRISB  &=  0xFC5F;  //3B8->3A0
       LATB  |=  0x03FF;
       TRISBbits.TRISB5=0;
       TRISBbits.TRISB6=1;
       TRISBbits.TRISB7=0;
       RPINR20bits.SDI1R=6;  //  SDI  RP6
       RPOR3bits.RP7R  =  7;  //  SDO  RP7
       RPOR2bits.RP5R  =  8;  //  SCK  RP5
       SPI1STAT  =  0x000C;
       SPI1CON1  =  0x0039;  //1:2  1:16  500kHz
       SPI1CON1bits.SMP  =  0;
       SPI1CON1bits.CKE  =  0;  //1;
       SPI1CON1bits.CKP  =  1;  //0;
       SPI1STATbits.SPIEN  =  1;
}

//****************************************
//  SPIマスタ送受信(MSSP使用)
//    IN:    txdat  マスタ送信データ
//    RET:  SPIRxData  マスタ受信データ
//****************************************
BYTE  SPIMsCom(BYTE  txdat)  {
       BYTE  rxdat;
       SPI1BUF  =  txdat;                //  マスタ送信データ設定,  送受信開始
       while(!SPI1STATbits.SPIRBF){};    //  SSPIFセット(通信完了)待ち
       rxdat  =  SPI1BUF;                //  マスタ受信データ取り出し
       SPI1STATbits.SPIRBF=0;
       return  rxdat;
}
void  lcdcmd(unsigned  char  work)
{
       CS=0;
       RS=0;
       SPIMsCom(work);
       CS=1;
}
void  lcddat(unsigned  char  work)
{
       CS=0;
       RS=1;
       SPIMsCom(work);
       CS=1;
}
void  AQM1248init()
{
//  AQM1248  initialize
       lcdcmd(0xAE);
       lcdcmd(0xA0);
       lcdcmd(0xC8);
       lcdcmd(0xA3);

       lcdcmd(0x2C);
       delay_ms(2);
       lcdcmd(0x2E);
       delay_ms(2);
       lcdcmd(0x2F);

       lcdcmd(0x23);
       lcdcmd(0x81);
       lcdcmd(0x1C);

       lcdcmd(0xA4);
       lcdcmd(0x40);
       lcdcmd(0xA6);
       lcdcmd(0xAF);
}
void  AQM1248clear()
{
       int  i,j;
       for(i=0;i<6;i++){
               lcdcmd(0xB0+i);  //page0
               lcdcmd(0x10);      //line00
               lcdcmd(0x00);
               for(j=0;j<128;j++){
                       lcdbuf[i][j]=0;
                       lcddat(0x00);
               }
       }
}
void  AQM1248plot(int  x,int  y,int  mode)
{
       if((x<0)||(x>127))  return;
       if((y<0)||(y>47))  return;
       lcdcmd(0xB0+5-(y/8));      //page0
       lcdcmd(0x10+(x>>4));        //line00
       lcdcmd(0x00+(x&0x0f));
       switch(mode){
       case  CLR:
               lcddat(lcdbuf[y/8][x]&=~bitmap[y&7]);  break;
       case  SET:
               lcddat(lcdbuf[y/8][x]|=  bitmap[y&7]);  break;
       case  XOR:
               lcddat(lcdbuf[y/8][x]^=  bitmap[y&7]);  break;
       }
}

#define  abs(a)    (((a)>0)  ?  (a)  :  -(a))
void  AQM1248line(int  x0,  int  y0,  int  x1,  int  y1,int  mode)
{
       int  steep,  t;
       int  deltax,  deltay,  error;
       int  x,  y;
       int  ystep;
       
       steep  =  (abs(y1  -  y0)  >  abs(x1  -  x0));
       if(steep){
               t  =  x0;  x0  =  y0;  y0  =  t;
               t  =  x1;  x1  =  y1;  y1  =  t;
       }
       if(x0  >  x1)  {
               t  =  x0;  x0  =  x1;  x1  =  t;
               t  =  y0;  y0  =  y1;  y1  =  t;
       }
       deltax  =  x1  -  x0;
       deltay  =  abs(y1  -  y0);
       error  =  0;
       y  =  y0;
       if(y0  <  y1)  ystep  =  1;  else  ystep  =  -1;
       for(x=x0;  x<x1;  x++)  {
               if(steep)  AQM1248plot(y,x,mode);  else  AQM1248plot(x,y,mode);
               error  +=  deltay;
               if((error  <<  1)  >=  deltax)  {
                       y  +=  ystep;
                       error  -=  deltax;
               }
       }
}
void  AQM1248box(int  x0,  int  y0,  int  x1,  int  y1,  int  mode)
{
       AQM1248line(x0,y0,x0,y1,mode);
       AQM1248line(x0,y0,x1,y0,mode);
       AQM1248line(x0,y1,x1,y1,mode);
       AQM1248line(x1,y0,x1,y1,mode);
}
int  main(void)
{
       unsigned  int    i;
       int  x,y;

       CLKDIV  =  0;
       TRISA  =  0x000F;  //  RA0,1  input
       TRISB  =  0x0003;
       CNPU1  =  0x003F;  //  CN2,3(RA0,1)CN0,1(RA4,RB4)
       CMCON  =  0;
       AD1PCFG  =  0xFFFF;
       for(i=0;i<50000;i++)  ;
       SPIMsInit();        //  SPIマスタ初期化
//  AQM1248  initialize
       AQM1248init();
       AQM1248clear();
       AQM1248box(0,0,127,47,SET);
       AQM1248line(0,24,127,24,SET);
       AQM1248line(64,0,64,47,SET);
       while(1){
               for(x=0;x<128;x++){
                       y=23*sin(2.0*3.14159/128*x)+24;
                       AQM1248plot(x,y,XOR);
                       y=23*cos(2.0*3.14159/128*x)+24;
                       AQM1248plot(x,y,XOR);
                       delay_ms(10);
               }      
               LATAbits.LATA4^=1;
       }
}


LCD&タッチセンサ活用の素 (基礎入門)
技術評論社
後閑 哲也

amazon.co.jpで買う
Amazonアソシエイト by LCD&タッチセンサ活用の素 (基礎入門) の詳しい情報を見る / ウェブリブログ商品ポータル


テーマ

注目テーマ 一覧


月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ
気持玉数 : 1
ナイス

コメント(0件)

内 容 ニックネーム/日時

コメントする help

ニックネーム
本 文
秋月パーツ、AQM1248でグラフィックPLOT,LINE 趣味のブログ/BIGLOBEウェブリブログ
文字サイズ:       閉じる