Hello,
I’ve been trying to develop my own code with the LCD128x64. And I’m quite happy that I learned a lot of things and enjoyed working with this LCD.
I’ve done pixel/line draw, send image and default non graphical chars.
I know drawing a box would be relatively easy but drawing a circle is really difficult I didn’t know what is the correct arithmetic to do it.
I want to learn how to draw a circle and custom chars. And also learn other things about the best way to use this LCD for GUI projects.
Here’s my code:
/*
Project name: lcd128x64
Author: r1s8k
Date: 22/12/2019, 12:25 AM
Project specs: This is the source file of the lcd128x64 driver that uses
MCP23017 as the lcd driver using SPI interface
*/
#include <avr/io.h>
#include <Arduino.h>
#include <SPI.h>
#include <avr/pgmspace.h>
#include "lcd128x64_spi.h"
////////////////////////////////////////////////////////////////////////////////////////////
// global variables
static uint8_t graphics, horizontal,y_pre,p_dr_act,block_pre;
//static uint16_t p_buf;
static uint16_t p_pre;
uint8_t p_hi,p_lo,p_block,p_pos,p_bit;
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// control functions
// init
void lcd128x64_init(void){
pinMode(CS_PIN, OUTPUT);
pinMode(CLK_PIN, OUTPUT);
pinMode(MOSI_PIN, OUTPUT);
digitalWrite(CS_PIN, LOW); // disable CS_PIN
SPI.begin();
_delay_ms(100); // trying initial delay
digitalWrite(CS_PIN, HIGH); // enable CS_PIN
_delay_ms(50); // datasheet says > 40ms
lcd128x64_cmd(FUNCTION_SET_BASIC); //_delay_us(28);// datasheet says > 100us - 72 = 28us
lcd128x64_cmd(FUNCTION_SET_BASIC); //_delay_us(28);// important for going to / coming back from graph mode
lcd128x64_cmd(DISABLE_V_SCROLL); // if you have extended list to scroll
lcd128x64_cmd(DISPLAY_CONTROL); //_delay_us(28);// display = 1, cursor = 0, blink = 0
lcd128x64_cmd(ENTERY_MODE); // cursor = right, display shift = 0
lcd128x64_cmd(DISPLAY_CLEAR);
lcd128x64_cmd(RETURN_HOME);
graphics = 0;
horizontal = 0;
}
// command tx
void lcd128x64_cmd(uint8_t cmd){
SPI.transfer(CMD_MSK);
SPI.transfer(cmd & 0xf0);
SPI.transfer(cmd << 4);
if(cmd == 0x01)_delay_us(1600); else _delay_us(72);
}
// data tx
void lcd128x64_data(uint8_t data){
SPI.transfer(DATA_MSK);
SPI.transfer(data & 0xf0);
SPI.transfer(data << 4);_delay_us(72);
}
// move cursor
void lcd128x64_move_cursor(uint8_t row, uint8_t col){
if (row == 1)lcd128x64_cmd(0x80 + (col - 1));
else if (row == 2)lcd128x64_cmd(0x90 + (col - 1));
else if (row == 3)lcd128x64_cmd(0x88 + (col - 1));
else if (row == 4)lcd128x64_cmd(0x98 + (col - 1));
}
// clear lcd
void lcd128x64_clr(void){
uint8_t y,x;
lcd128x64_graphics_set_mode(1);
for(y=0;y<32;y++){
for(x=0;x<8;x++){
lcd128x64_cmd(0x80+y);lcd128x64_cmd(0x80+x);
lcd128x64_data(0x00);lcd128x64_data(0x00);
}
}
for(y=32;y<64;y++){
for(x=0;x<8;x++){
lcd128x64_cmd(0x80+y-32);lcd128x64_cmd(0x88+x);
lcd128x64_data(0x00);lcd128x64_data(0x00);
}
}
}
// graphics mode
void lcd128x64_graphics_set_mode(uint8_t mode){
lcd128x64_cmd(FUNCTION_SET_EXTENDED);
if(mode){
lcd128x64_cmd(GRAPHICS_ON1);
lcd128x64_cmd(GRAPHICS_ON2);
graphics = GRAPH;
}
else{
lcd128x64_cmd(GRAPHICS_OFF1);
lcd128x64_cmd(GRAPHICS_OFF2);
graphics = TEXT;
}
}
// write chars
void lcd128x64_write_chars(uint8_t row, uint8_t col, uint8_t *str, uint8_t w){
// row1: 80H~8FH // row2: 90H~9FH // row3: 88H~AFH // row4: 98H~BFH
if(graphics){lcd128x64_graphics_set_mode(0);}
if (row == 1)lcd128x64_cmd(0x80 + (col - 1));
else if (row == 2)lcd128x64_cmd(0x90 + (col - 1));
else if (row == 3)lcd128x64_cmd(0x88 + (col - 1));
else if (row == 4)lcd128x64_cmd(0x98 + (col - 1));
uint8_t i;
for(i=0; i<w; i++){lcd128x64_data(str[i]);}
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
// draw functions
// pixel set
void lcd128x64_pixel_set(uint8_t y_axis, uint8_t x_axis){
uint16_t p_buf;
if(!graphics){lcd128x64_graphics_set_mode(1);}
p_block = x_axis / 16; // calculate x_axis block
x_axis ^= 127;
p_pos = (x_axis % 16); // calculate the position of pixel in 16-bit
p_buf = (1 << p_pos); // set the bit
if(!p_dr_act){
p_dr_act = 1; // set pixel draw activate flag
y_pre = y_axis; // copy y_axis current position
block_pre = p_block; // store the first block
}
if(block_pre != p_block){ // if block changed
p_pre = 0; // clear global pixel buffer
block_pre = p_block; // store new block,
} // to disable triggering this check
if(y_axis == y_pre){
p_pre |= p_buf; // put current pixel in global buffer
p_buf |= p_pre; // put previous pixels in local buffer
}
else{ // when changing the row,
y_pre = y_axis; // copy new row position
p_pre = 0; // clear global buffer
p_pre = p_buf; // store the last pixel position
}
if(y_axis<32){
lcd128x64_cmd(0x80+y_axis);
lcd128x64_cmd(0x80+p_block);
lcd128x64_data(p_buf>>8);
lcd128x64_data(p_buf);
}
else{
lcd128x64_cmd((0x80+y_axis)-32);
lcd128x64_cmd(0x88+p_block);
lcd128x64_data(p_buf>>8);
lcd128x64_data(p_buf);
}
}
// pixel clear
void lcd128x64_pixel_clear(uint8_t y_axis, uint8_t x_axis){
uint16_t p_msk;
if(!graphics){lcd128x64_graphics_set_mode(1);}
p_block = x_axis / 16;
x_axis ^= 127;
p_pos = (x_axis % 16);
p_msk &= ~(1 << p_pos);
if(y_axis<32){
lcd128x64_cmd(0x80+y_axis);
lcd128x64_cmd(0x80+p_block);
lcd128x64_data(p_msk>>8);
lcd128x64_data(p_msk);
}
else{
lcd128x64_cmd((0x80+y_axis)-32);
lcd128x64_cmd(0x88+p_block);
lcd128x64_data(p_msk>>8);
lcd128x64_data(p_msk);
}
}
// draw image
void lcd128x64_img(unsigned char *img){
uint8_t y,x;
if(!graphics){lcd128x64_graphics_set_mode(1);}
for(y=0;y<32;y++){
for(x=0;x<8;x++){
lcd128x64_cmd(0x80+y);
lcd128x64_cmd(0x80+x);
lcd128x64_data(pgm_read_byte_near(&img[(y*16)+(x*2)]));
lcd128x64_data(pgm_read_byte_near(&img[(y*16)+((x*2)+1)]));
}
}
for(y=32;y<64;y++){
for(x=0;x<8;x++){
lcd128x64_cmd((0x80+y)-32);
lcd128x64_cmd(0x88+x);
lcd128x64_data(pgm_read_byte_near(&img[(y*16)+(x*2)]));
lcd128x64_data(pgm_read_byte_near(&img[(y*16)+((x*2)+1)]));
}
}
}
// draw line
void lcd128x64_line(uint8_t y0, uint8_t y1, uint8_t x0, uint8_t x1){
uint8_t ih,iw,j,h,w,div;
h = y1 - y0;
w = x1 - x0;
if(w>h){
div = w/h;
for(ih=y0,iw=x0;iw<x1;iw++){
lcd128x64_pixel_set(ih,iw);
if((iw%div)==(div-1)){ih++;}
}
}
else{
div = h/w;
for(ih=y0,iw=x0;ih<y1;ih++){
lcd128x64_pixel_set(ih,iw);
if((ih%div)==(div-1)){iw++;}
}
}
}
And there is the current function to draw a circle I’m working on:
// draw circle
void lcd128x64_circle(uint8_t y, uint8_t x, uint8_t r){
uint8_t py,px,d,f;
if(y>x){
d = y/x;
for(py=y-r,px=x,f=0;py<y;py++){
lcd128x64_pixel_set(py,px);
//if(((px%d))==(d-1)){py++;}
if((py%(d%f))==1){px++;f++;}
}
}
else{
d = x/y;
for(py=y-r,px=x;px<x+r;px++){
lcd128x64_pixel_set(py,px);
if(((px%d))==(d-1)){py++;}
}
}
}