相关文章:
【GD32L233C-START评测】1、优点与缺点都很明显的GD32L233C-START(开箱)
【GD32L233C-START评测】2、非阻塞方式点灯,blink,blink,blink……
【GD32L233C-START评测】4、串口不定长数据接收
【GD32L233C-START评测】5、Flash读写——使用内部Flash存储数据
【GD32L233C-START评测】6、硬件I2C驱动0.96吋OLED
【GD32L233C-START评测】7、硬件SPI1驱动RC522
【GD32L233C-START评测】8、获取MCU96位唯一ID、SRAM、FLASH大小
【GD32L233C-START评测】9、IAP程序升级——基于YMODEM协议
【GD32L233C-START评测】10、使用内部参考电压校准adc,adc采样更准确
【GD32L233C-START评测】11、GD32 ISP软件还不支持GD32L233
【GD32L233C-START评测】12、按键——外部中断
【GD32L233C-START评测】13、I2C驱动环境光和接近传感器RPR-0521RS
【GD32L233C-START评测】14、RT-Thread移植到GD32L233(内核,finsh移植)
【GD32L233C-START评测】15、RT-Thread消息队列、多线程使用
【GD32L233C-START评测】16、RT-Thread事件集从中断唤醒任务
【GD32L233C-START评测】17、CMSIS-RTOS2 RTX5移植到GD32L233(内核,多线程)
1、硬件连接
GND GND
3.3V VCC
PB13 SCL
PB15 SDA
PB7 ERS(复位)
PB8 DC(命令数据选择)
PB12 CS(片选)
PB9 BL(背光)
2、字库取摸方式
取模方式:阴码、逆向、列行式
使用PCtoLCD2002软件取摸。
3、图片取摸
水平扫描,16位真彩色
使用Image2Lcd取摸。
4、代码实现
代码兼容软件SPI和硬件SPI两种方式,通过宏SOFTWARE_SPI_ENABLE选择。
(1)宏定义
#define SOFTWARE_SPI_ENABLE 0
#define LCD_RES_LOW() gpio_bit_reset(GPIOB,GPIO_PIN_7)//RES rst
#define LCD_RES_HIGH() gpio_bit_set(GPIOB,GPIO_PIN_7)
#define LCD_DC_LOW() gpio_bit_reset(GPIOB,GPIO_PIN_8)//DC data command select
#define LCD_DC_HIGH() gpio_bit_set(GPIOB,GPIO_PIN_8)
#define LCD_BLK_LOW() gpio_bit_reset(GPIOB,GPIO_PIN_9)//BLK
#define LCD_BLK_HIGH() gpio_bit_set(GPIOB,GPIO_PIN_9)
#define LCD_CS_LOW() gpio_bit_reset(GPIOB,GPIO_PIN_12)//CS
#define LCD_CS_HIGH() gpio_bit_set(GPIOB,GPIO_PIN_12)
#if SOFTWARE_SPI_ENABLE
#define LCD_SCLK_LOW() gpio_bit_reset(GPIOB,GPIO_PIN_13)//SCL=SCLK
#define LCD_SCLK_HIGH() gpio_bit_set(GPIOB,GPIO_PIN_13)
#define LCD_MOSI_LOW() gpio_bit_reset(GPIOB,GPIO_PIN_15)//SDA=MOSI
#define LCD_MOSI_HIGH() gpio_bit_set(GPIOB,GPIO_PIN_15)
#endif
#define USE_HORIZONTAL 1 //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏
#if USE_HORIZONTAL==0||USE_HORIZONTAL==1
#define LCD_W 128 //0x80
#define LCD_H 160 //0xA0
#else
#define LCD_W 160
#define LCD_H 128
#endif
(2)IO以及SPI初始化
void LcdIoInit(void)
{
rcu_periph_clock_enable(RCU_GPIOB);
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9);
#if SOFTWARE_SPI_ENABLE
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_12 |GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12 |GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
#else
/* SPI1 :
PB12/CS
PB13/SCK
PB14/MISO
PB15/MOSI
*/
/* SPI1 GPIO configuration: NSS/PB12 */
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_12 );
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
/* SPI1 GPIO configuration: SCK/PB13, MISO/PB14, MOSI/PB15 */
gpio_af_set(GPIOB, GPIO_AF_6, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
spi_parameter_struct spi_init_struct;
rcu_periph_clock_enable(RCU_SPI1);
spi_i2s_deinit(SPI1);
spi_struct_para_init(&spi_init_struct);
/* SPI1 parameter configuration */
spi_init_struct.trans_mode = SPI_BIDIRECTIONAL_TRANSMIT;
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;
spi_init_struct.prescale = SPI_PSC_2;
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI1, &spi_init_struct);
spi_crc_polynomial_set(SPI1, 7);
spi_enable(SPI1);
#endif
}
(3)SPI写数据
void LCD_Writ_Bus(uint8_t dat)
{
LCD_CS_LOW();
#if SOFTWARE_SPI_ENABLE
u8 i;
for(i=0;i<8;i++)
{
LCD_SCLK_LOW();
if(dat&0x80)
{
LCD_MOSI_HIGH();
}
else
{
LCD_MOSI_LOW();
}
LCD_SCLK_HIGH();
dat<<=1;
}
#else
spi_i2s_data_transmit(SPI1, dat);
while(spi_i2s_flag_get(SPI1, SPI_FLAG_TBE) == RESET) {};
#endif
LCD_CS_HIGH();
}
(4)驱动代码
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA8(uint8_t dat)
{
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA(uint16_t dat)
{
LCD_Writ_Bus(dat>>8);
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:LCD写入命令
入口数据:dat 写入的命令
返回值: 无
******************************************************************************/
void LCD_WR_REG(uint8_t dat)
{
LCD_DC_LOW();//写命令
LCD_Writ_Bus(dat);
LCD_DC_HIGH();//写数据
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
if(USE_HORIZONTAL==0)
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1+2);
LCD_WR_DATA(x2+2);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1+1);
LCD_WR_DATA(y2+1);
LCD_WR_REG(0x2c);//储存器写
}
else if(USE_HORIZONTAL==1)
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1+2);
LCD_WR_DATA(x2+2);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1+1);
LCD_WR_DATA(y2+1);
LCD_WR_REG(0x2c);//储存器写
}
else if(USE_HORIZONTAL==2)
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1+1);
LCD_WR_DATA(x2+1);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1+2);
LCD_WR_DATA(y2+2);
LCD_WR_REG(0x2c);//储存器写
}
else
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1+1);
LCD_WR_DATA(x2+1);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1+2);
LCD_WR_DATA(y2+2);
LCD_WR_REG(0x2c);//储存器写
}
}
/******************************************************************************
函数说明:LCD初始化,包含硬件IO
入口数据:无
返回值: 无
******************************************************************************/
void LcdInit(void)
{
LcdIoInit();//初始化GPIO
LCD_RES_LOW();//复位
DelayMs(100);
LCD_RES_HIGH();
DelayMs(100);
LCD_BLK_HIGH();//打开背光
DelayMs(100);
//************* Start Initial Sequence **********//
LCD_WR_REG(0x11); //Sleep out
DelayMs(120); //Delay 120ms
//------------------------------------ST7735S Frame Rate-----------------------------------------//
LCD_WR_REG(0xB1);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_REG(0xB2);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_REG(0xB3);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
//------------------------------------End ST7735S Frame Rate---------------------------------//
LCD_WR_REG(0xB4); //Dot inversion
LCD_WR_DATA8(0x03);
//------------------------------------ST7735S Power Sequence---------------------------------//
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x04);
LCD_WR_REG(0xC1);
LCD_WR_DATA8(0XC0);
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x8D);
LCD_WR_DATA8(0x2A);
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x8D);
LCD_WR_DATA8(0xEE);
//---------------------------------End ST7735S Power Sequence-------------------------------------//
LCD_WR_REG(0xC5); //VCOM
LCD_WR_DATA8(0x1A);
LCD_WR_REG(0x36); //MX, MY, RGB mode
if(USE_HORIZONTAL==0)
LCD_WR_DATA8(0x00);
else if(USE_HORIZONTAL==1)
LCD_WR_DATA8(0xC0);
else if(USE_HORIZONTAL==2)
LCD_WR_DATA8(0x70);
else
LCD_WR_DATA8(0xA0);
//------------------------------------ST7735S Gamma Sequence---------------------------------//
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x22);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x0A);
LCD_WR_DATA8(0x2E);
LCD_WR_DATA8(0x30);
LCD_WR_DATA8(0x25);
LCD_WR_DATA8(0x2A);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x26);
LCD_WR_DATA8(0x2E);
LCD_WR_DATA8(0x3A);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x13);
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x16);
LCD_WR_DATA8(0x06);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x2D);
LCD_WR_DATA8(0x26);
LCD_WR_DATA8(0x23);
LCD_WR_DATA8(0x27);
LCD_WR_DATA8(0x27);
LCD_WR_DATA8(0x25);
LCD_WR_DATA8(0x2D);
LCD_WR_DATA8(0x3B);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x13);
//------------------------------------End ST7735S Gamma Sequence-----------------------------//
LCD_WR_REG(0x3A); //65k mode
LCD_WR_DATA8(0x05);
LCD_WR_REG(0x29); //Display on
}
/******************************************************************************
函数说明:在指定区域填充颜色
入口数据:xsta,ysta 起始坐标
xend,yend 终止坐标
color 要填充的颜色
返回值: 无
******************************************************************************/
void LcdFill(uint16_t xsta,uint16_t ysta,uint16_t xend,uint16_t yend,uint16_t color)
{
uint16_t i,j;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);//设置显示范围
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
LCD_WR_DATA(color);
}
}
}
/******************************************************************************
函数说明:在指定位置画点
入口数据:x,y 画点坐标
color 点的颜色
返回值: 无
******************************************************************************/
void LcdDrawPoint(uint16_t x,uint16_t y,uint16_t color)
{
LCD_Address_Set(x,y,x,y);//设置光标位置
LCD_WR_DATA(color);
}
/******************************************************************************
函数说明:画线
入口数据:x1,y1 起始坐标
x2,y2 终止坐标
color 线的颜色
返回值: 无
******************************************************************************/
void LcdDrawLine(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t color)
{
uint16_t t;
int xerr=0,yerr=0,delta_x,delta_y,distance;
int incx,incy,uRow,uCol;
delta_x=x2-x1; //计算坐标增量
delta_y=y2-y1;
uRow=x1;//画线起点坐标
uCol=y1;
if(delta_x>0)incx=1; //设置单步方向
else if (delta_x==0)incx=0;//垂直线
else {incx=-1;delta_x=-delta_x;}
if(delta_y>0)incy=1;
else if (delta_y==0)incy=0;//水平线
else {incy=-1;delta_y=-delta_y;}
if(delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
else distance=delta_y;
for(t=0;t<distance+1;t++)
{
LcdDrawPoint(uRow,uCol,color);//画点
xerr+=delta_x;
yerr+=delta_y;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
/******************************************************************************
函数说明:画矩形
入口数据:x1,y1 起始坐标
x2,y2 终止坐标
color 矩形的颜色
返回值: 无
******************************************************************************/
void LcdDrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint16_t color)
{
LcdDrawLine(x1,y1,x2,y1,color);
LcdDrawLine(x1,y1,x1,y2,color);
LcdDrawLine(x1,y2,x2,y2,color);
LcdDrawLine(x2,y1,x2,y2,color);
}
/******************************************************************************
函数说明:画圆
入口数据:x0,y0 圆心坐标
r 半径
color 圆的颜色
返回值: 无
******************************************************************************/
void LcdDrawCircle(uint16_t x0,uint16_t y0,uint8_t r,uint16_t color)
{
int a,b;
a=0;b=r;
while(a<=b)
{
LcdDrawPoint(x0-b,y0-a,color); //3
LcdDrawPoint(x0+b,y0-a,color); //0
LcdDrawPoint(x0-a,y0+b,color); //1
LcdDrawPoint(x0-a,y0-b,color); //2
LcdDrawPoint(x0+b,y0+a,color); //4
LcdDrawPoint(x0+a,y0-b,color); //5
LcdDrawPoint(x0+a,y0+b,color); //6
LcdDrawPoint(x0-b,y0+a,color); //7
a++;
if((a*a+b*b)>(r*r))//判断要画的点是否过远
{
b--;
}
}
}
/******************************************************************************
函数说明:显示单个字符
入口数据:x,y显示坐标
ch 要显示的字符
fc 字的颜色
bc 字的背景色
csize 字号
返回值: 无
******************************************************************************/
void LcdShowChar(uint16_t x,uint16_t y,uint8_t ch,uint16_t fc,uint16_t bc,uint8_t csize)
{
const unsigned char *temp;
uint8_t i,j,k;
uint16_t x0=x,y0=y;
uint8_t row=0,column=0;
row=(csize/8+((csize%8)?1:0)); //计算行
column=csize/2; //列
ch=ch-' '; //得到偏移后的值
switch(csize)
{
case 12:temp=Ascii_6x12[ch]; break;
case 16:temp=Ascii_8x16[ch]; break;
case 24:temp=Ascii_12x24[ch]; break;
case 32:temp=Ascii_16x32[ch]; break;
default: temp=Ascii_6x12[ch]; break;
}
//显示要与取模方式保持一致
for(i=0;i<row;i++)
{
for(j=0;j<column;j++)
{
for(k=0;k<8;k++)
{
if((*temp)&(0x01<<k))
{
LcdDrawPoint(x,y,fc);//画一个点,字体色
}
else
{
LcdDrawPoint(x,y,bc);//画一个点,背景色
}
y++;
}
y=y0;
x++;
temp++;
}
x=x0;
y0+=8;
y=y0;
}
}
/******************************************************************************
函数说明:显示字符串
入口数据:x,y显示坐标
*p 要显示的字符串
fc 字的颜色
bc 字的背景色
csize 字号
返回值: 无
******************************************************************************/
void LcdShowString(uint16_t x,uint16_t y,const char *p,uint16_t fc,uint16_t bc,uint8_t csize)
{
while(*p!='\0')
{
LcdShowChar(x,y,*p,fc,bc,csize);
x+=csize/2;
p++;
}
}
/******************************************************************************
函数说明:显示汉字字符
入口数据:x,y显示坐标
index 汉字字符索引
fc 字的颜色
bc 字的背景色
返回值: 无
******************************************************************************/
void LcdShow16x16Hz(uint32_t x, uint32_t y, uint8_t index, uint16_t fc, uint16_t bc)
{
const char *temp=Hzk[index]; // 获取字体数据在数组中的的起始位置
uint8_t y0=y,x0=x;
uint8_t i,j,k;
uint8_t row=0,column=0;
row=16/8;
column=16;
//显示要与取模方式保持一致
for(i=0;i<row;i++)
{
for(j=0;j<column;j++)
{
for( k=0;k<8;k++)
{
if(*temp&(0x01<<k))
{
LcdDrawPoint(x,y,fc);//画一个点,字体色
}
else
{
LcdDrawPoint(x,y,bc);//画一个点,背景色
}
y++;
}
temp++;
x++;
y=y0;
}
x=x0;
y0+=8;
y=y0;
}
}
/******************************************************************************
函数说明:显示图片
入口数据:x,y显示坐标
width 图片宽度
height 图片高度
image 图片数据
返回值: 无
******************************************************************************/
void LcdShowImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const uint8_t *image)
{
uint16_t colorData=0;
uint32_t cnt=0;
uint16_t i,j;
for( i=0; i<height; i++) // 一行一行地显示
{
LCD_Address_Set(x, y+i, x+width, y+height); // 重新设置光标位置
for( j=0; j<width; j++) // 一行中,从左到事,逐个像素处理
{
colorData=(image[cnt*2+1]<<8) | image[cnt*2];
LCD_WR_DATA(colorData); // 写入16位颜色数据
cnt++;
}
}
}
(5)测试代码
void LcdTest(void)
{
LcdInit();//LCD初始化
LcdFill(0,0,LCD_W,LCD_H,BLACK);
LcdShow16x16Hz(32, 0, 0, YELLOW, BLACK);
LcdShow16x16Hz(48, 0, 1, YELLOW, BLACK);
LcdShow16x16Hz(64, 0, 2, YELLOW, BLACK);
LcdShow16x16Hz(80, 0, 3, YELLOW, BLACK);
LcdShowString(32,24,"GD32L233",BLUE, BLACK,16);
LcdShowImage (14,40, 100, 93, gImage_zan);//winxin_gImage_x
}
5、现象