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