Linux:LCD驱动开发

news2024/9/29 9:17:50

目录

1.不同接口的LCD硬件操作原理

应用工程师眼中看到的LCD

1.1像素的颜色怎么表示

​编辑 1.2怎么把颜色发给LCD

 驱动工程师眼中看到的LCD

统一的LCD硬件模型

8080接口

TFTRGB接口

什么是MIPI

Framebuffer驱动程序框架

 怎么编写Framebuffer驱动框架

硬件LCD时序分析

8080接口LCD

 TFTRGB接口LCD

IMX6ULL中的LCD控制器

一、LCD接口概述

 二、external Signal

 三、时钟

四、功能描述

单buffer和双biffer

使用双buffer


1.不同接口的LCD硬件操作原理

应用工程师眼中看到的LCD

LCD由一个一个像素组成:每行由xres个像素,有yres行,他的分辨率是:xres*yres.

只要我们能控制任意一个像素的颜色,就可以在LCD上绘制图片,文字

1.1像素的颜色怎么表示

用红绿蓝三种颜色来表示,可以用24位数据来表示红绿蓝,也可以用16位等等格式。比如:

  • bpp : bits per pixel ,每个像素用多少位来表示
  • 24bpp:实际上会用到32位,其中8位未使用,其余24位中分别用8位来表示红(R),绿(G),蓝(B)
  • 16bpp:有rbg565,rbg555
  1. rbg565:用5位表示红,用6位表示绿,用5位表示蓝
  2. rbg555:16位数据中用5位表示红,5位表示绿,5位表示蓝,浪费一位

 1.2怎么把颜色发给LCD

假设每个像素的颜色用16位来表示,那么一个LCD的所有像素点假设有xres*yres个,

需要的内存为:xres * yres *16/8 ,也就是要设置所有像素的颜色,需要这么大的内存

这块内存就被称为framebuffer:

  • Framebuffer中每块数据对应一个像素
  • 每块数据的大小可能是16位,32位,这跟LCD上的像素的颜色格式有关
  • 设置好LCD硬件后,只需要把颜色数据写入到Framebuffer即可

 驱动工程师眼中看到的LCD

驱动工程师对LCD的理解要深入硬件,必须要回答这几个问题:

  • Framebuffer在哪里
  • 谁把Framebuffer中的数据发给LCD

统一的LCD硬件模型

第一种情况:将显存,LCD控制器,LCD屏幕组成一个模组(LCM)

第二种情况:将LCD控制器,显存与LCD屏幕分隔开,LCD控制器是位于ARM芯片内部的,ARM                       芯片外接内存,从内存中分配出一块空间供显存使用

 第一种情况一般用于单片机MCU(F103):这种接口称为8080

第二种情况一般用于能运行Linux的高性能的芯片MPU:这种接口一般被称为TFTRGB接口

这两种接口是不一样的,但整个模块的原理是一样的

8080接口

用这种接口的单片机一般性能比较弱, 所以外接的模块用内存的接口最好,我们在访问内存时,一般用数据线访问(读信号,写信号,地址线,数据线,片选信号),这样的话需要的IO口太多了,如何进行精简呢?数据线不可少,所以只能精简地址线,可以通过将地址信号转换为数据通过数据线发送,但是怎么分辨发送的是数据还是地址呢,通过引出一个引脚来分辨(data/cmd)

这种显存在屏幕上,显存一般是SRAM,它比较贵,所以一般的 8080屏幕分辨率不高

要使用更高分辨率的屏幕,就可以用以下接口的方式,这种方式内存接口比较便宜

TFTRGB接口

LCD控制器在ARM芯片内部,它会自动获取Framebuffer中的数据,那它怎么将数据发送到LCD屏幕上边呢:

1.移动像素:DCLK

2.从最后跳到下一行:HSYNC(每来一个脉冲就执行一次)

3.跳回一帧的开始(从最后一个像素段跳到第一个像素点):VSYNC 

4.数据来源:RGB三组线(24条线)

5.当数据从最后跳到下一行和从会后一个像素点跳到第一个像素点的时候数据是无效的,所以使用:DE(来决定数据是否有效)

什么是MIPI

 实际上上边这两种接口的实质是一样的,这两种接口都可以归入一个标准:MIPI标准

MIPI表示“Mobile Industry Proc8080essor Interface”,即移动产业处理器接口,是MIPI联盟发起的为移动应用处理器制定的开放标准和一个规范。主要是手机内部的接口(摄像头,显示器接口,射频/基带接口)等标准化,从而减少手机内部接口的复杂程度及增加设计的灵活性

对于LCD,MIPI可以分为3类:

MIPI-DBI(Display Bus Interface)

既可以是Bus(总线),就是既能发送命令,常用的8080接口就是属于DBI接口

MIPI-DPI(Display Pixel Interface)

Pixel(像素),强调的是操作单个像素,在MPU上的LCD控制器就是这种接口 

MIPI-DSI(Display Serial Interface)

Serial,相比于DBI,DPI需要使用很多接口线,DSI需要的接口线大为减少 

Framebuffer驱动程序框架

它再怎么复杂,还是一个字符驱动程序

LCD驱动程序分为

1.上层比较通用性的代码(框架):fbmem.c

2.硬件驱动:对于不同的芯片还有不同的硬件相关的文件:s3c2410fb.c   STM32MP157_fb.c

调用关系:

示例1:
app: open("/dev/fb0", ...)  主设备号:29  , 次设备号: 0
---------------------------------------------------------------------------
kernel:
        fb_open
            int fbidx = iminor(inode);
            struct fb_info *info = = registered_fb[0];




示例2:
app:    read()
----------------------------------------------------------------------------
kernel:
        fb_read
            int fbidx = iminor(inode);
            struct fb_info *info = registered_fb[fbidx];
            if(info -> fbops -> fb_read)
                return info -> fbops -> fb_read(info, buf count ppos);
                
            src = (u32 __inomem *) (info -> screen_base + p);
            dst = buffer;
            *dst++ == fb_readl(src++);
            copy_to_user(buf, buffer, c);

 怎么编写Framebuffer驱动框架

核心:


struct fb_info {
	atomic_t count;
	int node;
	int flags;
	struct mutex lock;		/* Lock for open/release/ioctl funcs */
	struct mutex mm_lock;		/* Lock for fb_mmap and smem_* fields */
	struct fb_var_screeninfo var;	/* Current var */
	struct fb_fix_screeninfo fix;	/* Current fix */
	struct fb_monspecs monspecs;	/* Current Monitor specs */
	struct work_struct queue;	/* Framebuffer event queue */
	struct fb_pixmap pixmap;	/* Image hardware mapper */
	struct fb_pixmap sprite;	/* Cursor hardware mapper */
	struct fb_cmap cmap;		/* Current cmap */
	struct list_head modelist;      /* mode list */
	struct fb_videomode *mode;	/* current mode */

#ifdef CONFIG_FB_BACKLIGHT
	/* assigned backlight device */
	/* set before framebuffer registration, 
	   remove after unregister */
	struct backlight_device *bl_dev;

	/* Backlight level curve */
	struct mutex bl_curve_mutex;	
	u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
	struct delayed_work deferred_work;
	struct fb_deferred_io *fbdefio;
#endif

	struct fb_ops *fbops;
	struct device *device;		/* This is the parent */
	struct device *dev;		/* This is this fb device */
	int class_flag;                    /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
	struct fb_tile_ops *tileops;    /* Tile Blitting */
#endif
	union {
		char __iomem *screen_base;	/* Virtual address */
		char *screen_buffer;
	};
	unsigned long screen_size;	/* Amount of ioremapped VRAM or 0 */ 
	void *pseudo_palette;		/* Fake palette of 16 colors */ 
#define FBINFO_STATE_RUNNING	0
#define FBINFO_STATE_SUSPENDED	1
	u32 state;			/* Hardware state i.e suspend */
	void *fbcon_par;                /* fbcon use-only private area */
	/* From here on everything is device dependent */
	void *par;
	/* we need the PCI or similar aperture base/size not
	   smem_start/size as smem_start may just be an object
	   allocated inside the aperture so may not actually overlap */
	struct apertures_struct {
		unsigned int count;
		struct aperture {
			resource_size_t base;
			resource_size_t size;
		} ranges[0];
	} *apertures;

	bool skip_vt_switch; /* no VT switch on suspend/resume required */
};

1.分配fb_info:framebuffer_alloc

2.设置fb_info:var   ,    fbops       ,硬件相关操作

3.注册fb_info:register_framebuffer

4.进行硬件相关的操作

代码如下:

#include <linux/module.h>

#include <linux/compat.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/vt.h>
#include <linux/init.h>
#include <linux/linux_logo.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/console.h>
#include <linux/kmod.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/efi.h>
#include <linux/fb.h>

#include <asm/fb.h>

static strcut fb_info *myfb_info;

static struct fb_ops myfb_ops = {
	.owner = THIS_MODULE,
	.fb_fillrect = cfb_fillrect,
	.fb_copyarea = cfb_copyarea,
	.fb_imageblit = cfb_imageblit,
};

/*入口函数*/
static int __init lcd_drv_init(void)
{
	dma_addr_t phy_addr;
	
	/*分配fb_info*/
	myfb_info = framebuffer_alloc(0,NULL);
	
	/*设置fb_info*/
	/*1.var: LCD的分辨率,颜色格式等*/
	myfb_info -> var.xres = 1024;
	myfb_info -> var.yres = 600;
	myfb_info -> var.bits_per_pixel = 16;
	
	myfb_info -> var.red.offset = 11;
	myfb_info -> var.red.length = 5;
	
	myfb_info -> var.green.offset = 5;
	myfb_info -> var.green.length = 6;

	myfb_info -> var.blue.offset = 0;
	myfb_info -> var.blue.length = 5;
	/*2.fix*/
	myfb_info -> fiX.smem_len = myfb_info -> var.xres * myfb_info -> var.yres * 4;
	if(myfb_info ->var.bits_per_pixel == 24)
	{
		myfb_inco -> fix.smem_len = myfb_info -> var.xres * myfb_info -> var.yres * myfb_info -> var.bits_per_pixel / 8
	}
	//framebuffer的虚拟地址
	myfb_info -> screen_base = dma_alloc_wc(NULL,myfb_info -> fix.smem_len, &phy_addr, GFP_KERNEL);
	myfb_info -> fix.smem_start = phy_addr;  //framebuffer的物理地址
	
	myfb_info -> fix.type = FB_TYPE_PACKED_PIXELS;
	myfb_info -> fix.visual = FB_VISUAL_TRUECOLOR;
	
	/*3.fbops*/
	myfb_info->fbops = &myfb_ops;
	
	/*注册fb_info*/
	register_framebuffer(myfb_info);

	/*硬件操作*/
	
	
	return 0;
}

/*出口函数*/
static void __exit lcd_drv_exit(void)
{
	/*反过来操作*/
	
	/*反注册fb_info*/
	unregister_framebuffer(myfb_info);

	/*释放fb_info*/
	framebuffer_release(myfb_info);
	
}


module_init(lcd_drv_init);
module_exit(lcd_drv_exit);
MODULE_AUTHOR("zt");
MODULE_DESCRIPTION("Framebuffer driver for the linux");
MODULE_LICENSE("GPL");

对于硬件相关的操作:

这里使用QEMU中简单的四个寄存器

struct lcd_regs{
    volatile unsigned int fb_base_phys;   //这个寄存器存放的是显存的物理地址
    volatile unsigned int fb_xres;             //这个寄存器存放的是X像素
    volatile unsigned int fb_yres;             //这个寄存器存放的是Y像素
    volatile unsigned int fb_bpp;              //这个寄存器存放的是颜色的位数
};

static struct lcd_regs *mylcd_regs;

/*硬件操作*/

    //因为驱动不能直接操作物理地址所以需要将物理地址映射为虚拟地址
    mylcd_regs = ioremap(0x021C8000,sizeof(struct lcd_regs));
    //地址寄存器存放的是之前myfb_info分配的物理地址(也就是显存的物理地址)
    mylcd_regs->fb_base_phys = phy_addr;
    mylcd_regs->fb_xres = 500;
    mylcd_regs->fb_yres = 300;
    mylcd_regs->fb_bpp  = 16;

硬件LCD时序分析

8080接口LCD

8080接口其实就是一般的内存接口

显存,LCD控制器,LCD屏幕放在是一块的(LCM)

1.接口原理图

数据线,读信号,写信号,地址/数据引脚(当这个引脚为高电平时,传输的为数据,为低电平时,传输的是地址),片选引脚(在Linux中内存空间都是分开的,当使用其中一段内存空间的时候,对应的片选引脚会自动有效)

 当位于第一块内存区间时,片选7自动有效,当位于第二块内存区间时,片选6自动有效

其引脚图如下:

 TFTRGB接口LCD

IMX6ULL中的LCD控制器

下面只是简单介绍一下,具体请看这篇文章:LCD控制器

 它是TFTRGB的接口,显存和LCD控制器在IMX6Ull中所以主要就是LCD控制器与LCD屏幕进行互动

一、LCD接口概述

IMX6ULL的控制器名称为eLCDIF(增强型LCD接口)主要特性如下:

1.支持MPU模式:有些显示屏自带显存,只需要把命令、数据发送给显示屏就可以

2.支持DOTCLK模式:RGB接口,本板子就是此模式

3.VSYNC模式:针对高速数据传输(行场信号)

4.支持ITU-R BT.656接口,可以把4:2:2YcbCr格式的数据转换为模拟电视信号

5.8/16/18/24/32 bit的bpp数据都支持,取决于IO的复用设置及寄存器配置

6.MPU模式,VSYNC模式,DOTCLK模式,都可以配置时序参数

 二、external Signal

 三、时钟

 LCD控制器有两个时钟域:外设总线时钟域,LCD像素时钟域。前者是用来让LCD控制器来正常工作,后者是用来控制电子枪移动

四、功能描述

 我们在内存中划出一块内存,称之为显存,软件把数据写入到显存中

设置好LCD控制器之后,它会通过AXI总线协议从显存把RGB数据读入FIFO,再到达LCD接口(LCD Interface)。上图的Read_Data操作,在MPU模式下才用到。

单buffer和双biffer

首先要知道为什么要区分出单Buffer和双buffer

因为在IMX6ULL中,显存和LCD控制器都是在屏幕外的,当使用单buffer时,因为应用层和LCD控制器都是操作的一块显存(framebuffer),如果应用层写入数据时过快,LCD控制器还没有将显存中的数据写到屏幕中,显存有刷新了,此时就会出现问题。

使用双buffer甚至是多buffer可以有效的解决这个问题,因为应用层和LCD控制器操作的不是同一块显存,设有显存1和显存2(这里是在驱动层直接分配了两个显存大小的内存空间{实际上在IMX6ULL中是直接分配了32Mb的内存空间,相当于13个显存,是非常豪横的!!!}),刚开始应用层先写显存1,LCD控制器读显存2的数据,再一次LCD控制器读显存1的数据,应用层向显存2写数据,这样往复操作,就不会出现单buffer时的情况

使用双buffer

#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <time.h>

static int fd_fb;
static struct fb_fix_screeninfo fix;	/* Current fix */
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;

/**********************************************************************
 * 函数名称: lcd_put_pixel
 * 功能描述: 在LCD指定位置上输出指定颜色(描点),一个像素一个像素的放
 * 输入参数: x坐标,y坐标,颜色
 * 输出参数: 无
 * 返 回 值: 会
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2020/05/12	     V1.0	  zh(angenao)	      创建
 ***********************************************************************/ 
void lcd_put_pixel(void *fb_base, int x, int y, unsigned int color)
{
	//
	unsigned char *pen_8 = fb_base+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 (var.bits_per_pixel)
	{
		case 8:
		{
			*pen_8 = color;
			break;
		}
		case 16:
		{
			/* 565 */
			red   = (color >> 16) & 0xff;
			green = (color >> 8) & 0xff;
			blue  = (color >> 0) & 0xff;
			color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
			*pen_16 = color;
			break;
		}
		case 32:
		{
			*pen_32 = color;
			break;
		}
		default:
		{
			printf("can't surport %dbpp\n", var.bits_per_pixel);
			break;
		}
	}
}

void lcd_draw_screen(void *fb_base, unsigned int color)
{
	int x, y;
	for (x = 0; x < var.xres; x++)
		for (y = 0; y < var.yres; y++)
			lcd_put_pixel(fb_base, x, y, color);
}


/* ./multi_framebuffer_test single
 * ./multi_framebuffer_test double
 */
int main(int argc, char **argv)
{
	int i;
	int ret;
	//这个参数是记录的
	int nBuffers;
	int nNextBuffer = 1;
	char *pNextBuffer;
	unsigned int colors[] = {0x00FF0000, 0x0000FF00, 0x000000FF, 0, 0x00FFFFFF};  /* 0x00RRGGBB */
	struct timespec time;

	time.tv_sec  = 0;
	time.tv_nsec = 100000000;

	if (argc != 2)
	{
		printf("Usage : %s <single|double>\n", argv[0]);
		return -1;
	}
	
	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_FSCREENINFO, &fix))
	{
		printf("can't get fix\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;

	nBuffers = fix.smem_len / screen_size;
	printf("nBuffers = %d\n", nBuffers);
	
	fb_base = (unsigned char *)mmap(NULL , fix.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
	if (fb_base == (unsigned char *)-1)
	{
		printf("can't mmap\n");
		return -1;
	}

	if ((argv[1][0] == 's') || (nBuffers == 1))
	{
		while (1)
		{
			/* use single buffer */
			for (i = 0; i < sizeof(colors)/sizeof(colors[0]); i++)
			{
				lcd_draw_screen(fb_base, colors[i]);
				nanosleep(&time, NULL);
			}
		}
	}
	else
	{
		/* use double buffer */
		/* a. enable use multi buffers */
		var.yres_virtual = nBuffers * var.yres;
		ioctl(fd_fb, FBIOPUT_VSCREENINFO, &var);

		while (1)
		{
			for (i = 0; i < sizeof(colors)/sizeof(colors[0]); i++)
			{
				/* get buffer */
				pNextBuffer =  fb_base + nNextBuffer * screen_size;

				/* set buffer */
				lcd_draw_screen(pNextBuffer, colors[i]);

				/* switch buffer */
				var.yoffset = nNextBuffer * var.yres;
				ioctl(fd_fb, FBIOPAN_DISPLAY, &var);

				ret = 0;
				ioctl(fd_fb, FBIO_WAITFORVSYNC, &ret);
				
				nNextBuffer = !nNextBuffer;
				nanosleep(&time, NULL);
			}
		}
		
	}
	
	munmap(fb_base , screen_size);
	close(fd_fb);
	
	return 0;	
}


当输入single时使用单buffer,当输入double时使用双buffer,经过对比会发现明显的差异,使用双buffer的刷屏会更加流畅,并且不会出现颜色覆盖的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2176301.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenAI全新多模态内容审核模型上线:基于 GPT-4o,可检测文本和图像

在数字时代&#xff0c;内容安全问题愈发受到重视。9月26日&#xff0c;OpenAI 正式推出了一款全新的多模态内容审核模型&#xff0c;名为 “omni-moderation-latest”。 该模型基于最新的 GPT-4o 技术&#xff0c;能够准确地识别检测有害文本图像。这一更新将为开发者提供强大…

Java | Leetcode Java题解之第445题两数相加II

题目&#xff1a; 题解&#xff1a; class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {Deque<Integer> stack1 new ArrayDeque<Integer>();Deque<Integer> stack2 new ArrayDeque<Integer>();while (l1 ! null) {stack1.…

AI Agent应用出路到底在哪?

1 Agent/Function Call 的定义 Overview of a LLM-powered autonomous agent system&#xff1a; Agent学会调用外部应用程序接口&#xff0c;以获取模型权重中缺失的额外信息&#xff08;预训练后通常难以更改&#xff09;&#xff0c;包括当前信息、代码执行能力、专有信息源…

《深度学习》OpenCV 角点检测、特征提取SIFT 原理及案例解析

目录 一、角点检测 1、什么是角点检测 2、检测流程 1&#xff09;输入图像 2&#xff09;图像预处理 3&#xff09;特征提取 4&#xff09;角点检测 5&#xff09;角点定位和标记 6&#xff09;角点筛选或后处理&#xff08;可选&#xff09; 7&#xff09;输出结果 3、邻域…

深度学习反向传播-过程举例

深度学习中&#xff0c;一般的参数更新方式都是梯度下降法&#xff0c;在使用梯度下降法时&#xff0c;涉及到梯度反向传播的过程&#xff0c;那么在反向传播过程中梯度到底是怎么传递的&#xff1f;结合自己最近的一点理解&#xff0c;下面举个例子简单说明&#xff01; 一、…

Qt开发技巧(九)去掉切换按钮,直接传样式文件,字体设置,QImage超强,巧用Qt的全局对象,信号槽断连,低量数据就用sqlite

继续讲一些Qt开发中的技巧操作&#xff1a; 1.去掉切换按钮 QTabWidget选项卡有个自动生成按钮切换选项卡的机制&#xff0c;有时候不想看到这个烦人的切换按钮&#xff0c;可以设置usesScrollButtons为假&#xff0c;其实QTabWidget的usesScrollButtons属性最终是应用到QTabWi…

衡石分析平台系统管理手册-功能配置之AI 助手集成嵌入指南

AI 助手集成嵌入指南​ 本文档将引导您通过几个简单的步骤&#xff0c;将 AI 助手集成或嵌入到您的系统中。HENGSHI SENSE AI 助手提供了多种集成方式&#xff0c;您可以通过 iframe、JS SDK 或 API 调用等方式将 AI 助手嵌入集成到您的系统中。 1. 通过 iframe 集成​ ifra…

老板最想要的20套模板!基于 VUE 国产开源 IoT 物联网 Web 可视化大屏设计器

如有需求&#xff0c;文末联系小编 Cola-Designer 是一个基于VUE开发&#xff0c;实现拖拽和配置方式生成数据大屏&#xff0c;提供丰富的可视化模板&#xff0c;满足客户业务监控、数据统计、风险预警、地理信息分析等多种业务的展示需求。Cola-Designer 帮助工程师通过图形化…

MySQL - 单表增删改

1. MySQL 概述 MySQL 是一种流行的开源关系型数据库管理系统 (DBMS)&#xff0c;广泛应用于互联网公司和企业开发中。它支持 SQL 语句操作数据&#xff0c;并提供多种版本供选择。 1.1 MySQL 安装和连接 社区版&#xff1a;免费版本&#xff0c;适合开发者使用。商业版&…

sizeof 和 strlen

一 . sizeof 关键字 这个是我们的老朋友了昂&#xff0c;经常都在使用&#xff0c;它是专门用来计算变量所占内存空间大小的&#xff0c;单位是字节&#xff0c;当然&#xff0c;如果我们的操作对象是类型的话&#xff0c;计算的就是类型所创建的变量所占内存的大小&#xff0…

【笔记】神领物流day1.1.13前后端部署【未完】

使用jenkins 前端部署 需要将前端开发的vue进行编译&#xff0c;发布成html&#xff0c;然后通过nginx进行访问&#xff0c;这个过程已经在Jenkins中配置&#xff0c;执行点击发布即可 网址栏输入神领TMS管理系统 (sl-express.com)即可看见启动成功 后端部署看linux 回到Jenki…

25维谛技术面试最常见问题面试经验分享总结(包含一二三面题目+答案)

开头附上工作招聘面试必备问题噢~~包括综合面试题、无领导小组面试题资源文件免费&#xff01;全文干货。 【免费】25维谛技术面试最常见问题面试经验分享总结&#xff08;包含一二三面题目答案&#xff09;资源-CSDN文库https://download.csdn.net/download/m0_72216164/8979…

单调递增/递减栈

单调栈 单调栈分为单调递增栈和单调递减栈 单调递增栈&#xff1a;栈中元素从栈底到栈顶是递增的 单调递减栈&#xff1a;栈中元素从栈底到栈顶是递减的 应用&#xff1a;求解下一个大于x元素或者是小于x的元素的位置 给一个数组&#xff0c;返回一个大小相同的数组&#x…

一文了解:最新版本 Llama 3.2

Meta AI最近发布了 Llama 3.2。这是他们第一次推出可以同时处理文字和图片的多模态模型。这个版本主要关注两个方面&#xff1a; 视觉功能&#xff1a;他们现在有了能处理图片的模型&#xff0c;参数量从11亿到90亿不等。 轻量级模型&#xff1a;这些模型参数量在1亿到3亿之间…

llamafactory0.9.0微调qwen2vl

LLaMA-Factory/data/README_zh.md at main hiyouga/LLaMA-Factory GitHubEfficiently Fine-Tune 100+ LLMs in WebUI (ACL 2024) - LLaMA-Factory/data/README_zh.md at main hiyouga/LLaMA-Factoryhttps://github.com/hiyouga/LLaMA-Factory/blob/main

【Java SE】初遇Java,数据类型,运算符

&#x1f525;博客主页&#x1f525;&#xff1a;【 坊钰_CSDN博客 】 欢迎各位点赞&#x1f44d;评论✍收藏⭐ 1. Java 概述 1.1 Java 是什么 Java 是一种高级计算机语言&#xff0c;是一种可以编写跨平台应用软件&#xff0c;完全面向对象的程序设计语言。Java 语言简单易学…

Android平台如何获取CPU占用率和电池电量信息

技术背景 我们在做Android平台GB28181设备接入模块、轻量级RTSP服务模块和RTMP推流模块的时候&#xff0c;遇到这样的技术诉求&#xff0c;开发者希望把实时CPU占用、电池信息等叠加在视频界面。 获取CPU占用率 Android平台获取CPU占用情况&#xff0c;可以读取/proc/stat文…

第十三届蓝桥杯真题Java c组D.求和(持续更新)

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;蓝桥杯关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 【问题描述】 给定 n 个整数 a1, a2, , an &#xff0c;求它们两两相乘再相…

生信初学者教程(十六):GO富集分析

文章目录 介绍加载R包导入数据所需函数运行输出结果总结介绍 GO(Gene Ontology)是一个在生物信息学中广泛使用的概念,用于描述基因和基因产物的功能、它们所处的细胞位置以及它们参与的生物过程。GO项目是一个协作性的国际努力,旨在建立和维护一个适用于各种物种的、结构化…

用Python实现运筹学——Day 6: 单纯形法求解过程

一、学习内容 1. 单纯形法的详细步骤 单纯形法是通过迭代过程来优化线性规划问题的解决方案。该算法从可行解空间的一个顶点出发&#xff0c;逐步沿着可行解空间的边界移动到另一个顶点&#xff0c;直到找到最优解。单纯形法的求解过程分为以下几个步骤&#xff1a; 初始化&a…