说明
在HC32F460平台上以验证,通过模拟SPI的方式,驱动三线制双通道GC9306 LCD屏幕。(GC9306屏幕有多种规格有并口,3线制SPI,4线制SPI等多种规格)使用前一定要确认好自己屏幕的模式。若本文对你有有用,欢迎点赞收藏。
1. 三线制双通道 GC9306屏幕硬件介绍
引脚 | 功能 | 说明 |
---|---|---|
1 | gnd | 电源地 |
2 | Led_A+ | 背光+极 |
3 | VCC(2V8) | 电源+ |
4 | /Cs | 片选信号 |
5 | RSTB | 复位信号 |
6 | LSCK | SCK SPI时钟信号 |
7 | LSDA | LSDA SPI数据通道1 |
8 | LSA0 | A0 SPI数据通道2 |
9 | LPTE | 帧同步 |
10 | LOVCC | - |
11 | Led_k | 背光 -极 |
12 | gnd | 电源地 |
13 | YD/NC | NC |
14 | XL/NC | NC |
15 | YU/NC | NC |
16 | XR/NC | NC |
2.与HC32F460芯片引脚连接
屏幕 | 单片机 | |
---|---|---|
/cs | -> | PB10 |
LSCK | -> | PB13 |
LSDA | -> | PB14 |
RSTB | -> | PB12 |
A0 | -> | PB15 |
gc9306.h
#ifndef GC9306_H
#define GC9306_H
#define LCDCS(X) (X? (M4_PORT->POSRB_f.POS10 = 1) : (M4_PORT->PORRB_f.POR10 = 1))
#define LCDSDA(X) (X? (M4_PORT->POSRB_f.POS14 = 1) : (M4_PORT->PORRB_f.POR14 = 1))
#define RLCDSDA() M4_PORT->PIDRB_f.PIN14
#define LCDSCL(X) (X? (M4_PORT->POSRB_f.POS13 = 1) : (M4_PORT->PORRB_f.POR13 = 1))
#define LCDRESET(X) (X? (M4_PORT->POSRB_f.POS12 = 1) : (M4_PORT->PORRB_f.POR12 = 1))
#define RS(X) (X? (M4_PORT->POSRB_f.POS15 = 1) : (M4_PORT->PORRB_f.POR15 = 1)) //A0
//LCD的宽和高定义
#define LCD_Width 240
#define LCD_Height 320
void write_comm(INT16U command);
void write_data(INT16U datum);
void serial(INT8U send_data,INT8U comm_data);
void IC_code_init(void);
void read_ID(INT16U comm,INT8U count);
INT8U serial_read();
void writePixel(INT8U x_start, INT8U y_start, INT16U color);
void set_windows_x(INT16U x_strat_add,INT16U x_end_add);
void set_windows_y(INT16U y_strat_add,INT16U y_end_add);
void addres_set(INT16U strat_x,INT16U strat_y,INT16U end_x,INT16U end_y);
void grayotp(); //灰度测试
gc9306.C
#include "gc9306.h"
INT8U SRGB = 0x08;
INT16U driver_clar = 0;
INT8U scan = 0x80;
INT8U r_datum = 0;
INT8U r_data[128] = {0};
INT8U move_y=0; //1 //计算Y轴地址偏离,1就是Y轴偏离1个像素点
INT8U move_x=0; //2 //计算X轴地址偏离,1就是X轴偏离1个像素点
INT8U win_starty=0x00;
INT8U win_startx=0x00;
INT16U addy=320;
INT16U addx=240;
INT16U win_endy = 0x013F;
INT16U win_endx = 0xeF;
void delay(INT16U ms)
{
for(INT16U jj = 0; jj < ms; jj++)
{
for(int ii = 0; ii <10 ; ii++);
}
}
void write_comm(INT16U command)
{
serial(command, 0);
}
void write_data(INT16U datum)
{
serial(datum, 1);
}
void serial(INT8U send_data,INT8U comm_data)
{
INT16U serial1 = 0;
LCDCS(0);
#if serial_SPI4
RS=comm_data;
#else
LCDSDA(comm_data); delay(1);LCDSCL(0); delay(1); LCDSCL(1); delay(1);
#endif
serial1 = send_data;
//serial1 = serial1<<8;
delay(1);
LCDSDA((serial1 & 0X80) >> 7); LCDSCL(0); delay(1);LCDSCL(1);delay(1);
LCDSDA((serial1 & 0X40) >> 6); LCDSCL(0); delay(1);LCDSCL(1);delay(1);
LCDSDA((serial1 & 0X20) >> 5); LCDSCL(0); delay(1);LCDSCL(1);delay(1);
LCDSDA((serial1 & 0X10) >> 4); LCDSCL(0); delay(1);LCDSCL(1);delay(1);
LCDSDA((serial1 & 0X08) >> 3); LCDSCL(0); delay(1); LCDSCL(1);delay(1);
LCDSDA((serial1 & 0X04) >> 2); LCDSCL(0); delay(1);LCDSCL(1);delay(1);
LCDSDA((serial1 & 0X02) >> 1); LCDSCL(0); delay(1);LCDSCL(1);delay(1);
LCDSDA((serial1 & 0X01) >> 0); LCDSCL(0); delay(1);LCDSCL(1);delay(1);
delay(1);
//LCDSCL(0); delay(1);
LCDCS(1);delay(1);
}
void Dual_channel(INT8U H_data,INT8U L_data)
{
INT16U serial1 = 0;
INT16U serial2 = 0;
LCDCS(0);
LCDSDA(1);
//RS=1;
LCDSCL(0);LCDSCL(1);delay(1);LCDSCL(0);delay(1);
serial2=H_data;
serial1=L_data;
//serial2=serial2<<8;
//serial1=serial1<<8;
LCDSDA((serial2 & 0X80) >> 7); RS((serial1 & 0X80) >> 7);LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial2 & 0X40) >> 6); RS((serial1 & 0X40) >> 6);LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial2 & 0X20) >> 5); RS((serial1 & 0X20) >> 5);LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial2 & 0X10) >> 4); RS((serial1 & 0X10) >> 4);LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial2 & 0X08) >> 3); RS((serial1 & 0X08) >> 3);LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial2 & 0X04) >> 2); RS((serial1 & 0X04) >> 2);LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial2 & 0X02) >> 1); RS((serial1 & 0X02) >> 1);LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial2 & 0X01) >> 0); RS((serial1 & 0X01) >> 0);LCDSCL(0); delay(1); LCDSCL(1); delay(1);
// LCDSCL(0); delay(1);
LCDCS(1); delay(1);
}
void read_send(INT8U send_data,INT8U comm_data)
{
INT16U serial1 = 0;
LCDCS(0);
#if serial_SPI4
RS=comm_data;
#else
LCDSDA(comm_data);LCDSCL(0); delay(1);LCDSCL(1); delay(1);
#endif
serial1 = send_data;
//serial1 = serial1<<8;
LCDSDA((serial1 & 0X80) >> 7); LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial1 & 0X40) >> 6); LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial1 & 0X20) >> 5); LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial1 & 0X10) >> 4); LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial1 & 0X08) >> 3); LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial1 & 0X04) >> 2); LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial1 & 0X02) >> 1); LCDSCL(0); delay(1); LCDSCL(1); delay(1);
LCDSDA((serial1 & 0X01) >> 0); LCDSCL(0); delay(1); LCDSCL(1); delay(1);
// LCDSCL(0); delay(1);
LCDCS(0); delay(1);
}
void LCD_Init(void)
{
LCDRESET(1); //set the P4^1 as 1 for the LCDRESET();
delay(20); // Delay 1ms
LCDRESET(0); //set the P4^1 as 0 for the LCDRESET();
delay(100); // Delay 10ms
LCDRESET(1); //set the P4^1 as 1 for the LCDRESET();
delay(300); // Delay 200ms
//************************Start initial sequence****************************//
if(0)
{
// CPT2.8
write_comm(0xfe);
write_comm(0xef);
write_comm(0x36);
write_data(scan|SRGB);
write_comm(0x3a);
write_data(0x05);
//------end display control setting----//
//------Power Control Registers Initial----//
write_comm(0xa4);
write_data(0x44);
write_data(0x44);
write_comm(0xa5);
write_data(0x42);
write_data(0x42);
write_comm(0xaa);
write_data(0x88);
write_data(0x88);
write_comm(0xe8);
write_data(0x11);
write_data(0x0b);
write_comm(0xe3);
write_data(0x01);
write_data(0x10);
write_comm(0xff);
write_data(0x61);
write_comm(0xAC);
write_data(0x00);
write_comm(0xae);
write_data(0x2b);
write_comm(0xad);
write_data(0x33);
write_comm(0xaf);
write_data(0x55);
write_comm(0xa6);
write_data(0x2a);
write_data(0x2a);
write_comm(0xa7);
write_data(0x2b);
write_data(0x2b);
write_comm(0xa8);
write_data(0x18);
write_data(0x18);
write_comm(0xa9);
write_data(0x2a);
write_data(0x2a);
//-----display window 240X320---------//
write_comm(0x2a);
write_data(0x00);
write_data(0x00);
write_data(0x00);
write_data(0xef);
write_comm(0x2b);
write_data(0x00);
write_data(0x00);
write_data(0x01);
write_data(0x3f);
write_comm(0x2c);
write_comm(0x35);
write_data(0x00);
write_comm(0x44);
write_data(0x00);
write_data(0x0a);
write_comm(0xF0);
write_data(0x02);
write_data(0x00);
write_data(0x00);
write_data(0x01);
write_data(0x04);
write_data(0x09);
write_comm(0xF1);
write_data(0x01);
write_data(0x03);
write_data(0x00);
write_data(0x04);
write_data(0x0D);
write_data(0x11);
write_comm(0xF2);
write_data(0x0B);
write_data(0x07);
write_data(0x32);
write_data(0x04);
write_data(0x04);
write_data(0x45);
write_comm(0xF3);
write_data(0x13);
write_data(0x0D);
write_data(0x40);
write_data(0x04);
write_data(0x04);
write_data(0x50);
write_comm(0xF4);
write_data(0x0C);
write_data(0x18);
write_data(0x18);
write_data(0x1C);
write_data(0x1E);
write_data(0x0F);
write_comm(0xF5);
write_data(0x05);
write_data(0x11);
write_data(0x0E);
write_data(0x1B);
write_data(0x1B);
write_data(0x0F);
#if SPI_2DATA
write_comm(0xE9); //双通道
write_data(0x00);
#endif
write_comm(0x11);
delay(300);
write_comm(0x29);
write_comm(0x2c);
}
else
{
//GC9306__BOE2.8
write_comm(0xfe);
write_comm(0xef);
write_comm(0x36);
write_data(scan|SRGB);
write_comm(0x3a);
write_data(0x05);
//------end display control setting----//
//------Power Control Registers Initial----//
write_comm(0xa4);
write_data(0x44);
write_data(0x44);
write_comm(0xa5);
write_data(0x42);
write_data(0x42);
write_comm(0xaa);
write_data(0x88);
write_data(0x88);
write_comm(0xe8);
write_data(0x11);
write_data(0x0b);
write_comm(0xe3);
write_data(0x01);
write_data(0x10);//18
write_comm(0xAC);
write_data(0x00);
write_comm(0xAd);
write_data(0x33);
write_comm(0xae);
write_data(0x2b);
write_comm(0xAf);
write_data(0x55);
write_comm(0xff);
write_data(0x61);
write_comm(0xa6);
write_data(0x2a);
write_data(0x2a);
write_comm(0xa7);
write_data(0x2b);
write_data(0x2b);
write_comm(0xa8);
write_data(0x18);
write_data(0x18);
write_comm(0xa9);
write_data(0x2a);
write_data(0x2a);
//------------gamma setting------------------//
write_comm(0xF0);
write_data(0x02);
write_data(0x00);
write_data(0x00);
write_data(0x01);
write_data(0x03);
write_data(0x00);
write_comm(0xF1);
write_data(0x01);
write_data(0x02);
write_data(0x00);
write_data(0x00);
write_data(0x12);
write_data(0x1D);
write_comm(0xF2);
write_data(0x06);
write_data(0x06);
write_data(0x24);
write_data(0x04);
write_data(0x04);
write_data(0x35);
write_comm(0xF3);
write_data(0x18);
write_data(0x0D);
write_data(0x50);
write_data(0x04);
write_data(0x03);
write_data(0x60);
write_comm(0xF4);
write_data(0x0B);
write_data(0x17);
write_data(0x15);
write_data(0x08);
write_data(0x08);
write_data(0x0F);
write_comm(0xF5);
write_data(0x07);
write_data(0x14);
write_data(0x15);
write_data(0x2E);
write_data(0x30);
write_data(0x0F);
//--------end gamma setting--------------//
#if SPI_2DATA
write_comm(0xE9);
write_data(0x08);
#endif
write_comm(0x11);
delay(300);
write_comm(0x29);
}
//RID=0;
driver_clar=34;//GC9306的ID编码为 34
return;
}
void read_ID(INT16U comm,INT8U count)
{
INT8U count1;
#if serial_of_on
read_send(comm, 0);
#else
write_comm(comm);
#endif
LCDCS(0);
//RS=1;
#if serial_of_on
LCDSCL(1);//串口读ID脉冲,不用时请注解
LCDSCL(0);
#else
WRD=1;
RD0=1;
#endif
r_datum=0;
for(count1=0;count1<count;count1++)
{
#if serial_of_on
r_data[count1] = serial_read();//串口读ID不用时请注解
#else
RD0=0;
DBL=0xFF;
RD0=1;
r_data[count1]=DBL;
#endif
}
LCDCS(1);
r_datum=1;
}
INT8U serial_read()
{
INT8U serial_ID, a;
serial_ID=0;
r_datum=1;
LCDSDA(1);
r_datum=0;
for(a=0;a<8;a++)
{
LCDSCL(0);
__nop;
LCDSCL(1);
__nop;
serial_ID |= RLCDSDA();//LCDSDA();;//SPI4_SDO;
if(a<7)
serial_ID<<=1;
}
return serial_ID;
r_datum=1;
}
void writePixel(INT8U x_start, INT8U y_start, INT16U color)
{
addres_set(x_start,y_start,x_start,y_start);
write_comm(0x2C);
#if data_six_BUS
write_data(color);
#else
#if SPI_2DATA
Dual_channel(color>>8, color&0xff);
#else
write_data(color>>8);
write_data(color&0xff);
#endif
#endif
}
void addres_set(INT16U strat_x,INT16U strat_y,INT16U end_x,INT16U end_y)
{
set_windows_x(strat_x,end_x);
set_windows_y(strat_y,end_y);
}
void set_windows_x(INT16U x_strat_add,INT16U x_end_add)
{
x_strat_add+=move_x;
x_end_add+=move_x;
write_comm(0x2A);
write_data(x_strat_add>>8);
write_data(x_strat_add&0xFF);
write_data(x_end_add>>8);
write_data(x_end_add&0xFF);
}
void set_windows_y(INT16U y_strat_add,INT16U y_end_add)
{
y_strat_add+=move_y;
y_end_add+=move_y;
write_comm(0x2B);
write_data(y_strat_add>>8);
write_data(y_strat_add&0xFF);
write_data(y_end_add>>8);
write_data(y_end_add&0xFF);
}
void display_sixten(INT16U RGB)
{
INT8U hdata;
#if SPI_2DATA
hdata=RGB>>8;
Dual_channel(hdata,(RGB&0xff));
#else
serial(RGB>>8,1);
serial(RGB,1);
#endif
}
void grayotp() //灰度
{
unsigned int up,DOWN,x,cal_x;
INT8U g_up,g_dowy1,g_dowy2,g_dowx1,g_dowx2;
cal_x=addx/16;
g_up=addy/2;
g_dowy1=(g_up/2)/2;//50
g_dowy2=g_up/2;//60
g_dowx1=((addx/2)/2)/2;//30
g_dowx2=((addx/2)/2);//60
set_windows_x(win_startx,win_endx); //set windows to 128
set_windows_y(win_starty,win_endy); //set windows to 160
write_comm(0x2C);
for(up=0;up<g_up;up++)//1.44 64//1.77 80
{
for(x=0;x<cal_x;x++)//128*160=8//160*128=10 //1.44不变
{
display_sixten(0x0000);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0x1082);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0x2104);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0x3186);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0x4208);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0x528A);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0x630C);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0x738E);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0x8C71);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0x9CF3);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0xAD75);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0xBDF7);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0xCE79);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0xDEFB);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0xEF7D);
}
for(x=0;x<cal_x;x++)
{
display_sixten(0xFFFF);
}
}
/********************************************/
cal_x=addx/2;
for(DOWN=0;DOWN<g_dowy1;DOWN++)//y//1.44=21 //1.77=20//160*128=21
{
for(x=0;x<cal_x;x++)//x//128*160=64//160*128=80
{
display_sixten(0xFFFF);
}
for(x=0;x<cal_x;x++)//x//128*160=64//160*128=80
{
display_sixten(0x0000);
}
}
for(DOWN=0;DOWN<g_dowy2;DOWN++)//1.44=22//1.77=40//160*128=22
{
for(x=0;x<g_dowx1;x++)//1.77=16160*128=26
{
display_sixten(0xFFFF);
}
for(x=0;x<g_dowx2;x++)//1.77=32160*128=28
{
display_sixten(0xEF7D);
}
for(x=0;x<g_dowx1;x++)//1.77=16160*128=26
{
display_sixten(0xFFFF);
}
for(x=0;x<g_dowx1;x++)//1.77=16160*128=26
{
display_sixten(0x0000);
}
for(x=0;x<g_dowx2;x++)//1.77=32160*128=28
{
display_sixten(0x1082);
}
for(x=0;x<g_dowx1;x++)//1.77=16160*128=26
{
display_sixten(0x0000);
}
}
for(DOWN=0;DOWN<g_dowy1;DOWN++) //1.44=21//1.77=20//160*128=21
{
for(x=0;x<cal_x;x++)//x//128*160=64//160*128=80
{
display_sixten(0xFFFF);
}
for(x=0;x<cal_x;x++)//x//128*160=64//160*128=80
{
display_sixten(0x0000);
}
}
}
添加文件测试
在main函数中调用初始化程序后,再调用灰度测试函数。
void main()
{
IC_code_init();
while(1)
{
grayotp();
}
}
写在最后
当然以上方式刷新屏幕的速度太慢了,我们下一篇将使用硬件SPi +DMA的方式进行刷新屏幕