STM32----电容触摸屏,OLED屏和LCD屏

目录

电容触摸屏

OLED屏

LCD屏


 

  • 电容触摸屏

充放电电路原理:

 

电路充放电公式:

 

电容触摸按键原理:

R:外接电容充放电电阻。

Cs:TPAD和PCB间的杂散电容。

Cx:手指按下时,手指和TPAD之间的电容。

开关:电容放电开关,由STM32 IO口代替。

 

检测电容触摸按键过程:

  1. TPAD引脚设置为推挽输出,输出0,实现电容放电到0。
  2. TPAD引脚设置为浮空输入(IO复位后的状态),电容开始充电。
  3. 同时开启TPAD引脚的输入捕获开始捕获。
  4. 等待充电完成(充电到底Vx,检测到上升沿)。
  5. 计算充电时间。

(没有按下的时候,充电时间为T1(default)。按下TPAD,电容变大,所以充电时间为T2。我们可以通过检测充放电时间,来判断是否按下。如果T2-T1大于某个值,就可以判断 有按键按下。)

 

程序思路函数:

1.void TPAD_Reset(void)函数:复位TPAD      

设置IO口为推挽输出输出0,电容放电。等待放电完成之后,设置为浮空输入,从而开始充电。同时把计数器的CNT设置为0。

2. TPAD_Get_Val()函数:获取一次捕获值(得到充电时间)      

复位TPAD,等待捕获上升沿,捕获之后,得到定时器的值,计算充电时间。

3.TPAD_Get_MaxVal()函数:      

多次调用TPAD_Get_Val函数获取充电时间。获取最大的值。

4.TPAD_Init()函数:初始化TPAD      

在系统启动后,初始化输入捕获。先10次调用TPAD_Get_Val()函数获取10次充电时间,然后获取中间N(N=8或者6)次的平均值,作为在没有电容触摸按键按下的时候的充电时间缺省值tpad_default_val。 

5.TPAD_Scan()函数:扫描TPAD      

调用TPAD_Get_MaxVal函数获取多次充电中最大的充电时间,跟tpad_default_val比较,如果大于某个阈值,则认为有触摸动作。  

6.void TIM5_CH2_Cap_Init(u16 arr,u16 psc)//输入捕获通道初始化    

可以使用任何一个定时器。M3使用定时器5,M4使用的定时器2。

 

  • OLED屏

       OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。 OLED显示技术具有自发光的特性,采用非常薄的有机材料涂层和玻璃基板,当有电流通过时,这些有机材料就会发光,而且OLED显示屏幕可视角度大,并且能够节省电能,从2003年开始这种显示设备在MP3播放器上得到了应用。 LCD都需要背光,而OLED不需要,因为它是自发光的。这样同样的显示,OLED效果要来得好一些。以目前的技术,OLED的尺寸还难以大型化,但是分辨率确可以做到很高。

 

ALINETEK 0.96 寸OLED模块:

1)模块有单色和双色两种可选,单色为纯蓝色,而双色则为黄蓝双色。单色模块每个像素点只有亮与不亮两种情况,没有颜色区分。

2)尺寸小,显示尺寸为0.96寸,而模块的尺寸仅为27mm*26mm大小。

3)高分辨率,该模块的分辨率为128*64。

4)多种接口方式,该模块提供了总共4种接口包括:6800、8080两种并行接口方式、 4线的穿行SPI接口方式,、IIC接口方式(只需要2       根线就可以控制OLED了!)。

5)不需要高压,直接接3.3V就可以工作了。

 

4种模式通过模块的BS1/BS2设置,BS1/BS2的设置与模块接口模式的关系如表所示:

 

OLED 8080并行接口信号线:

CS:OLED片选信号。

WR:向OLED写入数据。

RD:从OLED读取数据。 D[7:0]:8位双向数据线。

RST(RES):硬复位OLED。

DC:命令/数据标志(0,读写命令;1,读写数据)。     

                        

 

SSD1306的命令:

  • 命令0X81:设置对比度。包含两个字节,第一个0X81为命令,随后发送的一个字节为要设置的对比度的值。这个值设置得越大屏幕就越亮。
  • 命令0XAE/0XAF:0XAE为关闭显示命令;0XAF为开启显示命令。
  • 命令0X8D:包含2个字节,第一个为命令字,第二个为设置值,第二个字节的BIT2表示电荷泵的开关状态,该位为1,则开启电荷泵,为0                      则关闭。在模块初始化的时候,这个必须要开启,否则是看不到屏幕显示的。
  • 命令0XB0~B7:用于设置页地址,其低三位的值对应着GRAM的页地址。
  • 命令0X00~0X0F:用于设置显示时的起始列地址低四位。
  • 命令0X10~0X1F:用于设置显示时的起始列地址高四位。

 

OLED初始化过程:

 

OLED初始化:

//初始化SSD1306					    
void OLED_Init(void)
{
 …//设置IO口模式,所有用到的io口设置为推挽模式。
GPIO_Init();
 …//初始化代码,写相关寄存器
OLED_WR_Byte(0xAE,OLED_CMD); //关闭显示
OLED_WR_Byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
OLED_WR_Byte(80,OLED_CMD);   //[3:0],分频因子;[7:4],震荡频率
OLED_WR_Byte(0xA8,OLED_CMD); //设置驱动路数
OLED_WR_Byte(0X3F,OLED_CMD); //默认0X3F(1/64) 
OLED_WR_Byte(0xD3,OLED_CMD); //设置显示偏移
OLED_WR_Byte(0X00,OLED_CMD); //默认为0
…
…
OLED_Clear();
}

 

OLED写一个字节:

//向SSD1306写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
   DATAOUT(dat);	    
  if(cmd)
     OLED_RS_Set();
  else 
     OLED_RS_Clr();		   
  OLED_CS_Clr();
  OLED_WR_Clr();	 
  OLED_WR_Set();
  OLED_CS_Set();	  
  OLED_RS_Set();	 
} 

 

OLED更新缓存,显示内容:

u8 OLED_GRAM[128][8];	

void OLED_Refresh_Gram(void)
{
   u8 i,n;		    
  for(i=0;i<8;i++)  
  {  
    OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
    OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
    OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
    
   for(n=0;n<128;n++)
     OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); 
  }   
}

 

OLED画点函数:

void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
   u8 pos,bx,temp=0;
   if(x>127||y>63)return;//超出范围了.
   pos=7-y/8;
   bx=y%8;
   temp=1<<(7-bx);
   if(t)OLED_GRAM[x][pos]|=temp;
   else OLED_GRAM[x][pos]&=~temp;	    
}

 

OLED字符显示函数:

//在指定位置显示一个字符,包括部分字符
//x:0~127  y:0~63
//mode:0,反白显示;1,            size:选择字体 12/16/24
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
{      			    
   u8 temp,t,t1; u8 y0=y;
   u8 csize=(size/8+((size%8)?1:0))*(size/2);	//得到字体一个字符对应点阵集所占的字节数
   chr=chr-' ';//得到偏移后的值		 
    for(t=0;t<csize;t++)
    {   
     if(size==12)temp=asc2_1206[chr][t]; 	 	//调用1206字体
    else if(size==16)temp=asc2_1608[chr][t];	//调用1608字体
    else if(size==24)temp=asc2_2412[chr][t];	//调用2412字体
    else return;	//没有的字库
     for(t1=0;t1<8;t1++)
    {
	if(temp&0x80)OLED_DrawPoint(x,y,mode);
	else OLED_DrawPoint(x,y,!mode);
	temp<<=1;
	y++;
	if((y-y0)==size)
	{
	  y=y0;
	  x++;  break;
	}
  }  	 
    }          
}

 

  • LCD屏

      TFTLCD即薄膜晶体管液晶显示器。它与无源TN-LCD、STN-LCD的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。TFTLCD具有:亮度好、对比度高、层次感强、颜色鲜艳等特点。是目前最主流的LCD显示器。广泛应用于电视、手机、电脑、平板等各种电子产品。

 

ALINETEK 2.8寸 TFTLCD 16位80并口驱动简介:

模块的8080并口读/写的过程为:

先根据要写入/读取的数据的类型,设置RS为高(数据)/低(命令),然后拉低片选,选中ILI9341,接着我们根据是读数据,还是要写数据置RD/WR为低,然后:

1.读数据:在RD的上升沿, 读取数据线上的数据(D[15:0]);

2.写数据:在WR的上升沿,使数据写入到ILI9341里面

                    

                                     并口写时序图                                                                                                        并口读时序图

 

 

0XD3指令

该指令为读ID4指令,用于读取LCD控制器的ID 。因此,同一个代码,可以根据ID的不同,执行不同的LCD驱动初始化,以兼容不同的LCD屏幕。

 

0X36指令

该指令为存储访问控制指令,可以控制ILI9341存储器的读写方向,简单的说,就是在连续写GRAM的时候,可以控制GRAM指针的增长方向,从而控制显示方式(读GRAM也是一样)。

 

0X2A指令

该指令是列地址设置指令,在从左到右,从上到下的扫描方式(默认)下面,该指令用于设置横坐标(x坐标)

 

0X2B指令

该指令是页地址设置指令,在从左到右,从上到下的扫描方式(默认)下面,该指令用于设置纵坐标(y坐标)

 

0X2C指令

该指令是写GRAM指令,在发送该指令之后,我们便可以往LCD的GRAM里面写入颜色数据了,该指令支持连续写 (地址自动递增)

 

0X2E指令

该指令是读GRAM指令,用于读取ILI9341的显存(GRAM),同0X2C指令,该指令支持连续读 (地址自动递增)

 

FSMC简介:

FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和16位PC存储器卡连接,STM32的FSMC接口支持包括SRAM、NAND FLASH、NOR FLASH和PSRAM等存储器。

 

      FSMC驱动外部SRAM时,外部SRAM的控制一般有:地址线(如A0~A25)、数据线(如D0~D15)、写信号(WE,即WR)、读信号(OE,即RD)、片选信号(CS),如果SRAM支持字节控制,那么还有UB/LB信号。      

      而TFTLCD的信号我们在前面介绍过,包括:RS、D0~D15、WR、RD、CS、RST和BL等,其中真正在操作LCD的时候需要用到的就只有:RS、D0~D15、WR、RD和CS。其操作时序和SRAM的控制完全类似,唯一不同就是TFTLCD有RS信号,但是没有地址信号。            TFTLCD通过RS信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如我们把RS接在A0上面,那么当FSMC控制器写地址0的时候,会使得A0变为0,对TFTLCD来说,就是写命令。而FSMC写地址1的时候,A0将会变为1,对TFTLCD来说,就是写数据了。这样,就把数据和命令区分开了,他们其实就是对应SRAM操作的两个连续地址。当然RS也可以接在其他地址线上,战舰V3和精英板开发板都是把RS连接在A10上面,而探索者STM32F4把RS接在A6上面。          

     因此,可以把TFTLCD当成一个SRAM来用,只不过这个SRAM有2个地址,这就是FSMC可以驱动LCD的原理。

 

7个底层接口函数:

1,写寄存器值函数 :void LCD_WR_REG(u16 regval)

2,写数据函数:void LCD_WR_DATA(u16 data)

3,读数据函数:u16 LCD_RD_DATA(void)

4,写寄存器内容函数: void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)

5,读寄存器内容函数: u16 LCD_ReadReg(u16 LCD_Reg)

6,开始写GRAM函数: void LCD_WriteRAM_Prepare(void)

7,写GRAM函数: void LCD_WriteRAM(u16 RGB_Code)

LCD初始化函数伪代码:

//LCD初始化
void LCD_Init(void)
{
    初始化GPIO;
    初始化FSMC;		             	//Mini板不需要
    读取LCD ID;	
    printf(“LCD ID:%x\r\n”,lcddev.id);//打印LCD ID,用到了串口1
                                        //所以必须初始化串口1,否则黑屏	
    根据不同的ID执行LCD初始化代码;
    LCD_Display_Dir(0);		 	//默认为竖屏
    LCD_LED=1;			 	//点亮背光
    LCD_Clear(WHITE);			//清屏
}

//设置光标位置
//Xpos:横坐标
//Ypos:纵坐标
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{	 
     if(lcddev.id==0X9341||lcddev.id==0X5310)
     {		    
          LCD_WR_REG(lcddev.setxcmd); 
          LCD_WR_DATA(Xpos>>8);
          LCD_WR_DATA(Xpos&0XFF);  
          LCD_WR_REG(lcddev.setycmd); 
	 LCD_WR_DATA(Ypos>>8);
	 LCD_WR_DATA(Ypos&0XFF); 
     }else if(lcddev.id==XXXX)	//根据不同的LCD型号,执行不同的代码
     { 
	 ……//省略部分代码
     }
}
		 
//画点
//x,y:坐标
//POINT_COLOR:此点的颜色
void LCD_DrawPoint(u16 x,u16 y)
{
    LCD_SetCursor(x,y);		//设置光标位置 
    LCD_WriteRAM_Prepare();	//开始写入GRAM
    LCD->LCD_RAM=POINT_COLOR; 	//非Mini板的操作方式   
}
//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24
//mode:叠加方式(1)还是非叠加方式(0)
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode)
{  							  
       u8 temp,t1,t;
       u16 y0=y;
       u8 csize=(size/8+((size%8)?1:0))*(size/2);	//得到字体一个字符对应点阵集所占的字节数	
       num=num-' ';	//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
       for(t=0;t<csize;t++)
       {  
if(size==12)temp=asc2_1206[num][t]; 		//调用1206字体
             else if(size==16)temp=asc2_1608[num][t];	//调用1608字体
             else if(size==24)temp=asc2_2412[num][t];	//调用2412字体
             else return;			//没有的字库
             for(t1=0;t1<8;t1++)
             {			    
      if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);
      else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR);
                    temp<<=1;
                    y++;
                    if(y>=lcddev.height)return;		//超区域了
                    if((y-y0)==size)
                    {
	y=y0;
	x++;
	if(x>=lcddev.width)return;		//超区域了
	break;
                     }
              }  	 
        }  	    	   	 	  
} 

 

  • 5
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值