OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 8521|回复: 11

学习STM32 玩TFT屏 第七季

[复制链接]

71

主题

467

帖子

0

精华

高级会员

Rank: 4

积分
800
金钱
800
注册时间
2011-11-18
在线时间
5 小时
发表于 2012-6-24 00:18:58 | 显示全部楼层 |阅读模式
上一季说了,我们还可以做个没有背景颜色的显示字符函数.
所以在写一个字符之前我们要先知道要写的那点颜色是什么,咋办咧~~~~~~

有办法的,我们先读这一点的颜色出来!!
怎么样读呢,我们先看下代码

//返回值:此点的颜色
u16 LCD_ReadPoint(u16 x,u16 y)
{
u16 t;
LCD_WriteReg(0x0020,x);  //X
LCD_WriteReg(0x0021,y);  //Y

LCD_WR_REG(0x22);       //选择GRAM地址
 
GPIOB->CRL=0X88888888; //PB0-7  上拉输入
GPIOB->CRH=0X88888888; //PB8-15 上拉输入
GPIOB->ODR=0XFFFF;     //全部输出高

LCD_RS_SET;
LCD_CS_CLR;
//读取数据(读GRAM时,需要读2次)
LCD_RD_CLR;    
LCD_RD_SET;
delay_us(2);//FOR 9320,延时2us    
//dummy READ
LCD_RD_CLR;    
delay_us(2);//FOR 8989,延时2us    
LCD_RD_SET;
t=DATAIN;  
LCD_CS_SET;

 
GPIOB->CRL=0X33333333; //PB0-7  上拉输出
GPIOB->CRH=0X33333333; //PB8-15 上拉输出
GPIOB->ODR=0XFFFF;    //全部输出高  

return t;
 
}


LCD_WriteReg(0x0020,x);  //X
LCD_WriteReg(0x0021,y);  //Y

LCD_WR_REG(0x22);       //选择GRAM地址


首先,蓝色的字很好理解,先确定要读的位置坐标,然后用指令0x22 用函数  LCD_WR_REG;  写进去,表示你已确定了,下一步是读还是写数据 由你来定.

好,这里我们要的是读,所以将 IO设面输入模式:  

GPIOB->CRL=0X88888888; //PB0-7  上拉输入
GPIOB->CRH=0X88888888; //PB8-15 上拉输入
GPIOB->ODR=0XFFFF;     //全部输出高

然后开始读操作:

LCD_RS_SET;     <<=======  SET读写数据, 如是CLR
LCD_CS_CLR;
                                                       //读取数据(读GRAM时,需要读2次)
LCD_RD_CLR;    
LCD_RD_SET;
delay_us(2);                                  //FOR 9320,延时2us    
                                                      //dummy READ
LCD_RD_CLR;    
delay_us(2);                                  //FOR 8989,延时2us    
LCD_RD_SET;

t=DATAIN;  

LCD_CS_SET;

这里要注意了,读取数据的时候,要将LCD_RD拉底一次,拉高一次,然后再拉底一次,然后还要再拉高一次,才能读GPIOB->IDR;
为什么要读两次,这是厂家研发时定好的,我们就不要理它了,反正记住就行.

( PS:    #define DATAIN       GPIOB->IDR;           //数据输入     <<=======  我们在开头已经设了)  


好了,拿到数据后记住将IO设回输出状态,  ARM输入输出设置是比51麻烦多了,可能功能越强大就越麻烦吧.

GPIOB->CRL=0X33333333; //PB0-7  上拉输出
GPIOB->CRH=0X33333333; //PB8-15 上拉输出
GPIOB->ODR=0XFFFF;    //全部输出高  

最后,记住给调用它的程式返回一个读出的值.

        return t;


好了,读出颜色了有办法了,我们就写个代码将字符显示出来吧.其实和上一季的差不多.改动一下就OK了.

以下是我写的:

//透明背景色的显示字符函数  ***********************************************************************************

void SHOW_char_NBC(u8 Page,u8 List,u8 onechar)
{
 u8 i,j;
 u16 temp1,temp2,temp3,temp4;

 temp1=onechar-' ';

 temp3=F_COLOR;

 for (i=0;i<16;i++)
{
temp4=asc2_1608[temp1];      <<==========取字模  

for (j=0;j<8;j++)
{
temp2 = temp4;             <<======红色的这三行是 取出字模的每一个Bit
temp2 &= 0x01;             <<======记住了噢,从最底位开始取
temp4 >>=1;


if(temp2==0)
{
F_COLOR=LCD_ReadPoint(List*8+j,Page*16+i);     <<====如果是取出来的是  0 ,那就将读出来的颜色原位再写回去,下边绿色的4行就是做这个的
}
else
    {
    F_COLOR=temp3;   <<===============如果 是 1 的地方画上前景色
}


LCD_WriteReg(0x0020,List*8+j);  //X                                 <<====标定位置   X 及 Y
LCD_WriteReg(0x0021,Page*16+i);  //Y
LCD_WR_REG(0x22);       <<========================  确定位置

LCD_WR_DATA(F_COLOR);     <<=======开炮~~~~~~~~~~~~将颜色数值写进去
}
}
}


好了,我们将昨天的main主程式改动一丁点:   (就是红色的那一丁点)

// 主函数   ************************************************************************************************
int main(void)
{
  u8   k=' ';

  Stm32_Clock_Init(9);
  delay_init(72);
  uart_init(72,9600);
  LCD_IO_Init();
  LCD_init();


  while (1) 
    {   
B_COLOR=color(7,14,7);
clear_lcd();


B_COLOR = color(30,0,0);
F_COLOR = color(30,60,30);

SHOW_char_NBC(9,14,k); //void SHOW_char(u8 Page,u8 List,u8 onechar)

k=k+1;
if (k-' '>=95)k=' ';


delay_ms(500);
}
}


好,编译好丢板子看看~~~~~~~~~~~~~~~~~~~

上一季的背景色红色没了~~~~~~~~~是不是更和谐了呢   ^-^Y
  

以下是全部代码,大家可以改动来玩玩.记住.会改了,就是懂了.



#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "FONT.h"


//快速IO
#define LCD_CS_SET  GPIOC->BSRR=1<<9    //片选端口          PC9
#define LCD_RS_SET GPIOC->BSRR=1<<8    //数据/命令            C8    
#define LCD_WR_SET GPIOC->BSRR=1<<7    //写数据    PC7
#define LCD_RD_SET GPIOC->BSRR=1<<6    //读数据    PC6
    
#define LCD_CS_CLR  GPIOC->BRR=1<<9     //片选端口          PC9
#define LCD_RS_CLR GPIOC->BRR=1<<8     //数据/命令            C8    
#define LCD_WR_CLR GPIOC->BRR=1<<7     //写数据    PC7
#define LCD_RD_CLR GPIOC->BRR=1<<6     //读数据    PC6
    
//慢速IO
#define LCD_CS PCout(9)  //片选端口        PC9
#define LCD_RS PCout(8)  //数据/命令        C8    
#define LCD_WR PCout(7)  //写数据  PC7
#define LCD_RD PCout(6)  //读数据  PC6

#define LCD_LED PCout(10)  //背光

//PB0~15,作为数据线
#define DATAOUT(x)   GPIOB->ODR=x;         //数据输出
#define DATAIN       GPIOB->IDR;           //数据输入

#define LCD_WR_DATA(data){\
LCD_RS_SET;\
LCD_CS_CLR;\
DATAOUT(data);\
LCD_WR_CLR;\
LCD_WR_SET;\
LCD_CS_SET;\
}

u16  F_COLOR,B_COLOR;



void LCD_IO_Init(void)
  RCC->APB2ENR|=1<<3;//先使能外设PORTB时钟
  RCC->APB2ENR|=1<<4;//先使能外设PORTC时钟

RCC->APB2ENR|=1<<0;    //开启辅助时钟
JTAG_Set(SWD_ENABLE);  //开启SWD
 
//PORTC6~10  推挽输出 
GPIOC->CRH&=0XFFFFF000;
GPIOC->CRH|=0X00000333; 
GPIOC->CRL&=0X00FFFFFF;
GPIOC->CRL|=0X33000000;  
GPIOC->ODR|=0X07C0;   
//PORTB 推挽输出 
GPIOB->CRH=0X33333333;
GPIOB->CRL=0X33333333;   
GPIOB->ODR=0XFFFF;
}

////正常IO写 寄存器 函数
//void LCD_WR_REG(u8 data)
//{ 
// LCD_RS=0;//写地址  
//  LCD_CS=0; 
// DATAOUT(data); 
// LCD_WR=0; 
// LCD_WR=1; 
//  LCD_CS=1;   
//} 
//
////正常IO写 8位数据 函数
//void LCD_WR_DATA(u16 data)
//
//{
//LCD_RS=1;
//LCD_CS=0;
//DATAOUT(data);
//LCD_WR=0;
//LCD_WR=1;
//LCD_CS=1;
//} 
//写寄存器函数=>快
void LCD_WR_REG(u8 data)
LCD_RS_CLR;//写地址  
  LCD_CS_CLR; 
DATAOUT(data); 
LCD_WR_CLR; 
LCD_WR_SET; 
  LCD_CS_SET;   
}


//写寄存器
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{
LCD_WR_REG(LCD_Reg);  
LCD_WR_DATA(LCD_RegValue);       
}


//读寄存器
u16 LCD_ReadReg(u8 LCD_Reg)
{    
u16 t;
LCD_WR_REG(LCD_Reg);    //写入要读的寄存器号  
GPIOB->CRL=0X88888888;  //PB0-7  上拉输入
GPIOB->CRH=0X88888888;  //PB8-15 上拉输入
GPIOB->ODR=0XFFFF;      //全部输出高

LCD_RS=1;
LCD_CS=0;
//读取数据(读寄存器时,并不需要读2次)
LCD_RD=0;    
LCD_RD=1;
t=DATAIN;  
LCD_CS=1; 
 
GPIOB->CRL=0X33333333; //PB0-7  上拉输出
GPIOB->CRH=0X33333333; //PB8-15 上拉输出
GPIOB->ODR=0XFFFF;    //全部输出高
return t;  
}      



//返回值:此点的颜色
u16 LCD_ReadPoint(u16 x,u16 y)
{
u16 t;
LCD_WriteReg(0x0020,x);  //X
LCD_WriteReg(0x0021,y);  //Y

LCD_WR_REG(0x22);       //选择GRAM地址
 
GPIOB->CRL=0X88888888; //PB0-7  上拉输入
GPIOB->CRH=0X88888888; //PB8-15 上拉输入
GPIOB->ODR=0XFFFF;     //全部输出高

LCD_RS_SET;
LCD_CS_CLR;
//读取数据(读GRAM时,需要读2次)
LCD_RD_CLR;    
LCD_RD_SET;
delay_us(2);//FOR 9320,延时2us    
//dummy READ
LCD_RD_CLR;    
delay_us(2);//FOR 8989,延时2us    
LCD_RD_SET;
t=DATAIN;  
LCD_CS_SET;

 
GPIOB->CRL=0X33333333; //PB0-7  上拉输出
GPIOB->CRH=0X33333333; //PB8-15 上拉输出
GPIOB->ODR=0XFFFF;    //全部输出高  

return t;
 
}



void LCD_init()                       //  LCD ID: 0xB505
{
LCD_WriteReg(0x0000,0x0000);
LCD_WriteReg(0x0000,0x0000);
LCD_WriteReg(0x0000,0x0000);
LCD_WriteReg(0x0000,0x0000);
LCD_WriteReg(0x00a4,0x0001);
delay_ms(20);   
LCD_WriteReg(0x0060,0x2700);
LCD_WriteReg(0x0008,0x0202);
LCD_WriteReg(0x0030,0x0214);
LCD_WriteReg(0x0031,0x3715);
LCD_WriteReg(0x0032,0x0604);
LCD_WriteReg(0x0033,0x0e16);
LCD_WriteReg(0x0034,0x2211);
LCD_WriteReg(0x0035,0x1500);
LCD_WriteReg(0x0036,0x8507);
LCD_WriteReg(0x0037,0x1407);
LCD_WriteReg(0x0038,0x1403);
LCD_WriteReg(0x0039,0x0020);
LCD_WriteReg(0x0090,0x001a);
LCD_WriteReg(0x0010,0x0000);
LCD_WriteReg(0x0011,0x0007);
LCD_WriteReg(0x0012,0x0000);
LCD_WriteReg(0x0013,0x0000);
delay_ms(20);
LCD_WriteReg(0x0010,0x0730);
LCD_WriteReg(0x0011,0x0137);
delay_ms(20);
LCD_WriteReg(0x0012,0x01b8);
delay_ms(20);
LCD_WriteReg(0x0013,0x0f00);
LCD_WriteReg(0x002a,0x0080);
LCD_WriteReg(0x0029,0x0048);
delay_ms(20);
LCD_WriteReg(0x0001,0x0100);
LCD_WriteReg(0x0002,0x0700);
LCD_WriteReg(0x0003,0x1230);//LCD_WriteReg(0x0003,0x1230);
LCD_WriteReg(0x0008,0x0202);
LCD_WriteReg(0x000a,0x0000);
LCD_WriteReg(0x000c,0x0000);
LCD_WriteReg(0x000d,0x0000);
LCD_WriteReg(0x000e,0x0030);
LCD_WriteReg(0x0050,0x0000);
LCD_WriteReg(0x0051,0x00ef);
LCD_WriteReg(0x0052,0x0000);
LCD_WriteReg(0x0053,0x013f);
LCD_WriteReg(0x0060,0x2700);
LCD_WriteReg(0x0061,0x0001);
LCD_WriteReg(0x006a,0x0000);
//LCD_WriteReg(0x0080,0x0000);
//LCD_WriteReg(0x0081,0x0000);
LCD_WriteReg(0x0090,0X0011);
LCD_WriteReg(0x0092,0x0600);
LCD_WriteReg(0x0093,0x0402);
LCD_WriteReg(0x0094,0x0002);
delay_ms(20);
LCD_WriteReg(0x0007,0x0001);
delay_ms(20);
LCD_WriteReg(0x0007,0x0061);
LCD_WriteReg(0x0007,0x0173);
LCD_WriteReg(0x0020,0x0000);
LCD_WriteReg(0x0021,0x0000);   
LCD_WriteReg(0x00,0x22); 

LCD_LED=1;
}

//设置一种颜色************************************************************************************************
u16 color(u8 R,u8 G,u8 B)
{
u16  CRGB,RGB0,RGB1,RGB2,RGB3,RGB4;

RGB0=B;

RGB1=G;
RGB2=RGB1<<5;

RGB3=R;
RGB4=RGB3<<11;

CRGB =RGB0|RGB2|RGB4;

return CRGB;
}


//画一个点   ************************************************************************************************
void DrawPoint(u16 x,u16 y)
{
LCD_WriteReg(0x0020,x);  //X
LCD_WriteReg(0x0021,y);  //Y

LCD_WR_REG(0x22);
LCD_WR_DATA(F_COLOR);
}



//以背景色清屏 ************************************************************************************************
void clear_lcd()
{
u16  i,j;

LCD_WriteReg(0x0020,0x00);  //X
LCD_WriteReg(0x0021,0x00);  //Y
LCD_WR_REG(0x22);

for (i=0;i<320;i++) 
{
for (j=0;j<240;j++)
{
LCD_WR_DATA(B_COLOR);
}
}
}

 //透明背景色的显示字符函数  ***********************************************************************************

void SHOW_char_NBC(u8 Page,u8 List,u8 onechar)
{
 u8 i,j;
 u16 temp1,temp2,temp3,temp4;

 temp1=onechar-' ';

 temp3=F_COLOR;

 for (i=0;i<16;i++)
{
temp4=asc2_1608[temp1];




for (j=0;j<8;j++)
{
temp2 = temp4;
temp2 &= 0x01;
temp4 >>=1;


if(temp2==0)
{
F_COLOR=LCD_ReadPoint(List*8+j,Page*16+i);
}
else
    {
    F_COLOR=temp3;
}


LCD_WriteReg(0x0020,List*8+j);  //X
LCD_WriteReg(0x0021,Page*16+i);  //Y
LCD_WR_REG(0x22);

LCD_WR_DATA(F_COLOR);
}
}
}

//固定前影色和背景色的显示字符函数  ************************************************************************************************
void SHOW_char(u8 Page,u8 List,u8 onechar)    

{
u8 i,j;
u16 temp1,temp2,temp3,temp4;

temp1=onechar-' ';

temp3=F_COLOR;

LCD_WriteReg(0x0050,List*8);
LCD_WriteReg(0x0051,(List*8)+7);

LCD_WriteReg(0x0052,Page*16);
LCD_WriteReg(0x0053,(Page*16)+15);

LCD_WriteReg(0x0020,List*8);  //X
LCD_WriteReg(0x0021,Page*16);  //Y

LCD_WR_REG(0x22);

for (i=0;i<16;i++)
{
temp4=asc2_1608[temp1];
for (j=0;j<8;j++)
{
temp2 = temp4;
temp2 &= 0x01;
temp4 >>=1;


if(temp2==0)
{
F_COLOR=B_COLOR;
}
else
    {
    F_COLOR=temp3;
}

LCD_WR_DATA(F_COLOR);
}
}

}


// 主函数   ************************************************************************************************
int main(void)
{
  u8   k=' ';

  Stm32_Clock_Init(9);
  delay_init(72);
  uart_init(72,9600);
  LCD_IO_Init();
  LCD_init();


  while (1) 
    {   
B_COLOR=color(7,14,7);
clear_lcd();


B_COLOR = color(30,0,0);
F_COLOR = color(30,60,30);

SHOW_char_NBC(9,14,k); //void SHOW_char(u8 Page,u8 List,u8 onechar)

k=k+1;
if (k-' '>=95)k=' ';


delay_ms(500);
}
}
我的工作就是天天在玩
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
发表于 2012-6-24 01:47:47 | 显示全部楼层
"这里要注意了,读取数据的时候,要将LCD_RD拉底一次,拉高一次,然后再拉底一次,然后还要再拉高一次,才能读GPIOB->IDR;
为什么要读两次,这是厂家研发时定好的,我们就不要理它了,反正记住就行."

第一次称为“假读”,后面的就不是了,datasheet的结构图里有个锁存,第一次读的时候锁存的内容没有更新,是无效的




手册中是这么说明,但是解释得也不详细:

ILI9320 has a 16-bit index register (IR), an 18-bit write- data register (WDR), and an  18-bit read-data register  
(RDR). 

The IR is the register to  store index information from control registers and the internal GRAM. The  
WDR is the register to temporarily store data to be written to control registers and the internal GRAM. The  
RDR is the register to temporarily store data read from the GRAM. 

Data from the MPU to be written to the internal GRAM are first written to the WDR and then autom atically
written to the internal GRAM in internal operation. Data are read via the RDR from the internal GRAM. 
Therefore, invalid data are read out to the data  bus when the ILI9320 read the first data from the internal GRAM.

 Valid data are read out after the ILI9320 performs the second read operation. 

我的理解是每读完一次后 RDR 就从 GRAM 更新数据,所以第一次读到的数据是无效的。

作为驱动代码的使用者,大可不必了解这些。但是如果要把驱动代码移植到新的MCU的时候,可能就不得不去啃手册了。
我玩51的时候以前买过个HX8347的屏,卖家给的代码是不带读功能的,后来都得自己对着手册写。

https://github.com/roxma
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2012-6-24 02:05:37 | 显示全部楼层
深夜来顶.
回复 支持 反对

使用道具 举报

71

主题

467

帖子

0

精华

高级会员

Rank: 4

积分
800
金钱
800
注册时间
2011-11-18
在线时间
5 小时
 楼主| 发表于 2012-6-24 03:41:07 | 显示全部楼层
噢呀,假读.明白了.
我的工作就是天天在玩
回复 支持 反对

使用道具 举报

25

主题

163

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
443
金钱
443
注册时间
2012-4-29
在线时间
38 小时
发表于 2013-7-30 19:24:10 | 显示全部楼层
还有个思路是,不用读,在需要写背景色的那些点,把地址跳过去,重新设置传输数据的起始位置。
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
22
金钱
22
注册时间
2013-9-28
在线时间
0 小时
发表于 2013-9-28 16:13:28 | 显示全部楼层

谢谢楼主。。。学习了很多

There's always hope.....
回复 支持 反对

使用道具 举报

8

主题

76

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
264
金钱
264
注册时间
2013-9-5
在线时间
31 小时
发表于 2013-9-30 07:46:47 | 显示全部楼层
学习记号备用
回复 支持 反对

使用道具 举报

28

主题

1489

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1656
金钱
1656
注册时间
2013-7-24
在线时间
1 小时
发表于 2013-9-30 08:51:05 | 显示全部楼层
读出要写的点的颜色目的是什么?直接写入就行吧
于20150522停用该账号:http://www.microstar.club
回复 支持 反对

使用道具 举报

63

主题

305

帖子

1

精华

高级会员

Rank: 4

积分
853
金钱
853
注册时间
2012-8-3
在线时间
79 小时
发表于 2013-10-29 01:45:58 | 显示全部楼层
回复【8楼】styleno1:
---------------------------------
GUI中,写一个弹出窗口之前要将原来的数据记录下来,当窗口关闭后可以恢复原来的画面
回复 支持 反对

使用道具 举报

28

主题

1489

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1656
金钱
1656
注册时间
2013-7-24
在线时间
1 小时
发表于 2013-10-29 19:19:26 | 显示全部楼层
回复【9楼】EDA3rd:
---------------------------------
哦,这样子啊。我一般记录特征然后重建。
于20150522停用该账号:http://www.microstar.club
回复 支持 反对

使用道具 举报

17

主题

168

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
260
金钱
260
注册时间
2014-4-12
在线时间
0 小时
发表于 2014-10-22 19:58:19 | 显示全部楼层
学的太彻底了
规格严格,功夫到家
回复 支持 反对

使用道具 举报

86

主题

983

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1848
金钱
1848
注册时间
2013-4-15
在线时间
163 小时
发表于 2015-8-3 16:49:36 | 显示全部楼层
假读,mark
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-18 22:53

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表