历史上的今天
返回首页

历史上的今天

今天是:2024年09月27日(星期五)

正在发生

2019年09月27日 | STM32学习之旅⑤ SPI控制TFT,从底层到顶层的设计

2019-09-27 来源:eefocus

一、认识其本质

(一)认识SPI

SPI是串行外设接口(Serial Peripheral Interface)的缩写,SPI 总线是Motorola公司推出的同步串行接口技术,(关于同步还是异步,主要看通信双方的时钟线是否连在一起)。SPI由四根线完成数据传输,分别是SCK(时钟)、MOSI(主出从入)、MISO(主入从出)和SSEL(片选)。通讯时序图如下(当然很多SPI器件的数据手册都会给出响应的时序图):

这里写图片描述

SPI主要特点有:


可以同时发出和接收串行数据,是一种全双工的通信;

可以当作主机或从机工作

提供频率可编程时钟

发送结束中断标志

写冲突保护

总线竞争保护等

结构简单

传输速度快,通常可以达到几兆到几十兆每秒,常用于数据量比较大的传输。

主要缺点:

需要占用较多的接口线

只能有一个主机

没有应答机制

(二)常见显示器

关于常见的LCD、OLED、TFT

(三)TFT优势

TFT(Thin Film Transistor)是薄膜晶体管的缩写。是有源矩阵液晶的一种。是最好的LCD彩色显示器之一,TFT式显示器具有高响应度、高亮度、高对比度等优点,其显示效果接近CRT式显示器


TFT上的每个液晶像素点都是由集成在像素点后面的薄膜晶体管来驱动,因此反应时间较快,


并且可视角度大,一般可达130度左右


色彩丰富,可支持65536色


回到顶部


二、所需材料

TFT显示屏,看着高大上的电容屏真的买不起。。。


逻辑分析仪,对没错贫穷限制人的想象,不过24M的采样率测个SPI还是勉强能够应付


取模工具, 密码:4h7h


三、底层建筑

(一)模拟SPI

STM32内部外设自带SPI接口,为什么还要用IO口去模拟呢?原因就是移植性,用IO口模拟的程序移植性是最好的,无论是51、msp430还是stm32,或者是DSP,都可以用IO口实现,我们知道经典的51单片机是没有SPI接口的,这时候就需要IO口模拟去实现;在初期写显示驱动程序的时候,IO口模拟出错的可能性比直接用SPI接口小很多,可以大大提高我们写驱动的效率;另外,用IO口模拟SPI还可以让我们对SPI的读写时序有更深刻的认识。

这是TFT手册中对引脚的描述

这里写图片描述

由设备最短高电平保持时间,可以粗略计算出该设备能够兼容的SPI最高速度为1/(15*2ns)=33MHz,可见SPI是一种高速协议,然而STM32中SPI2的最高速度只支持16MHz,没有能发挥TFT的最高性能

这里写图片描述

根据以下时序图可以用软件模拟出数据传输的时序,并对TFT进行控制


这里写图片描述

/****************************************************************************

* 名    称:void  SPIv_WriteData(u8 Data)

* 功    能:STM32_模拟SPI写一个字节数据底层函数

* 入口参数:Data

* 出口参数:无

* 说    明:STM32_模拟SPI读写一个字节数据底层函数

****************************************************************************/

void  SPIv_WriteData(u8 Data)

{

    unsigned char i=0;

    for ( i = 8; i > 0; i --)

    {

        LCD_SCL_CLR;

        if ( Data & 0x80)

            LCD_SDA_SET; //输出数据

        else 

            LCD_SDA_CLR;    

        LCD_SCL_SET;

        Data <<= 1; 

    }

}

//******************************************************************

//函数名:  LCD_WR_DATA

//功能:    向液晶屏总线写入写8位数据

//输入参数:Data:待写入的数据

//返回值:  无

//修改记录:无

//******************************************************************

void LCD_WR_DATA(u8 data)

{   

    LCD_CS_CLR;          //软件控制片选信号

    LCD_RS_SET;

    SPIv_WriteData(data);

    LCD_CS_SET;          //软件控制片选信号

}

//******************************************************************

//函数名:  LCD_WR_DATA

//功能:    向液晶屏总线写入写8位数据

//输入参数:Data:待写入的数据

//返回值:  无

//修改记录:无

//******************************************************************

void LCD_WR_DATA(u8 data)

{   

    LCD_CS_CLR;          //软件控制片选信号

    LCD_RS_SET;

    SPIv_WriteData(data);

    LCD_CS_SET;          //软件控制片选信号

}

//******************************************************************

//函数名:  LCD_WR_REG

//功能:    向液晶屏总线写入写16位指令

//输入参数:Reg:待写入的指令值

//返回值:  无

//修改记录:无

//******************************************************************

void LCD_WR_REG(u16 data)

    LCD_CS_CLR;          //软件控制片选信号

    LCD_RS_CLR;

    SPIv_WriteData(data);

    LCD_CS_SET;          //软件控制片选信号

}


调用底层写命令和数据的函数来写寄存器

//******************************************************************

//函数名:  LCD_WriteReg

//功能:    写寄存器数据

//输入参数:LCD_Reg:寄存器地址

//LCD_RegValue:要写入的数据

//返回值:  无

//修改记录:无

//******************************************************************

void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)

{

    LCD_WR_REG(LCD_Reg);  

    LCD_WR_DATA(LCD_RegValue);     

}

//******************************************************************

//函数名:  LCD_WriteRAM_Prepare

//功能:    开始写GRAM

//在给液晶屏传送RGB数据前,应该发送写GRAM指令

//输入参数:无

//返回值:  无

//修改记录:无

//******************************************************************

void LCD_WriteRAM_Prepare(void)

{

    LCD_WR_REG(lcddev.wramcmd);

} 


复位函数

//******************************************************************

//函数名:  LCD_Reset

//功能:    LCD复位函数,液晶初始化前要调用此函数

//输入参数:无

//返回值:  无

//修改记录:无

//******************************************************************

void LCD_RESET(void)

{

#ifdef LCD_RST

    LCD_RST_CLR;

#endif

    LCD_WR_REG(0x01);

    delay_ms(100);

#ifdef LCD_RST

    LCD_RST_SET;

#endif

    LCD_WR_REG(0x01);

    delay_ms(50);

}


初始化GPIO

//******************************************************************

//函数名:  LCD_GPIOInit

//功能:    液晶屏IO初始化,液晶初始化前要调用此函数

//输入参数:无

//返回值:  无

//修改记录:无

//******************************************************************

void LCD_GPIOInit(void)

{

    GPIO_InitTypeDef  GPIO_InitStructure;

      

    RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB ,ENABLE);

#ifdefLCD_RST

    GPIO_InitStructure.GPIO_Pin = LCD_LED| LCD_RS| LCD_CS | LCD_SCL | LCD_SDA | LCD_RST;

#else

    GPIO_InitStructure.GPIO_Pin = LCD_LED| LCD_RS| LCD_CS | LCD_SCL | LCD_SDA;

#endif

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

    

    GPIO_Init(GPIOB, &GPIO_InitStructure);      

}


初始化TFT

//******************************************************************

//函数名:  LCD_Init

//功能:    LCD初始化

//输入参数:无

//返回值:  无

//修改记录:无

//******************************************************************

void LCD_Init(void)

{  

    LCD_GPIOInit();//使用模拟SPI

    LCD_RESET(); //液晶屏复位


    //************* Start Initial Sequence **********//

    //开始初始化液晶屏

    LCD_WR_REG(0x11);//Sleep exit 

    delay_ms (120);

    //ST7735R Frame Rate

    LCD_WR_REG(0xB1); 

    LCD_WR_DATA(0x01); 

    LCD_WR_DATA(0x2C); 

    LCD_WR_DATA(0x2D); 


    LCD_WR_REG(0xB2); 

    LCD_WR_DATA(0x01); 

    LCD_WR_DATA(0x2C); 

    LCD_WR_DATA(0x2D); 


    LCD_WR_REG(0xB3); 

    LCD_WR_DATA(0x01); 

    LCD_WR_DATA(0x2C); 

    LCD_WR_DATA(0x2D); 

    LCD_WR_DATA(0x01); 

    LCD_WR_DATA(0x2C); 

    LCD_WR_DATA(0x2D); 


    LCD_WR_REG(0xB4); //Column inversion 

    LCD_WR_DATA(0x07); 


    //ST7735R Power Sequence

    LCD_WR_REG(0xC0); 

    LCD_WR_DATA(0xA2); 

    LCD_WR_DATA(0x02); 

    LCD_WR_DATA(0x84); 

    LCD_WR_REG(0xC1); 

    LCD_WR_DATA(0xC5); 


    LCD_WR_REG(0xC2); 

    LCD_WR_DATA(0x0A); 

    LCD_WR_DATA(0x00); 


    LCD_WR_REG(0xC3); 

    LCD_WR_DATA(0x8A); 

    LCD_WR_DATA(0x2A); 

    LCD_WR_REG(0xC4); 

    LCD_WR_DATA(0x8A); 

    LCD_WR_DATA(0xEE); 


    LCD_WR_REG(0xC5); //VCOM 

    LCD_WR_DATA(0x0E); 


    LCD_WR_REG(0x36); //MX, MY, RGB mode  

    LCD_WR_DATA(0xC8); 


    //ST7735R Gamma Sequence

    LCD_WR_REG(0xe0); 

    LCD_WR_DATA(0x0f); 

    LCD_WR_DATA(0x1a); 

    LCD_WR_DATA(0x0f); 

    LCD_WR_DATA(0x18); 

    LCD_WR_DATA(0x2f); 

    LCD_WR_DATA(0x28); 

    LCD_WR_DATA(0x20); 

    LCD_WR_DATA(0x22); 

    LCD_WR_DATA(0x1f); 

    LCD_WR_DATA(0x1b); 

    LCD_WR_DATA(0x23); 

    LCD_WR_DATA(0x37); 

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x07); 

    LCD_WR_DATA(0x02); 

    LCD_WR_DATA(0x10); 


    LCD_WR_REG(0xe1); 

    LCD_WR_DATA(0x0f); 

    LCD_WR_DATA(0x1b); 

    LCD_WR_DATA(0x0f); 

    LCD_WR_DATA(0x17); 

    LCD_WR_DATA(0x33); 

    LCD_WR_DATA(0x2c); 

    LCD_WR_DATA(0x29); 

    LCD_WR_DATA(0x2e); 

    LCD_WR_DATA(0x30); 

    LCD_WR_DATA(0x30); 

    LCD_WR_DATA(0x39); 

    LCD_WR_DATA(0x3f); 

    LCD_WR_DATA(0x00); 

    LCD_WR_DATA(0x07); 

    LCD_WR_DATA(0x03); 

    LCD_WR_DATA(0x10);  


    LCD_WR_REG(0x2a);

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x7f);


    LCD_WR_REG(0x2b);

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x00);

    LCD_WR_DATA(0x9f);


    LCD_WR_REG(0xF0); //Enable test command  

    LCD_WR_DATA(0x01); 

    LCD_WR_REG(0xF6); //Disable ram power save mode 

    LCD_WR_DATA(0x00); 


    LCD_WR_REG(0x3A); //65k mode 

    LCD_WR_DATA(0x05);

    LCD_WR_REG(0x29);//Display on


    LCD_SetParam();//设置LCD参数 

    LCD_LED_SET;//点亮背光 

}


接下来是关键一步,这一步成功与否决定底层建筑是否搭建成功,在指定位置写入一个像素点


//******************************************************************

//函数名:  LCD_DrawPoint

//功能:    在指定位置写入一个像素点数据

//输入参数:(x,y):光标坐标

//返回值:  无

//修改记录:无

//******************************************************************

void LCD_DrawPoint(u16 x,u16 y)

{

    LCD_SetCursor(x,y);//设置光标位置 

    LCD_WR_DATA_16Bit(BLACK);

}


然后再主函数中调用这个函数

#include "stm32f10x.h"

#include "stm32f10x_gpio.h"

#include "timer.h"

int main()

{

    SystemInit();                //初始化系统,系统时钟设定为72MHz       

    delay_init();               //配置systick,中断时间设置为72000/72000000 = 1us

推荐阅读

史海拾趣

上海国芯(Gcore)公司的发展小趣事
加入必要的保护电路,如过流保护、过压保护等,防止电路因外部因素损坏。
Crouzet公司的发展小趣事

Crouzet公司,这家以生产自控产品为主的跨国公司,于1921年正式成立。创立之初,Crouzet主要专注于自控产品的研发和生产,凭借其卓越的技术和创新能力,很快在市场中占据了一席之地。公司逐渐扩大生产规模,提升产品质量,赢得了客户的信赖。

Gem Asia Enterprise Co Ltd公司的发展小趣事

随着全球对环保问题的日益关注,Gem Asia积极响应号召,将环保理念融入企业发展中。公司投入大量资源研发绿色电子产品和生产工艺,减少了对环境的影响。同时,Gem Asia还建立了完善的废旧电子产品回收体系,实现了资源的循环利用。这些举措不仅提升了企业的社会形象,还为企业带来了长期的经济效益和社会效益。

Axiohm公司的发展小趣事

随着环保意识的日益增强,Axiohm公司积极响应国家绿色发展的号召,将环保理念融入产品设计和生产过程中。公司投入大量资金研发环保材料和生产工艺,成功推出了一系列绿色电子产品。这些产品不仅符合环保标准,还具有良好的性能价格比,受到了消费者的广泛好评。Axiohm因此赢得了业界的赞誉和政府的支持。

CLAIREX公司的发展小趣事

随着订单的不断增加,Clairex意识到必须提升生产能力以满足市场需求。于是,公司投入大量资金引进了先进的生产设备和技术,并对生产线进行了优化改造。同时,Clairex还建立了严格的质量控制体系,从原材料采购到产品出厂的每一个环节都进行严格把关。这些措施确保了Clairex产品的质量和稳定性,赢得了客户的信任和好评。

FCT Electronics公司的发展小趣事

在国内市场取得成功后,FCT Electronics开始将目光投向国际市场。公司积极参加国际电子展会,与多家国际知名企业建立了合作关系。凭借出色的产品性能和专业的客户服务,FCT Electronics的测试设备逐渐在海外市场上占据了一席之地,为公司的国际化发展奠定了坚实基础。

问答坊 | AI 解惑

FPGA 设计的四种常用思想与技巧(一)

FPGA/CPLD 的设计思想与技巧是一个非常大的话题,由于篇幅所限,本文仅介绍一些常用的设计思想与技巧,包括乒乓球操作、串并转换、流水线操作和数据接口的同步方法。希望本文能引起工程师们的注意,如果能有意识地利用这些原则指导日后的设计工作, ...…

查看全部问答>

大家看看这两个波形的同步怎么产生?

大家帮帮我,其中三角波的频率是5KHz,梯形波是100个阶梯一个周期,上下对称,希望频率可调…

查看全部问答>

摄像机芯片组合(厂家内部资料)

为了提高广大技术员的摄像机识别能力,特把一些常见的芯片组合列出: 专业红外夜视摄像SONY产品型号及芯片组合   1、A4212SP/G4212SP/D4212SP:   芯片: CXD3141、CXD1267、CXA2096+ICX405; 2、A4512SP/G4512SP/D451 ...…

查看全部问答>

热烈慰问下考完研的兄弟姐妹们

今天考研就结束了,不管结果如何,很多人都可以暂时解脱了。 有个朋友辞了工作专门准备考研,EEWORLD一位同事的男朋友也在潜心考研,真的希望他们付出的能够有收获。…

查看全部问答>

内部资料-开关电源设计要领及设计全过程

内部资料-开关电源设计要领及设计全过程…

查看全部问答>

不明白+-*/的用法

LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;USE IEEE.STD_LOGIC_ARITH.ALL;USE IEEE.STD_LOGIC_UNSIGNED.ALL;ENTITY dat2bcd ISPORT(CLK:IN STD_LOGIC;     DAT:IN STD_LOGIC_VECTOR(7 DOWNTO 0);     BCD ...…

查看全部问答>

关于热释电红外传感器re200b和BISS0001的问题

电路图如上,做的是一个人体检测报警器 有采用菲涅尔透镜,传感器焊在电路板上,透镜盖在上面 现在按照以上的电路及参数做了板子,具体情况如下: 1.有人时,输出重复跳变,每次输出“1”约10秒,输出“0”约0.5秒; 2.没人时,基本跟有人的 ...…

查看全部问答>

基于LM3Sx9xx(With Net)的带RJ45接口的核心模块

本核心模块是基于LM3S6911\\6916\\8962及其引脚兼容芯片而设计,核心电路及网络接口(RJ45)已全部集成到模块之上,并将芯片GPIO及电源引脚引出; 模块采用双侧双排针对外连接而出,各排针间为标准2.54或2.54的整数倍间距,方便嵌入到各类板上应用,以增加 ...…

查看全部问答>

模电、数电参考书

我个人认为,初学者或者一般水平的人,看模电,推荐使用清华童诗白的模电、阎石的数电,还不错的。浙大的电路原理也还可以。…

查看全部问答>