嵌入式 在开发板使用libfreetype字库、使用触摸屏

嵌入式 在开发板使用libfreetype字库、使用触摸屏

一、简述

        记--在开发板使用libfreetype开源字库,简单的使用触摸屏(未处理消抖、去波等操作)。

二、在开发板显示中文

        代码打包:链接:https://pan.baidu.com/s/1It0LHG5UNNg_Nm444k6p9A 密码:9lw3

        2.1效果:

                      

        2.2工程结构:

                                                     

     

          3.3源文件

                freetype.c文件

#include <sys/mman.h>
#include <stdio.h>
#include <linux/fb.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <wchar.h>
#include <string.h>
#include <ft2build.h>
#include FT_FREETYPE_H

#include <lcd.h>


#define	SIM_TTY_PATH	"font/simsun.ttc"
/*	
	功能:根据得到的RGB24数据,进行图像任意位置显示
	(主要是迎合上面的各种转换函数的显示测试)
	x:显示的x轴起点
	y:显示的y轴起点
	w:显示图像宽度。
	h:显示图像高度。
	bit_dept:要显示的图像位深 24/32
	pbmp_data:要进行显示的RGB24_buf
*/
int Show_FreeType_Bitmap(FT_Bitmap*  bitmap,int start_x,int start_y,int color, unsigned int *lcd_buf_ptr)
{
	int  buff_x, buff_y;	//遍历bitmap时使用
	int  x,y;	//循环遍历使用
	int  end_x = start_x + bitmap->width;	//图像宽度
	int  end_y = start_y + bitmap->rows;	//图像高度

	for ( x = start_x, buff_x = 0; x < end_x; buff_x++, x++ )	//y表示起点y,x表示起点x
	{
		for ( y = start_y, buff_y = 0; y < end_y; buff_y++, y++ )	//y表示起点y,x表示起点x
		{
			//LCD边界处理
			if ( x < 0 || y < 0 || x >=800   || y >= 480 )
				continue;

			if(bitmap->buffer[buff_y * bitmap->width + buff_x] )	//判断该位上是不是为1,1则表明需要描点
				lcd_draw_point(start_x+buff_x , start_y+buff_y ,  color, lcd_buf_ptr);		//在当前x位置加上p的偏移量(p表示buff中列的移动)
				//在当前y位置加上q的偏移量(q表示buff中行的移动)
			
		}
	}
} 

void Lcd_Show_FreeType(wchar_t *wtext, int size, int color, int start_x, int start_y, unsigned int *lcd_buf_ptr)
{

	//1.定义库所需要的变量
	FT_Library    library;
	FT_Face       face;
	FT_GlyphSlot  slot;	//用于指向face中的glyph
	FT_Vector     pen;                    
	FT_Error      error;

	int n;

	
	//2.初始化库
	error = FT_Init_FreeType( &library );            

	//3.打开一个字体文件,并加载face对象:
	error = FT_New_Face( library, SIM_TTY_PATH, 0, &face ); 
	slot = face->glyph;
	
	//4.设置字体大小
	error = FT_Set_Pixel_Sizes(face, size, 0); 
	
	//x起点位置:start_x。需要*64
	pen.x = start_x * 64;	
	//y起点位置:LCD高度 - start_y。需要*64
	pen.y = ( 480 - start_y ) * 64;
	
	//每次取出显示字符串中的一个字
	for ( n = 0; n < wcslen( wtext ); n++ )	
	{
		//5.设置显示位置和旋转角度,0为不旋转,pen为提前设置好的坐标
		FT_Set_Transform( face, 0, &pen );
		
		
		//将字形槽的字形图像,转为位图,并存到 face->glyph->bitmap->buffer[],并且更新bitmap下的其他成员,
		//	face->glyph->bitmap.rows:图像总高度
		//	face->glyph->bitmap.width:图像总宽度
		//	face->glyph->bitmap.pitch:每一行的字节数
		//	face->glyph->bitmap.pixel_mode:像素模式(1单色 8反走样灰度)
		//	face->glyph->bitmap.buffer:点阵位图的数据缓冲区
	

		
		error = FT_Load_Char( face, wtext[n], FT_LOAD_RENDER );
			//FT_LOAD_RENDER表示转换RGB888的位图像素数据
			
		//出错判断	
		if ( error )
		  continue;                
		
		
		Show_FreeType_Bitmap(&slot->bitmap, slot->bitmap_left, 480 - slot->bitmap_top, color, lcd_buf_ptr);
		
		//增加笔位
		pen.x += slot->advance.x;
		
	}	
	
	FT_Done_Face(face);
	FT_Done_FreeType(library);
	
}






                lcd.c文件

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "lcd.h"

/*lcd_draw_point:在lcd上画一个点
 *x:x轴坐标   (左上角为原点,x轴分别向右,y轴下递增)
 *y:y轴坐标
 *color:点的颜色
 *lcd_ptr:LCD的操作指针
 */
void lcd_draw_point(unsigned int x, unsigned int y, unsigned int color, unsigned int *lcd_ptr)
{
	if( x>=0 && x<LCD_WIDTH && y>=0 && y<LCD_HEIGHT )
	{
		*(lcd_ptr+LCD_WIDTH*y+x) = color;
	}
}

/*lcd_draw_full_srceen_single_color:用一种颜色画满整个屏幕
 *color:点的颜色
 *lcd_ptr:LCD的操作指针
 */
void lcd_draw_full_srceen_single_color(unsigned int color, unsigned int *lcd_ptr)
{
	int x, y;
	for(y=0;y<LCD_HEIGHT;++y)
	{
		for(x=0;x<LCD_WIDTH;++x)
		{
			lcd_draw_point(x, y, color, lcd_ptr);
		}
	}
}

/*open_lcd_device:打开LCD
 *lcd_ptr:LCD的内存映射首地址
 *返回值:lcd_fd:LCD的描述符
 */
int open_lcd_device(unsigned int **lcd_ptr)
{

	int lcd_fd;
	lcd_fd = open("/dev/fb0", O_RDWR);//打开LCD设备
	if(lcd_fd == -1)
	{
		perror("open lcd device failed\n");
		return -1;
	}

	//内存映射
	*lcd_ptr = mmap( NULL, LCD_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, lcd_fd, 0);
	if(lcd_ptr == MAP_FAILED)
	{
		perror("map lcd_fb error\n");
		return -1;
	}

	return lcd_fd;
}

/*close_lcd_device:关闭LCD
 *lcd_fd:LCD的描述符
 *lcd_ptr:LCD的内存映射首地址
 */
int close_lcd_device(int lcd_fd, unsigned int *lcd_ptr)
{
	munmap(lcd_ptr, LCD_SIZE);
	return close(lcd_fd);
}

                main.c文件

#include <stdio.h>
#include <stdlib.h>

#include "lcd.h"
#include "to_wchar.h"
#include "freetype.h"

int main(int argc, char *argv[])
{
	int lcd_fd;
	int dis_ret;
	unsigned int *lcd_ptr;

	//打开LCD
	lcd_fd = open_lcd_device(&lcd_ptr);
	if(lcd_fd == -1)
	{
		return -1;
	}

	//白屏
	lcd_draw_full_srceen_single_color(WHITE_COLOR, lcd_ptr);
	
	//显示宽字符
	wchar_t *w_text = L"路漫漫,勤为径";
	Lcd_Show_FreeType(w_text,32,0x00,20,+50, lcd_ptr);
	
	//多字节字符转宽字符	
	wchar_t *w_pathname = NULL;
	if( mchars_to_wchars("mbschar to wchar_t", &w_pathname) == 0)//将多字节转换为宽字符(汉字未能转换成功)
	{
		//显示字体             字、大小、字体颜色与背景颜色、起始x坐标,起始y坐标、LCD 操作指针
		Lcd_Show_FreeType(w_pathname,32,0xFF0000,20,100, lcd_ptr);
		free(w_pathname);
	}
	
	//关闭LCD
	close_lcd_device(lcd_fd, lcd_ptr);

	return 0;
}

                to_wchar.c文件

#include <wctype.h>
#include <locale.h>
#include <wchar.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/*mchars_to_wchars:多字节转宽字符
 *mbs_char:多字节字符串
 *w_char:宽字符
 */
int mchars_to_wchars(const char *mbs_char, wchar_t **w_char)
{
	int mbslen = mbstowcs(NULL, mbs_char, 0);
	if (mbslen == (size_t) -1) 
	{
		perror("mbstowcs");
		return -1;
    }
    *w_char = NULL;
/*	if (setlocale(LC_CTYPE, "zh_CN.utf8") == NULL) 
	{
               perror("setlocale");
	       return -1;
        }
*/
	*w_char = calloc(mbslen + 1, sizeof(wchar_t));
	if(*w_char == NULL )
	{
		perror("calloc\n");
		return -1;
	}
	if (mbstowcs(*w_char, mbs_char, mbslen + 1) == (size_t) -1)
	{
		perror("mbstowcs");
		free(*w_char);
		return -1;
	}
	//printf("Wide character string is: %ls (%zu characters)\n", *w_char, mbslen);
	return 0;
}

                Makefile文件

make:
	arm-linux-gcc src/*.c -o lcd -I include -I include/freetype2 -L lib -lfreetype

三、使用触摸屏的简单例子

        代码打包:链接:https://pan.baidu.com/s/1TbEsS95h4N9WmscFJ8pNGw 密码:6shg

       3.1效果

                    

       3.2工程结构

                   

       3.3代码文件

                  lcd.c文件     (同上)

                 main.c文件

          

#include <stdio.h>

#include "ts.h"
#include "lcd.h"

int main(int argc, char *argv[])
{
	int lcd_fd;
	unsigned int *lcd_ptr;

	lcd_fd = open_lcd_device(&lcd_ptr);
	if(lcd_fd == -1)
	{
		return -1;
	}

	touch_screen(lcd_ptr);
	
	close_lcd_device(lcd_fd, lcd_ptr);
	return 0;
}

                 ts.c文件

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "ts.h"
#include "lcd.h"

int touch_screen(unsigned int *lcd_ptr)
{
	int ts_fd;
	struct input_event ts_ev;
	Screen pos;

	//打开触摸屏(驱动触摸屏)
	ts_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK);
	if(ts_fd == -1)
	{
		perror("open ts error\n");
		return -1;
	}

	while(1)//不断的监听触摸事件
	{
		get_touch_position(ts_fd, &ts_ev, &pos);
		if(pos.prs_sta == 1 )//有触摸过
		{
			//触摸一下,即单击一下 (简单消抖:在稍微点击一下难免会有抖动(细微的滑动效果), 
			//所以在一定范围内算是触摸一下而不是滑动)
			if( (pos.x_end-pos.x_str)*(pos.x_end-pos.x_str) <= 300 &&
			    (pos.y_end-pos.y_str)*(pos.y_end-pos.y_str) <= 300
			)
			{
				printf("当前位置:(%d,%d)|(%d,%d)\n", pos.x_end, pos.y_end, pos.x_str, pos.y_str);
			}
			//滑动
			else 
			{
				//上下滑动  (左右偏移幅度 < 上下偏移幅度)
				if( (pos.x_end-pos.x_str)*(pos.x_end-pos.x_str) <
					(pos.y_end-pos.y_str)*(pos.y_end-pos.y_str)
				)
				{
					if(pos.y_end-pos.y_str >= 0)
					{
						printf("向下滑动\n");
					}
					else
					{
						printf("向上滑动\n");
					}
					
				}
				else //左右滑动  (左右偏移幅度 >= 上下偏移幅度)
				{
					if(pos.x_end-pos.x_str >= 0)
					{
						printf("向右滑动\n");
					}
					else
					{
						printf("向左滑动\n");
					}
				}
			}
		}
	}
	
	close(ts_fd);
	return 0;
}

/*get_touch_position:获取触摸位置信息
 *ts_fd:触摸屏的描述符
 *ts_ev:触摸屏事件结构体
 *pos:触摸位置信息
 */
void get_touch_position( int ts_fd, struct input_event *ts_ev, Screen *pos)
{
	int i, retval;
	memset(pos, 0, sizeof(*pos));
	pos->x_str = -1;
	pos->x_end = -1;
	pos->y_str = -1;
	pos->y_end = -1;
	pos->prs_sta = 0;
	
	do
	{
		retval = read(ts_fd, ts_ev, sizeof(*ts_ev));
		if(retval != sizeof(*ts_ev) )// no touch
		{
			continue;
		}
		if(ts_ev->type == EV_ABS)//如果是坐标信息
		{
			switch(ts_ev->code)
			{
				case ABS_X:       //x坐标信息
		               	        if(pos->prs_sta == 0)
					{
						pos->x_str = ts_ev->value;
					}
					pos->x_end = ts_ev->value;
					break;
				case ABS_Y:      //y坐标信息
					if(pos->prs_sta == 0)
					{
						pos->y_str = ts_ev->value;
					}
					pos->y_end = ts_ev->value;
					break;
			}
		}
		
		if((ts_ev->type == EV_KEY) && (ts_ev->code == BTN_TOUCH))//是否触摸
		{
			pos->prs_on = ts_ev->value;
			if( (pos->prs_sta == 0) && (pos->x_str != -1) && (pos->y_str != -1) )
			{
				pos->prs_sta = 1;
			}
		}

	}while( (pos->prs_sta == 0) || (pos->prs_on == 1) );		
}

                 Makefile文件

make:
	arm-linux-gcc src/*.c -o ts -I include

触摸屏相关头文件详细请看:/usr/include/linux/input.h

猜你喜欢

转载自blog.csdn.net/nanfeibuyi/article/details/82622775
今日推荐