STM32F103学习笔记之在TFT LCD屏幕上显示字符

在屏幕上显示字符我之前就在做好了,之前只是可以显示。这两天把显示部分做了些修改。
修改如下
1.加了换行
2.字体大小大小的适应,如果以后换了字体简单修改后就可以用了
3.显示内容过多时自动换行
4.字距 行距的控制
5.加入了个显示控制结构体,方便做参数修改,
6.增加了print参数的单独配置函数
字库下载方法跳转

先声明

开发板 德飞莱STM32系列尼莫M3S

1.TFTLCD屏幕的配置是引用开发板的汉字显示程序
2.串口指令是参照“C语言中文网中的51单片机教程”
3.flash SPI也是借鉴开发板程序做了大量修改来符合自己的程序。。

在屏幕上显示字符的前提

1.最重要的当然是要有TFTLCD屏幕啦并且配置好参数,还有有个LCD显存地址设置函数 还有窗口设置函数
2.还有就是字库了,一般使用点阵字库,网上有字库生成工具,
3.把字库写到flash芯片。
4flash 要有个 读取指定个数的函数,

下面看代码

在这里插入代码片

    #include "text.h"
    extern struct  
    	{ u16 backC;  ///底色
        u16 pen;     ///画笔颜色
	}LCD_Colour;
	
    InitLcdPrintTypedef PrintInit;
    uint32_t CN_PYL;
    uint32_t CH_PYL;
		 /*--------------------print参数初始化--------------------*/
    void InitPrint(){
    PrintInit.backC = LCD_Colour.backC; ;       //底色
     PrintInit.pen = LCD_Colour.pen;                 //字体颜色颜色
    PrintInit.Print_X = 1;     //起始打印位置 X方向
    PrintInit.Print_Y = 2;      //起始打印位置 Y方向
    PrintInit.size_H = 32;      //字体大小 高度
    PrintInit.size_L = 32;       //字体大小 宽度
    PrintInit.Word_Spacing = 1;   //字距
    PrintInit.Line_Spacing = 1;   //行距
    PrintInit.Word_Wrap = 1;      //自动换行
    //计数中文字符要读取的点阵字节数
    CN_PYL = ((uint32_t)PrintInit.size_H * (uint32_t)PrintInit.size_L)/8; 
    //计数英文字符要读取的点阵字节数
    CH_PYL = ((uint32_t)PrintInit.size_H * (uint32_t)PrintInit.size_L)/16; 
    }
    /*--------------------print字体颜色配置--------------------*/
    void ConfigPrintColour(uint16_t Print_backC, uint16_t Print_pen) {
	PrintInit.backC = Print_backC;
	PrintInit.pen = Print_pen;
    }		
    /*--------------------print起始打印位置--------------------*/
    void ConfigPrintSite(uint16_t Print_X, uint16_t Print_Y) {
	PrintInit.Print_X = Print_X;
	PrintInit.Print_Y = Print_Y;
    }
    /*--------------------print字体大小配置--------------------*/
    void ConfigPrintSize(uint8_t size_H, uint8_t size_L) {
	PrintInit.size_H = size_H;
	PrintInit.size_L = size_L;
	CN_PYL = ((uint32_t)PrintInit.size_H * (uint32_t)PrintInit.size_L) / 8;
	CH_PYL = ((uint32_t)PrintInit.size_H * (uint32_t)PrintInit.size_L) / 16;
    }
    /*--------------------print行距字距配置--------------------*/
    void ConfigPrintSpacing(uint8_t Word_Spacing, uint8_t Line_Spacing) {
	PrintInit.Word_Spacing = Word_Spacing;
	PrintInit.Line_Spacing = Line_Spacing;
    }
    /*--------------------print自动换行配置--------------------*/
    void ConfigPrintWord_Wrap(uint8_t Word_Wrap) {
	PrintInit.Word_Wrap = Word_Wrap;
    }
    /*--------------------打印字体点阵--------------------*/
    void LCD_CharDot(uint8_t *dot, uint8_t c) {	
	uint8_t p = 0x01;        //像素点控制,	 
	KS_GRAM;                 //LCD RAM入口
	/*汉字打印*/
	if (c > 1) {  
		p = 0x80;            //这与点阵字体的存储方式有关
		  //打印点阵行控制
		for (uint8_t i = PrintInit.size_H; i > 0; i--) {    
		      //打印点阵列控制
			for(uint8_t j = PrintInit.size_L / 8; j > 0; j--){  
			while (p) { 
       if(*dot&p)
          W_GRAM = PrintInit.pen;           //字体打印
       else
          W_GRAM = PrintInit.backC;         //底色打印
			   p = p >> 1;
			}
				p = 0x80;
		  	dot++;
		}
			
		}
	}
	
	/*英文打印*/
	else {
		for (uint8_t i = PrintInit.size_H; i > 0; i--) {
	
       for(uint8_t j = PrintInit.size_L / 16; j > 0; j--){
			while (p) {
     if(*dot&p)
       W_GRAM = PrintInit.pen;        //字体打印
     else
       W_GRAM = PrintInit.backC;      //底色打印    
       p = p << 1;
			}
				p = 0x01;
			  dot++;
		}
		}
	}
    }

    /*-----------------在LCD屏上打印字符串-----------------*/

    void LCD_print(uint8_t *string) {
	uint8_t dot[128];  //临时存储 用来存储从Flash中读出的字符点阵数据
	uint8_t GBK_H, GBK_L; //GBK编码 高字节 和低字节
	uint32_t GBK;      //字符点阵在flash中的地址
	

	uint16_t x = PrintInit.Print_X; //字符打印位置控制 X方向
	uint16_t y = PrintInit.Print_Y; //字符打印位置控制 Y方向
	


	while (*string!='\0') {
		GBK_H = *string;

		if(*string=='\n'){
		x = PrintInit.Print_X; y = y + (PrintInit.Line_Spacing + PrintInit.size_H) - 1;
		}
		
		else{
		
		/*汉字*/
		if (GBK_H > 0x80) {
			GBK_L = *(++string);

			GBK_H -= 0x81;

			if (GBK_L > 0x7f)
				GBK_L -= 0x41;
			else
				GBK_L -= 0x40;
           //计算所打印的字符在Flash字库存储的位置
			GBK = ((uint32_t)190 * GBK_H + GBK_L) * CN_PYL+ (uint32_t)CH_PYL * 96 ; 
			//从Flash字库中读取字符点阵存放到dot数组中
			FLASH_Read_Data(dot, GBK,  CN_PYL);       
               //设置打印窗口
			LCD_Window(x, x + PrintInit.size_L - 1, y, y + PrintInit.size_H - 1);    
			LCD_X_Y(x, y);          //设置打印起始地址
			LCD_CharDot(dot, 2);     //打印字符
               //调整字距字距
			x = x + (PrintInit.size_L - 1 + PrintInit.Word_Spacing);   
              //检测本行是否无法显示所有内容,判断是否要自动换
			if ((239 - x < PrintInit.size_L || x >= 239) && PrintInit.Word_Wrap) { 行
				x = PrintInit.Print_X; y = y + (PrintInit.Line_Spacing + PrintInit.size_H) - 1;
		}
	}
		/*英文*/
		else {
			
			
		/*---------ASCII码一共有128个可以显示出来的只有96个字库里也只有这96个--------*/
			GBK = (GBK_H-0x20)* CH_PYL;    //计算所打印的字符在Flash字库存储的位置
			FLASH_Read_Data(dot, GBK, CH_PYL);                  
                   //ASCII码一共有128个可以显示出来的只有96个字库里也只有这96个
			LCD_Window(x, x + PrintInit.size_L / 2 - 1, y, y + PrintInit.size_H -1); 
			LCD_X_Y(x, y);
			LCD_CharDot(dot, 1);

			x = x + (PrintInit.size_L / 2 + PrintInit.Word_Spacing)-1;

			if ((239 - x < (PrintInit.size_L/2) || x >= 239) && PrintInit.Word_Wrap) {
				x = PrintInit.Print_X; y = y + (PrintInit.Line_Spacing + PrintInit.size_H) - 1;
		}
	}
		
	    	
		}
		string++;
	}
	}
    }
    }
		

下面是头文件

	#ifndef __TEXT_H
#define __TEXT_H

#include "stm32f10x.h"
#include "tft.h"
#include "usart.h"

typedef struct
{
uint16_t backC;              //底色
uint16_t pen;                //字体颜色颜色
uint16_t Print_X;            //起始打印位置 X方向
uint16_t Print_Y;            //起始打印位置 Y方向
uint8_t size_H;              //字体大小 高度
uint8_t size_L;              //字体大小 宽度
uint8_t Word_Spacing;        //字距
uint8_t Line_Spacing;        //行距
uint8_t Word_Wrap;           //自动换行
}InitLcdPrintTypedef;

void InitPrint();                                                          //print参数初始化
void ConfigPrintColour(uint16_t backC, uint16_t pen);                      //print字体颜色配置
void ConfigPrintSite(uint16_t Print_X, uint16_t Print_Y);                  //print起始打印位置
void ConfigPrintSize(uint8_t size_H, uint8_t size_L);                      //print字体大小配置
void ConfigPrintSpacing(uint8_t Word_Spacing, uint8_t Line_Spacing);       //print行距字距配置
void ConfigPrintWord_Wrap(uint8_t Word_Wrap);                              //print自动换行配置 1:自动换行 0:不自动换行
void LCD_CharDot(uint8_t *dot, uint8_t c);                                 //打印字体点阵
void LCD_print(uint8_t *string);                                           //在LCD屏上打印字符串


#endif

下面开始代码讲解

为了以后方便使用我写了5个print配置函数,因为有的时候不一定全部参数都会配置,所以做了单独配置的函数。
GBK字库地址的计算:
GBK汉字的编码方式
第一个字节为 0x81~0xFE 称为汉字的区码
第二字节为两部分 1:0x40~0x7E 2:0x80~0xFE 称为汉字的位码 这就是汉字的区位码
接下来就是怎么把区位码转换成我们下载到Flash中字库的地址,首先我们要弄清楚几个问题
1.一个汉字的点阵集是多少个字节,如 3232的汉字 3232/8=128字节 英文的话 16*32/8=64字节
2.字库的点阵集是连续下载到Flash里的(我的字库ASCII和GBK是连着的,我先下载的ASCII接着下载GBK)
3.ASCII可以在屏幕上显示的只有96个字符

先判断第一个字节 若小于等于0x80,则编码为ASCII,说明是英文字符 英文字符因为前面32个是控制字符所以 ASCII字库的起始编码为0x20

					uint32_t CH_PYL;    //英文字符要读取的点阵字节数
					uint32_t GBK;               //字符点阵在flash中的地址
					uint8_t GBK_H, GBK_L;       //GBK编码 高字节 和低字节
					uint8_t *string          //要显示的字符
					
					GBK_H = *string;
					if (GBK_H <=0x80)
					GBK = (GBK_H-0x20)* CH_PYL;

若第一个字节大于0x80说明编码为GBK第一个字节和第二个字节组成区位码
第一个字节减去0x81就是我们字库的正确区码
然后判断第二个字节 如果小于0x7f则减去0x40,如大于0x7f则减去0x41。

uint32_t CH_PYL;    //英文字符要读取的点阵字节数
					uint32_t GBK;               //字符点阵在flash中的地址
					uint8_t GBK_H, GBK_L;       //GBK编码 高字节 和低字节
					uint8_t *string          //要显示的字符
					
					GBK_H = *string;     //第一个字节
if (GBK_H > 0x80) {
		GBK_L = *(++string);      //第二个字节

		GBK_H -= 0x81;

		if (GBK_L > 0x7f)
			GBK_L -= 0x41;
		else
			GBK_L -= 0x40;

		GBK = ((uint32_t)190 * GBK_H + GBK_L) * CN_PYL+ (uint32_t)CH_PYL * 96 ;      //计算所打印的字符在Flash字库存储的位置

为什么高位要*190:因为GBK一个区有190个位,为什么减去0x41:因为0x400x7E与0x800xFE空了个0x7f,+ (uint32_t)CH_PYL * 96是为什么:因为GBK字库紧随ASCII其后,ascii在flash的起始地址为0x00

最后

我认为这次汉字显示中有难度的是:
1.怎么把字库下载到flash中 下载ASCII时没问题 但下GBK时非常容易中断,32*32的GBK字库文件有3MB大
2.字库区位码转换成flash中的地址,我在网上看了好多资料。
3.这只是我的笔记

本文由博客群发一文多发等运营工具平台 OpenWrite 发布

  • 7
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值