最近闲的无事在淘宝发现的贼性价比的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);
}
}
其他的什么显示字符串、画图什么的自行补充就行,运行的结果就这样了