




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、FrameBuffer的原理118131 0500 20 0OTHER 119 042 4243 01 0星级BLOG 0yjvijfhvk#FFFFFF#187218 no-repeat _blank 142802 02010-08-22 22:10:52 148752 02010-12-12 19:00:32 149421 02010-12-25 22:18:31 142904 02010-08-25 00:12:50 142900 02010-08-24 23:40:46 143241 02010-08-29 21:58:21 143218 02010-08-29 13:44:47 14
2、2597 02010-08-18 23:50:04 142902 02010-08-25 00:11:34 142602 02010-08-18 23:51:00 144883 02010-09-27 20:50:3020100819,20100822,20100824,20100825,20100829,20100830,20100831,20100901,20100902,20100905,20100906,20100927,20101106,20101108,20101109,20101110,20101111,20101113,20101114,20101206,20101212,20
3、101223,20101224,20101225,2448686 149421 2010-12-25 22:26:35 2010-12-25 22:26:35 10 0FrameBuffer的原理FrameBuffer是出现在2.2.xx内核当中的一种驱动程序接口。Linux是工作在保护模式下,所以用户态进程是无法象DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Linux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。Framebuffer机制模仿显卡的功能,将显卡硬件结构抽象掉,可以通过Framebuffer的读写直接对显存进行操作。用户可以将Framebuffe
4、r看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer设备驱动来完成的。但Framebuffer本身不具备任何运算数据的能力,就只好比是一个暂时存放水的水池.CPU将运算后的结果放到这个水池,水池再将结果流到显示器.中间不会对数据做处理.应用程序也可以直接读写这个水池的内容.在这种机制下,尽管Framebuffer需要真正的显卡驱动的支持,但所有显示任务都有CPU完成,因此CPU负担很重.framebuffer的设备文件一般是/de
5、v/fb0、/dev/fb1等等。可以用命令:#dd if=/dev/zero of=/dev/fb清空屏幕.如果显示模式是1024x768-8位色,用命令:$dd if=/dev/zero of=/dev/fb0 bs=1024 count=768清空屏幕用命令:#dd if=/dev/fb of=fbfile可以将fb中的内容保存下来;可以重新写回屏幕:#dd if=fb在使用Framebuffer时,Linux是将显卡置于图形模式下的.在应用程序中,一般通过将FrameBuffer设备映射到进程地址空间的方式使用,比如下面的程序就打开/dev/fb0设备,并通过mmap系统调用进行地址映
6、射,随后用memset将屏幕清空(这里假设显示模式是1024x768-8位色模式,线性内存模式):int fb;unsigned char*fb_mem;fb=open(/dev/fb0,O_RDWR);fb_mem=mmap(NULL,1024*768,PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);memset(fb_mem,0,1024*768);FrameBuffer设备还提供了若干ioctl命令,通过这些命令,可以获得显示设备的一些固定信息(比如显示内存大小)、与显示模式相关的可变信息(比如分辨率、象素结构、每扫描线的字节宽度),以及伪彩色模式下的调色板信
7、息等等。通过FrameBuffer设备,还可以获得当前内核所支持的加速显示卡的类型(通过固定信息得到),这种类型通常是和特定显示芯片相关的。比如目前最新的内核(2.4.9)中,就包含有对S3、Matrox、nVidia、3Dfx等等流行显示芯片的加速支持。在获得了加速芯片类型之后,应用程序就可以将PCI设备的内存I/O(memio)映射到进程的地址空间。这些memio一般是用来控制显示卡的寄存器,通过对这些寄存器的操作,应用程序就可以控制特定显卡的加速功能。PCI设备可以将自己的控制寄存器映射到物理内存空间,而后,对这些控制寄存器的,给变成了对物理内存的访问。因此,这些寄存器又被称为memio
8、。一旦被映射到物理内存,Linux的普通进程就可以通过mmap将这些内存I/O映射到进程地址空间,这样就可以直接访问这些寄存器了。当然,因为不同的显示芯片具有不同的加速能力,对memio的使用和定义也各自不同,这时,就需要针对加速芯片的不同类型来编写实现不同的加速功能。比如大多数芯片都提供了对矩形填充的硬件加速支持,但不同的芯片实现方式不同,这时,就需要针对不同的芯片类型编写不同的用来完成填充矩形的函数。FrameBuffer只是一个提供显示内存和显示芯片寄存器从物理内存映射到进程地址空间中的设备。所以,对于应用程序而言,如果希望在FrameBuffer之上进行图形编程,还需要自己动手完成其他
9、许多工作。二、FrameBuffer在LINUX中实现和机制Framebuffer对应的源文件在linux/drivers/video/目录下。总的抽象设备文件为fbcon.c,在这个目录下还有与各种显卡驱动相关的源文件。(一)、分析Framebuffer设备驱动需要特别提出的是在INTEL平台上,老式的VESA 1.2卡,如CGA/EGA卡,是不能支持Framebuffer的,因为Framebuffer要求显卡支持线性帧缓冲,即CPU可以访问显缓冲中的每一位,但是VESA 1.2卡只能允许CPU一次访问64K的地址空间。FrameBuffer设备驱动基于如下两个文件:1)linux/incl
10、ude/linux/fb.h 2)linux/drivers/video/fbmem.c下面分析这两个文件。1、fb.h几乎主要的结构都是在这个中文件定义的。这些结构包括:1)fb_var_screeninfo这个结构描述了显示卡的特性:struct fb_var_screeninfo_u32 xres;/*visible resolution*/_u32 yres;_u32 xres_virtual;/*virtual resolution*/_u32 yres_virtual;_u32 xoffset;/*offset from virtual to visible resolution*
11、/_u32 yoffset;_u32 bits_per_pixel;/*guess what*/_u32 grayscale;/*!=0 Gray levels instead of colors*/struct fb_bitfield red;/*bitfield in fb mem if true color,*/struct fb_bitfield green;/*else only length is significant*/struct fb_bitfield blue;struct fb_bitfield transp;/*transparency*/_u32 nonstd;/*
12、!=0 Non standard pixel format*/_u32 activate;/*see FB_ACTIVATE_*/_u32 height;/*height of picture in mm*/_u32 width;/*width of picture in mm*/_u32 accel_flags;/*acceleration flags(hints)*/*Timing:All values in pixclocks,except pixclock(of course)*/_u32 pixclock;/*pixel clock in ps(pico seconds)*/_u32
13、 left_margin;/*time from sync to picture*/_u32 right_margin;/*time from picture to sync*/_u32 upper_margin;/*time from sync to picture*/_u32 lower_margin;_u32 hsync_len;/*length of horizontal sync*/_u32 vsync_len;/*length of vertical sync*/_u32 sync;/*see FB_SYNC_*/_u32 vmode;/*see FB_VMODE_*/_u32 r
14、eserved6;/*Reserved for future compatibility*/;2)fb_fix_screeninfon这个结构在显卡被设定模式后创建,它描述显示卡的属性,并且系统运行时不能被修改;比如FrameBuffer内存的起始地址。它依赖于被设定的模式,当一个模式被设定后,内存信息由显示卡硬件给出,内存的位置等信息就不可以修改。struct fb_fix_screeninfochar id16;/*identification string egTT Builtin*/unsigned long smem_start;/*Start of frame buffer mem
15、*/*(physical address)*/_u32 smem_len;/*Length of frame buffer mem*/_u32 type;/*see FB_TYPE_*/_u32 type_aux;/*Interleave for interleaved Planes*/_u32 visual;/*see FB_VISUAL_*/_u16 xpanstep;/*zero if no hardware panning*/_u16 ypanstep;/*zero if no hardware panning*/_u16 ywrapstep;/*zero if no hardware
16、 ywrap*/_u32 line_length;/*length of aline in bytes*/unsigned long mmio_start;/*Start of Memory Mapped I/O*/*(physical address)*/_u32 mmio_len;/*Length of Memory Mapped I/O*/_u32 accel;/*Type of acceleration available*/_u16 reserved3;/*Reserved for future compatibility*/;3)fb_cmap描述设备无关的颜色映射信息。可以通过F
17、BIOGETCMAP和FBIOPUTCMAP对应的ioctl操作设定或获取颜色映射信息.struct fb_cmap_u32 start;/*First entry*/_u32 len;/*Number of entries*/_u16*red;/*Red values*/_u16*green;_u16*blue;_u16*transp;/*transparency,can be NULL*/;4)fb_info定义当显卡的当前状态;fb_info结构仅在内核中可见,在这个结构中有一个fb_ops指针,指向驱动设备工作所需的函数集。struct fb_infochar modename40;/
18、*default video mode*/kdev_t node;int flags;int open;/*Has this been open already?*/#define FBINFO_FLAG_MODULE 1/*Low-level driver is amodule*/struct fb_var_screeninfo var;/*Current var*/struct fb_fix_screeninfo fix;/*Current fix*/struct fb_monspecs monspecs;/*Current Monitor specs*/struct fb_cmap cm
19、ap;/*Current cmap*/struct fb_ops*fbops;char*screen_base;/*Virtual address*/struct display*disp;/*initial display variable*/struct vc_data*display_fg;/*Console visible on this display*/char fontname40;/*default font name*/devfs_handle_t devfs_handle;/*Devfs handle for new name*/devfs_handle_t devfs_l
20、handle;/*Devfs handle for compat.symlink*/int(*changevar)(int);/*tell console var has changed*/int(*switch_con)(int,struct fb_info*);/*tell fb to switch consoles*/int(*updatevar)(int,struct fb_info*);/*tell fb to update the vars*/void(*blank)(int,struct fb_info*);/*tell fb to(un)blank the screen*/*a
21、rg=0:unblank*/*arg 0:VESA level(arg-1)*/void*pseudo_palette;/*Fake palette of 16 colors and the cursors color for non palette mode*/*From here on everything is device dependent*/void*par;5)struct fb_ops用户应用可以使用ioctl()系统调用来操作设备,这个结构就是用一支持ioctl()的这些操作的。struct fb_ops/*open/release and usage marking*/st
22、ruct module*owner;int(*fb_open)(struct fb_info*info,int user);int(*fb_release)(struct fb_info*info,int user);/*get non settable parameters*/int(*fb_get_fix)(struct fb_fix_screeninfo*fix,int con,struct fb_info*info);/*get settable parameters*/int(*fb_get_var)(struct fb_var_screeninfo*var,int con,stru
23、ct fb_info*info);/*set settable parameters*/int(*fb_set_var)(struct fb_var_screeninfo*var,int con,struct fb_info*info);/*get colormap*/int(*fb_get_cmap)(struct fb_cmap*cmap,int kspc,int con,struct fb_info*info);/*set colormap*/int(*fb_set_cmap)(struct fb_cmap*cmap,int kspc,int con,struct fb_info*inf
24、o);/*pan display(optional)*/int(*fb_pan_display)(struct fb_var_screeninfo*var,int con,struct fb_info*info);/*perform fb specific ioctl(optional)*/int(*fb_ioctl)(struct inode*inode,struct int cmd,unsigned long arg,int con,struct fb_info*info);/*perform fb specific mmap*/int(*fb_mmap)(struct fb_info*i
25、nfo,struct vm_area_struct*vma);/*switch to/from raster image mode*/int(*fb_rasterimg)(struct fb_info*info,int start);6)structure map struct fb_info_gen|struct fb_info|fb_var_screeninfo|fb_fix_screeninfo|fb_cmap|modename40|fb_ops-|-ops on var|.|fb_open|fb_release|fb_ioctl|fb_mmap|struct fbgen_hwswitc
26、h-|-detect|encode_fix|encode_var|decode_fix|decode_var|get_var|set_var|getcolreg|setcolreg|pan_display|blank|set_disp编排有点困难,第一行的第一条竖线和下面的第一列竖线对齐,第一行的第二条竖线和下面的第二列竖线对齐就可以了这个结构fbgen_hwswitch抽象了硬件的操作.虽然它不是必需的,但有时候很有用.2、fbmem.c fbmem.c处于Framebuffer设备驱动技术的中心位置.它为上层应用程序提供系统调用也为下一层的特定硬件驱动提供接口;那些底层硬件驱动需要用到这儿
27、的接口来向系统内核注册它们自己.fbmem.c为所有支持FrameBuffer的设备驱动提供了通用的接口,避免重复工作.1)全局变量struct fb_info*registered_fbFB_MAX;int num_registered_fb;这两变量记录了所有fb_info结构的实例,fb_info结构描述显卡的当前状态,所有设备对应的fb_info结构都保存在这个数组中,当一个FrameBuffer设备驱动向系统注册自己时,其对应的fb_info结构就会添加到这个结构中,同时num_registered_fb为自动加1.static structconst char*name;int(*
28、init)(void);int(*setup)(void);fb_drivers _initdata=.;如果FrameBuffer设备被静态链接到内核,其对应的入口就会添加到这个表中;如果是动态加载的,即使用insmod/rmmod,就不需要关心这个表。static struct fb_ops=owner:THIS_MODULE,read:fb_read,write:fb_write,ioctl:fb_ioctl,mmap:fb_mmap,open:fb_open,release:fb_release;这是一个提供给应用程序的接口.2)fbmem.c实现了如下函数.register_fram
29、ebuffer(struct fb_info*fb_info);unregister_framebuffer(struct fb_info*fb_info);这两个是提供给下层FrameBuffer设备驱动的接口,设备驱动通过这两函数向系统注册或注销自己。几乎底层设备驱动所要做的所有事情就是填充fb_info结构然后向系统注册或注销它。(二)一个LCD显示芯片的驱动实例以Skeleton LCD控制器驱动为例,在LINUX中存有一个/fb/skeleton.c的skeleton的Framebuffer驱动程序,很简单,仅仅是填充了fb_info结构,并且注册/注销自己。设备驱动是向用户程序提供
30、系统调用接口,所以我们需要实现底层硬件操作并且定义结构来向系统提供系统调用接口,从而实现更有效的LCD控制器驱动程序。1)在系统内存中分配显存在fbmem.c文件中可以看到,结构中的open()和release()操作不需底层支持,但read()、write()和mmap()操作需要函数fb_get_fix()的支持.因此需要重新实现函数fb_get_fix()。另外还需要在系统内存中分配显存空间,大多数的LCD控制器都没有自己的显存空间,被分配的地址空间的起始地址与长度将会被填充到fb_fix_screeninfo结构的smem_start和smem_len的两个变量中.被分配的空间必须是物
31、理连续的。2)实现fb_ops中的函数用户应用程序通过ioctl()系统调用操作硬件,fb_ops中的函数就用于支持这些操作。(注:fb_ops结构与结构不同,fb_ops是底层操作的抽象,而是提供给上层系统调用的接口,可以直接调用.ioctl()系统调用在文件fbmem.c中实现,通过观察可以发现ioctl()命令与fb_opss中函数的关系:FBIOGET_VSCREENINFO fb_get_var FBIOPUT_VSCREENINFO fb_set_var FBIOGET_FSCREENINFO fb_get_fix FBIOPUTCMAP fb_set_cmap FBIOGETCM
32、AP fb_get_cmap FBIOPAN_DISPLAY fb_pan_display如果我们定义了fb_XXX_XXX方法,用户程序就可以使用FBIOXXXX宏的ioctl()操作来操作硬件。文件linux/drivers/video/fbgen.c或者linux/drivers/video目录下的其它设备驱动是比较好的参考资料。在所有的这些函数中fb_set_var()是最重要的,它用于设定显示卡的模式和其它属性,下面是函数fb_set_var()的执行步骤:1)检测是否必须设定模式2)设定模式3)设定颜色映射4)根据以前的设定重新设置LCD控制器的各寄存器。第四步表明了底层操作到底放
33、置在何处。在系统内存中分配显存后,显存的起始地址及长度将被设定到LCD控制器的各寄存器中(一般通过fb_set_var()函数),显存中的内容将自动被LCD控制器输出到屏幕上。另一方面,用户程序通过函数mmap()将显存映射到用户进程地址空间中,然后用户进程向映射空间发送的所有数据都将会被显示到LCD显示器上。三、FrameBuffer的应用(一)、一个使用FrameBuffer的例子1、FrameBuffer主要是根据VESA标准的实现的,所以只能实现最简单的功能。2、由于涉及内核的问题,FrameBuffer是不允许在系统起来后修改显示模式等一系列操作。(好象很多人都想要这样干,这是不被允
34、许的,当然如果你自己写驱动的话,是可以实现的).3、对FrameBuffer的操作,会直接影响到本机的所有控制台的输出,包括XWIN的图形界面。好,现在可以让我们开始实现直接写屏:1、打开一个FrameBuffer设备2、通过mmap调用把显卡的物理内存空间映射到用户空间3、直接写内存。/*:fbtools.h*/#ifndef _FBTOOLS_H_#define _FBTOOLS_H_#i nclude/a framebuffer device structure;typedef struct fbdevint fb;unsigned long fb_mem_offset;unsigned
35、 long fb_mem;struct fb_fix_screeninfo fb_fix;struct fb_var_screeninfo fb_var;char dev20;FBDEV,*PFBDEV;/open&init aframe buffer/to use this function,/you must set FBDEV.dev=/dev/fb0/or/dev/fbX/its your frame fb_open(PFBDEV pFbdev);/close aframe buffer int fb_close(PFBDEV pFbdev);/get displ
36、ay depth int get_display_depth(PFBDEV pFbdev);/full screen clear void fb_memset(void*addr,int c,size_t len);#endif/*:fbtools.c*/#i nclude#i nclude#i nclude#i nclude#i nclude#i nclude#i nclude#i nclude#i ncludefbtools.h#define TRUE 1#define FALSE 0#define MAX(x,y)(x)(y)?(x)y)#define MIN(x,y)(x)/open&
37、init aframe buffer int fb_open(PFBDEV pFbdev)pFbdev-fb=open(pFbdev-dev,O_RDWR);if(pFbdev-fbprintf(Error opening%s:%m.Check kernel confign,pFbdev-dev);return FALSE;if(-1=ioctl(pFbdev-fb,FBIOGET_VSCREENINFO,&(pFbdev-fb_var)printf(ioctl FBIOGET_VSCREENINFOn);return FALSE;if(-1=ioctl(pFbdev-fb,FBIOGET_F
38、SCREENINFO,&(pFbdev-fb_fix)printf(ioctl FBIOGET_FSCREENINFOn);return FALSE;/map physics address to virtual address pFbdev-fb_mem_offset=(unsigned long)(pFbdev-fb_fix.smem_start)&(PAGE_MASK);pFbdev-fb_mem=(unsigned long int)mmap(NULL,pFbdev-fb_fix.smem_len+pFbdev-fb_mem_offset,PROT_READ|PROT_WRITE,MA
39、P_SHARED,pFbdev-fb,0);if(-1L=(long)pFbdev-fb_mem)printf(mmap error!mem:%d offset:%dn,pFbdev-fb_mem,pFbdev-fb_mem_offset);return FALSE;return TRUE;/close frame buffer int fb_close(PFBDEV pFbdev)close(pFbdev-fb);pFbdev-fb=-1;/get display depth int get_display_depth(PFBDEV pFbdev);if(pFbdev-fbprintf(fb
40、 device not open,open it firstn);return FALSE;return pFbdev-fb_var.bits_per_pixel;/full screen clear void fb_memset(void*addr,int c,size_t len)memset(addr,c,len);/use by test#define DEBUG#ifdef DEBUG main()FBDEV fbdev;memset(&fbdev,0,sizeof(FBDEV);strcpy(fbdev.dev,/dev/fb0);if(fb_open(&fbdev)=FALSE)
41、printf(open frame buffer errorn);return;fb_memset(fbdev.fb_mem+fbdev.fb_mem_offset,0,fbdev.fb_fix.smem_len);fb_close(&fbdev);(二)基于Linux核心的汉字显示的尝试我们以一个简单的例子来说明字符显示的过程。我们假设是在虚拟终端1(/dev/tty1)下运行一个如下的简单程序。main()puts(hello,world.n);puts函数向缺省输出文件(/dev/tty1)发出写的系统调用write(2)。系统调用到linux核心里面对应的核心函数是console.c中
42、的con_write(),con_write()最终会调用do_con_write()。在do_con_write()中负责把hello,world.n这个字符串放到tty1对应的缓冲区中去。do_con_write()还负责处理控制字符和光标的位置。让我们来看一下do_con_write()这个函数的声明。static int do_con_write(struct tty_struct*tty,int from_user,const unsigned char*buf,int count)其中tty是指向tty_struct结构的指针,这个结构里面存放着关于这个tty的所有信息(请参照li
43、nux/include/linux/tty.h)。Tty_struct结构中定义了通用(或高层)tty的属性(例如宽度和高度等)。在do_con_write()函数中用到了tty_struct结构中的driver_data变量。driver_data是一个vt_struct指针。在vt_struct结构中包含这个tty的序列号(我们正使用tty1,所以这个序号为1)。Vt_struct结构中有一个vc结构的数组vc_cons,这个数组就是各虚拟终端的私有数据。static int do_con_write(struct tty_struct*tty,int from_user,const un
44、signed char*buf,int count)struct vt_struct*vt=(struct vt_struct*)tty-driver_data;/我们用到了driver_data变量.currcons=vt-vc_num;我们在这里的vc_nums就是1.要访问虚拟终端的私有数据,需使用vc_conscurrcons.d指针。这个指针指向的结构含有当前虚拟终端上光标的位置、缓冲区的起始地址、缓冲区大小等等。hello,world.n中的每一个字符都要经过conv_uni_to_pc()这个函数转换成8位的显示字符。这要做的主要目的是使不同语言的国家能把16位的UniCode码
45、映射到8位的显示字符集上,目前还是主要针对欧洲国家的语言,映射结果为8位,不包含对双字节(double byte)的范围。这种UNICODE到显示字符的映射关系可以由用户自行定义。在缺省的映射表上,会把中文的字符映射到其他的字符上,这是我们不希望看到也是不需要的。所以我们有两个选择1不进行conv_uni_to_pc()的转换。2加载符合双字节处理的映射关系,即对非控制字符进行1对1的不变映射。我们自己定制的符合这种映射关系的UNICODE码表是direct.uni。要想查看/装载当前系统的unicode映射表,可使外部命令loadunimap。经过conv_uni_to_pc()转换之后,h
46、ello,world.n中的字符被一个一个地填写到tty1的缓冲区中。然后do_con_write()调用下层的驱动,把缓冲区中的内容输出到显示器上(也就相当于把缓冲区的内容拷贝到VGA显存中去)。sw-con_putcs(vc_conscurrcons.d,(u16*)draw_from,(u16*)draw_to-(u16*)draw_from,y,draw_x);之所以要调用底层驱动,是因为存在不同的显示设备,其对应VGA显存的存取方式也不一样。上面的Sw-con_putcs()就会调用到fbcon.c中的fbcon_putcs()函数(con_putcs是一个函数的指针,在Frameb
47、uffer模式下指向fbcon_putcs()函数)。也就是说在do_con_write()函数中是直接调用了fbcon_putcs()函数来进行字符的绘制。比如说在256色模式下,真正负责输出的函数是void fbcon_cfb8_putcs(struct vc_data*conp,struct display*p,const unsigned short*s,int count,int yy,int xx)显示中文比如说我们试图输出一句中文putcs(你好n);(你好的内码为0xc4,0xe3,0xba,0xc3)。这时候会怎么样呢,有一点可以肯定,你好肯定不会出现在屏幕上,国为核心中没有
48、汉字字库,中文显示就是无米之炊了.1在负责字符显示的void fbcon_cfb8_putcs()函数中,原有操作如下对于每个要显示的字符,依次从虚拟终端缓冲区中以WORD为单位读取(低位字节是ASCII码,高8位是字符的属性),由于汉字是双字节编码方式,所以这种操作是不可能显示出汉字的,只能显示出xxxx_putcs()是一个一个VGA字符.要解决的问题确保在do_con_write()时unipc转换不会改变原有编码。一个很直接的实现方式就是加载一个我们自己定制的UNICODE映射表,loadunimapdirect.uni,或者直接把direct.uni置为核心的缺省映射表。针对如上问题
49、,我们要做的第一个尝试方案是如下。首先需要在核心中加载汉字字库,然后修改fbcon_cfb8_putcs()函数,在fbcon_cfb8_putcs()中一次读两个WORD,检查这两个WORD的低位字节是否能拼成一个汉字,如果发现能拼成一个汉字,就算出这个汉字在汉字字库中的偏移,然后把它当成一个16 x16的VGA字符来显示。试验的结果表明1能够输出汉字,但仍有许多不理想的地方,比如说,输出以半个汉字开始的一串汉字,则这半个汉字后面的汉字都会是乱码。这是半个汉字的问题。2光标移动会破坏汉字的显示。表现为,光标移动过的汉字会变成乱码。这是因为光标的更新是通过xxxx_putc()函数来完成的。xxxx_putc()函数与xxxx_putcs()函数
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- Module 3 Unit 2 On Monday I'll go swimming(教学设计)-2023-2024学年外研版(三起)英语四年级下册
- DB1331T 097-2024土壤环境背景值
- 人教版《道德与法治》七年级上册:8.1《生命可以永恒吗》教学设计1
- 近五年江苏省中考数学试题及答案2024
- 12米气动天线升降杆安装使用说明书
- WILIOT 的室内资产智能零售解决方案
- 脑瘫儿童康复设备企业制定与实施新质生产力战略研究报告
- 氢化异戊橡胶轮胎材料企业制定与实施新质生产力战略研究报告
- 皮具制作工艺培训企业制定与实施新质生产力战略研究报告
- 导电聚合物助剂企业制定与实施新质生产力战略研究报告
- DeepSeek+DeepResearch-让科研像聊天一样简单(内含AI学术工具公测版)
- 宋代农书研究出版对宋代农业研究的价值4篇
- 5.2《稻》教案-【中职专用】高二语文同步教学(高教版2023·拓展模块下册)
- 2025年超长期特别国债申报工作及成功案例
- 电梯困人培训课件
- 熔化焊接与热切割作业题库题库(1455道)
- 金属冶炼中的铍冶炼与铍合金生产
- 2025年中国中煤华东分公司招聘笔试参考题库含答案解析
- 2025年河南郑州医药健康职业学院招考聘用高频重点提升(共500题)附带答案详解
- 铁路运输碳排放分析-洞察分析
- 第16课数据管理与编码(教案)四年级全一册信息技术人教版
评论
0/150
提交评论