❤️你见过Linux下内核的应用程序hellowolrd吗?你说你会用c语言写hellowolrd?我不信❤️

文章目录

  • 一、Linux内核是什么?
  • 二、如何在linux内核下写程序
  • 三、代码编写
        • 1.应用程序的编写
        • 2.驱动程序的编写
        • 3.使用Makefile进行程序的编译
        • 4.把在ubuntu生成的.ko文件和应用程序放在arm板子上执行
  • 总结


一、Linux内核是什么?

Linux是一种开源电脑操作系统内核。它是一个用C语言写成,符合POSIX标准的类Unix操作系统 。操作系统是一个用来和硬件打交道并为用户程序提供一个有限服务集的低级支撑软件。一个计算机系统是一个硬件和软件的共生体,它们互相依赖,不可分割。计算机的硬件,含有外围设备、处理器、内存、硬盘和其他的电子设备组成计算机的发动机。但是没有软件来操作和控制它,自身是不能工作的。完成这个控制工作的软件就称为操作系统,在Linux的术语中被称为“内核”,也可以称为“核心”。Linux内核的主要模块(或组件)分以下几个部分:存储管理、CPU和进程管理、文件系统、设备管理和驱动、网络通信,以及系统的初始化(引导)、系统调用等。

二、如何在linux内核下写程序

  • Linux内核可以放在很多框架上,如ARM框架处理器,x86架构CPU等等。如果我们要驱动一个设备,就必须写一个驱动程序来驱动设备,而驱动程序又依赖于Linux内核,换句话来说,Linux驱动 = 软件框架 + 硬件操作。驱动程序依赖于Linux内核,你为开发板A开发驱动,那就先在Ubuntu中得到、配置、编译开发板A所使用的Linux内核。接下来教大家从0开始写一个hello world程序运行在ARM开发板上(ARM开发板也是用的Linux内核)。我们以ARM开发板IMX6ULL为例子。
  • 内核和应用层的关联。linux分为应用层编程和内核层,内核层主要是指驱动开发,应用层开发主要是网络编程,进程编程,多线程编程这些。或者再加一些QT这种应用层软件开发。内核给我们应用层提供的open/read/write等函数指针,这些函数在内核的fs.h中用一个名为file_operation结构体进行封装。驱动源码中提供真正的open、read、write、close等函数实体。我们只是通过这个结构体和应用层进行关联,这些函数都是内核本身给我们提供的,可以先不用深入了解。 ❤️你见过Linux下内核的应用程序hellowolrd吗?你说你会用c语言写hellowolrd?我不信❤️_第1张图片
  • 开发板的程序是如何跑起来,我们需要在linux内核下创建一个设备结点,你可以理解为通过这个设备结点来控制开发板的,如按键的操作,led点灯等。至于为什么可以通过这个设备结点来操控开发板,我们可以不用关心,我们只用知道可以提供一个驱动程序来供这个设备结点使用,
  • 总结
    ① 写一个应用层的程序,就和平常的一样
    ② 定义自己的file_operations结构体,和应用层关联起来,
    ③ 把file_operations结构体注册进内核
    ④ 创建设备结点,这个设备结点直接操控硬件,而设备节点需要驱动程序来执行
    这是比较简化的操作,其中的一些细节方面我就不一 一说明了。

三、代码编写

1.应用程序的编写

#include 
#include 
#include 
#include 
#include 
#include 
int main(int argc, char **argv)
{
	int fd;
	char buf[1024];
	int len;

	/* 1. 打开文件 */
	fd = open("/dev/hello", O_RDWR);
	if (fd == -1)
	{
		printf("can not open file /dev/hello\n");
		return -1;
	}

	/* 3. 写文件或读文件 */ 
		write(fd, "hello world", len);
		len = read(fd, buf, 1024);		
		buf[1023] = '\0';
		printf("APP read : %s\n", buf);
			
	return 0;
}

2.驱动程序的编写

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

/* 1. 确定主设备号                                                                 */
static int major = 0;
static char kernel_buf[1024];
static struct class *hello_class;
#define MIN(a, b) (a < b ? a : b)

/* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
/*读函数,连接应用层的read()函数*/
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
	int err;
	err = copy_to_user(buf, kernel_buf, MIN(1024, size));
	return MIN(1024, size);
}
/*写函数,连接应用层的write()函数*,/
static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
	int err;
	err = copy_from_user(kernel_buf, buf, MIN(1024, size));
	return MIN(1024, size);
}
/*打开函数,连接应用层的open()函数*,/
static int hello_drv_open (struct inode *node, struct file *file)
{
	return 0;
}


/* 2. 定义自己的file_operations结构体                                              */
static struct file_operations hello_drv = {
	.owner	 = THIS_MODULE,
	.open    = hello_drv_open,
	.read    = hello_drv_read,
	.write   = hello_drv_write,
};

/* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
/* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
static int __init hello_init(void)
{
	int err;
	major = register_chrdev(0, "hello", &hello_drv); //注册file_operations 结构体
	//你只用知道下面两个函数是自动生成设备结点
	hello_class = class_create(THIS_MODULE, "hello_class");
	device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
	return 0;
}

/* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 ,如果不进行卸载的话驱动程序将会一直都在*/
static void __exit hello_exit(void)
{
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
	device_destroy(hello_class, MKDEV(major, 0));
	class_destroy(hello_class);
	unregister_chrdev(major, "hello");
}
/* 7. 告诉内核哪个函数是入口函数,哪个函数是出口函数 ,出口函数在卸载驱动时调用
,入口函数在驱动注册时调用 */
module_init(hello_init);
module_exit(hello_exit);
//因为Linux内核是开源的,所以所有的开发者都要遵循这个GPL协议
MODULE_LICENSE("GPL");

3.使用Makefile进行程序的编译

在你的驱动程序和应用程序下写一个makefile

/*你内核的所在目录*/
KERN_DIR = /home/book/100ask_roc-rk3399-pc/linux-4.4
all:
   //去到这个内核的目录下编译驱动模块
	make -C $(KERN_DIR) M=`pwd` modules 
	//使用交叉编译工具链进行,生成应用程序,这样就可以在arm平台下进行程序的运行了
	$(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c 

clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order
	rm -f hello_drv_test
/要编译哪个文件?这也需要指定,设置obj-m变量即可/
obj-m	+= hello_drv.o

4.把在ubuntu生成的.ko文件和应用程序放在arm板子上执行

1.ubuntu要想把文件传输到arm平台上有很多种方式,相当于ubuntu和windows通信类似,可以使用tftp通信方式,或者NFS通信方式进行数据的传输。这里使用NFS通信

  1. 使用下面命令挂载NFS
    挂载的意思:打个比方你要挂载hello这个文件到arm上,那么你的arm上的某个目录将会有和你这个hello文件一模一样的东西,如果你修改了东西,另外一个平台上的hello文件也会修改。
    #mount -t nfs -o nolock,vers=3 192.168.1.100:/home/book/nfs_rootfs /mnt

2.在你挂载的目录下安装驱动程序:insmod hello_drv.ko ,这是将会在/dev/自动创建一个设备结点。
3.运行你的应用层程序:./hello_drv_test 。
这时候你的屏幕上将会显示应用层写入helloworld字符串。

总结

因为这其中涉及大量的准备工作,需要配置好很多的环境,所以说完成上机实验比较难,只是让大家了解一下驱动的开发流程,让大家有一个大体的了解。
我可以说这是我见过最难的hellowrold的编写,我不信你见过比这个更难得helloworld程序的编写。如果你想更深入的了解嵌入式,你可以去看韦东山老师的视频,Linux嵌入式教学第一人。
❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️❤️

你可能感兴趣的:(linux,嵌入式,驱动,linux,c语言,驱动程序,底层应用开发)