LED驱动程序第一课

1、LED驱动程序是怎么被调用的

首先我们来看看应用程序怎么去操作一个led灯:

int main(int argc, char **argv)
{
	int fd,status;//文件句柄和led灯状态
	fd = open("/dev/myled", O_RDWR);//打开led设备节点(初始化led)
	if (fd < 0)
	{
		printf("can not open /dev/myled");
		return -1;
	}
	status=1;//led亮
	write(fd, &status, 1);//写led设备节点(点亮led)
	return 0;	
}

点亮一个led灯大致是以上的过程,当然前提是已经注册了led驱动程序并生成设备节点myled,后面会提到怎么生成这个设备节点。那么问题来了,这个和驱动程序有什么关系呢?且看下面分析:
我们说led的open函数,就相当于是对led进行初始化的函数。为什么这么说呢?当led应用程序执行open函数时,会导致异常(软件中断)进入内核,从而调用内核函数sys_open,而sys_open函数会找到led灯对应的file_operations结构体,进而调用结构体成员open指向的led_open函数,从而实现对led灯的初始化。
在这里插入图片描述

2、怎么写一个LED驱动程序

看到这里你可能会有疑问,怎么写一个驱动程序呢?
我们写led驱动程序的目的是什么——让应用程序可以点亮led灯。这是我们的led驱动程序使命。那么首先我们需要做的就是对led灯进行初始化,我们需要让应用程序调用open函数时,能找到我们自己实现的led_open函数。
如何找到?我们回顾一下应用程序中的open函数:

fd = open("/dev/myled", O_RDWR);//打开led设备节点(初始化led)

①这里open的参数有一个是myled设备节点。这就意味着我们需要创建一个led设备节点
②如何创建设备节点?我们使用class_create、device_create函数来实现自动创建设备节点。device_create函数有一个参数是MKDEV(major, minor),(其中major为主设备号,minor为次设备号,次设备号暂时不用管)。
③主设备号从哪里来?这就回归到我们一开始说的file_operations结构体了。当我们使用register_chrdev函数向内核注册led_fops(led_fops是我们定义的file_operations结构体变量)时,会返回一个主设备号

static int __init led_init(void)
{
	......
	major = register_chrdev(0, "100ask_led", &led_fops);
	led_class = class_create(THIS_MODULE, "myled");
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); /* /dev/myled */
	......
}

④既然需要向内核注册led_fops,那么led_fops总不能是空的吧?我们来看一个例子:

//构建一个file_operations结构体变量led_fops
static struct file_operations led_fops = {
	......
	.open		= led_open,
	......
};

//实现led_open函数,初始化led灯
static int led_open(struct inode *inode, struct file *filp)
{
	......
	//以上实现寄存器配置(需要使用ioremap函数对物理地址进行重映射)
	return 0;
}

⑤led_fops的成员open指向led_open函数,该函数实现对led灯相关寄存器的配置,实现对led灯的初始化。led_open的具体实现可以参考韦东山老师的程序,这里不再赘述。
以上①-⑤的过程,就完成了从应用程序的open到驱动程序的led_open的整个过程。类似的,应用程序的write、read函数等,也是类似的过程。
接下来就整理一下驱动程序的大致组成吧:
入口函数:led_init,在加载驱动程序时调用,实现字符设备的注册(即向内核注册file_operations结构体)以及设备节点的创建;
出口函数:led_exit,与入口函数对应;
(入口函数和出口函数需要使用下面的宏进行声明,在驱动程序单独编译成模块和驱动程序编译进内核两种情况下,该宏函数可体现出作用,具体可查阅相关资料学习)
module_init(led_init);
module_exit(led_exit);
file_operations结构体及其成员所指向的函数的实现,我们在驱动程序中,定义file_operations结构体变量led_fops,并实现led_open,led_write等函数。

3、总结

换个角度,从驱动程序的led_open往上追溯至应用程序的open:
①驱动程序中,实现led_open函数,在该函数中配置led相关寄存器。led_open实现之后呢?把它给到file_operations结构体变量led_fops对应的成员open;
②file_operations结构体变量有了,那就注册进内核,能得到一个主设备号;
③主设备号有了,那就创建一个设备节点;
④设备节点有了,那应用程序就可以使用open去打开它。

注:
参考《嵌入式linux应用开发完全手册4.0》
参考韦东山老师的其他相关材料

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在本课中,您将学习如何编程Arduino以使Arduino的内置LED闪烁。 材料清单 Arduino Uno R3 1块 USB引线 - 类型A到B 1根 Arduino有两排连接器,用于连接电子设备和插入式“屏蔽层”,使Arduino能够做得更多。 然而,Arduino也有一个LED,你可以从你的草图中控制。 该LED内置于Arduino板上,通常称为“L”LED,因为这是它在电路板上的标记。 这个LED的位置在下面的Arduino Uno和Leonardo的图片上以红色圈出。 您可能会发现,将Arduino电路板的“L”LED连接到USB插头时,它已经闪烁。 这是因为Arduino主板通常会随附预装的“Blink”草图。 在本课中,我们将使用我们自己的Blink草图重新编程Arduino,然后更改闪烁的速率。 在第0课中,您将设置Arduino IDE,并确保您可以找到正确的串行端口以连接到您的Arduino板。 现在已经到了将该连接用于测试和编程Arduino板的时候了。 Arduino IDE包含大量您可以加载和使用的示例草图。 这包括使'L'LED闪烁的示例草图。 在文件→示例→01.Basics下载入IDE菜单系统中的'Blink'草图。 当草图窗口打开时,将其放大,以便您可以在窗口中看到整个草图。 保存'闪烁'的副本 Arduino IDE附带的示例草图是“只读”的。 也就是说,您可以将它们上传到Arduino板,但如果您更改它们,则无法将它们保存为相同的文件。 我们将改变这个草图,所以,你需要做的第一件事就是保存你自己的副本,你可以改变你喜欢的副本。 从Arduino IDE的File菜单中选择'Save As ..'选项,然后用名称'MyBlink'保存草图。 您已将您的“闪烁”副本保存在写生簿中。 这意味着如果你想再次找到它,你可以使用File→Sketchbook菜单选项来打开它。 将Blink上传至电路板 使用USB电缆将Arduino板连接到计算机,并检查“Board Type”和“Serial Port”是否设置正确。 您可能需要参考第0课。 Arduino IDE将显示窗口底部板子的当前设置。 点击“上传”按钮。 工具栏左侧的第二个按钮。 如果您观看IDE的状态区域,您将看到一个进度条和一系列消息。 起初它会说'编译草图..'。 这将草图转换为适合上传到电路板的格式。 接下来,状态将变为“正在上传”。 此时,Arduino上的LED会在草图传输时开始闪烁。 最后,状态将变为“完成”。 另一条消息告诉我们,草图使用32,256字节中的1,084字节。在“编译草图..”阶段之后,您可能会收到以下错误消息: 线索位于顶部,这可能意味着您的主板根本没有连接,或者驱动程序尚未安装(如有必要)或者选择了错误的串行端口。 如果你得到这个,回到第0课并检查你的安装。 上传完成后,电路板应重新启动并开始闪烁。 'Blink'如何工作 Blink草图的代码见附件。 首先要注意的是,很多这种草图就是所谓的“评论”。 评论不是实际的程序指令,它们只是关于程序如何工作的评论。 他们在那里是为了得到好处,所以伴随草图有一些解释。 草图顶部的/ *和* /之间的所有内容都是块注释,它解释了草图的用途。 也有以//开头的单行注释,并且在行末尾的所有内容都被视为注释。 第一个实际的代码行是: int led = 13; 正如上面的评论所解释的那样,这给了LED所连接的引脚的名称。 这在大多数Arduinos中都是13,包括Uno和Leonardo。 接下来,我们有'设置'功能。 同样,如评论所述,按下重置按钮时会运行。 它也会在电路板因任何原因(例如首先应用电源或重新上传草图后)重置时运行。 void setup() { // initialize the digital pin as an output. pinMode(led, OUTPUT); } 每个Arduino草图都必须具有“设置”功能,其中可能需要添加自己指令的部分位于{和}之间。 在这种情况下,那里只有一个命令,正如注释状态告诉Arduino开发板,我们将使用LED引脚作为输出。具有“循环”功能的草图也是强制性的。 与只能运行一次的“设置”功能不同,复位后,“循环”功能将在完成其命令后立即重新启动。 void loop() { digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level) delay(1000); // wait for a second digitalWrite(led, LOW); // turn the LED off by making the vol

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值