软件模拟8080时序驱动2.8寸LCD屏驱动,实现指定位置画点、绘制直线、矩形、显示图片等功能。

8080时序介绍见我上篇文章软件模拟8080通信https://blog.csdn.net/qq_69110655/article/details/162700202?fromshare=blogdetail&sharetype=blogdetail&sharerId=162700202&sharerefer=PC&sharesource=qq_69110655&sharefrom=from_link

完整代码(基于STM32)

my_lcd.h

#ifndef __MY_LCD_H
#define __MY_LCD_H

#include "stm32f10x.h"
#include "my_8080.h"

//颜色宏定义       RGB565
#define WHITE      	0xFFFF
#define BLACK      	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 //灰色

void lcd_init(void);
void lcd_readId(void);

// 指定点设置指定颜色
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color);
// 画线
void lcd_draw_line(uint16_t s_x, uint16_t s_y, uint16_t e_x, uint16_t e_y, uint16_t color);
// 显示图片
void lcd_show_pic(uint16_t x0,uint16_t y0,uint16_t width,uint16_t height,const uint8_t *pic);
// 绘制矩形
void lcd_draw_rect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
// 绘制实心填充矩形
void lcd_draw_fill_rect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

#endif

my_lcd.c

#include "myLCD.h"
#include "delay.h"
#include "stdio.h"

// 背光引脚配置
#define lcd_BL_PIN    GPIO_Pin_0
#define lcd_BL_PORT   GPIOB
#define lcd_backlight_control(x) GPIO_WriteBit(lcd_BL_PORT, lcd_BL_PIN, (x) ? Bit_SET : Bit_RESET)

struct lcd_cmd
{
    uint16_t setPointColor; // 设置像素点颜色信息; 将数据从 MCU(微控制器)传输到帧存储器(显存/GRAM)。
    uint16_t setX;          // 设置x坐标
    uint16_t setY;          // 设置y坐标
    uint16_t readID;        // 读ID
    uint16_t setScanDir;    // 设置扫描方向
};

typedef struct {
    uint16_t width;     // 屏幕宽度
    uint16_t height;    // 屏幕高度
    uint16_t id;        // 屏幕ID
    uint8_t  dir;       // 屏幕显示方向  1横屏  0 竖屏
    struct lcd_cmd cmd; // 屏幕控制命令集
} LCD_DrvTypeDef;

LCD_DrvTypeDef lcd = 
{
    .dir = 1, // 使用横屏
    .width = 320,
    .height = 240,
    
//    .dir = 0, // 使用竖屏
//    .width = 240,
//    .height = 320,
    
    .cmd.setPointColor = 0x2C,
    .cmd.setX = 0x2A,   // 设置列地址命令
    .cmd.setY = 0x2B,   // 设置行地址命令
    .cmd.readID = 0xD3, // 获取ID命令
    .cmd.setScanDir = 0x36,  // Memory Access Control (36h)
};

void lcd_readId(void)
{
    //9341 ID的读取		
	my8080_writeCommand(0XD3);				   
	lcd.id=my8080_readData();	//dummy read 	
	lcd.id=my8080_readData();	//读到0X00
	lcd.id=my8080_readData();   	//读取93								   
	lcd.id<<=8;
	lcd.id|=my8080_readData();  	//读取41	
	printf("lcd id:%X\r\n", lcd.id);
}

static void lcd_Config(void)
{
    my8080_writeCommand(0xCF);  
	my8080_writeData(0x00); 
	my8080_writeData(0xC1); 
	my8080_writeData(0X30);
	
	my8080_writeCommand(0xED);  
	my8080_writeData(0x64); 
	my8080_writeData(0x03); 
	my8080_writeData(0X12); 
	my8080_writeData(0X81);
	
	my8080_writeCommand(0xE8);  
	my8080_writeData(0x85); 
	my8080_writeData(0x10); 
	my8080_writeData(0x7A); 
	
	my8080_writeCommand(0xCB);  
	my8080_writeData(0x39); 
	my8080_writeData(0x2C); 
	my8080_writeData(0x00); 
	my8080_writeData(0x34); 
	my8080_writeData(0x02); 
	
	my8080_writeCommand(0xF7);  
	my8080_writeData(0x20); 
	
	my8080_writeCommand(0xEA);  
	my8080_writeData(0x00); 
	my8080_writeData(0x00); 
	
	my8080_writeCommand(0xC0);    //Power control 
	my8080_writeData(0x1B);   //VRH[5:0] 
	
	my8080_writeCommand(0xC1);    //Power control 
	my8080_writeData(0x01);   //SAP[2:0];BT[3:0] 
	
	my8080_writeCommand(0xC5);    //VCM control 
	my8080_writeData(0x30); 	 //3F
	my8080_writeData(0x30); 	 //3C
	
	my8080_writeCommand(0xC7);    //VCM control2 
	my8080_writeData(0XB7); 
	
	my8080_writeCommand(0x36);    // Memory Access Control 
	my8080_writeData(0x48); 
	
	my8080_writeCommand(0x3A);   
	my8080_writeData(0x55); 
	
	my8080_writeCommand(0xB1);   
	my8080_writeData(0x00);   
	my8080_writeData(0x1A); 
	
	my8080_writeCommand(0xB6);    // Display Function Control 
	my8080_writeData(0x0A); 
	my8080_writeData(0xA2); 
	
	my8080_writeCommand(0xF2);    // 3Gamma Function Disable 
	my8080_writeData(0x00); 
	
	my8080_writeCommand(0x26);    //Gamma curve selected 
	my8080_writeData(0x01); 
	
	my8080_writeCommand(0xE0);    //Set Gamma 
	my8080_writeData(0x0F); 
	my8080_writeData(0x2A); 
	my8080_writeData(0x28); 
	my8080_writeData(0x08); 
	my8080_writeData(0x0E); 
	my8080_writeData(0x08); 
	my8080_writeData(0x54); 
	my8080_writeData(0XA9); 
	my8080_writeData(0x43); 
	my8080_writeData(0x0A); 
	my8080_writeData(0x0F); 
	my8080_writeData(0x00); 
	my8080_writeData(0x00); 
	my8080_writeData(0x00); 
	my8080_writeData(0x00); 	
	
	my8080_writeCommand(0XE1);    //Set Gamma 
	my8080_writeData(0x00); 
	my8080_writeData(0x15); 
	my8080_writeData(0x17); 
	my8080_writeData(0x07); 
	my8080_writeData(0x11); 
	my8080_writeData(0x06); 
	my8080_writeData(0x2B); 
	my8080_writeData(0x56); 
	my8080_writeData(0x3C); 
	my8080_writeData(0x05); 
	my8080_writeData(0x10); 
	my8080_writeData(0x0F); 
	my8080_writeData(0x3F); 
	my8080_writeData(0x3F); 
	my8080_writeData(0x0F); 
	
    my8080_writeCommand(0x2A);    // 宽
	my8080_writeData(0x00);
	my8080_writeData(0x00);
//	my8080_writeData(0x01);
//	my8080_writeData(0x3f);	   //0x13F  319
    my8080_writeData(lcd.width >> 8);    
	my8080_writeData(lcd.width & 0xFF);
    
	my8080_writeCommand(0x2B);   //设置屏高 
	my8080_writeData(0x00);
	my8080_writeData(0x00);
	// my8080_writeData(0x00);
	// my8080_writeData(0xef);    //0xEF  239
    my8080_writeData(lcd.height >> 8);    
	my8080_writeData(lcd.height & 0xFF);    
    
    
	
	my8080_writeCommand(0x11); //Exit Sleep
	Delay_ms(120);
	my8080_writeCommand(0x29); //display on		

    
}

// 在指定位置写入一个数据
void lcd_write_reg(uint16_t reg, uint16_t data)
{
    my8080_writeCommand(reg);
    my8080_writeData(data);
}

// 设置屏幕显示方向
// 0竖屏     1横屏(逆时针转90)
void lcd_set_dir(uint8_t dir)
{
    switch(dir)
    {
        case 0:// 竖屏
//            lcd.width = 240;
//            lcd.height = 320;
            my8080_writeCommand(lcd.cmd.setScanDir);
            my8080_writeData(0x00);
            break;
        case 1: // 横屏
//            lcd.width = 320;
//            lcd.height = 240;
            my8080_writeCommand(lcd.cmd.setScanDir);
            // my8080_writeData(0x68);
            my8080_writeData(0x60);   // RGB565
            break;
    }
}
void lcd_init(void)
{
    my8080_pinInit(); //
    // 背光pin初始化
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    GPIO_InitStructure.GPIO_Pin = lcd_BL_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(lcd_BL_PORT, &GPIO_InitStructure);
    
    lcd_Config();
    
    lcd_backlight_control(1); // 打开背光
    lcd_set_dir(lcd.dir);     // 设置显示方向
}

// 设置光标位置
void lcd_set_cursor(uint16_t x, uint16_t y)
{
    my8080_writeCommand(lcd.cmd.setX);
    my8080_writeData(x >> 8);  // x 高8位
    my8080_writeData(x & 0xFF); // x 低8位
    my8080_writeCommand(lcd.cmd.setY);
    my8080_writeData(y >> 8);  // y 高8位
    my8080_writeData(y & 0xFF); // y 低8位
}

// 指定点设置指定颜色
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color)
{
    lcd_set_cursor(x, y);
    my8080_writeCommand(lcd.cmd.setPointColor);
    my8080_writeData(color);
}
/**
 * @brief  画线函数
 * @param  s_x,s_y: 起点坐标
 * @param  e_x,e_y: 终点坐标
 * @param  color:   画线颜色
 * @note   
 */
void lcd_draw_line(uint16_t s_x, uint16_t s_y, uint16_t e_x, uint16_t e_y, uint16_t color)
{
    int16_t dx, dy;
    int16_t x, y;
    int16_t incx, incy;
    int16_t err;

    // 计算坐标差值
    dx = e_x - s_x;
    dy = e_y - s_y;

    // 判断步进方向
    if(dx > 0)      incx = 1;
    else if(dx < 0) incx = -1;
    else            incx = 0;

    if(dy > 0)      incy = 1;
    else if(dy < 0) incy = -1;
    else            incy = 0;

    // 取绝对值
    dx = dx > 0 ? dx : -dx;
    dy = dy > 0 ? dy : -dy;

    x = s_x;
    y = s_y;

    // 斜率绝对值小于1
    if(dx > dy)
    {
        err = dx / 2;
        for(uint16_t i = 0; i <= dx; i++)
        {
            lcd_draw_point(x, y, color);
            err -= dy;
            if(err < 0)
            {
                err += dx;
                y += incy;
            }
            x += incx;
        }
    }
    // 斜率绝对值大于等于1
    else
    {
        err = dy / 2;
        for(uint16_t i = 0; i <= dy; i++)
        {
            lcd_draw_point(x, y, color);
            err -= dx;
            if(err < 0)
            {
                err += dy;
                x += incx;
            }
            y += incy;
        }
    }
}

/**
 * @brief  LCD显示RGB565格式图片
 * @param  x0,y0: 图片左上角起始坐标
 * @param  width: 图片宽度
 * @param  height:图片高度
 * @param  pic:   图片像素数组(取模生成)
 */
void lcd_show_pic(uint16_t x0,uint16_t y0,uint16_t width,uint16_t height,const uint8_t *pic)
{
    uint16_t x,y;
    uint16_t color;
    uint32_t i=0;
    // 逐行扫描
    for(y=0;y<height;y++)
    {
        // 逐列扫描
        for(x=0;x<width;x++)
        {
            // RGB565 2字节存一个颜色
            color = pic[i+1]<<8 | pic[i];
            lcd_draw_point(x0+x,y0+y,color);
            i+=2;
        }
    }
}


/**
 * @brief  绘制实心填充矩形
 * @param  x1,y1: 左上角
 * @param  x2,y2: 右下角
 * @param  color: 填充颜色
 */
void lcd_draw_fill_rect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{          
	u16 i,j;
	u16 xlen=0;
	xlen=x2-x1+1;	 
	for(i=y1;i<=y2;i++)
	{
		lcd_set_cursor(x1,i);      				//设置光标位置 
		my8080_writeCommand(0x2C);     			//开始写入GRAM	  
		for(j=0;j<xlen;j++)
		{			

				my8080_writeData(color);
			
		}			
	} 
}

/**
 * @brief  绘制空心矩形
 * @param  x1,y1: 左上角坐标
 * @param  x2,y2: 右下角坐标
 * @param  color: 边框颜色
 */
void lcd_draw_rect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
    // 上边框
    lcd_draw_line(x1, y1, x2, y1, color);
    // 下边框
    lcd_draw_line(x1, y2, x2, y2, color);
    // 左边框
    lcd_draw_line(x1, y1, x1, y2, color);
    // 右边框
    lcd_draw_line(x2, y1, x2, y2, color);
}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐