122人参与 • 2024-08-01 • 嵌入式
st7735s是一块1.8英寸采用spi通信的tft全彩屏,分辨率是128*160,这里采用rgb565 16bit的色块编译模式(rgb565即高五位为red,第五位为blue,中间六位为green,共16位)。本文仅设计该屏幕的简单应用,不对底层原理进行深究。
blk:这里用不到,可以不用连接
cs:片选信号
dc:数据模式选择信号 1为写命令/0为写数据
rst:复位信号
sda:spi数据线
scl:spi时钟线
vdd:兼容+5v和+3.3v
gnd:接地
用的单片机是stm32f103c8t6,主频72mhz,硬件模拟spi,cubemx的gpio配置如下
复位信号低电平有效,要求时间大于10us,复位后最好再等待120ms`
void lcd_reset()
{
rst_l;//rst引脚拉低
hal_delay(1);
rst_h;//rst引脚拉高
hal_delay(120);
}
参数配置的大体流程如下:
1.执行0x11命令,退出睡眠模式,执行命令后延时120ms
2.配置0xb1,0xb2,0xb3,0xb4寄存器,配置在不同颜色模式下屏幕的刷新率,0xb4寄存器配置屏幕是否反色
3.配置0xc0,0xc1,0xc2,0xc3,0xc4寄存器,配置显示屏在不同颜色不同模式下的电压
4.配置0x36寄存器,设置显存数据访问方式。我在复制代码的时候没有仔细地阅读手册,导致到最后的颜色不正,研究了半天才发现是用的bgr的颜色顺序,最开始还以为是屏幕坏了,还特地写了一个调换顺序的函数,到后来仔细读了一遍手册之后发现是有一位可以控制顺序的,36h的rgb位从1变到0颜色就正常了。
5.配置0xe0,0xe1寄存器,配置伽马极性
6.执行0x3a,设置像素格式
7.执行0x29命令,进行显示
如果不想了解具体的寄存器参数配置的话可以直接使用官方给出的程序进行初始化,直接复制下面的代码就可以了
void lcd_init()
{
lcd_reset();//reset before lcd init.
//lcd init for 1.44inch lcd panel with st7735r.
lcd_write_command(0x11);//sleep exit
hal_delay(120);
//st7735r frame rate 4
lcd_write_command(0xb1);
lcd_write_data(0x01);
lcd_write_data(0x2c);
lcd_write_data(0x2d);
lcd_write_command(0xb2);
lcd_write_data(0x01);
lcd_write_data(0x2c);
lcd_write_data(0x2d);
lcd_write_command(0xb3);
lcd_write_data(0x01);
lcd_write_data(0x2c);
lcd_write_data(0x2d);
lcd_write_data(0x01);
lcd_write_data(0x2c);
lcd_write_data(0x2d);
lcd_write_command(0xb4); //column inversion
lcd_write_data(0x07);
//st7735r power sequence
lcd_write_command(0xc0);
lcd_write_data(0xa2);
lcd_write_data(0x02);
lcd_write_data(0x84);
lcd_write_command(0xc1);
lcd_write_data(0xc5);
lcd_write_command(0xc2);
lcd_write_data(0x0a);
lcd_write_data(0x00);
lcd_write_command(0xc3);
lcd_write_data(0x8a);
lcd_write_data(0x2a);
lcd_write_command(0xc4);
lcd_write_data(0x8a);
lcd_write_data(0xee);
lcd_write_command(0xc5); //vcom
lcd_write_data(0x0e);
lcd_write_command(0x36); //mx, my, rgb mode
lcd_write_data(0xa0); //竖屏c8 横屏08 a8
// lcd_write_data(0xc0); //竖屏c8 横屏08 a8
//st7735r gamma sequence
lcd_write_command(0xe0);
lcd_write_data(0x0f);
lcd_write_data(0x1a);
lcd_write_data(0x0f);
lcd_write_data(0x18);
lcd_write_data(0x2f);
lcd_write_data(0x28);
lcd_write_data(0x20);
lcd_write_data(0x22);
lcd_write_data(0x1f);
lcd_write_data(0x1b);
lcd_write_data(0x23);
lcd_write_data(0x37);
lcd_write_data(0x00);
lcd_write_data(0x07);
lcd_write_data(0x02);
lcd_write_data(0x10);
lcd_write_command(0xe1);
lcd_write_data(0x0f);
lcd_write_data(0x1b);
lcd_write_data(0x0f);
lcd_write_data(0x17);
lcd_write_data(0x33);
lcd_write_data(0x2c);
lcd_write_data(0x29);
lcd_write_data(0x2e);
lcd_write_data(0x30);
lcd_write_data(0x30);
lcd_write_data(0x39);
lcd_write_data(0x3f);
lcd_write_data(0x00);
lcd_write_data(0x07);
lcd_write_data(0x03);
lcd_write_data(0x10);
lcd_write_command(0x2a);
lcd_write_data(0x00);
lcd_write_data(0x00+2);
lcd_write_data(0x00);
lcd_write_data(0x80+2);
lcd_write_command(0x2b);
lcd_write_data(0x00);
lcd_write_data(0x00+3);
lcd_write_data(0x00);
lcd_write_data(0x80+3);
lcd_write_command(0xf0); //enable test command
lcd_write_data(0x01);
lcd_write_command(0xf6); //disable ram power save mode
lcd_write_data(0x00);
lcd_write_command(0x3a); //65k mode
lcd_write_data(0x05);
lcd_write_command(0x29);//display on
}
st7735s的分辨率为128*160,直接可以用四个八位的数据表示,分别是x的起始坐标和终点坐标,y的起始坐标和终点坐标,通过写入0x2a和0x2b寄存器将四个八位坐标发送至屏幕,因为分辨率仅用低八位就可以表示,所以高八位全为0。之后配置0x2c寄存器,进行坐标范围内的颜色配置。
//写入屏幕地址函数
void lcd_write_address(uint8_t x_start,uint8_t y_start,uint8_t x_end,uint8_t y_end)
{
lcd_write_command(0x2a);
lcd_write_data(x_start >> 8);
lcd_write_data(x_start);
lcd_write_data(x_end >> 8);
lcd_write_data(x_end);
lcd_write_command(0x2b);
lcd_write_data(y_start >> 8);
lcd_write_data(y_start);
lcd_write_data(y_end >> 8);
lcd_write_data(y_end);
lcd_write_command(0x2c);
}
颜色填充大概的思路是先选定颜色区域最后用两个for循环遍历区域,每个像素点都写入一个16位的颜色数据就可以了。
//常用的颜色数据
#define red 0xf800
#define green 0x07e0
#define blue 0x001f
#define white 0xffff
#define black 0x0000
#define yellow 0xffe0
//全屏颜色填充
void lcd_set_color(uint16_t color)
{
lcd_write_address(0,0,159,127);//像素160*128
for(int i = 0; i < 160; i++)
{
for(int j = 0; j < 128; j++)
{
lcd_write_data_u16(color);
}
}
}
区域填充原理也是和全屏填充的原理一样,划定区域后计算出区域的长和宽的像素点个数,之后用两个for循环对区域的每个像素点进行遍历然后写入16位的颜色数据就可以了。
//区域颜色填充
void lcd_set_area_color(uint8_t x_start,uint8_t y_start,uint8_t x_end,uint8_t y_end,uint16_t color)
{
lcd_write_address(x_start,y_start,x_end,y_end);
//计算填充区域的长度和宽度,终点坐标减起点坐标+1
uint8_t x_len = x_end - x_start + 1;//计算x坐标的长度
uint8_t y_len = y_end - y_start + 1;//计算y坐标的长度
for(int i = 0; i < x_len; i++)
{
for(int j = 0; j < y_len; j++)
{
lcd_write_data_u16(color);
}
}
}
描点函数就不用计算x与y坐标的长度了,直接写入要描的点的x,y坐标后写入颜色数据就可以了。
//描点函数
void lcd_set_point_color(uint8_t x_point,uint8_t y_point,uint16_t color)
{
lcd_write_address(x_point,y_point,x_point,y_point);
lcd_write_data_u16(color);
}
画图函数需要在像素点软件上生成一个图像数组后直接遍历数组就可以了,但是要手动的填写你需要显示的图片的分辨率,比如我现在要显示的图像的分辨率是160*120的,把地址的x和y的起始坐标写到0,终点坐标写到160-1和120-1就可以了。因为软件生成的数组是八位的,所以需要一个for循环把前后两个数据合并成一个16位的颜色数据发送出去,然后遍历一下就可以了。
void showimage(const unsigned char *p) //显示图片
{
unsigned char pich,picl;
lcd_set_color(0xffff); //清屏
lcd_write_address(0,0,159,119);
for(uint16_t i=0;i<160*120;i++)
{
picl=*(p+i*2); //数据低位在前
pich=*(p+i*2+1);
lcd_write_data_u16(pich<<8|picl);
}
}
如果我们想要在屏幕上显示我们想要的图片,那么就需要用到图片取模软件来把对应的图片进行取模,也就是转换成数组进行显示。我用的是image2lcd这个软件,下面来简单介绍一下这个软件。
生成好数组后直接把数组拷贝到程序中然后遍历这个数组就可以了,要注意的是单片机的flash能不能容得下这个图片大小。
在这里放上一些硬件spi的基本函数,如果不想自己写的话可以直接copy。
#define scl_h hal_gpio_writepin(gpioa,scl_pin,gpio_pin_set) //scl --> high
#define scl_l hal_gpio_writepin(gpioa,scl_pin,gpio_pin_reset) //scl --> low
#define sda_h hal_gpio_writepin(gpioa,sda_pin,gpio_pin_set) //sda --> high
#define sda_l hal_gpio_writepin(gpioa,sda_pin,gpio_pin_reset) //sda --> low
#define rst_h hal_gpio_writepin(gpioa,rst_pin,gpio_pin_set) //rst --> high
#define rst_l hal_gpio_writepin(gpioa,rst_pin,gpio_pin_reset) //rst --> low
#define dc_h hal_gpio_writepin(gpioa,dc_pin,gpio_pin_set) //dc --> high
#define dc_l hal_gpio_writepin(gpioa,dc_pin,gpio_pin_reset) //dc --> low
#define cs_h hal_gpio_writepin(gpioa,cs_pin,gpio_pin_set) //cs --> high
#define cs_l hal_gpio_writepin(gpioa,cs_pin,gpio_pin_reset) //cs --> low
//写数据: dc = 0
void lcd_write_data(uint8_t data)
{
cs_l;
dc_h;
for(int i = 0; i < 8; i++)
{
if(data & 0x80) sda_h;
else sda_l;
scl_l;
scl_h;
data = data << 1;
}
cs_h;
}
//写操作: dc = 1
void lcd_write_command(uint8_t data)
{
cs_l;
dc_l;
for(int i = 0; i < 8; i++)
{
if(data & 0x80) sda_h;
else sda_l;
scl_l;
scl_h;
data = data << 1;
}
cs_h;
}
//写十六位数据
void lcd_write_data_u16(uint16_t data)
{
lcd_write_data(data >> 8);
lcd_write_data(data & 0x0f);
}
发送数据的逻辑遵循下面的时序图
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论