嵌入式 在开发板使用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