一、概述

延时和时间一章,初步体验了下系统编程。不过既然是想做嵌入式开发,还是脱离不了硬件,现在就完成一次点灯。

Linux也好,单片机也好,灯总是那个灯的,高低电平给进去,或亮或灭。只是给电平的方式不一样:或者直接配置寄存器,或者通过HAL库函数,而Linux下,LED作为一个字符设备,则需要通过文件IO进行操作

二、文件IO

还没开始认真学习Linux,就听过好几次Linux下一切皆文件。几个文件IO函数从这篇学习笔记开始,会经常用到,这里简单记录下。

2.1 open和close

open函数用于打开文件,原型如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags); 
int open(const char *pathname, int flags,mode_t mode);  

pathname是文件名;flags是打开方式,如只读、只写、可读可写、阻塞等;当flags中含有O_CREAT时,open函数应包括参数mode,表示创建文件的权限。
函数调用成功返回文件描述符fd,在后面几个IO函数中均会用到。

close函数用于关闭文件,原型如下:

#include <unistd.h>
int close(int fd);

fd是open返回的文件描述符。

2.2 write和read

write函数原型如下:

#include <unistd.h>
ssize_t write(int fd,const void *buf,size_t count)

将参数 *buf 中最多 count 个字节写入到 fd 指向的文件中。返回实际写入的字节数,出错返回-1。

read函数原型如下:

#include <unistd.h>
ssize_t read(int fd,void *buf,size_t count)

从 fd 指向的文件中,最多读取 count 个字节,保存到参数 *buf 中。返回实际读取的字节数,出错返回-1。

2.3 ioctrl

ioctl函数原型如下:

#include<unistd.h>
int ioctl( int fd, int request, int cmd);  

request 和 cmd的具体含义,由驱动实现决定。request 可以表示具体的 IO 管脚,cmd表示高低电平。也可以反过来,cmd 可以表示具体的 IO 管脚,request 表示高低电平。

现在系统编程学习,按照讯为开发板的实现定义来使用接口,等后面进入到驱动学习的时候,再展开看如何实现的。

三、点亮LED

现在开始正式点灯。例程是通过传入参数,控制两个LED的点亮和熄灭。这里结合上一篇提到的sleep函数,小改动了下,变成了控制LED按照传入的时间和次数进行闪烁。

3.1 程序流程

点灯流程大致如下:
在这里插入图片描述

3.2 代码实现

首先查看LED的设备节点

ls /dev/led*

在这里插入图片描述
有了设备节点就可以开始编写程序了。

	//使用ioctl函数将参数传入内核
	if((fd = open(leds, O_RDWR|O_NOCTTY|O_NDELAY)) < 0) {
		printf("open %s failed\n",leds);
	}
	else {
		printf("open %s success\n",leds);
		while(flicker_count--)
		{
			ioctl(fd, LED_ON, atoi(argv[1]));
			sleep(atoi(argv[2]));
			ioctl(fd, LED_OFF, atoi(argv[1]));
			sleep(atoi(argv[2]));
		}
	}

需要注意的是,通过main传入的参数是字符格式,需要转化成整型再传递给sleepioctl函数。函数原型为:

#include <stdlib.h>
int atoi(const char *nptr);

3.3 编译验证

对C文件进行编译后,拷贝到tftp服务器目录下。注意使用交叉编译指令arm-none-linux-gnueabi-gcc
在这里插入图片描述
在开发板上tftp -g -l led -r led 192.168.1.72获取led文件,结果发现获取超时了:
在这里插入图片描述
ping一下虚拟机,发现无法ping通。发现是电脑同时接入网线、连接了wifi,断开WiFi即可正常获取。测试下运行效果:
在这里插入图片描述
权限不够时,注意调整下文件的权限。学习使用嘛,我就直接777权限了。可以观察到板载LED按照1秒间隔闪烁了2次,和期望相符。打印的debug输出,是驱动部分完成的,后面自己写驱动可以修改或去除这些打印。

四、控制蜂鸣器

控制蜂鸣器的方式与点亮LED是完全相同的,唯一区别在于ioctl函数的传参。

ioctl(fd, LED_ON, atoi(argv[1]));
ioctl(fd, BUZZER_ON, NULL);

在LED中,ioctl的后面两个参数,分别是控制哪个灯、点亮还是熄灭。而buzzer中,实际只用到了第一个参数,表示响还是停止;第二个参数实际并没有用到,我这里直接传入了NULL(例程中传入了atoi(argv[2]))。
前面提到这与驱动程序的设计有关,做应用开发,只需要按照函数接口传参即可。

五、总结

本篇主要是通过点灯熟悉文件IO函数的使用,了解下设备节点概念。main函数传参时,注意需要转化类型。

Logo

更多推荐