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

目录

一个驱动.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]);

}

}

相关推荐
三佛科技-1341638421210 分钟前
高速风筒方案开发 高速风筒MCU控制方案设计
单片机·嵌入式硬件·智能家居·pcb工艺
清风6666666 小时前
基于单片机的螺旋藻生长大棚PH智能控制设计
单片机·嵌入式硬件·毕业设计·课程设计
ting_zh7 小时前
微控制器(Micro Controller Unit, MCU)基础整理
单片机·嵌入式硬件
清风6666667 小时前
基于单片机的图书馆智能座位管理平台
数据库·单片机·嵌入式硬件·毕业设计·课程设计
得单片机的运9 小时前
STM32的以太网的搭建
stm32·单片机·嵌入式硬件·物联网·以太网·iot·w5500
酷飞飞9 小时前
RTC和看门狗基于GD32F407VE的天空星的配置
stm32·单片机·嵌入式硬件·mcu
WD1372980155711 小时前
WD5030A,24V降5V,15A 大电流,应用于手机、平板、笔记本充电器
stm32·单片机·嵌入式硬件·智能手机·汽车·电脑·51单片机
日更嵌入式的打工仔11 小时前
GPIO 中断通用配置指南
stm32·单片机·嵌入式硬件
平凡灵感码头11 小时前
基于 STM32 的智能门锁系统,系统界面设计
stm32·单片机·嵌入式硬件
Truffle7电子12 小时前
STM32理论 —— 存储、中断
stm32·嵌入式硬件·嵌入式·存储·中断