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

目录

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

1. Include files

2. Local type definitions ('typedef')

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

4. Local variable definitions ('static')

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

5.1 驱动初始化

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           设置扫描方向 | 宽 高 写指令

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                        清屏

/**
 * @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]);
    }
}

你可能感兴趣的:(分享,嵌入式硬件)