STM32F103C8T6 3Line SPI驱动MD144-QQVGA TFT屏幕

最近闲的无事在淘宝发现的贼性价比的tft屏幕,9块钱3块。这不买来试试怎么对得起他3块钱的价格。如果想看资料这个就是该厂家的屏幕资料:MD144-QQVGA14P-01-V01 – LcmWikihttps://lcmwiki.com/md144-qqvga14p-01-v01/

买来之后看资料,他的驱动型号是ILI9163,不过相比我们传统买的TFT屏幕,他少了个D/C引脚,在一般的tft屏幕驱动器手册上,带D/C的spi是4-Line,而不带D/C的spi是3-line。

如下是该厂家的屏幕引脚图。

观察3-line spi的时序,他一个数据是发9bit,而第一个就是指定这个数据是D还是C(D=数据,C=命令,1代表D,0代表C)。

剩下来寄存器介绍配置我就懒得说了,都是和8080,4-line spi一样的,具体怎么样看看别人的文章,还是老规矩,我也不浪费手指打字,直接上涉及的代码。

pin.c

#include "pin.h"
#include "stdlib.h"
#include "string.h"

//初始化
int pin_dev_init(pin_dev_t *dev, const char *port, pin_mode_t mode)
{
	/*获取引脚号*/
	dev->pin = atoi(&port[2]);
	
	/*初始化RCC时钟*/
	switch (port[1])
	{
		case 'A': RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); dev->gpio = GPIOA; dev->portsouce = GPIO_PortSourceGPIOA; break;
		case 'B': RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); dev->gpio = GPIOB; dev->portsouce = GPIO_PortSourceGPIOB; break;
		case 'C': RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); dev->gpio = GPIOC; dev->portsouce = GPIO_PortSourceGPIOC; break;
		case 'D': RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); dev->gpio = GPIOD; dev->portsouce = GPIO_PortSourceGPIOD; break;
		case 'E': RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE); dev->gpio = GPIOE; dev->portsouce = GPIO_PortSourceGPIOE; break;
		case 'F': RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE); dev->gpio = GPIOF; dev->portsouce = GPIO_PortSourceGPIOF; break;
		case 'G': RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); dev->gpio = GPIOG; dev->portsouce = GPIO_PortSourceGPIOG; break;
		default: return -1;
	}
	
	/**
		JTMS/SWDIO PA13 
		JTCK/SWCLK PA14 
		JTDI PA15 
		JTDO/TRACESWO PB3 
		JNTRST PB4
	******************************/
	/*关闭JTAG引脚*/
	if (strcmp(port,"PB3")  == 0 || \
			strcmp(port,"PB4")  == 0 || \
			strcmp(port,"PA15") == 0)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
		GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
	}
	else if (strcmp(port,"PA13") == 0 || strcmp(port,"PA14") == 0)
	{
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
		GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);
	}
	
	/*初始化GPIO*/
	dev->inittype.GPIO_Pin = 0x01 << dev->pin;
	dev->inittype.GPIO_Mode = (GPIOMode_TypeDef)mode;
	dev->inittype.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(dev->gpio, &dev->inittype);
	
	return 0;
}

//输出模式
void pin_out_mode(pin_dev_t *dev, pin_mode_t mode)
{
	dev->inittype.GPIO_Mode = (GPIOMode_TypeDef)mode;
	GPIO_Init(dev->gpio, &dev->inittype);
}

//写
void pin_write(pin_dev_t dev, uint8_t n)
{
	if (n != 0)
	{
		pin_set(dev);
	}
	else
	{
		pin_reset(dev);
	}
}

//配置中断
void pin_set_exit(pin_dev_t *dev, int8_t trigger, uint8_t pre, uint8_t sub)
{
	int nvic;
	NVIC_InitTypeDef exit_nvicinittype;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	
	//初始化GPIO
	dev->inittype.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(dev->gpio, &dev->inittype);
	
	//配置GPIO源
	GPIO_EXTILineConfig(dev->portsouce,dev->pin);
	
	//配置中断
	EXTI_InitTypeDef exit_inittype;
	exit_inittype.EXTI_LineCmd = ENABLE;
	exit_inittype.EXTI_Mode = EXTI_Mode_Interrupt;
	exit_inittype.EXTI_Line = 0x01 << dev->pin;

	//选择极性
	if (trigger > 0)
	{
		exit_inittype.EXTI_Trigger = EXTI_Trigger_Rising;
	}
	else if (trigger < 0)
	{
		exit_inittype.EXTI_Trigger = EXTI_Trigger_Falling;
	}
	else
	{
		exit_inittype.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	}
	EXTI_Init(&exit_inittype);
	
	//配置NVIC
	switch (dev->pin)
	{
		case 0: nvic = EXTI0_IRQn; break;
		case 1: nvic = EXTI1_IRQn; break;
		case 2: nvic = EXTI2_IRQn; break;
		case 3: nvic = EXTI3_IRQn; break;
		case 4: nvic = EXTI4_IRQn; break;
		default:
			if (dev->pin >= 5 && dev->pin < 10)
			{	
				nvic = EXTI9_5_IRQn;
			}	
			else
			{
				nvic = EXTI15_10_IRQn;
			}
	}
	exit_nvicinittype.NVIC_IRQChannel = nvic;
	exit_nvicinittype.NVIC_IRQChannelCmd = ENABLE;
	exit_nvicinittype.NVIC_IRQChannelPreemptionPriority = pre;
	exit_nvicinittype.NVIC_IRQChannelSubPriority = sub;
	NVIC_Init(&exit_nvicinittype);
}











pin.h

#ifndef __PIN_H__
#define __PIN_H__
	#include "stm32f10x.h"

	typedef enum 
	{
		PIN_OUTPUT_PP = GPIO_Mode_Out_PP,
		PIN_OUTPUT_OD = GPIO_Mode_Out_OD,
		PIN_INPUT_U   = GPIO_Mode_IPU,
		PIN_INPUT_D   = GPIO_Mode_IPD,
		PIN_INPUT_IN  = GPIO_Mode_IN_FLOATING,
	} pin_mode_t;
	
	typedef struct 
	{
		GPIO_InitTypeDef inittype;
		GPIO_TypeDef  *gpio;
		uint16_t pin;
		uint8_t portsouce;
	} pin_dev_t;
	
	#define pin_set(dev)				(dev.gpio->BSRR = (0x01 << dev.pin))
	#define pin_reset(dev)			(dev.gpio->BRR  = (0x01 << dev.pin))
	#define pin_read(dev)				((dev.gpio->IDR & (0x0001 << dev.pin)) != 0x00)

	int pin_dev_init(pin_dev_t *dev, const char *port, pin_mode_t mode);
	void pin_out_mode(pin_dev_t *dev, pin_mode_t mode);
	void pin_set_exit(pin_dev_t *dev, int8_t trigger, uint8_t pre, uint8_t sub);
	void pin_write(pin_dev_t dev, uint8_t n);
#endif /*__PIN_H__*/

spi.c

#include "spi.h"


//SPI初始化
spi_dev_t spi_dev_init(const char *css, const char *scl, const char *miso, const char *mosi, uint8_t mode, uint8_t bit)
{
	spi_dev_t dev = {0};
	dev.mode = mode;
	dev.first_bit = bit;
	
	if (css)
	{
		pin_dev_init(&dev.css, css, PIN_OUTPUT_PP);
		pin_set(dev.css);
	}
	if (scl)
	{
		pin_dev_init(&dev.scl, scl, PIN_OUTPUT_PP);
	}
	if (miso)
	{
		pin_dev_init(&dev.miso, miso, PIN_INPUT_U);
	}
	if (mosi)
	{
		pin_dev_init(&dev.mosi, mosi, PIN_OUTPUT_PP);
	}
	spi_set_mode(&dev, mode);
	return dev;
}

//设置模式
void spi_set_mode(spi_dev_t *dev, uint8_t mode)
{
	if (mode == 0 || mode == 1)
	{
		pin_reset(dev->scl);
	}
	else if (mode == 2 || mode == 3)
	{
		pin_set(dev->scl);
	}
	else
	{
		pin_reset(dev->scl);
		mode = 0;
	}
	dev->mode = mode;
}

//设置位模式
void spi_set_firstbit(spi_dev_t *dev, uint8_t bit)
{
	dev->first_bit = bit;
}

void spi_css_set(spi_dev_t dev)
{
	pin_set(dev.css);
}

void spi_css_reset(spi_dev_t dev)
{
	pin_reset(dev.css);
}


//写一个字节
void spi_writebyte(spi_dev_t dev, uint8_t byte)
{
  //mode:[0:00;1:01;2:10;3:11]
	uint8_t i;

	switch (dev.mode)
	{
		case 0:
		{
			for (i = 0; i < 8; i++)
			{
				pin_write(dev.mosi,dev.first_bit ? byte & (0x80 >> i) : byte & (0x01 << i));
				pin_set(dev.scl); //00;上升沿有效数据
				pin_reset(dev.scl);
			}
		} break;
		case 1:
		{
			for (i = 0; i < 8; i++)
			{
				pin_set(dev.scl);
				pin_write(dev.mosi,dev.first_bit ? byte & (0x80 >> i) : byte & (0x01 << i));
				pin_reset(dev.scl); //01;下升沿有效数据
			}
		} break;
		case 2:
		{
			for (i = 0; i < 8; i++)
			{
				pin_write(dev.mosi,dev.first_bit ? byte & (0x80 >> i) : byte & (0x01 << i));
				pin_reset(dev.scl); //10;下升沿有效数据
				pin_set(dev.scl);
			}
		} break;
		case 3:
		{
			for (i = 0; i < 8; i++)
			{
				pin_reset(dev.scl);
				pin_write(dev.mosi,dev.first_bit ? byte & (0x80 >> i) : byte & (0x01 << i));
				pin_set(dev.scl); //11;上升沿有效数据
			}
		}
		default: 
		{
			for (i = 0; i < 8; i++)
			{
				pin_write(dev.mosi,dev.first_bit ? byte & (0x80 >> i) : byte & (0x01 << i));
				pin_set(dev.scl); //00;上升沿有效数据
				pin_reset(dev.scl);
			}
		}
	}
}

//读一个字节
uint8_t spi_readbyte(spi_dev_t dev)
{
	uint8_t i;
	uint8_t byte = 0x00;
	switch (dev.mode)
	{
		case 0:
		{
			for (i = 0; i < 8; i++)
			{
				pin_set(dev.scl); //00;上升沿有效数据
				if (pin_read(dev.miso) != 0)
				{
					byte |= (dev.first_bit ? (0x80 >> i) : (0x01 << i));
				}
				pin_reset(dev.scl);
			}
		} break;
		case 1:
		{
			for (i = 0; i < 8; i++)
			{
				pin_set(dev.scl);
				pin_reset(dev.scl); //01;下升沿有效数据
				if (pin_read(dev.miso) != 0)
				{
					byte |= (dev.first_bit ? (0x80 >> i) : (0x01 << i));
				}
			}
		} break;
		case 2:
		{
			for (i = 0; i < 8; i++)
			{
				pin_reset(dev.scl); //10;下升沿有效数据
				if (pin_read(dev.miso) != 0)
				{
					byte |= (dev.first_bit ? (0x80 >> i) : (0x01 << i));
				}
				pin_set(dev.scl);
			}
		} break;
		case 3:
		{
			for (i = 0; i < 8; i++)
			{
				pin_reset(dev.scl);
				pin_set(dev.scl); //11;上升沿有效数据
				if (pin_read(dev.miso) != 0)
				{
					byte |= (dev.first_bit ? (0x80 >> i) : (0x01 << i));
				}
			}
		}
		default: 
		{
			for (i = 0; i < 8; i++)
			{
				pin_set(dev.scl); //00;上升沿有效数据
				if (pin_read(dev.miso) != 0)
				{
					byte |= (dev.first_bit ? (0x80 >> i) : (0x01 << i));
				}
				pin_reset(dev.scl);
			}
		}
	}
	return byte;
}













spi.h

#ifndef __SPI_H__
#define __SPI_H__
	#include "pin.h"
	
	typedef struct
	{
		uint8_t mode;
		uint8_t first_bit;
		pin_dev_t css;
		pin_dev_t scl;
		pin_dev_t miso;
		pin_dev_t mosi;
	} spi_dev_t;

	spi_dev_t spi_dev_init(const char *css, const char *scl, const char *miso, const char *mosi, uint8_t mode, uint8_t bit);
	void spi_set_mode(spi_dev_t *dev, uint8_t mode);
	void spi_set_firstbit(spi_dev_t *dev, uint8_t bit);
	void spi_css_set(spi_dev_t dev);
	void spi_css_reset(spi_dev_t dev);
	void spi_writebyte(spi_dev_t dev, uint8_t byte);
	uint8_t spi_readbyte(spi_dev_t dev);
#endif /*__SPI_H__*/

md144.c

#include "md114.h"
#include "delay.h"


spi_dev_t md144_spi;
pin_dev_t md144_res;

//初始化端口
void md144_port_init(const char *css, const char *scl, const char *sda, const char *res)
{
	//PIN[CS.;RES;SCL;SDA;VCC;GND]
	md144_spi = spi_dev_init(css, scl, 0, sda, 0, 1);
	pin_dev_init(&md144_res, res, PIN_OUTPUT_PP);
	pin_set(md144_res);
}

//设置数据/命令模式
void md144_set_dcmode(uint8_t mode)
{ 
	//1:Data;0:Commad
	pin_write(md144_spi.mosi, mode);
	pin_set(md144_spi.scl);
	pin_reset(md144_spi.scl);
}

//写入一个字节
void md144_writebyte(uint8_t byte)
{
	spi_writebyte(md144_spi, byte);
}


//写入寄存器
void md144_write_reg(uint8_t reg)
{
	spi_css_reset(md144_spi);
	
	md144_set_dcmode(0);
	md144_writebyte(reg);
	
	spi_css_set(md144_spi);
}

//写入参数
void md144_write_param(uint8_t param)
{
	spi_css_reset(md144_spi);
	
	md144_set_dcmode(1);
	md144_writebyte(param);
	
	spi_css_set(md144_spi);
}

//写数据
void md144_write_data(uint16_t dat)
{
	md144_write_param(dat>>8);
	md144_write_param(dat&0xFF);
}

//复位
void md144_reset(void)
{
	pin_set(md144_res);
	delay_ms(50);
	pin_reset(md144_res);
	delay_ms(200);	
	pin_set(md144_res);
	delay_ms(200);
}

//初始化
void md144_init(void)
{
	//PIN[CS.;RES;SCL;SDA;VCC;GND]
	md144_port_init("PB6","PB8","PB9","PB7");

	md144_reset();
	
	//ILI9163C,FOR LB1.41
	md144_write_reg(0x11); //Exit Sleep
	delay_ms(50);
	
	md144_write_reg(0x26); //Set Default Gamma
	md144_write_param(0x04);
	
	md144_write_reg(0xB1);//Set Frame Rate
	md144_write_param(0x0C);
	md144_write_param(0x14);
	
	md144_write_reg(0xC0); //Set VRH1[4:0] & VC[2:0] for VCI1 & GVDD
	md144_write_param(0x0C);
	md144_write_param(0x05);
	
	md144_write_reg(0xC1); //Set BT[2:0] for AVDD & VCL & VGH & VGL
	md144_write_param(0x02);//0x00
	
	md144_write_reg(0xC5); //Set VMH[6:0] & VML[6:0] for VOMH & VCOML
	md144_write_param(0x29);  //31  21  29
	md144_write_param(0x43);  //58   48  43
	
	md144_write_reg(0xC7);
	md144_write_param(0x40);
	
	md144_write_reg(0x3a); //Set Color Format
	md144_write_param(0x05);
	
	md144_write_reg(0x2A); //Set Column Address
	md144_write_param(0x00);
	md144_write_param(0x00);
	md144_write_param(0x00);
	md144_write_param(0x7F);
	
	md144_write_reg(0x2B); //Set Page Address
	md144_write_param(0x00);
	md144_write_param(0x00);
	md144_write_param(0x00);
	md144_write_param(0x9F);
	
	md144_write_reg(0x36); //Set Scanning Direction
	md144_write_param(0xC8); //0xc8
	
	md144_write_reg(0xB7); //Set Source Output Direction
	md144_write_param(0x00);
	
	md144_write_reg(0xF2); //Enable Gamma bit
	md144_write_param(0x01);
	
	md144_write_reg(0xE0);
	md144_write_param(0x36);//p1
	md144_write_param(0x29);//p2
	md144_write_param(0x12);//p3
	md144_write_param(0x22);//p4
	md144_write_param(0x1C);//p5
	md144_write_param(0x15);//p6
	md144_write_param(0x42);//p7
	md144_write_param(0xB7);//p8
	md144_write_param(0x2F);//p9
	md144_write_param(0x13);//p10
	md144_write_param(0x12);//p11
	md144_write_param(0x0A);//p12
	md144_write_param(0x11);//p13
	md144_write_param(0x0B);//p14
	md144_write_param(0x06);//p15
	
	
	md144_write_reg(0xE1);
	md144_write_param(0x09);//p1
	md144_write_param(0x16);//p2
	md144_write_param(0x2D);//p3
	md144_write_param(0x0D);//p4
	md144_write_param(0x13);//p5
	md144_write_param(0x15);//p6
	md144_write_param(0x40);//p7
	md144_write_param(0x48);//p8
	md144_write_param(0x53);//p9
	md144_write_param(0x0C);//p10
	md144_write_param(0x1D);//p11
	md144_write_param(0x25);//p12
	md144_write_param(0x2E);//p13
	md144_write_param(0x34);//p14
	md144_write_param(0x39);//p15

	md144_write_reg(0x29); // Display On
	
	md144_write_reg(0x2c);
	
	md144_fill_color(0,0,128,128,0xFFFF);
}


//设置窗口
void md144_set_windowns(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
{
	md144_write_reg(0x2a);
	md144_write_param((x)>>8);
	md144_write_param((x));
	md144_write_param((x+w)>>8);
	md144_write_param(x+w);

	md144_write_reg(0x2b);
	md144_write_param((y)>>8);
	md144_write_param((y));
	md144_write_param((y+h)>>8);
	md144_write_param(y+h);

	md144_write_reg(0x2c);  //写PSARM
}


//填充单颜色
void md144_fill_color(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
{
	uint32_t size = w*h;
	
	md144_set_windowns(x, y, w, h);

	spi_css_reset(md144_spi);
	while (size--)
	{
		md144_set_dcmode(1);
		md144_writebyte(color>>8);
		md144_set_dcmode(1);
		md144_writebyte(color&0xFF);
	}
	spi_css_set(md144_spi);
}



//填充颜色
void md144_fill_pcolor(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t *pcolor)
{
	uint32_t size = w*h;
	
	md144_set_windowns(x, y, w, h);
	
	spi_css_reset(md144_spi);
	while (size--)
	{
		md144_set_dcmode(1);
		md144_writebyte((*pcolor)>>8);
		md144_set_dcmode(1);
		md144_writebyte((*pcolor)&0xFF);
		pcolor++;
	}
	spi_css_set(md144_spi);
}













md144.h

#ifndef __MD114_H__
#define __MD114_H__
	#include "spi.h"
	void md144_init(void);
	void md144_set_windowns(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
	void md144_fill_color(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color);
	void md144_fill_pcolor(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t *pcolor);
#endif /*__MD114_H__*/

main.c

#include "stm32f10x.h"
#include "md114.h"
#include "delay.h"
#include "string.h"

int main(void)
{
	delay_init(72);
	md144_init();
	
	
	while (1)
	{
		md144_fill_color(0,0, 128, 128, 0XF800);
		md144_fill_color(0,0, 128, 128, 0XAFE5);
		md144_fill_color(0,0, 128, 128, 0X001F); 
	}
}




















其他的什么显示字符串、画图什么的自行补充就行,运行的结果就这样了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值