Linux系统编程二:字符设备控制之点亮LED灯、控制蜂鸣器
字符
一、概述
延时和时间一章,初步体验了下系统编程。不过既然是想做嵌入式开发,还是脱离不了硬件,现在就完成一次点灯。
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
传入的参数是字符格式,需要转化成整型再传递给sleep
和ioctl
函数。函数原型为:
#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函数传参时,注意需要转化类型。
更多推荐
所有评论(0)