首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

嵌入式应用实例→电子产品量产工具→显示系统的代码阅读和上机测试记录

  • 25-03-05 05:22
  • 4150
  • 8211
blog.csdn.net

目录

  • 系统框图
  • 头文件`disp_manager.h`:定义与显示系统有关的结构体和函数
    • 宏定义空指针
    • 结构体`DispBuff`
    • 结构体`Region`
    • 结构体`struct DispOpr`
    • 函数声明
  • 文件`framebuffer.c`:Frambuffer设备的初始化和管理
    • 需要的全局变量:
    • 函数`FbDeviceInit()`
    • 函数`FbDeviceExit()`
    • 函数`FbGetBuffer()`
    • 函数`FbFlushRegion()`
    • 初始化显示系统的顶层顶结体`struct DispOpr`
    • 函数`FramebufferInit()`
  • 文件“disp_manager.c”:上层应用程序和下层设备管理程序的中间过渡层
    • 需要的全局变量
    • 绘图函数PutPixel()
    • 函数`DisplayInit()`:这个函数实现设备的实始化
    • 函数`RegisterDisplay()`:实现注册显示设备结构体`struct DispOpr`
    • 函数`SelectDefaultDisplay()`:显示设备选择函数
    • 函数`InitDefaultDisplay()`:当前选择的显示设备进行初始化
    • 函数GetDisplayBuffer():获取结构体`struct DispBuff`的指针
    • 函数FlushDisplayRegion():对指定的区域进行刷新操作
  • 文件`disp_test.c`:显示系统测试实例
    • 功能描述
    • 一堆需要的头文件
    • ASCII码点阵库
    • 函数lcd_put_ascii()
    • 主函数main()分析
  • 编译并下载到板子上测试
  • 附完整源代码

系统框图

见链接 https://kdocs.cn/l/ckwixdBIP6lf

头文件disp_manager.h:定义与显示系统有关的结构体和函数

路径:“\source\01_display_struct\disp_manager.h”

宏定义空指针

#define NULL (void *)0
  • 1

详细介绍见 http://iyenn.com/rec/1709682.html
这个NULL的宏定义后面在disp_manager.c中会用到,就是下面的两句代码会运到:

static PDispOpr g_DispDevs = NULL;
static PDispOpr g_DispDefault = NULL;
  • 1
  • 2

结构体DispBuff

typedef struct DispBuff {
	int iXres;
	int iYres;
	int iBpp;
	char *buff;
}DispBuff, *PDispBuff;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

DispBuff结构体用于存储设备返回的x方向的分辨率(iXres)、y方向的分辨率(iYres)、每个像素点用多少位表示(iBpp)、虚拟内存映射的基指针buff。

结构体Region

typedef struct Region {
	int iLeftUpX;
	int iLeftUpY;
	int iWidth;
	int iHeigh;
}Region, *PRegion;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这个结构体用于存储一个具体的区域,这个在区域刷新显示时会用到。

结构体struct DispOpr

typedef struct DispOpr {
	char *name;
	int (*DeviceInit)(void);
	int (*DeviceExit)(void);
	int (*GetBuffer)(PDispBuff ptDispBuff);
	int (*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);
	struct DispOpr *ptNext;
}DispOpr, *PDispOpr;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这个结构体就是一个设备的底层信息的汇总结构体,是该显示系统中非常重要的结构体。
注意:成员DeviceInit、DeviceExit、GetBuffer、FlushRegion都是函数指针,以int (*DeviceInit)(void);为例说明如下:
int:指向的函数返回一个 int 类型值。
(*DeviceInit):表明 DeviceInit 是一个函数指针。
(void):表示函数指针所指向的函数没有参数。

函数声明

void RegisterDisplay(PDispOpr ptDispOpr);

void DisplayInit(void);
int SelectDefaultDisplay(char *name);
int InitDefaultDisplay(void);
int PutPixel(int x, int y, unsigned int dwColor);
int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);
PDispBuff GetDisplayBuffer(void);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

具体的这些函数的作用请见下面对各源文件中各函数的分析。

文件framebuffer.c:Frambuffer设备的初始化和管理

需要的全局变量:

static int fd_fb;
static struct fb_var_screeninfo var;	/* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

前面的static表示这些变量仅限在本文件内使用,如果想深入了解这些变量,把博文 http://iyenn.com/rec/1709395.html 看一遍就行了。
下面是详细解释:
fd_fb:代表文件描述符。
var:这是 fb_var_screeninfo 结构体的指针,ioctl 函数通过此结构体返回获取到的显示设备信息。
screen_size:屏幕大小。
fb_base:将 /dev/fb0 设备的内存映射到进程的虚拟内存空间的地址;
line_width:LCD屏一行所占的字节数;
pixel_width:每个像素的字节宽度。

函数FbDeviceInit()

static int FbDeviceInit(void)
{
	fd_fb = open("/dev/fb0", O_RDWR);
	if (fd_fb < 0)
	{
		printf("can't open /dev/fb0\n");
		return -1;
	}
	if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
	{
		printf("can't get var\n");
		return -1;
	}

	line_width  = var.xres * var.bits_per_pixel / 8;
	pixel_width = var.bits_per_pixel / 8;
	screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
	fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
	if (fb_base == (unsigned char *)-1)
	{
		printf("can't mmap\n");
		return -1;
	}

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

这个函数实际上就是博文 IMX6ULL开发板基础实验:Framebuffer驱动程序的简单应用实例代码详细分析里的代码,主要作用就是打开Framebuffer设备文件,获得文件描述符,并映射到程序的虚拟内存。

函数FbDeviceExit()

static int FbDeviceExit(void)
{
	munmap(fb_base, screen_size);
	close(fd_fb);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这个函数没有啥讲头,就是把映射的虚拟内存空间释放,并且销毁对应的文件描述符。

函数FbGetBuffer()

static int FbGetBuffer(PDispBuff ptDispBuff)
{
	ptDispBuff->iXres = var.xres;
	ptDispBuff->iYres = var.yres;
	ptDispBuff->iBpp  = var.bits_per_pixel;
	ptDispBuff->buff  = (char *)fb_base;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这个函数实际上是把ioctl 函数返回的fb_var_screeninfo 结构体中存储的与LCD有关的信息和内存映射基地址存储到结构体ptDispBuff)中。
ptDispBuff->iXres 中存储的是LCD屏一行有多少个像素点。
ptDispBuff->iYres 中存储的是LCD屏一列有多少个像素点。
ptDispBuff->iBpp 中存储的是一个像素点用多个位表示。
ptDispBuff->buff的值fb_base是全局变量,是函数DeviceInit()运行后得到的虚拟内存基地址。

函数FbFlushRegion()

static int FbFlushRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{
	return 0;
}
  • 1
  • 2
  • 3
  • 4

这个函数没有具体的语句,主要是两个输入参数,一个是在头文件中定义的结构体struct Region结针
ptRegion,另一个是字符串指针buffer。
之所以没有具体的语句,是因为咱们开发板上的LCD在Framebuffer数据变化后,自动就显示最新的了,所以不需要再去作刷新操作。
当然,这其中也离不开语句:

fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
  • 1

中参数MAP_SHARED的作用。
这里之所以写出这个函数,是为了程序能适应更多的显示设备。

初始化显示系统的顶层顶结体struct DispOpr

static DispOpr g_tFramebufferOpr = {
	.name        = "fb",
	.DeviceInit  = FbDeviceInit,
	.DeviceExit  = FbDeviceExit,
	.GetBuffer   = FbGetBuffer,
	.FlushRegion = FbFlushRegion,
};

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

函数FramebufferInit()

void FramebufferInit(void)
{
	RegisterDisplay(&g_tFramebufferOpr);
}
  • 1
  • 2
  • 3
  • 4

这个函数调用disp_manager.c中的注册函数RegisterDisplay,并把初始化的结构体struct DispOpr的实例&g_tFramebufferOpr作为参数传入。

文件“disp_manager.c”:上层应用程序和下层设备管理程序的中间过渡层

在这里插入图片描述

需要的全局变量

static PDispOpr g_DispDevs = NULL;
static PDispOpr g_DispDefault = NULL;
static DispBuff g_tDispBuff;
static int line_width;
static int pixel_width;
  • 1
  • 2
  • 3
  • 4
  • 5

要点分析:
PDispOpr是之前在头文件里定义的实现FrameBuffer的重要结构体struct DispOpr的指针类型,相关代码如下:

typedef struct DispOpr {
	char *name;
	int (*DeviceInit)(void);
	int (*DeviceExit)(void);
	int (*GetBuffer)(PDispBuff ptDispBuff);
	int (*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);
	struct DispOpr *ptNext;
}DispOpr, *PDispOpr;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这里定义了两个PDispOpr类型的变量,分别为g_DispDevs和 g_DispDefault。根据下文的分析可知,g_DispDevs用于存储最新注册的显示设备结构体, g_DispDefault存储用户选择的设备的结构体,用户选择通过函数SelectDefaultDisplay()实现。

DispBuff是之前在头文件里定义的结构体类型struct DispBuff:

typedef struct DispBuff {
	int iXres;
	int iYres;
	int iBpp;
	char *buff;
}DispBuff, *PDispBuff;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

line_width:是LCD一行所占的字节数。
pixel_width:是一个像素所用的字节数。

绘图函数PutPixel()

这个函数已在博文 IMX6ULL开发板基础实验:Framebuffer驱动程序的简单应用实例代码详细分析中进行了详细学习,这里不再赘述,代码如下:

int PutPixel(int x, int y, unsigned int dwColor)
{
	unsigned char *pen_8 = (unsigned char *)(g_tDispBuff.buff+y*line_width+x*pixel_width);
	unsigned short *pen_16;	
	unsigned int *pen_32;	

	unsigned int red, green, blue;	

	pen_16 = (unsigned short *)pen_8;
	pen_32 = (unsigned int *)pen_8;

	switch (g_tDispBuff.iBpp)
	{
		case 8:
		{
			*pen_8 = dwColor;
			break;
		}
		case 16:
		{
			/* 565 */
			red   = (dwColor >> 16) & 0xff;
			green = (dwColor >> 8) & 0xff;
			blue  = (dwColor >> 0) & 0xff;
			dwColor = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
			*pen_16 = dwColor;
			break;
		}
		case 32:
		{
			*pen_32 = dwColor;
			break;
		}
		default:
		{
			printf("can't surport %dbpp\n", g_tDispBuff.iBpp);
			return -1;
			break;
		}
	}

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

函数DisplayInit():这个函数实现设备的实始化

void DisplayInit(void)
{
	
	extern void FramebufferInit(void);
	FramebufferInit();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

函数RegisterDisplay()会调用framebuffer.c中的函数FramebufferInit(),函数FramebufferInit()的详细介绍见上文。

函数RegisterDisplay():实现注册显示设备结构体struct DispOpr

void RegisterDisplay(PDispOpr ptDispOpr)
{
	ptDispOpr->ptNext = g_DispDevs;
	g_DispDevs = ptDispOpr;
}
  • 1
  • 2
  • 3
  • 4
  • 5

输入参数是下面这个结构体的指针类型:

typedef struct DispOpr {
	char *name;
	int DeviceInit(void);
	int DeviceExit(void);
	int GetBuffer(PDispBuff ptDispBuff);
	int FlushRegion(PRegion ptRegion, PDispBuff ptDispBuff);
	struct DispOpr *ptNext;
}DispOpr, *PDispOpr;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

这个函数RegisterDisplay()实现多个结构体struct DispOpr的链表结构,从而实现设备的注册,具体原理如下:
假设现在我传入struct DispOpr 结构体指针:g_DispDevs_2,那么首先会让g_DispDevs_2的成员ptNext指向g_DispDevs,然后再让g_DispDevs 指向这个新的结构体指针:g_DispDevs_2,也就是说g_DispDevs中永远是最新的结构体struct DispOpr的指针,而之前的结构体通过链表进行了存储。
函数RegisterDisplay用于向结构体struct DispOpr的链接中加入新的结构体,从而实现设备的注册,说白了,设备的注册就是有完整的结构体struct DispOpr,并加入到链接中。

函数SelectDefaultDisplay():显示设备选择函数

int SelectDefaultDisplay(char *name)
{
	PDispOpr pTmp = g_DispDevs;
	while (pTmp) 
	{
		if (strcmp(name, pTmp->name) == 0)
		{
			g_DispDefault = pTmp;
			return 0;
		}

		pTmp = pTmp->ptNext;
	}

	return -1;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

根据对上一个函数RegisterDisplay()的分析,我们发现指针变量g_DispDevs中永远存储的是最新的显示设备的结构体,但同时也形也了一个链表,所以函数SelectDefaultDisplay()能通过对字符串char *name的比较,然后遍历链表中的所有结构体,来通过设备名字找到你所选择的设备。并把设备结构体存储中在g_DispDefault中。

函数InitDefaultDisplay():当前选择的显示设备进行初始化

int InitDefaultDisplay(void)
{
	int ret;
	
	ret = g_DispDefault->DeviceInit();
	if (ret)
	{
		printf("DeviceInit err\n");
		return -1;
	}

	
	ret = g_DispDefault->GetBuffer(&g_tDispBuff);
	if (ret)
	{
		printf("GetBuffer err\n");
		return -1;
	}

	line_width  = g_tDispBuff.iXres * g_tDispBuff.iBpp/8;
	pixel_width = g_tDispBuff.iBpp/8;

	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

值得注意的是,下面这段代码是有问题的。

	ret = g_DispDefault->GetBuffer(&g_tDispBuff);
	if (ret)
	{
		printf("GetBuffer err\n");
		return -1;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

问题在于GetBuffer()这个函数其实它的返回值应该始终为0才对,这里的GetBuffer()的代码如下:

static int FbGetBuffer(PDispBuff ptDispBuff)
{
	ptDispBuff->iXres = var.xres;
	ptDispBuff->iYres = var.yres;
	ptDispBuff->iBpp  = var.bits_per_pixel;
	ptDispBuff->buff  = (char *)fb_base;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

从这段代码来看,只要这段代码编译通过并且执行了,那么返回值都为0,所以韦老师的这段代码显然不太严谨。

函数GetDisplayBuffer():获取结构体struct DispBuff的指针

PDispBuff GetDisplayBuffer(void)
{
	return &g_tDispBuff;
}
  • 1
  • 2
  • 3
  • 4
typedef struct DispBuff {
	int iXres;
	int iYres;
	int iBpp;
	char *buff;
}DispBuff, *PDispBuff;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

获取结构体struct DispBuff的指针后,方便函数static int FbFlushRegion(PRegion ptRegion, PDispBuff ptDispBuff)的调用,因为这里面有个参数是PDispBuff ptDispBuf
这里要分析一个问题,g_tDispBuff的值是何时有的?g_tDispBuff是在文件disp_manager.c中定义的,在函数InitDefaultDisplay()中有代码:

ret = g_DispDefault->GetBuffer(&g_tDispBuff);
  • 1

GetBuffer的代码如下:

static int FbGetBuffer(PDispBuff ptDispBuff)
{
	ptDispBuff->iXres = var.xres;
	ptDispBuff->iYres = var.yres;
	ptDispBuff->iBpp  = var.bits_per_pixel;
	ptDispBuff->buff  = (char *)fb_base;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

可见通过这个调用,相关的分辨率,像素位深度、内存基址都通过指过形参的指针传递放到了结构变量g_tDispBuff中。

函数FlushDisplayRegion():对指定的区域进行刷新操作

int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)
{
	return g_DispDefault->FlushRegion(ptRegion, ptDispBuff);
}
  • 1
  • 2
  • 3
  • 4

文件disp_test.c:显示系统测试实例

功能描述

测试实例的功能是在屏幕上显示字符A,这个字符A是用点阵的数据格式来存储的。

一堆需要的头文件

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

这些需要的头文件已经在博文 http://iyenn.com/rec/1709395.html 中进行了介绍。

ASCII码点阵库

这个点阵库是在Linux内核中的文件Font_8×16.c中提取出来的。
在这里插入图片描述

#define FONTDATAMAX 4096

static const unsigned char fontdata_8x16[FONTDATAMAX] = {

	/* 0 0x00 '^@' */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x00, /* 00000000 */

	/* 1 0x01 '^A' */
	0x00, /* 00000000 */
	0x00, /* 00000000 */
	0x7e, /* 01111110 */
	0x81, /* 10000001 */
	0xa5, /* 10100101 */
	0x81, /* 10000001 */
	0x81, /* 10000001 */
	0xbd, /* 10111101 */
.......
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

这里边一共有256个字符,每个字符是16个字节,所以需要的数组大小为 16*256=4096个,也就是FONTDATAMAX定义的大小。

函数lcd_put_ascii()

void lcd_put_ascii(int x, int y, unsigned char c)
{
	unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
	int i, b;
	unsigned char byte;

	for (i = 0; i < 16; i++)
	{
		byte = dots[i];
		for (b = 7; b >= 0; b--)
		{
			if (byte & (1<<b))
			{
				/* show */
				PutPixel(x+7-b, y+i, 0xffffff); /* 白 */
			}
			else
			{
				/* hide */
				PutPixel(x+7-b, y+i, 0); /* 黑 */
			}
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

这个函数就是调用之前写好的函数像素描点函数PutPixel(),把每个具体的字符的每一个点都画到LCD屏上去。
参数x和y分别代表每个字符的左上顶点的坐标。
在这里插入图片描述

主函数main()分析

int main(int argc, char **argv)
{
	Region region;
	PDispBuff ptBuffer;
		
	DisplayInit();

	SelectDefaultDisplay("fb");

	InitDefaultDisplay();

	lcd_put_ascii(100, 100, 'A');

	region.iLeftUpX = 100;
	region.iLeftUpY = 100;
	region.iWidth   = 8;
	region.iHeigh   = 16;

	ptBuffer = GetDisplayBuffer();
	FlushDisplayRegion(&region, ptBuffer);
	
	return 0;	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

首先调用DisplayInit();注册好一个显示的结构体g_tFramebufferOpr,这个结构体表明这个设备的名字是fb

static DispOpr g_tFramebufferOpr = {
	.name        = "fb",
	.DeviceInit  = FbDeviceInit,
	.DeviceExit  = FbDeviceExit,
	.GetBuffer   = FbGetBuffer,
	.FlushRegion = FbFlushRegion,
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

然后用SelectDefaultDisplay("fb");选择当前使用的设备。

选择好当前设备后再用InitDefaultDisplay();初始化当前设备。

初始当前设备后就可以用lcd_put_ascii(100, 100, 'A');绘图了。

后面的代码:

	region.iLeftUpX = 100;
	region.iLeftUpY = 100;
	region.iWidth   = 8;
	region.iHeigh   = 16;

	ptBuffer = GetDisplayBuffer();
	FlushDisplayRegion(&region, ptBuffer);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在IMX6ULL开发析,用LCD显示字符的这个实验中并没有用,因为咱们的LCD配合下面这句代码的参数MAP_SHARED,只需要内存中的值改变了,那么屏幕上的内容也变了,并不需要再手动去刷新区域。

fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
  • 1

编译并下载到板子上测试

首先按博文 http://iyenn.com/rec/1709618.html编译出目标文件
在这里插入图片描述
把test文件复制到NFS目录/home/book/nfs_rootfs中
在这里插入图片描述
打开串口…

启动开发板…

测试能否Ping通…

挂载网络文件系统…

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt
  • 1

把test文件复制到开发板的用户home目录下的myprogram目录

cp /mnt/test ~/myprogram/test
  • 1

给这个文件添加执行权限

chmod +x ~/myprogram/test
  • 1

运行之前在博文:
IMX6ULL开发板把屏幕刷黑(黑屏)的程序
中编译好的把屏幕刷黑的程序把屏蔽刷黑,如果不刷黑是看不出效果的,因为我这个测试程序的效果就是屏幕上显示一个白色的字符A。

~/myprogram/draw_lcd_black
  • 1

然后再执行咱们这里的测试程序:

~/myprogram/test
  • 1

因为显示的字符A比较小,所以这里拍照看不出效果,就略去效果图了。

附完整源代码

https://pan.baidu.com/s/1alxPD7geby7XCUU4l2W2Qg?pwd=6xjw

昊虹嵌入式技术交流群
QQ群名片
注:本文转载自blog.csdn.net的昊虹AI笔记的文章"https://blog.csdn.net/wenhao_ir/article/details/144460054"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top