单片机常见的屏幕驱动移植

目录

一个驱动.c文件的典型模块划分(5)

[1. Include files](#1. Include files)

[2. Local type definitions ('typedef')](#2. Local type definitions ('typedef'))

3. Local pre-processor symbols/macros ('#define'))

[4. Local variable definitions ('static')](#4. Local variable definitions ('static'))

[5. Function implementation - global ('extern') and local ('static')](#5. Function implementation - global ('extern') and local ('static'))

[5.1 驱动初始化](#5.1 驱动初始化)

[5.2 底层函数](#5.2 底层函数)


一个驱动.c文件的典型模块划分(5)

1. Include files

/*******************************************************************************

* Include files

******************************************************************************/

在文件的顶部列出,.C文件所要包含的头文件

2. Local type definitions ('typedef')

/*******************************************************************************

* Local type definitions ('typedef')

******************************************************************************/

/**

* @brief LCD Device Structure Definition

*/

typedef struct {

uint16_t u16Dir; /*!< Direction: 0, Vertical; 1, Horizontal */

uint16_t u16ID; /*!< LCD ID */

uint16_t u16Width; /*!< LCD Width */

uint16_t u16Height; /*!< LCD Heigth */

uint16_t u16WRamCmd; /*!< Start to write GRAM */

uint16_t u16SetXCmd; /*!< Set X axis */

uint16_t u16SetYCmd; /*!< Set Y axis */

} stc_lcd_device_t;

这是基本通用的屏幕参数:

屏幕方向:水平显示,垂直显示

屏幕ID:通过不同方式读取屏幕ID,根据不同ID兼容不同型号的屏幕

屏幕宽度和高度:屏幕真实像素点个数

屏幕写指令:将像素点数据写入GRAM

屏幕坐标设置指令:将指针设置到指定像素点位置

对于屏幕宽高,指的是像素大小,如240*320屏幕,表示屏幕为240*320像素 即76800个像素点,而不是屏幕尺寸。

对于用过的 NT35310 / 9341 / 5310 / 7789 ,其写指令、坐标设置指令都一样,分别是0X2C,0X2A,0X2B。

/**

* @brief LCD Device Controller Structure Definition

*/

typedef struct {

volatile uint16_t u16REG;

volatile uint16_t u16RAM;

} stc_lcd_controller_t;

这是最常用的LCD通讯实现方式,EXMC或FSMC。

EXMC接口一般用 D[0:18] 进行通讯,一般用RGB565即16根数据线进行通讯。

有WR\RD\CS\RS\RST五根控制线,CS用于片选器件,RS用于控制发送数据还是命令,WR和RS分别是写使能和读使能(基本都是低电平有效)。

用EXMC接口驱动LCD屏幕时,其实是把它当成SRAM来用,只不过这个SRAM有2个地址,一个是写寄存器地址,一个是写数据地址。具体可搜索"FSMC驱动LCD的原理"去理解。

具体地址定义如下:

/* Use EXMC A16 as the RS signal */

#define BSP_NT35510_BASE (0x70000000UL | ((1UL << 17U) - 2UL))

对应到最终写寄存器、写数据,就是直接修改指定地址的数据。

FSMC一般有普通IO模拟、SPI和I2C等方式替代,FMC速率最高,普通IO并行模拟次之。

除此之外,高分辨率屏幕,一般用RGB LCD接口,RGB分别是8位以上的数据线,还有DE数据使能线、VS垂直同步线、HS水平同步线、和DCLK像素时钟线。STM32可以用LTDC接口直接驱动,还有DMA2D图形加速。

3. Local pre-processor symbols/macros ('#define')

/*******************************************************************************

* Local pre-processor symbols/macros ('#define')

******************************************************************************/

/* LCD Scan Direction */

#define LCD_SCAN_DIR (LCD_SCAN_DIR_L2R_U2D)

定义屏幕扫描方向为从左到右,从上到下

4. Local variable definitions ('static')

/*******************************************************************************

* Local variable definitions ('static')

******************************************************************************/

static stc_lcd_device_t m_stcLcdDevice;

5. Function implementation - global ('extern') and local ('static')

5.1 驱动初始化

static void LCD_XXXX_Config(stc_lcd_controller_t *pstcLCD)

{

NT35510_WriteReg(pstcLCD, 0xE0); //Set Gamma

NT35510_WriteData(pstcLCD, 0x0F);

...

NT35510_WriteData(pstcLCD, 0XE1); //Set Gamma

NT35510_WriteData(pstcLCD, 0x00);

...

}

屏幕驱动初始化设置大同小异,也主要是屏幕的寄存器定义基本类似。

基本流程:

  1. 复位

  2. 进入正常模式或设置模式

  3. 显示颜色和方向设置

  4. 帧率设置

  5. 电源设置

  6. gama设置

不同屏幕的指令可能相同也有可能不一样,

相同驱动ID的屏幕,厂家不同,gama设置以及其它设置也有可能不一样。

具体都需要厂家提高参考代码。

5.2 底层函数

必备的底层函数一览:

void NT35510_Init(stc_lcd_controller_t *pstcLCD);

void NT35510_WriteData(stc_lcd_controller_t *pstcLCD, uint16_t u16Data);

void NT35510_WriteReg(stc_lcd_controller_t *pstcLCD, uint16_t u16Reg);

uint16_t NT35510_ReadData(stc_lcd_controller_t *pstcLCD);

void NT35510_WriteRegData(stc_lcd_controller_t *pstcLCD, uint16_t u16Reg, uint16_t u16Data);

uint16_t NT35510_ReadRegData(stc_lcd_controller_t *pstcLCD, uint16_t u16Reg);

uint16_t NT35510_ReadID(stc_lcd_controller_t *pstcLCD);

void NT35510_DisplayOn(stc_lcd_controller_t *pstcLCD);

void NT35510_DisplayOff(stc_lcd_controller_t *pstcLCD);

uint16_t NT35510_GetPixelWidth(void);

uint16_t NT35510_GetPixelHeight(void);

void NT35510_SetScanDir(stc_lcd_controller_t *pstcLCD, uint16_t u16Dir);

void NT35510_SetDisplayDir(stc_lcd_controller_t *pstcLCD, uint16_t u16Dir);

void NT35510_PrepareWriteRAM(stc_lcd_controller_t *pstcLCD);

void NT35510_SetBackLight(stc_lcd_controller_t *pstcLCD, uint8_t u8PWM);

void NT35510_SetCursor(stc_lcd_controller_t *pstcLCD, uint16_t u16Xpos, uint16_t u16Ypos);

void NT35510_WritePixel(stc_lcd_controller_t *pstcLCD, uint16_t u16Xpos, uint16_t u16Ypos, uint16_t u16RGBCode);

void NT35510_Clear(stc_lcd_controller_t *pstcLCD, uint16_t u16RGBCode);

具体实现:

需要做兼容处理的部分:

NT35510_Init 驱动初始化

NT35510_ReadID 读取驱动芯片ID

NT35510_SetScanDir 设置扫描方向 | 宽 高 写指令

cpp 复制代码
void NT35510_Init(stc_lcd_controller_t *pstcLCD)
{
    /* NOP */
    NT35510_WriteRegData(pstcLCD, 0x0000U, 0x00U);

    /* Read ID */
    m_stcLcdDevice.u16ID = NT35510_ReadID(pstcLCD);
	
	/* Chip Init */
	if(m_stcLcdDevice.u16ID == 0x9341){
		LCD_9341_Config(pstcLCD);
	} else if(m_stcLcdDevice.u16ID == 0x7789){
		LCD_7789_Config(pstcLCD);
	} else {
        /* Unsupported LCD */
    }
	
	/* Set LCD cursor */
    NT35510_SetDisplayDir(pstcLCD, LCD_DISPLAY_VERTICAL);

    /* Set cursor */
    NT35510_SetCursor(pstcLCD, 0U, 0U);

    /* Prepare to write to LCD RAM */
    NT35510_PrepareWriteRAM(pstcLCD);
}

/**
 * @brief  Read LCD ID.
 * @param  [in] pstcLCD:                LCD controller @ref stc_lcd_controller_t structure.
 * @retval LCD Register Value.
 */
uint16_t NT35510_ReadID(stc_lcd_controller_t *pstcLCD)
{
    uint16_t u16ID;

    /* Try to read ID: 0x9341 */
    NT35510_WriteReg(pstcLCD, 0xD3U);
    (void)NT35510_ReadData(pstcLCD);                /* dummy read */
    (void)NT35510_ReadData(pstcLCD);                /* read: 0x00 */
    u16ID  = NT35510_ReadData(pstcLCD) << 8;        /* read: 0x93 */
    u16ID |= NT35510_ReadData(pstcLCD);             /* read: 0x41 */
	if (u16ID != 0x9341U) {
        /* Try to read ID: 0x8552 */
        NT35510_WriteReg(pstcLCD, 0x04U);
        (void)NT35510_ReadData(pstcLCD);            /* dummy read */
        (void)NT35510_ReadData(pstcLCD);            /* read: 0x85 */
        u16ID  = NT35510_ReadData(pstcLCD) << 8;    /* read: 0x85 */
        u16ID |= NT35510_ReadData(pstcLCD);         /* read: 0x41 */
        if (u16ID == 0x8552U) {
            u16ID = 0x7789U;                        /* ID convert to: 0x7789 */
        }
		else {
			u16ID = 0U;                         	/* Unsupported LCD */
		}
	}
    return u16ID;
}

/**
 * @brief  Set scan direction.
 * @param  [in] pstcLCD:                LCD controller
 * @param  [in] u16Dir:                 Scan direction
 *         This parameter can be one of the following values:
 *           @arg LCD_SCAN_DIR_L2R_U2D: From left to right && from up to down
 *           @arg LCD_SCAN_DIR_L2R_D2U: From left to right && from down to up
 *           @arg LCD_SCAN_DIR_R2L_U2D: From right to left && from up to down
 *           @arg LCD_SCAN_DIR_R2L_D2U: From right to left && from down to up
 *           @arg LCD_SCAN_DIR_U2D_L2R: From up to down && from left to right
 *           @arg LCD_SCAN_DIR_U2D_R2L: From up to down && from right to left
 *           @arg LCD_SCAN_DIR_D2U_L2R: From down to up && from left to right
 *           @arg LCD_SCAN_DIR_D2U_R2L: From down to up && from right to left
 * @retval None
 */
void NT35510_SetScanDir(stc_lcd_controller_t *pstcLCD, uint16_t u16Dir)
{
    uint16_t u16Temp;
    uint16_t dirreg;
    uint16_t regval = 0U;

    /* when display dir is VERTICAL, 1963 IC change scan-direction, other IC don't change
       when display dir is HORIZONTAL, 1963 IC don't change scan-direction, other IC change */
    if (((0U == m_stcLcdDevice.u16Dir) && (m_stcLcdDevice.u16ID == 0x1963U)) || \
        ((1U == m_stcLcdDevice.u16Dir) && (m_stcLcdDevice.u16ID != 0x1963U))) {
        if (0U == u16Dir) {
            u16Dir = 6U;
        } else if (1U == u16Dir) {
            u16Dir = 7U;
        } else if (2U == u16Dir) {
            u16Dir = 4U;
        } else if (3UL == u16Dir) {
            u16Dir = 5U;
        } else if (4U == u16Dir) {
            u16Dir = 1U;
        } else if (5U == u16Dir) {
            u16Dir = 0U;
        } else if (6U == u16Dir) {
            u16Dir = 3U;
        } else if (7U == u16Dir) {
            u16Dir = 2U;
        } else {
            u16Dir = 6U;
        }
    }

    switch (u16Dir) {
        case LCD_SCAN_DIR_L2R_U2D:
            regval |= ((0U << 7) | (0U << 6) | (0U << 5));
            break;
        case LCD_SCAN_DIR_L2R_D2U:
            regval |= ((1U << 7) | (0U << 6) | (0U << 5));
            break;
        case LCD_SCAN_DIR_R2L_U2D:
            regval |= ((0U << 7) | (1U << 6) | (0U << 5));
            break;
        case LCD_SCAN_DIR_R2L_D2U:
            regval |= ((1U << 7) | (1U << 6) | (0U << 5));
            break;
        case LCD_SCAN_DIR_U2D_L2R:
            regval |= ((0U << 7) | (0U << 6) | (1U << 5));
            break;
        case LCD_SCAN_DIR_U2D_R2L:
            regval |= ((0U << 7) | (1U << 6) | (1U << 5));
            break;
        case LCD_SCAN_DIR_D2U_L2R:
            regval |= ((1U << 7) | (0U << 6) | (1U << 5));
            break;
        case LCD_SCAN_DIR_D2U_R2L:
            regval |= ((1U << 7) | (1U << 6) | (1U << 5));
            break;
        default:
            break;
    }

    if (0x5510U == m_stcLcdDevice.u16ID) {
        dirreg = 0x3600U;
    } else {
        dirreg = 0x36U;
    }

    /* 0x9341 & 0x7789 set BGR bit */
    if ((0x9341U == m_stcLcdDevice.u16ID) || (0x7789U == m_stcLcdDevice.u16ID)) {
        regval |= 0x08U;
    }

    NT35510_WriteRegData(pstcLCD, dirreg, regval);

    /* 1963 don't handle coordinate */
    if (m_stcLcdDevice.u16ID != 0x1963U) {
        if ((regval & 0x20U) > 0U) {
            /* swap X,Y */
            if (m_stcLcdDevice.u16Width < m_stcLcdDevice.u16Height) {
                u16Temp = m_stcLcdDevice.u16Width;
                m_stcLcdDevice.u16Width = m_stcLcdDevice.u16Height;
                m_stcLcdDevice.u16Height = u16Temp;
            }
        } else {
            /* swap X,Y */
            if (m_stcLcdDevice.u16Width > m_stcLcdDevice.u16Height) {
                u16Temp = m_stcLcdDevice.u16Width;
                m_stcLcdDevice.u16Width = m_stcLcdDevice.u16Height;
                m_stcLcdDevice.u16Height = u16Temp;
            }
        }
    }

    /* Set display window size */
	NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetXCmd);
	NT35510_WriteData(pstcLCD, 0U);
	NT35510_WriteData(pstcLCD, 0U);
	NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Width - 1U) >> 8);
	NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Width - 1U) & 0xFFU);
	NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd);
	NT35510_WriteData(pstcLCD, 0U);
	NT35510_WriteData(pstcLCD, 0U);
	NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Height - 1U) >> 8);
	NT35510_WriteData(pstcLCD, (m_stcLcdDevice.u16Height - 1U) & 0xFFU);
}

/**
 * @brief  Set screen direction.
 * @param  [in] pstcLCD:                LCD controller
 * @param  [in] u16Dir:                 Screen direction
 *         This parameter can be one of the following values:
 *           @arg LCD_DISPLAY_VERTICAL:   LCD vertical display
 *           @arg LCD_DISPLAY_HORIZONTAL: LCD horizontal display
 * @retval None
 */
void NT35510_SetDisplayDir(stc_lcd_controller_t *pstcLCD, uint16_t u16Dir)
{
	/* NT35310 / 9341 / 5310 / 7789 etc */
	m_stcLcdDevice.u16WRamCmd = 0x2CU;
	m_stcLcdDevice.u16SetXCmd = 0x2AU;
	m_stcLcdDevice.u16SetYCmd = 0x2BU;
	m_stcLcdDevice.u16Width  = 320U;
	m_stcLcdDevice.u16Height = 240U;
	
    m_stcLcdDevice.u16Dir = u16Dir;
    NT35510_SetScanDir(pstcLCD, LCD_SCAN_DIR);
}

底层通用函数:

NT35510_WriteData 写数据

NT35510_WriteReg 写寄存器

NT35510_ReadData 读数据

NT35510_WriteRegData 写寄存器数据

NT35510_ReadRegData 读寄存器数据

NT35510_DisplayOn 打开显示

NT35510_DisplayOff 关闭显示

NT35510_GetPixelWidth 获取像素宽度

NT35510_GetPixelHeight 获取像素高度

NT35510_PrepareWriteRAM 写RAM

NT35510_SetCursor 设置坐标

NT35510_WritePixel 写单个像素点颜色

NT35510_Clear 清屏

cpp 复制代码
/**
 * @brief  Write data on LCD data register.
 * @param  [in] pstcLCD:                LCD controller @ref stc_lcd_controller_t structure.
 * @param  [in] u16Data:                Data to be written
 * @retval None
 */
void NT35510_WriteData(stc_lcd_controller_t *pstcLCD, uint16_t u16Data)
{
    pstcLCD->u16RAM = u16Data;
}

/**
 * @brief  Write register on LCD register.
 * @param  [in] pstcLCD:                LCD controller @ref stc_lcd_controller_t structure.
 * @param  [in] u16Reg:                 Address of the selected register.
 * @retval None
 */
void NT35510_WriteReg(stc_lcd_controller_t *pstcLCD, uint16_t u16Reg)
{
    pstcLCD->u16REG = u16Reg;
}

/**
 * @brief  Read data from LCD data register.
 * @param  [in] pstcLCD:                LCD controller @ref stc_lcd_controller_t structure.
 * @retval Read data.
 */
uint16_t NT35510_ReadData(stc_lcd_controller_t *pstcLCD)
{
    return pstcLCD->u16RAM;
}

/**
 * @brief  Write to the selected LCD register.
 * @param  [in] pstcLCD:                LCD controller @ref stc_lcd_controller_t structure.
 * @param  [in] u16Reg:                 Address of the selected register.
 * @param  [in] u16Data:                Data to be written
 * @retval None
 */
void NT35510_WriteRegData(stc_lcd_controller_t *pstcLCD, uint16_t u16Reg, uint16_t u16Data)
{
    /* Write 16-bit index */
    pstcLCD->u16REG = u16Reg;

    /* Write 16-bit Reg */
    pstcLCD->u16RAM = u16Data;
}

/**
 * @brief  Read the selected LCD register.
 * @param  [in] pstcLCD:                LCD controller @ref stc_lcd_controller_t structure.
 * @param  [in] u16Reg:                 Address of the selected register.
 * @retval Register value
 */
uint16_t NT35510_ReadRegData(stc_lcd_controller_t *pstcLCD, uint16_t u16Reg)
{
    /* Write 16-bit index*/
    pstcLCD->u16REG = u16Reg;

    return pstcLCD->u16RAM;
}

/**
 * @brief  Enable the Display.
 * @param  [in] pstcLCD:                LCD controller
 * @retval None
 */
void NT35510_DisplayOn(stc_lcd_controller_t *pstcLCD)
{
    if (m_stcLcdDevice.u16ID == 0x5510U) {
        NT35510_WriteReg(pstcLCD, 0x2900U);     /* 5510 */
    } else {
        NT35510_WriteReg(pstcLCD, 0x29U);       /* 9341/5310/1963/7789 */
    }
}

/**
 * @brief  Disable the Display.
 * @param  [in] pstcLCD:                LCD controller
 * @retval None
 */
void NT35510_DisplayOff(stc_lcd_controller_t *pstcLCD)
{
    if (m_stcLcdDevice.u16ID == 0x5510U) {
        NT35510_WriteReg(pstcLCD, 0x2800U);     /* 5510 */
    } else {
        NT35510_WriteReg(pstcLCD, 0x28U);       /* 9341/5310/1963/7789 */
    }
}

/**
 * @brief  Get LCD PIXEL WIDTH.
 * @param  None
 * @retval LCD PIXEL WIDTH.
 */
uint16_t NT35510_GetPixelWidth(void)
{
    return m_stcLcdDevice.u16Width;
}

/**
 * @brief  Get LCD PIXEL HEIGHT.
 * @param  None
 * @retval LCD PIXEL HEIGHT.
 */
uint16_t NT35510_GetPixelHeight(void)
{
    return m_stcLcdDevice.u16Height;
}

/**
 * @brief  Prepare to write LCD RAM.
 * @param  [in] pstcLCD:                LCD controller
 * @retval None
 */
void NT35510_PrepareWriteRAM(stc_lcd_controller_t *pstcLCD)
{
    NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16WRamCmd);
}

/**
 * @brief  Set screen backlight.
 * @param  [in] pstcLCD:                LCD controller
 * @param  [in] u8PWM:                  PWM level
           This parameter can be a value between Min_Data = 0 and Max_Data = 100
 * @retval None
 */
void NT35510_SetBackLight(stc_lcd_controller_t *pstcLCD, uint8_t u8PWM)
{
    float32_t f32PWM = ((float32_t)u8PWM * 2.55F);

    NT35510_WriteReg(pstcLCD, 0xBEU);
    NT35510_WriteData(pstcLCD, 0x05U);
    NT35510_WriteData(pstcLCD, (uint16_t)f32PWM);
    NT35510_WriteData(pstcLCD, 0x01U);
    NT35510_WriteData(pstcLCD, 0xFFU);
    NT35510_WriteData(pstcLCD, 0x00U);
    NT35510_WriteData(pstcLCD, 0x00U);
}

/**
 * @brief  Set Cursor position.
 * @param  [in] pstcLCD:                LCD controller
 * @param  u16Xpos:                     Specifies the X position.
 * @param  u16Ypos:                     Specifies the Y position.
 * @retval None
 */
void NT35510_SetCursor(stc_lcd_controller_t *pstcLCD, uint16_t u16Xpos, uint16_t u16Ypos)
{
	NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetXCmd);
	NT35510_WriteData(pstcLCD, (u16Xpos >> 8));
	NT35510_WriteData(pstcLCD, (u16Xpos & 0xFFU));
	NT35510_WriteReg(pstcLCD, m_stcLcdDevice.u16SetYCmd);
	NT35510_WriteData(pstcLCD, (u16Ypos >> 8));
	NT35510_WriteData(pstcLCD, (u16Ypos & 0xFFU));
}

/**
 * @brief  Write pixel.
 * @param  [in] pstcLCD:                LCD controller
 * @param  u16Xpos:                     Specifies the X position.
 * @param  u16Ypos:                     Specifies the Y position.
 * @param  u16RGBCode:                  The RGB pixel color in RGB565 format
 * @retval None
 */
void NT35510_WritePixel(stc_lcd_controller_t *pstcLCD, uint16_t u16Xpos, uint16_t u16Ypos, uint16_t u16RGBCode)
{
    /* Set cursor */
    NT35510_SetCursor(pstcLCD, u16Xpos, u16Ypos);

    /* Prepare to write to LCD RAM */
    NT35510_PrepareWriteRAM(pstcLCD);

    NT35510_WriteData(pstcLCD, u16RGBCode);
}

/**
 * @brief  Clear screen.
 * @param  [in] pstcLCD:                LCD controller
 * @param  u16RGBCode:                  The RGB pixel color in RGB565 format
 * @retval None
 */
void NT35510_Clear(stc_lcd_controller_t *pstcLCD, uint16_t u16RGBCode)
{
    uint32_t i;
    uint32_t u32TotalPoint;

    /* Set cursor */
    NT35510_SetCursor(pstcLCD, 0U, 0U);

    /* Prepare to write to LCD RAM */
    NT35510_PrepareWriteRAM(pstcLCD);

    u32TotalPoint = (uint32_t)m_stcLcdDevice.u16Width * (uint32_t)m_stcLcdDevice.u16Height;

    for (i = 0UL; i < u32TotalPoint; i++) {
        NT35510_WriteData(pstcLCD, u16RGBCode);
    }
}

5.3 画线

利用差值法画线。包括水平线、垂直线、斜线。

画线是最基本的函数,基于画线函数可以衍生出画圆、画弧线、画矩形等多种图形。

/**

* @brief Draw line.

* @param [in] pstcLCD: LCD controller

* @param u16X1: Specifies the X position 1.

* @param u16X2: Specifies the X position 2.

* @param u16Y1: Specifies the Y position 1.

* @param u16Y2: Specifies the Y position 2.

* @param u16RGBCode: The RGB pixel color in RGB565 format

* @retval None

*/

void NT35510_DrawLine(stc_lcd_controller_t *pstcLCD, uint16_t u16X1, uint16_t u16Y1,

uint16_t u16X2, uint16_t u16Y2, uint16_t u16RGBCode)

{

int16_t t;

int16_t xerr = 0;

int16_t yerr = 0;

int16_t delta_x;

int16_t delta_y;

int16_t distance;

int16_t incx;

int16_t incy;

int16_t Row;

int16_t Col;

Row = (int16_t)u16X1;

Col = (int16_t)u16Y1;

delta_x = ((int16_t)u16X2 - (int16_t)u16X1); /* calc delta X, Y*/

delta_y = ((int16_t)u16Y2 - (int16_t)u16Y1);

if (delta_x > 0) {

incx = 1; /* forward u8Direction */

} else if (delta_x == 0) {

incx = 0; /* vertical line */

} else {

incx = -1; /* reverse direction */

delta_x = -delta_x;

}

if (delta_y > 0) {

incy = 1; /* downward direction */

} else if (delta_y == 0) {

incy = 0; /* horizontal line */

} else {

incy = -1; /* upward direction */

delta_y = -delta_y;

}

if (delta_x > delta_y) {

distance = delta_x; /* set axis */

} else {

distance = delta_y;

}

for (t = 0; t <= (distance + 1); t++) {

NT35510_WritePixel(pstcLCD, (uint16_t)Row, (uint16_t)Col, u16RGBCode); /* draw pixel */

xerr += delta_x ;

yerr += delta_y ;

if (xerr > distance) {

xerr -= distance;

Row += incx;

}

if (yerr > distance) {

yerr -= distance;

Col += incy;

}

}

}

Bresenham算法画圆

/**

* @brief Draw a circle.

* @param [in] pstcLCD: LCD controller

* @param [in] u16Xpos: X position

* @param [in] u16Ypos: Y position

* @param [in] u16Radius: Circle radius

* @param u16RGBCode: The RGB pixel color in RGB565 format

* @retval None

*/

void NT35510_DrawCircle(stc_lcd_controller_t *pstcLCD, uint16_t u16Xpos, uint16_t u16Ypos,

uint16_t u16Radius, uint16_t u16RGBCode)

{

int32_t decision; /* Decision Variable */

uint32_t current_x; /* Current X Value */

uint32_t current_y; /* Current Y Value */

decision = 3 - ((int32_t)u16Radius * 2);

current_x = 0U;

current_y = u16Radius;

while (current_x <= current_y) {

NT35510_WritePixel(pstcLCD, (u16Xpos + (uint16_t)current_x), (u16Ypos - (uint16_t)current_y), u16RGBCode);

NT35510_WritePixel(pstcLCD, (u16Xpos + (uint16_t)current_y), (u16Ypos - (uint16_t)current_x), u16RGBCode);

NT35510_WritePixel(pstcLCD, (u16Xpos + (uint16_t)current_y), (u16Ypos + (uint16_t)current_x), u16RGBCode);

NT35510_WritePixel(pstcLCD, (u16Xpos + (uint16_t)current_x), (u16Ypos + (uint16_t)current_y), u16RGBCode);

NT35510_WritePixel(pstcLCD, (u16Xpos - (uint16_t)current_x), (u16Ypos + (uint16_t)current_y), u16RGBCode);

NT35510_WritePixel(pstcLCD, (u16Xpos - (uint16_t)current_y), (u16Ypos + (uint16_t)current_x), u16RGBCode);

NT35510_WritePixel(pstcLCD, (u16Xpos - (uint16_t)current_x), (u16Ypos - (uint16_t)current_y), u16RGBCode);

NT35510_WritePixel(pstcLCD, (u16Xpos - (uint16_t)current_y), (u16Ypos - (uint16_t)current_x), u16RGBCode);

current_x++;

/* Bresenham algorithm */

if (decision < 0) {

decision += ((4 * (int32_t)current_x) + 6);

} else {

decision += (10 + (4 * ((int32_t)current_x - (int32_t)current_y)));

current_y--;

}

}

}

5.4 显示图片

像素点其实就是:

1)事先将要显示的图,转化成位图,确定每个像素点要显示的颜色

2)依次显示这些点

基于这种方法,可以衍生出显示文字符合、特殊图像等等。

不过该方法对内存要求高,需要占用RAM或ROM 来存储这些像素点颜色数据。

/**

* @brief Show Picture.

* @param [in] pstcLCD: LCD controller

* @param u16RGBCode: The RGB pixel color in RGB565 format

* @retval None

*/

void NT35510_Picture(stc_lcd_controller_t *pstcLCD, uint16_t *pu16RGBData)

{

uint32_t i;

uint32_t u32TotalPoint;

/* Set cursor */

NT35510_SetCursor(pstcLCD, 0U, 0U);

/* Prepare to write to LCD RAM */

NT35510_PrepareWriteRAM(pstcLCD);

u32TotalPoint = (uint32_t)m_stcLcdDevice.u16Width * (uint32_t)m_stcLcdDevice.u16Height;

for (i = 0UL; i < u32TotalPoint; i++) {

NT35510_WriteData(pstcLCD, pu16RGBData[i]);

}

}

相关推荐
森旺电子2 小时前
51单片机仿真摇号抽奖机源程序 12864液晶显示
单片机·嵌入式硬件·51单片机
不过四级不改名6774 小时前
蓝桥杯嵌入式备赛教程(1、led,2、lcd,3、key)
stm32·嵌入式硬件·蓝桥杯
小A1594 小时前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
Rorsion4 小时前
各种电机原理介绍
单片机·嵌入式硬件
善 .7 小时前
单片机的内存是指RAM还是ROM
单片机·嵌入式硬件
超级码农ProMax7 小时前
STM32——“SPI Flash”
stm32·单片机·嵌入式硬件
Asa3198 小时前
stm32点灯Hal库
stm32·单片机·嵌入式硬件
end_SJ10 小时前
初学stm32 --- 外部中断
stm32·单片机·嵌入式硬件
gantengsheng11 小时前
基于51单片机和OLED12864的小游戏《贪吃蛇》
单片机·嵌入式硬件·游戏·51单片机
嵌入式小强工作室11 小时前
stm32 查找进硬件错误方法
stm32·单片机·嵌入式硬件