
グラフィックLCD AQM1248A + PIC 18F4553
投稿日 2014/01/01
48 x 128(132)ドット グラフィックLCD AQM1248AをPIC 18F4553で制御してみました。
AQM1248AのインターフェースはSPIですが、PIC 18F4553が内蔵するSPI(MMSP)は使用せず、ソフトによるGPIO制御としました。
今回は温度センサADT7410によって計測した温度を、グラフィックLCDのY軸48ドットに対応付け(1℃/ドット)てドット表示し、温度変化がグラフで見られるようにしてみました。

写真:昼から夜にかけての室温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)