ESP32驱动非常规LCD屏幕(三线SPI)0.85寸
·
最近用到了非常小众的TFT LCD屏幕,其尺寸只有0.85寸(128x160),驱动芯片是GC9107,通讯接口是半双工SPI,功能引脚为:
mosi 数据线,在半双工模式收和发都通过这一条数据线,同一时刻只能接受或者发送。
clk 时钟线,同步通信。
cs 片选线。
dc 写命令/数据控制线,有的地方叫rs。
可以用esp32的通用spi接口驱动或者用io口模拟spi通信驱动。
一、硬件spi驱动
spi_device_handle_t spi_dev;
void init_spi_3wire()
{
// 1. 配置SPI总线
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI, // MOSI/SDIO引脚
.miso_io_num = -1, // 禁用MISO
.sclk_io_num = PIN_NUM_CLK, // SCK时钟引脚
.quadhd_io_num = -1, // 禁用其他功能
.quadwp_io_num = -1,
.max_transfer_sz = 4096, // 最大传输长度
.flags = SPICOMMON_BUSFLAG_DUAL // 启用半双工标志
};
spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH_AUTO);
// 2. 添加从设备
spi_device_interface_config_t dev_cfg = {
.clock_speed_hz = 10 * 1000 * 1000, // 时钟频率10MHz
.mode = 3, // SPI模式3 (CPOL=1, CPHA=1)
.spics_io_num = PIN_NUM_CS, // CS片选引脚
.queue_size = 7, // 事务队列长度
// .pre_cb = lcd_spi_pre_transfer_callback, // SPI发送数据前执行的回调函数,一般用于SPI屏幕的D/C信号切换
.flags = SPI_DEVICE_HALFDUPLEX // 半双工模式
};
spi_bus_add_device(SPI2_HOST, &dev_cfg, &spi_dev);
}
初始化:(初始化dc引脚,调用以上spi初始化)
//硬件SPI初始化
void SPI_COM_Init(void)
{
gpio_config_t lcd_dc_cfg = {
.pin_bit_mask = (1ULL<<PIN_NUM_DC), //配置引脚
.mode =GPIO_MODE_OUTPUT, //输出模式
.pull_up_en = GPIO_PULLUP_DISABLE, //不使能上拉
.pull_down_en = GPIO_PULLDOWN_DISABLE, //不使能下拉
.intr_type = GPIO_INTR_DISABLE //不使能引脚中断
};
gpio_config(&lcd_dc_cfg);
init_spi_3wire();
}
发送:
// 发送命令(TX模式)
uint8_t cmd = 0x9F;
spi_transaction_t t = {
.length = 8, // 命令长度(位)
.tx_buffer = &cmd,
.rx_buffer = NULL
};
spi_device_transmit(spi_dev, &t);
接收:(发送空白buffer会返回数据)spi通信本质是数据交换
// 切换为接收模式(RX模式)
uint8_t id_buf[3] = {0};
t.length = 24; // 3字节ID
t.tx_buffer = NULL;
t.rx_buffer = id_buf;
spi_device_transmit(spi_dev, &t); // 自动切换MOSI为输入
二、往lcd驱动gc9107寄存器写值
硬件spi写:(写命令/写数据通过设置dc引脚决定)
//写寄存器函数
//data:寄存器值
void LCD_WR_REG(u8 data)
{
LCD_RS_CLR;//dc引脚
spi_transaction_t t = {
.length = 8, // 命令长度(位)
.tx_buffer = &data,
.rx_buffer = NULL
};
spi_device_transmit(spi_dev, &t);
LCD_RS_SET;
}
//写8位数据函数
void LCD_WR_DATA(u8 data)
{
LCD_RS_SET;
spi_transaction_t t = {
.length = 8, // 命令长度(位)
.tx_buffer = &data,
.rx_buffer = NULL
};
spi_device_transmit(spi_dev, &t);
}
软件spi(io口模拟):
//写寄存器函数
//data:寄存器值
void LCD_WR_REG(u8 data)
{
u8 i;
LCD_RS_CLR;
LCD_CS_CLR;
//以下为软件SPI代码
for(i=0;i<8;i++)
{
LCD_CLK_CLR;
if(data&0x80)
{
LCD_DATA_SET;
}
else
{
LCD_DATA_CLR;
}
LCD_CLK_SET;
data<<=1;
}
LCD_CS_SET;
LCD_RS_SET;
}
//写8位数据函数
//用宏定义,提高速度.
void LCD_WR_DATA(u8 data)
{
u8 i;
LCD_RS_SET;
LCD_CS_CLR;
//以下为软件SPI代码
for(i=0;i<8;i++)
{
LCD_CLK_CLR;
if(data&0x80)
{
LCD_DATA_SET;
}
else
{
LCD_DATA_CLR;
}
LCD_CLK_SET;
data<<=1;
}
LCD_CS_SET;
}
三、完整驱动
lcd.c
#include "spi_lcd.h"
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "stdlib.h"
#include "font.h"
/////////////////////////////// SPI ////////////////////////////////
// void lcd_spi_pre_transfer_callback(spi_transaction_t *t)
// {
// int dc=(int)t->user;
// gpio_set_level(PIN_NUM_DC, dc);
// }
spi_device_handle_t spi_dev;
void init_spi_3wire()
{
// 1. 配置SPI总线
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI, // MOSI/SDIO引脚
.miso_io_num = -1, // 禁用MISO
.sclk_io_num = PIN_NUM_CLK, // SCK时钟引脚
.quadhd_io_num = -1, // 禁用其他功能
.quadwp_io_num = -1,
.max_transfer_sz = 4096, // 最大传输长度
.flags = SPICOMMON_BUSFLAG_DUAL // 启用半双工标志
};
spi_bus_initialize(SPI2_HOST, &bus_cfg, SPI_DMA_CH_AUTO);
// 2. 添加从设备
spi_device_interface_config_t dev_cfg = {
.clock_speed_hz = 10 * 1000 * 1000, // 时钟频率10MHz
.mode = 3, // SPI模式3 (CPOL=1, CPHA=1)
.spics_io_num = PIN_NUM_CS, // CS片选引脚
.queue_size = 7, // 事务队列长度
// .pre_cb = lcd_spi_pre_transfer_callback, // SPI发送数据前执行的回调函数,一般用于SPI屏幕的D/C信号切换
.flags = SPI_DEVICE_HALFDUPLEX // 半双工模式
};
spi_bus_add_device(SPI2_HOST, &dev_cfg, &spi_dev);
}
/////////////////////////////// lcd ///////////////////////////////////
//画笔颜色,背景颜色
u16 POINT_COLOR = 0x0000,BACK_COLOR = 0xFFFF;
u16 DeviceCode;
//////////////////////////////////////
//硬件SPI初始化
void SPI_COM_Init(void)
{
gpio_config_t lcd_dc_cfg = {
.pin_bit_mask = (1ULL<<PIN_NUM_DC), //配置引脚
.mode =GPIO_MODE_OUTPUT, //输出模式
.pull_up_en = GPIO_PULLUP_DISABLE, //不使能上拉
.pull_down_en = GPIO_PULLDOWN_DISABLE, //不使能下拉
.intr_type = GPIO_INTR_DISABLE //不使能引脚中断
};
gpio_config(&lcd_dc_cfg);
init_spi_3wire();
}
//////////////////////////////////////
//写寄存器函数
//data:寄存器值
void LCD_WR_REG(u8 data)
{
// u8 i;
LCD_RS_CLR;
// LCD_CS_CLR;
spi_transaction_t t = {
.length = 8, // 命令长度(位)
.tx_buffer = &data,
.rx_buffer = NULL
};
spi_device_transmit(spi_dev, &t);
#if 0
//以下为软件SPI代码
// for(i=0;i<8;i++)
// {
// LCD_CLK_CLR;
// if(data&0x80)
// {
// LCD_DATA_SET;
// }
// else
// {
// LCD_DATA_CLR;
// }
// LCD_CLK_SET;
// data<<=1;
}
#endif
// LCD_CS_SET;
LCD_RS_SET;
}
//写8位数据函数
//用宏定义,提高速度.
void LCD_WR_DATA(u8 data)
{
// u8 i;
LCD_RS_SET;
// LCD_CS_CLR;
spi_transaction_t t = {
.length = 8, // 命令长度(位)
.tx_buffer = &data,
.rx_buffer = NULL
};
spi_device_transmit(spi_dev, &t);
#if 0
//以下为软件SPI代码
// for(i=0;i<8;i++)
// {
// LCD_CLK_CLR;
// if(data&0x80)
// {
// LCD_DATA_SET;
// }
// else
// {
// LCD_DATA_CLR;
// }
// LCD_CLK_SET;
// data<<=1;
// }
#endif
// LCD_CS_SET;
}
void LCD_WR_DATA16(u16 dat)
{
LCD_WR_DATA(dat >> 8);
LCD_WR_DATA(dat);
}
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
{
LCD_WR_REG(0x2a);//?????
LCD_WR_DATA16(x1);
LCD_WR_DATA16(x2);
LCD_WR_REG(0x2b);//?????
LCD_WR_DATA16(y1);
LCD_WR_DATA16(y2);
LCD_WR_REG(0x2c);//????
}
void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color)
{
u16 i,j;
// u8 retry=0;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);//??????
//以下为提升帧频速度时考虑使用的,18Mhz时帧频大概16帧/S
// LCD_RS_SET;
// LCD_CS_CLR;
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
LCD_WR_DATA16(color);
//以下为提升帧频速度时考虑使用的,18Mhz时帧频大概16帧/S
// while((SPI1->SR&1<<1)==0)//等待发送区空
// {
// retry++;
// if(retry>200)return;
// }
// SPI1->DR=color >> 8; //发送一个byte
//
// retry=0;
// while((SPI1->SR&1<<1)==0)//等待发送区空
// {
// retry++;
// if(retry>200)return ;
// }
// SPI1->DR=color; //发送一个byte
}
}
LCD_CS_SET;
}
void LCD_Fill_PIC(u16 xsta,u16 ysta,u16 xend,u16 yend,const u8 *data)
{
u16 i,j;
// u8 retry=0;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);//??????
//以下为提升帧频速度时考虑使用的,18Mhz时帧频大概16帧/S
// LCD_RS_SET;
// LCD_CS_CLR;
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
LCD_WR_DATA(*data);
data++;
LCD_WR_DATA(*data);
data++;
//以下为提升帧频速度时考虑使用的,18Mhz时帧频大概16帧/S
// while((SPI1->SR&1<<1)==0)//等待发送区空
// {
// retry++;
// if(retry>200)return;
// }
// SPI1->DR=color >> 8; //发送一个byte
//
// retry=0;
// while((SPI1->SR&1<<1)==0)//等待发送区空
// {
// retry++;
// if(retry>200)return ;
// }
// SPI1->DR=color; //发送一个byte
}
}
LCD_CS_SET;
}
// void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color)
// {
// u16 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_DATA16(color);
// LCD_WR_DATA(color >> 8);
// LCD_WR_DATA(color);
// }
// }
// }
//写寄存器
//LCD_Reg:寄存器编号
//LCD_RegValue:要写入的值
void LCD_WriteReg(u8 LCD_Reg,u16 LCD_RegValue)
{
LCD_WR_REG(LCD_Reg);
LCD_WR_DATA(LCD_RegValue);
}
//开始写GRAM
void LCD_WriteRAM_Prepare(void)
{
if(DeviceCode==0X9341)LCD_WR_REG(0x2C);//ILI9341是以0X2C开始的
else LCD_WR_REG(R34);
}
//LCD写GRAM
//RGB_Code:颜色值
void LCD_WriteRAM(u16 RGB_Code)
{
LCD_WR_DATA(RGB_Code);//写十六位GRAM
}
//从ILI93xx读出的数据为GBR格式,而我们写入的时候为RGB格式。
//通过该函数转换
//c:GBR格式的颜色值
//返回值:RGB格式的颜色值
u16 LCD_BGR2RGB(u16 c)
{
u16 r,g,b,rgb;
b=(c>>0)&0x1f;
g=(c>>5)&0x3f;
r=(c>>11)&0x1f;
rgb=(b<<11)+(g<<5)+(r<<0);
return(rgb);
}
//LCD开启显示
void LCD_DisplayOn(void)
{
if(DeviceCode==0X9341)LCD_WR_REG(0X29); //开启显示
else LCD_WriteReg(R7,0x0173); //开启显示
}
//LCD关闭显示
void LCD_DisplayOff(void)
{
if(DeviceCode==0X9341)LCD_WR_REG(0X28); //关闭显示
else LCD_WriteReg(R7, 0x0);//关闭显示
}
//设置光标位置
//Xpos:横坐标
//Ypos:纵坐标
__inline void LCD_SetCursor(u16 Xpos, u16 Ypos)
{
#if USE_HORIZONTAL==1
if(DeviceCode==0X8989)
{
Xpos=319-Xpos;
LCD_WriteReg(0X4E, Ypos);
LCD_WriteReg(0X4F, Xpos);
}else if(DeviceCode==0X9341)//9341,设置坐标
{
LCD_WR_REG(0x2B);
LCD_WR_DATA(Ypos>>8);
LCD_WR_DATA(Ypos&0XFF);
LCD_WR_REG(0x2A);
LCD_WR_DATA(Xpos>>8);
LCD_WR_DATA(Xpos&0XFF);
}else
{
Xpos=319-Xpos;
LCD_WriteReg(R32,Ypos);
LCD_WriteReg(R33,Xpos);
}
#else
if(DeviceCode==0X8989)
{
LCD_WriteReg(0X4E, Xpos);
LCD_WriteReg(0X4F, Ypos);
}else if(DeviceCode==0X9341)
{
LCD_WR_REG(0x2A);
LCD_WR_DATA(Xpos>>8);
LCD_WR_DATA(Xpos&0XFF);
LCD_WR_REG(0x2B);
LCD_WR_DATA(Ypos>>8);
LCD_WR_DATA(Ypos&0XFF);
}else
{
LCD_WriteReg(R32, Xpos);
LCD_WriteReg(R33, Ypos);
}
#endif
}
//设置LCD的自动扫描方向
//注意:其他函数可能会受到此函数设置的影响(尤其是9341这个奇葩),所以,
//一般设置为L2R_U2D即可,如果设置为其他扫描方式,可能导致显示不正常.
//0~7:代表8个方向(具体定义见lcd.h)
//9320/9325/9328/4531/4535/1505/b505/8989/5408/9341等IC已经实际测试
void LCD_Scan_Dir(u8 dir)
{
u16 regval=0;
u8 dirreg=0;
#if USE_HORIZONTAL//使用横屏
switch(dir)//方向转换
{
case 0:dir=6;break;
case 1:dir=7;break;
case 2:dir=4;break;
case 3:dir=5;break;
case 4:dir=1;break;
case 5:dir=0;break;
case 6:dir=3;break;
case 7:dir=2;break;
}
#endif
if(DeviceCode==0x9341)//9341,很特殊
{
switch(dir)
{
case L2R_U2D://从左到右,从上到下
regval|=(0<<7)|(0<<6)|(0<<5);
break;
case L2R_D2U://从左到右,从下到上
regval|=(1<<7)|(0<<6)|(0<<5);
break;
case R2L_U2D://从右到左,从上到下
regval|=(0<<7)|(1<<6)|(0<<5);
break;
case R2L_D2U://从右到左,从下到上
regval|=(1<<7)|(1<<6)|(0<<5);
break;
case U2D_L2R://从上到下,从左到右
regval|=(0<<7)|(0<<6)|(1<<5);
break;
case U2D_R2L://从上到下,从右到左
regval|=(0<<7)|(1<<6)|(1<<5);
break;
case D2U_L2R://从下到上,从左到右
regval|=(1<<7)|(0<<6)|(1<<5);
break;
case D2U_R2L://从下到上,从右到左
regval|=(1<<7)|(1<<6)|(1<<5);
break;
}
dirreg=0X36;
regval|=0X08;//BGR
LCD_WriteReg(dirreg,regval);
if(regval&0X20)
{
LCD_WR_REG(0x2A);
LCD_WR_DATA(0);LCD_WR_DATA(0);
LCD_WR_DATA(319>>8);LCD_WR_DATA(319&0XFF);
LCD_WR_REG(0x2B);
LCD_WR_DATA(0);LCD_WR_DATA(0);
LCD_WR_DATA(239>>8);LCD_WR_DATA(239&0XFF);
}else
{
LCD_WR_REG(0x2A);
LCD_WR_DATA(0);LCD_WR_DATA(0);
LCD_WR_DATA(239>>8);LCD_WR_DATA(239&0XFF);
LCD_WR_REG(0x2B);
LCD_WR_DATA(0);LCD_WR_DATA(0);
LCD_WR_DATA(319>>8);LCD_WR_DATA(319&0XFF);
}
}else
{
switch(dir)
{
case L2R_U2D://从左到右,从上到下
regval|=(1<<5)|(1<<4)|(0<<3);
break;
case L2R_D2U://从左到右,从下到上
regval|=(0<<5)|(1<<4)|(0<<3);
break;
case R2L_U2D://从右到左,从上到下
regval|=(1<<5)|(0<<4)|(0<<3);
break;
case R2L_D2U://从右到左,从下到上
regval|=(0<<5)|(0<<4)|(0<<3);
break;
case U2D_L2R://从上到下,从左到右
regval|=(1<<5)|(1<<4)|(1<<3);
break;
case U2D_R2L://从上到下,从右到左
regval|=(1<<5)|(0<<4)|(1<<3);
break;
case D2U_L2R://从下到上,从左到右
regval|=(0<<5)|(1<<4)|(1<<3);
break;
case D2U_R2L://从下到上,从右到左
regval|=(0<<5)|(0<<4)|(1<<3);
break;
}
if(DeviceCode==0x8989)//8989 IC
{
dirreg=0X11;
regval|=0X6040; //65K
}else//其他驱动IC
{
dirreg=0X03;
regval|=1<<12;
}
LCD_WriteReg(dirreg,regval);
}
}
//画点
//x:0~239
//y:0~319
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x,u16 y)
{
// LCD_SetCursor(x,y); //设置光标位置
// LCD_WriteRAM_Prepare(); //开始写入GRAM
// LCD_WR_DATA(POINT_COLOR);
LCD_Address_Set(x,y,x,y);//??????
LCD_WR_DATA16(POINT_COLOR);
}
//初始化lcd
void LCD_Init(void)
{
// RCC->APB2ENR|=1<<2;//先使能外设PORTA时钟
// RCC->APB2ENR|=1<<4;//先使能外设PORTC时钟
// RCC->APB2ENR|=1<<0; //开启辅助时钟
// JTAG_Set(SWD_ENABLE); //开启SWD
//运行指示灯-推挽输出
// GPIOC->CRH&=0XFF0FFFFF;
// GPIOC->CRH|=0X00300000;
//PORTA3~7复用推挽输出
// GPIOA->CRL&=0X00000000;
// GPIOA->CRL|=0X33333333;
// GPIOA->ODR|=0X00FF;
// GPIOA->CRL&=0XFFFF0000;
// GPIOA->CRL|=0X00003333;
// GPIOA->ODR|=0X00FF;
// LCD_RES_SET;
// delay_ms(10); //
// LCD_RES_CLR;
// delay_ms(10);
// LCD_RES_SET;
// delay_ms(150);
LCD_WR_REG(0x11);
vTaskDelay(120 / portTICK_PERIOD_MS); //Delay 120ms
LCD_WR_REG(0xFE);
LCD_WR_REG(0xEF);
LCD_WR_REG(0xB0);
LCD_WR_DATA(0xC0);
LCD_WR_REG(0xB2);
LCD_WR_DATA(0x2F);
LCD_WR_REG(0xB3);
LCD_WR_DATA(0x03);
LCD_WR_REG(0xB6);
LCD_WR_DATA(0x19);
LCD_WR_REG(0xB7);
LCD_WR_DATA(0x01);
LCD_WR_REG(0xAC);
LCD_WR_DATA(0xCB);
LCD_WR_REG(0xAB);
LCD_WR_DATA(0x0e);
LCD_WR_REG(0xB4);
LCD_WR_DATA(0x04);
LCD_WR_REG(0xA8);
LCD_WR_DATA(0x19);
LCD_WR_REG(0x3A);
LCD_WR_DATA(0x05);
LCD_WR_REG(0xb8);
LCD_WR_DATA(0x08);
LCD_WR_REG(0xE8);
LCD_WR_DATA(0x24);
LCD_WR_REG(0xE9);
LCD_WR_DATA(0x48);
LCD_WR_REG(0xea);
LCD_WR_DATA(0x22);
LCD_WR_REG(0xC6);
LCD_WR_DATA(0x30);
LCD_WR_REG(0xC7);
LCD_WR_DATA(0x18);
LCD_WR_REG(0xF0);
LCD_WR_DATA(0x1F);
LCD_WR_DATA(0x28);
LCD_WR_DATA(0x04);
LCD_WR_DATA(0x3E);
LCD_WR_DATA(0x2A);
LCD_WR_DATA(0x2E);
LCD_WR_DATA(0x20);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x0C);
LCD_WR_DATA(0x06);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x1C);
LCD_WR_DATA(0x1F);
LCD_WR_DATA(0x0f);
LCD_WR_REG(0xF1);
LCD_WR_DATA(0X00);
LCD_WR_DATA(0X2D);
LCD_WR_DATA(0X2F);
LCD_WR_DATA(0X3C);
LCD_WR_DATA(0X6F);
LCD_WR_DATA(0X1C);
LCD_WR_DATA(0X0B);
LCD_WR_DATA(0X00);
LCD_WR_DATA(0X00);
LCD_WR_DATA(0X00);
LCD_WR_DATA(0X07);
LCD_WR_DATA(0X0D);
LCD_WR_DATA(0X11);
LCD_WR_DATA(0X0f);
LCD_WR_REG(0x21);
vTaskDelay(120 / portTICK_PERIOD_MS);
LCD_WR_REG(0x29);
vTaskDelay(120 / portTICK_PERIOD_MS);
}
//清屏函数
//Color:要清屏的填充色
void LCD_Clear(u16 Color)
{
u32 index=0;
LCD_SetCursor(0x00,0x0000);//设置光标位置
LCD_WriteRAM_Prepare(); //开始写入GRAM
for(index=0;index<(240*240);index++)
{
LCD_WR_DATA(Color);
}
}
//在指定区域内填充指定颜色
//区域大小:(xend-xsta+1)*(yend-ysta+1)
//xsta
//color:要填充的颜色
// void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
// {
// u16 i,j;
// u16 xlen=0;
// LCD_Scan_Dir(L2R_U2D);
// #if USE_HORIZONTAL==1
// xlen=ey-sy+1;
// for(i=sx;i<=ex;i++)
// {
// LCD_SetCursor(i,sy); //设置光标位置
// LCD_WriteRAM_Prepare(); //开始写入GRAM
// for(j=0;j<xlen;j++)LCD_WR_DATA(color); //设置光标位置
// }
// #else
// xlen=ex-sx+1;
// for(i=sy;i<=ey;i++)
// {
// LCD_SetCursor(sx,i); //设置光标位置
// LCD_WriteRAM_Prepare(); //开始写入GRAM
// for(j=0;j<xlen;j++)LCD_WR_DATA(color); //设置光标位置
// }
// #endif
// LCD_Scan_Dir(DFT_SCAN_DIR);
// }
//画线
//x1,y1:起点坐标
//x2,y2:终点坐标
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
u16 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++ )//画线输出
{
LCD_DrawPoint(uRow,uCol);//画点
xerr+=delta_x ;
yerr+=delta_y ;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
//画矩形
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
{
LCD_DrawLine(x1,y1,x2,y1);
LCD_DrawLine(x1,y1,x1,y2);
LCD_DrawLine(x1,y2,x2,y2);
LCD_DrawLine(x2,y1,x2,y2);
}
//在指定位置画一个指定大小的圆
//(x,y):中心点
//r :半径
void Draw_Circle(u16 x0,u16 y0,u8 r)
{
int a,b;
int di;
a=0;b=r;
di=3-(r<<1); //判断下个点位置的标志
while(a<=b)
{
LCD_DrawPoint(x0-b,y0-a); //3
LCD_DrawPoint(x0+b,y0-a); //0
LCD_DrawPoint(x0-a,y0+b); //1
LCD_DrawPoint(x0-b,y0-a); //7
LCD_DrawPoint(x0-a,y0-b); //2
LCD_DrawPoint(x0+b,y0+a); //4
LCD_DrawPoint(x0+a,y0-b); //5
LCD_DrawPoint(x0+a,y0+b); //6
LCD_DrawPoint(x0-b,y0+a);
a++;
//使用Bresenham算法画圆
if(di<0)di +=4*a+6;
else
{
di+=10+4*(a-b);
b--;
}
LCD_DrawPoint(x0+a,y0+b);
}
}
//在指定位置显示一个字符
//x:0~234
//y:0~308
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16
//mode:叠加方式(1)还是非叠加方式(0)
//在指定位置显示一个字符
//x:0~234
//y:0~308
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16
//mode:叠加方式(1)还是非叠加方式(0)
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode)
{
#if USE_HORIZONTAL==1
#define MAX_CHAR_POSX (YPOS_END - 8)
#define MAX_CHAR_POSY (XPOS_END - 8)
#else
#define MAX_CHAR_POSX (XPOS_END - 8)
#define MAX_CHAR_POSY (YPOS_END - 8)
#endif
u8 temp;
u8 pos,t;
u16 x0=x;
u16 colortemp=POINT_COLOR;
if(x>MAX_CHAR_POSX||y>MAX_CHAR_POSY)return;
//设置窗口
num=num-' ';//得到偏移后的值
if(!mode) //非叠加方式
{
for(pos=0;pos<size;pos++)
{
if(size==12)temp=asc2_1206[num][pos];//调用1206字体
else temp=asc2_1608[num][pos]; //调用1608字体
for(t=0;t<size/2;t++)
{
if(temp&0x01)POINT_COLOR=colortemp;
else POINT_COLOR=BACK_COLOR;
LCD_DrawPoint(x,y);
temp>>=1;
x++;
}
x=x0;
y++;
}
}else//叠加方式
{
for(pos=0;pos<size;pos++)
{
if(size==12)temp=asc2_1206[num][pos];//调用1206字体
else temp=asc2_1608[num][pos]; //调用1608字体
for(t=0;t<size/2;t++)
{
if(temp&0x01)LCD_DrawPoint(x+t,y+pos);//画一个点
temp>>=1;
}
}
}
POINT_COLOR=colortemp;
}
//m^n函数
u32 mypow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//color:颜色
//num:数值(0~4294967295);
void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size)
{
u8 t,temp;
u8 enshow=0;
for(t=0;t<len;t++)
{
temp=(num/mypow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
LCD_ShowChar(x+(size/2)*t,y,' ',size,0);
continue;
}else enshow=1;
}
LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,0);
}
}
//显示2个数字
//x,y:起点坐标
//size:字体大小
//mode:模式 0,填充模式;1,叠加模式
//num:数值(0~99);
void LCD_Show2Num(u16 x,u16 y,u16 num,u8 len,u8 size,u8 mode)
{
u8 t,temp;
for(t=0;t<len;t++)
{
temp=(num/mypow(10,len-t-1))%10;
LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,mode);
}
}
//显示字符串
//x,y:起点坐标
//*p:字符串起始地址
//用16字体
void LCD_ShowString(u16 x,u16 y,const u8 *p)
{
while(*p!='\0')
{
if(x>MAX_CHAR_POSX){x=0;y+=16;}
if(y>MAX_CHAR_POSY){y=x=0;LCD_Fill(XPOS_START,YPOS_START,XPOS_END,YPOS_END,WHITE);}
LCD_ShowChar(x,y,*p,16,1);
x+=8;
p++;
}
}
lcd.h
#pragma once
#include "stdlib.h"
#include "driver/gpio.h"
typedef unsigned long u32;
typedef unsigned short u16;
typedef unsigned char u8;
#define LCD_HOST SPI2_HOST
//半双工
#define PIN_NUM_MOSI 4
#define PIN_NUM_CLK 3
#define PIN_NUM_CS 19
#define PIN_NUM_DC 5
#define LCD_RS_CLR gpio_set_level(PIN_NUM_DC, 0)
#define LCD_RS_SET gpio_set_level(PIN_NUM_DC, 1)
#define LCD_CS_SET gpio_set_level(PIN_NUM_CS, 1)
/////////////////////////////////////用户配置区///////////////////////////////////
//以下2个宏定义,定义屏幕的显示方式及IO速度
#define USE_HORIZONTAL 0 //定义是否使用横屏 0,不使用.1,使用.
#define LCD_FAST_IO 0 //定义是否使用快速IO 0,不实用.1,使用
//////////////////////////////////////////////////////////////////////////////////
//TFTLCD部分外要调用的函数
extern u16 POINT_COLOR;//默认红色
extern u16 BACK_COLOR; //背景颜色.默认为白色
//定义LCD的尺寸
#if USE_HORIZONTAL==1 //使用横屏
#define LCD_W 160
#define LCD_H 128
#else
#define LCD_W 128
#define LCD_H 160
#endif
#define XPOS_START 0
#define XPOS_END 160
#define YPOS_START 0
#define YPOS_END 160
//////////////////////////////////////////////////////////////////////
//扫描方向定义
#define L2R_U2D 0 //从左到右,从上到下
#define L2R_D2U 1 //从左到右,从下到上
#define R2L_U2D 2 //从右到左,从上到下
#define R2L_D2U 3 //从右到左,从下到上
#define U2D_L2R 4 //从上到下,从左到右
#define U2D_R2L 5 //从上到下,从右到左
#define D2U_L2R 6 //从下到上,从左到右
#define D2U_R2L 7 //从下到上,从右到左
#define DFT_SCAN_DIR L2R_U2D //默认的扫描方向
//画笔颜色
#define WHITE 0x0000//0xFFFF
#define BLACK 0xFFFF//0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
//GUI颜色
#define DARKBLUE 0X01CF //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458 //灰蓝色
//以上三色为PANEL的颜色
#define LIGHTGREEN 0X841F //浅绿色
//#define LIGHTGRAY 0XEF5B //浅灰色(PANNEL)
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
extern u16 BACK_COLOR, POINT_COLOR ;
void SPI_COM_Init(void);
void LCD_Init(void);
void LCD_DisplayOn(void);
void LCD_DisplayOff(void);
void LCD_Clear(u16 Color);
void LCD_SetCursor(u16 Xpos, u16 Ypos);
void LCD_Scan_Dir(u8 dir);
void LCD_DrawPoint(u16 x,u16 y);//画点
u16 LCD_ReadPoint(u16 x,u16 y); //读点
void Draw_Circle(u16 x0,u16 y0,u8 r);
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2);
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color);
void LCD_Fill_PIC(u16 sx,u16 sy,u16 ex,u16 ey,const u8 *data);
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode);//显示一个字符
void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size); //显示一个数字
void LCD_Show2Num(u16 x,u16 y,u16 num,u8 len,u8 size,u8 mode);//显示2个数字
void LCD_ShowString(u16 x,u16 y,const u8 *p); //显示一个字符串,16字体
u16 LCD_RD_DATA(void);//读取LCD数据
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue);
u16 LCD_ReadReg(u8 LCD_Reg);
void LCD_WriteRAM_Prepare(void);
void LCD_WriteRAM(u16 RGB_Code);
u16 LCD_ReadRAM(void);
u16 LCD_BGR2RGB(u16 c);
//9320/9325 LCD寄存器
#define R0 0x00
#define R1 0x01
#define R2 0x02
#define R3 0x03
#define R4 0x04
#define R5 0x05
#define R6 0x06
#define R7 0x07
#define R8 0x08
#define R9 0x09
#define R10 0x0A
#define R12 0x0C
#define R13 0x0D
#define R14 0x0E
#define R15 0x0F
#define R16 0x10
#define R17 0x11
#define R18 0x12
#define R19 0x13
#define R20 0x14
#define R21 0x15
#define R22 0x16
#define R23 0x17
#define R24 0x18
#define R25 0x19
#define R26 0x1A
#define R27 0x1B
#define R28 0x1C
#define R29 0x1D
#define R30 0x1E
#define R31 0x1F
#define R32 0x20
#define R33 0x21
#define R34 0x22
#define R36 0x24
#define R37 0x25
#define R40 0x28
#define R41 0x29
#define R43 0x2B
#define R45 0x2D
#define R48 0x30
#define R49 0x31
#define R50 0x32
#define R51 0x33
#define R52 0x34
#define R53 0x35
#define R54 0x36
#define R55 0x37
#define R56 0x38
#define R57 0x39
#define R59 0x3B
#define R60 0x3C
#define R61 0x3D
#define R62 0x3E
#define R63 0x3F
#define R64 0x40
#define R65 0x41
#define R66 0x42
#define R67 0x43
#define R68 0x44
#define R69 0x45
#define R70 0x46
#define R71 0x47
#define R72 0x48
#define R73 0x49
#define R74 0x4A
#define R75 0x4B
#define R76 0x4C
#define R77 0x4D
#define R78 0x4E
#define R79 0x4F
#define R80 0x50
#define R81 0x51
#define R82 0x52
#define R83 0x53
#define R96 0x60
#define R97 0x61
#define R106 0x6A
#define R118 0x76
#define R128 0x80
#define R129 0x81
#define R130 0x82
#define R131 0x83
#define R132 0x84
#define R133 0x85
#define R134 0x86
#define R135 0x87
#define R136 0x88
#define R137 0x89
#define R139 0x8B
#define R140 0x8C
#define R141 0x8D
#define R143 0x8F
#define R144 0x90
#define R145 0x91
#define R146 0x92
#define R147 0x93
#define R148 0x94
#define R149 0x95
#define R150 0x96
#define R151 0x97
#define R152 0x98
#define R153 0x99
#define R154 0x9A
#define R157 0x9D
#define R192 0xC0
#define R193 0xC1
#define R229 0xE5
更多推荐



所有评论(0)