3. LED的控制
3.1 LED驱动程序
实质就是一个linux字符设备驱动
$:' cd project
$:' mkdir drivers
$:' cd drivers
$:' mkdir leds
$:' cd leds
// ---> madir drivers/leds -p
$:' vi led_drv.c
$:' vi Makefile
$:' make
$:' mkdir ../../rootfs/home/drivers
$:' cp leds_drv.ko ../../rootfs/home/drivers/
$:' vi test.c
// 验证程序。使用arm-...-gcc编译。
编译test.c,测试驱动程序是否好用
3.2 编写LED的控制应用程序
有两种方式
3.2.1 简单的方式 - 槽函数方式1
当点击亮灯按钮时,完成该信号的槽函数
在槽函数中
fd = open("/dev/leds", ...)
ioctl(fd, CMD_LED_ON, &i); // i 是第几盏灯
close (fd);
修改图片
再次点击时灭灯
fd = open("/dev/leds", ...)
ioctl(fd, CMD_LED_OFF, &i);
close (fd);
修改图片
GUI界面程序一定部署到开发板才能有效果
3.2.2 复杂方式 - 槽函数方式2
希望GUI界面程序不管是运行在PC
或者运行在开发板,都能控制开发板的LED状态
'Client (GUI 开发板/PC)' 'Server (UDP 运行在开发板)'
点击按钮发送命令LED_ON 接收命令,根据命令open设备 ioctl亮灯
sendto (sd, cmd);
公共头文件:project/include/ehome.h
1)界面客户端程序 client
$:' mkdir gui_client
$:' cd gui_client
$:' qtcreator
建立工程 完成界面编程
先将mainwindow窗口的大小调整为 1024*600
添加按钮 - 转到槽
槽函数中给UDP服务器发送命令
---> 3.2.1
2)服务器程序 server
$:' cd project
$:' mkdir server
$:' cd server
$:' vi server.c
// udp 创建socket,接收客户端发送的命令,解析命令调用不同的硬件操作
recvfrom(cmd)
if(cmd == LED_ON)
open("/dev/leds",...)
ioctl(fd, LED_ON, 0)
$:' vi leds.c
// 进一步解析命令:操作哪盏灯,如何操作,调用对应灯的对应操作函数
$:' vi leds_hw.c
// hw 代表硬件 hardware,操作硬件
open
ioctl
close
$:' arm-cor.....gcc server.c -o server
$:' cp server rootfs/home/bin/
#:' insmod /home/drivers/leds_drv.ko
#:' source /home/etc/profile
#:' /home/bin/server &
#:' /home/bin/client
启动server
启动client
点击按钮实验是否亮灯
注意编程过程中的调试技巧
#define DEBUG
#ifdef DEBUG
/*##表示如果可变参数被忽略或为空,将使预处理器( preprocessor )去除掉它前面的那个逗号。*/
#define pr_debug(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define pr_debug(fmt, ...)
#endif
BUG的调试,顺着数据流分析该调用的函数是否调用到。
/* leds_drv.c 驱动源代码 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <mach/platform.h>
#include <linux/uaccess.h>
MODULE_LICENSE("GPL");
#define LED_ON 0x100001
#define LED_OFF 0x100002
struct led_desc
{
char *name;
int gpio;
};
struct led_desc leds[]=
{
{"led_bedroom", PAD_GPIO_C+12},
{"led_saloon", PAD_GPIO_C+7},
{"led_kitchen", PAD_GPIO_C+11},
{"led_restroom", PAD_GPIO_B+26},
};
long leds_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
//1.定义内核缓冲区
int kindex = 0;
int ret = 0;
int status = 0;
//2.拷贝用户缓冲区到内核
ret = copy_from_user(&kindex, (int *)arg, 4);
//3.解析命令,操作硬件
switch(cmd) {
case LED_ON:
status = 0;
break;
case LED_OFF:
status = 1;
break;
default:
return -EINVAL;
}
if(kindex>= 0 && kindex <4)
{
gpio_direction_output(leds[kindex].gpio, status);
}
return 0;
}
struct file_operations leds_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = leds_ioctl,
};
struct miscdevice leds_misc =
{
.minor = MISC_DYNAMIC_MINOR,//自动分配次设备号
.name = "leds", //设备文件名称
.fops = &leds_fops,
};
int __init leds_drv_init(void)
{
int i = 0;
for(; i<ARRAY_SIZE(leds); i++)
{
gpio_request(leds[i].gpio, leds[i].name);
}
misc_register(&leds_misc);
return 0;
}
void __exit leds_drv_exit(void)
{
int i = 0;
misc_deregister(&leds_misc);
for(; i<ARRAY_SIZE(leds); i++)
{
gpio_free(leds[i].gpio);
}
}
module_init(leds_drv_init);
module_exit(leds_drv_exit);