グラフィックLCD AQM1248A + PIC 18F4553

投稿日 2014/01/01

48 x 128(132)ドット グラフィックLCD AQM1248APIC 18F4553で制御してみました。

 

AQM1248AのインターフェースはSPIですが、PIC 18F4553が内蔵するSPI(MMSP)は使用せず、ソフトによるGPIO制御としました。

 

今回は温度センサADT7410によって計測した温度を、グラフィックLCDのY軸48ドットに対応付け(1℃/ドット)てドット表示し、温度変化がグラフで見られるようにしてみました。

AQM1248A_1.jpg

写真:昼から夜にかけての室温15時間分を10分間隔でグラフ表示してみました

上部左から計測インターバル(600秒=10分) 計測回数(90回) 計測終了回数(90回目) 計測終了状態

右上から 最高温度(18.0℃) 現在温度(8.5℃) 最低温度(8.5℃)

目盛は10℃毎 1℃/ドットで表示

 

温度を数字でも表示したいので、ASCII文字のフォントを用意しました。
このフォントは独自に作ったもので、8 x 16ドットで1文字を構成しています。
フォント作りは慣れないので、ちょっと格好が悪いですが、後からゆっくり改善しようかと思います。

 

48 x 132ドット分のメモリ領域をSRAMに確保しました
いわゆるグラフィックメモリです。
AQM1248AはY軸方向に8ビット単位(ページ)でアクセスするので、unsigned charの配列で確保しています。
Y軸方向に6ページ。つまり6 x 8 = 48ドットです。 X軸方向(カラム)は132ドットなので、6 x 132 = 792バイトのSRAMが必要です。PICの定番 18F14K50のSRAMは768バイトですから不足するので使用は無理です。そこでSRAMが2KBある18F4553を使用しました。
(前述の文字フォントはコンスタントに確保するのでフラッシュROMに焼かれます)

 

用意した関数(メインからコールしている関数)は、
文字列をポジションx, yに表示する関数 glcd_graphicwrite(x, y, string)
グラフィックメモリ初期化関数 glcd_initgraphic()
1ドット表示する関数 glcd_putpixel(x, y, pixel)
起点から整数値に基づいて垂直(y軸)方向にラインを引く関数 glcd_vline(x, y, value)
グラフィックを描画する glcd_drowgraphic()
グラフィックを消去する関数 glcd_cleargraphic()

 

ソースコード:以下で構成されています。(文字フォントは数字以外は未完成です)
文字数制限により省略部分があります。
コンパイルエラーが出るかも知れません。
main.c
glcd.c
i2c.c
i2c_sensADT7410.c
function.c(ftostring(), itostring()は後閑氏のHPから借用 中身は省略)

 

開発環境
microchip社 MPLAB XIDE V1.70
XC18
pickit3 

 

//main.c
#include <xc.h>
#include <p18f4553.h>

 

#define LED_RED PORTCbits.RC0

 

#pragma config PLLDIV = 5 // (20MHz crystal)
#pragma config CPUDIV = 0 // 1/2 Fosc = 10MHz
#pragma config USBDIV = 2 // Clock source from 96MHz PLL/2
#pragma config FOSC = HS
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config PWRT = OFF
#pragma config BOR = ON
#pragma config BORV = 3
#pragma config VREGEN = ON
#pragma config WDT = OFF
#pragma config WDTPS = 32768
#pragma config MCLRE = ON

 

int timer0_cnt = 0;
unsigned char interval_flag = 0;
int interval;
int temp_value, int_temp;
int loop_cnt, stop_cnt, total_time;
char string[10];
float temp, min_temp, max_temp;

 

void interrupt isr(void){
timer0_cnt++;
if(timer0_cnt >= interval) {

interval_flag = 1;
LED_RED = 1;
timer0_cnt = 0;

}
INTCONbits.TMR0IF = 0; // Clear Interrupt Flag
TMR0H = 255 - 76 + 1; // 1s
TMR0L = 0;
}

 

void init(void){

ADCON1 = 0b00001111; // All Digital
CMCON = 0b00000111; // No Comparator
TRISA = 0;
TRISB = 0;
TRISC = 0;
TRISD = 0;
TRISE =    0;
LATA = 0;
LATB = 0;
LATC = 0;
LATD = 0;
LATE = 0;

}

 

void drow_grid(void){
unsigned char xpos, ypos, limit;

for(xpos = 0; xpos < 95; xpos++){

glcd_putpixel(xpos, 0, 1);

}
for(ypos = 0; ypos < 48; ypos++){

glcd_putpixel(0, ypos, 1);

}
for(ypos = 10; ypos < 50; ypos += 10){
if(ypos == 40) limit = 20; else limit = 95;
for(xpos = 0; xpos < limit; xpos++){

glcd_putpixel(xpos, ypos, 1);

}
}
}

 

void display_info(void){
itostring(4, interval, string);
string[4] = 0;
glcd_graphicwrite(2, 25, string);
itostring(2, loop_cnt, string);
string[2] = 0;
glcd_graphicwrite(2, 60, string);
if(stop_cnt != 0)
itostring(2, stop_cnt, string);
else {

string[0] = 'L';
string[1] = 'P';

}
string[2] = 0;
glcd_graphicwrite(2, 80, string);
//itostring(2, total_time, string);
//glcd_graphicwrite(2, 65, string);
}

 

void main(void){
unsigned char high_byte, low_byte, column;

init();

i2c_init();
i2c_enable();

glcd_init();
glcd_initgraphic();

drow_grid();
glcd_drowgraphic();

T0CON = 0x87; //10bit mode, 1:256
TMR0H = 255 - 76 + 1;
TMR0L = 0;
INTCONbits.TMR0IE = 1;

column = 0;
temp = 0.0;
min_temp = 99.9;
max_temp = 0.0;
interval_flag = 1;
interval = 600;
loop_cnt = 0;
stop_cnt = 90; // 0 = loop

display_info();

INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;

while(1){
if(interval_flag){
while((ADT7410_Get_regvalue(0x02) & 0x80));
high_byte = ADT7410_Get_regvalue(0x00);
low_byte = ADT7410_Get_regvalue(0x01);

temp_value = (high_byte << 5) | (low_byte >> 3);
temp = (float)temp_value / 16.0;
if(temp < min_temp) min_temp = temp;
if(temp >= max_temp) max_temp = temp;
string[4] = 0;
ftostring(2, 1, temp, string);
glcd_graphicwrite(1, 98, string); //temp
ftostring(2, 1, max_temp, string);
glcd_graphicwrite(2, 98, string); //max_temp
ftostring(2, 1, min_temp, string);
glcd_graphicwrite(0, 98, string); //min_temp

int_temp = (int)(temp + 0.5);
glcd_putvline(column, int_temp);
column++;
if(column >= 95) column = 0;

drow_grid();
glcd_drowgraphic();

if(stop_cnt != 0) {
if(loop_cnt >= stop_cnt){

LED_RED = 1;
while(1);

}
loop_cnt++;
}

display_info();
interval_flag = 0;
LED_RED = 0;
}
}
}

 

//glcd.c
#include <xc.h>
#include <p18F4553.h>

 

#define CS PORTDbits.RD4
#define RS PORTDbits.RD5
#define SDI PORTDbits.RD7
#define SCLK PORTDbits.RD6

 

#define _XTAL_FREQ 10000000 

 

unsigned char graphic_mem[6][132]; //グラフィックメモリ

 

const char char_table[95][12] = { //ASCII文字フォント 数字以外は未完成 9以下は省略

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //SP
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //!
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //"
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //#
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //$
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //%
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //&
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //'
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //(
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //)
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //*
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //+
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //,
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, //-
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x00}, //.
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, ///
{0xFE, 0x03, 0x83, 0x63, 0x1B, 0xFE, 0x1F, 0x36, 0x31, 0x30, 0x30, 0x1F}, //0
{0x00, 0x00, 0x06, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x30, 0x3F, 0x3F, 0x30}, //1
{0x1E, 0x03, 0xC3, 0x63, 0x33, 0x1E, 0x18, 0x1E, 0x19, 0x18, 0x18, 0x18}, //2
{0x1E, 0x03, 0xC3, 0xC3, 0xFF, 0xFE, 0x1E, 0x30, 0x30, 0x30, 0x3F, 0x1F}, //3
{0xC0, 0x30, 0x0C, 0x03, 0xFF, 0x00, 0x0F, 0x0C, 0x0C, 0x0C, 0x1F, 0x0C}, //4
{0x3F, 0x63, 0x63, 0x63, 0x63, 0x83, 0x18, 0x30, 0x30, 0x30, 0x30, 0x0F}, //5
{0xFE, 0xC3, 0xC3, 0xC3, 0xC3, 0x86, 0x1F, 0x30, 0x30, 0x30, 0x30, 0x1F}, //6
{0x03, 0x03, 0xC3, 0x63, 0x33, 0x1E, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, //7
{0x3C, 0xC3, 0xC3, 0xC3, 0xC3, 0x3C, 0x0F, 0x30, 0x30, 0x30, 0X30, 0X0f}, //8
{0x3C, 0xC3, 0xC3, 0xC3, 0xC3, 0x7C, 0x00, 0x30, 0x30, 0x30, 0x30, 0x0F}, //9

 

//文字数制限により省略 A - Z a- z その他記号


 

{0x03, 0x03, 0x03, 0xE3, 0x3B, 0x0F, 0x3C, 0x37, 0x33, 0x30, 0x30, 0x30}, //~

};

 

int glcd_IOCtl(unsigned char data){
unsigned char page_offset, byte;

byte = data;
for(page_offset = 0; page_offset < 8; page_offset++){
SCLK = 0;
if(byte & 0x80)

SDI = 1;

else

SDI = 0;

__delay_us(10);
SCLK = 1;
byte = byte << 1;
}
}

 

void glcd_write_command(unsigned char command){

CS = 0;
RS = 0;
glcd_IOCtl(command);
CS = 1;

}

 

void glcd_write_data(unsigned char data){

CS = 0;
RS = 1;
glcd_IOCtl(data);
CS = 1;

}

 

void glcd_init(void){

glcd_write_command(0xAE);
glcd_write_command(0xA0);
glcd_write_command(0xC8);
glcd_write_command(0xA3);

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

glcd_write_command(0x23);
glcd_write_command(0x81);
glcd_write_command(0x13);

glcd_write_command(0xA4);
glcd_write_command(0x40);
glcd_write_command(0xA6);
glcd_write_command(0xAF);

}

 

void glcd_cleargraphic(void){
unsigned char page, column;

for(page = 0; page < 6; page++){
for(column = 0; column < 132; column++){

graphic_mem[page][column] = 0;

}
}
}

 

void glcd_initgraphic(void){

glcd_cleargraphic();

}

 

void glcd_position(unsigned char page, unsigned char column){

unsigned char page_num, column_num;
unsigned char column_H, column_L;

page_num = 0xB0 | (page & 0x0F);
column_num = column;
glcd_write_command(page_num);
column_H = 0x10 | ((column_num >> 4) & 0x0F);
column_L = 0x00 | (column_num & 0x0F);
glcd_write_command(column_H);
glcd_write_command(column_L);

}

 

void glcd_drowgraphic(){
unsigned char page, column;

for(page = 0; page < 6; page++){
glcd_position(page, 0);
for(column = 0; column < 132; column++){

glcd_write_data(graphic_mem[page][column]);

}
}
}

 

void glcd_putpixel(unsigned char xpos, unsigned char ypos, unsigned char pixel){
unsigned char byte, page_num, column_num, page_offset;

page_num = ypos / 8;
page_offset = ypos % 8;
column_num = xpos;
if(pixel == 1) {

byte = 0x80 >> page_offset;
graphic_mem[5 - page_num][column_num] = (graphic_mem[5 - page_num][column_num] & ~byte) | byte;

} else{

byte = 0x80 >> page_offset;
byte = ~byte;
graphic_mem[5 - page_num][column_num] = (graphic_mem[5 - page_num][column_num] & ~byte);

}
}

 

void glcd_putvline(unsigned char column, unsigned char y_value){
unsigned char ypos;

for(ypos = 0; ypos < 48; ypos++){

glcd_putpixel(column, ypos, 0);

}
for(ypos = 0; ypos < y_value; ypos++){

glcd_putpixel(column, ypos, 1);

}
}

 

void glcd_putchar(unsigned char page, unsigned char column, char moji){
unsigned char offset, byte, page_num, column_num;

page_num = page * 2 + 1;
column_num = column;
for(offset = 0; offset < 6; offset++){

byte = char_table[moji - 0x20][offset];
graphic_mem[5 - page_num][column_num] = byte;
column_num++;

}
page_num = page * 2;
column_num = column;
for(offset = 0; offset < 6; offset++){

byte = char_table[moji - 0x20][offset + 6];
graphic_mem[5 - page_num][column_num] = byte;
column_num++;

}
}

 

void glcd_graphicwrite(unsigned char page, unsigned char column, unsigned char* ptr){
unsigned char cnt, column_num;

cnt = 0;
while(*ptr != 0x00){

column_num = column + (cnt * 8);

glcd_putchar(page, column_num, *ptr);

cnt++;

ptr++;

}

}

 

//I2C.c
#include <xc.h>
#include <p18F4553.h>

 

void i2c_init(void)
{

SSPCON1bits.SSPEN = 0;

 

SSPCON1bits.SSPM = 8;
SSPADD = 25;
TRISBbits.TRISB1 = 1;
TRISBbits.TRISB0 = 1;

}

 

void i2c_enable()
{

SSPCON1bits.SSPEN = 1;

}

 

void i2c_disable()
{

SSPCON1bits.SSPEN = 0;

}

 

void i2c_checkbusy()
{

while(SSPCON2bits.SEN || SSPCON2bits.PEN || SSPCON2bits.RCEN

|| SSPCON2bits.ACKEN || SSPSTATbits.BF);
}

 

//i2c_sensADT7410.c
#include <xc.h>
#include <p18f4553.h>

 

#define ADT7410_I2C_ADDR 0x90
#define WRITE_MODE 0x00
#define READ_MODE 0x01

 

void ADT7410_Put_regvalue(unsigned char reg_address, unsigned char byte){
SSPCON2bits.SEN = 1;
while(SSPCON2bits.SEN == 1);

SSPBUF = ADT7410_I2C_ADDR | WRITE_MODE;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){

SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;

}

SSPBUF = reg_address;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){

SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;

}

SSPBUF = byte;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){

SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;

}

SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return;
}

 

unsigned char ADT7410_Get_regvalue(unsigned char reg_address){
unsigned char reg_value;

SSPCON2bits.SEN = 1;
while(SSPCON2bits.SEN == 1);

SSPBUF = ADT7410_I2C_ADDR | WRITE_MODE;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){

SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return(0);

}

delay_us(10);
SSPBUF = reg_address;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){

SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return(0);

}

delay_us(10);
SSPCON2bits.RSEN = 1;
while(SSPCON2bits.RSEN);

SSPBUF = ADT7410_I2C_ADDR | READ_MODE;
while(SSPSTATbits.BF);
if (SSPCON2bits.ACKSTAT){

SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return(0);

}

delay_us(10);
SSPCON2bits.RCEN = 1;
while(SSPCON2bits.RCEN);
reg_value = SSPBUF;
while(SSPSTATbits.BF);
SSPCON2bits.ACKDT = 1;

delay_us(10);
SSPCON2bits.PEN = 1;
while(SSPCON2bits.PEN);
return(reg_value);
}

 

//function.c
#include <xc.h>
#include <p18f4553.h>

 

#define _XTAL_FREQ 10000000

 

void delay_us(int time){

int i;
for(i = 0; i < time; i++) __delay_us(1);

}

 

void delay_ms(int time){

int i;
for(i = 0; i < time; i++) __delay_ms(1);

}

 

void itostring(unsigned char digit, int data, unsigned char *buffer){
//省略
}

 

void ftostring(int seisu, int shousu, float data, unsigned char *buffer){
//省略
}


 

(JF1VRR)