STM32F429 Discovery FMC驱动原子4.3寸LCD

    本人手里有块STM32F429 Discovery板子,因为某种原因需要使用8080接口的LCD,而该块开发板自带的LCD接口采用LTDC驱动,所以就在正点原子这里买了一块4.3寸电容触摸屏,驱动IC为NT35510。
    为了快速搭建软件工程,本人使用STM32CubeMX工具生成代码模板,并编写了lcd.c和nt35510.c两个文件,代码如下:

lcd.c

typedef struct _LCD_DRV{
	uint32_t (*checkid)(void);
	void (*init)(void);
	void (*setpixel)(uint16_t color, uint16_t x, uint16_t y);
	void (*fillrect)(uint16_t color, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
	void (*bitmap)(uint16_t color[], uint16_t x0, uint16_t y0, uint16_t width, uint16_t height);
	void (*clear)(uint16_t color);
	int (*ioctrl)(uint32_t cmd, uint32_t param);
	uint16_t (*getpixel)(uint16_t x, uint16_t y);
}lcd_drv_t;

const lcd_drv_t* lcd_module[] = {
	&nt35510_module,
	&st7789v_module,
	/*any other lcd module*/
};

const lcd_drv_t *lcd_drv = 0;

void LCD_GPIO_Cfg(void)
{
	/*由于FMC的GPIO已由CubeMx自动配置,所以这里只设置RESET引脚*/
	
  	GPIO_InitTypeDef GPIO_InitStruct;

	GPIO_InitStruct.Pin = GPIO_PIN_0;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

void LCD_FMC_Cfg(void)
{
	/*
		由于STM32 CubeMx已自动生成相关FMC配置的代码,
		所以这里就无需额外设置
	*/
}


void LCD_Reset(void)
{
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
	delay_ms(100);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
	delay_ms(100);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
	delay_ms(100);
}


uint8_t LCD_CheckID(void)
{
	uint32_t id;
	int i;
	
	for(i = 0; i < (sizeof(lcd_module) / sizeof(lcd_module[0])); i++)
	{
		id = lcd_module[i]->checkid();
		if(0 != id)
		{
			printf("Found ID: %x\r\n", id);
			lcd_drv = lcd_module[i];
			return 1;
		}
	}
	
	return 0;
}

void LCD_Init(void)
{
	LCD_GPIO_Cfg();
	LCD_FMC_Cfg();
	LCD_Reset();
	if(LCD_CheckID())
	{
		lcd_drv->init();
	}
}

void LCD_DrawPixel(uint16_t color, uint16_t x, uint16_t y)
{
	if(lcd_drv)
		lcd_drv->setpixel(color, x, y);
}

void LCD_FillRect(uint16_t color, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{
	if(lcd_drv)
		lcd_drv->fillrect(color, x0, y0, x1, y1);
}

void LCD_DrawBitmap(uint16_t color[], uint16_t x0, uint16_t y0, uint16_t width, uint16_t height)
{
	if(lcd_drv)
		lcd_drv->bitmap(color, x0, y0, width, height);
}

void LCD_Clear(uint16_t color)
{
	if(lcd_drv)
		lcd_drv->clear(color);
}

要注意的是,如果你是使用的正点原子的模板或是自己搭建的模板,则需要实现LCD_GPIO_Cfg()及LCD_FMC_Cfg()两个函数,由于STM32CubeMX在配置GPIO及FMC时,已经自动生成了相应的代码,所以这里为空。另外,我的硬件上是将LCD_RS接在了 FMC_A0上的,所以LCD_DATA的地址为0x6C000002,请针对于自己的硬件自行修改。

void NT35510_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue)
{	
	LCD_WR_REG(LCD_Reg);
	LCD_WR_DATA(LCD_RegValue);
}	   

uint16_t NT35510_ReadReg(uint16_t LCD_Reg)
{										   
	LCD_WR_REG(LCD_Reg);		//写入要读的寄存器序号
	delay_us(5);		  
	return LCD_RD_DATA();		//返回读到的值
}   

//开始写GRAM
void NT35510_WriteRAM_Prepare(void)
{
	LCD_WR_REG(0X2C00);
}	 


void NT35510_DisplayOn(void)
{					   
	LCD_WR_REG(0X2900);	//开启显示
}	 

void NT35510_DisplayOff(void)
{	   
	LCD_WR_REG(0X2800);	//关闭显示
}   


void NT35510_SetWindow(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1)
{   
	NT35510_WriteReg(0x2A00, x0 >> 8);  
	NT35510_WriteReg(0x2A01, x0 & 0XFF);	  
	NT35510_WriteReg(0x2A02, x1 >> 8);   
	NT35510_WriteReg(0x2A03, x1 & 0XFF);   
	NT35510_WriteReg(0x2B00, y0 >> 8);   
	NT35510_WriteReg(0x2B01, y0 & 0XFF);  
	NT35510_WriteReg(0x2B02, y1 >> 8);   
	NT35510_WriteReg(0x2B03, y1 & 0XFF);  
} 


void NT35510_DrawPixel(uint16_t color, uint16_t x, uint16_t y)
{
	NT35510_SetWindow(x, y, x, y);		//设置光标位置 
	NT35510_WriteRAM_Prepare();	//开始写入GRAM
	LCD_WR_DATA(color); 
}


//清屏函数
void NT35510_Clear(uint16_t color)
{
	uint32_t i;      
	
	NT35510_SetWindow(0, 0, Width - 1, Height - 1);
	NT35510_WriteRAM_Prepare();     		 
	for(i = 0; i < Width * Height; i++)
	{
		LCD_WR_DATA(color);		
	}
}  


uint32_t NT35510_CheckID(void)
{
	uint8_t id1, id2, id3;
	
	id1 = NT35510_ReadReg(0XDA00);	//should be 0x00
	id2 = NT35510_ReadReg(0XDB00);	//should be 0x80
	id3 = NT35510_ReadReg(0XDC00);	//should be 0x00
 	printf(" Read ID:%x, %x, %x\r\n", id1, id2, id3);  
	
	if((id1 == 0x00) && (id2 == 0x80) && (id3 == 0x00))
		return 0x35510;
	else
		return 0;
}


void NT35510_Init(void)
{ 										  
 	delay_ms(50);
 	NT35510_WriteReg(0x0000,0x0001);
	delay_ms(50);  
		
	NT35510_WriteReg(0xF000,0x55);
	NT35510_WriteReg(0xF001,0xAA);
	NT35510_WriteReg(0xF002,0x52);
	NT35510_WriteReg(0xF003,0x08);
	NT35510_WriteReg(0xF004,0x01);
	
        ......
}

void NT35510_FillRect(uint16_t color, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
{          
	uint32_t i;
	uint16_t width, height;

	width = x1-x0+1;
	height = y1-y0+1;
	
	NT35510_SetWindow(x0, y0, x1, y1);
	NT35510_WriteRAM_Prepare();
	for(i = 0; i < width * height; i++)
	{
		LCD_WR_DATA(color);	   
	}
}  

//位图显示函数,位图中每个像素大小为16bit,高字节在前低字节在后
void NT35510_DrawBitmap(uint16_t color[], uint16_t x0, uint16_t y0, uint16_t width, uint16_t height)
{
	uint32_t i;
	uint16_t x1, y1;

	x1 = x0 + width - 1;
	y1 = y0 + height - 1;

	NT35510_SetWindow(x0, y0, x1, y1);
	NT35510_WriteRAM_Prepare();
	for(i = 0; i < width * height; i++)
	{
		LCD_WR_DATA(color[i]);
	}	
}


int NT35510_IOCtrl(uint32_t cmd, uint32_t param)
{
    switch(cmd)
    {
    case LCD_CMD_SLEEP_IN:
        break;

    case LCD_CMD_SLEEP_OUT:
        break;

    case LCD_CMD_SET_DIR:
        break;
		
    default:
        break;
    }
	return 0;
}


const lcd_drv_t nt35510_module = {
	NT35510_CheckID,
	NT35510_Init,
	NT35510_DrawPixel,
	NT35510_FillRect,
	NT35510_DrawBitmap,
	NT35510_Clear,
	NT35510_IOCtrl
};

工程源码请见附件: 点击打开链接

实验效果图片如下:




发布了68 篇原创文章 · 获赞 112 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/hexiaolong2009/article/details/45273035