七、实现网页端控制LED灯

1、流程

在这里插入图片描述

2、LED灯驱动程序(基于设备树)

/*************************************************************************
    > File Name: led_dtb.c
    > Author: wrf
    > Mail: wrf6758@qq.com 
    > Created Time: 2022年09月13日 星期二 14时48分44秒
	> led灯设备驱动程序设备树版
 ************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>


#include "led_dev.h"

int major = 12;
int minor = 0;
int myled_num = 1;

struct myled_dev
{
    struct cdev mydev;
	unsigned int led2gpio;
	unsigned int led3gpio;
	unsigned int led4gpio;
	unsigned int led5gpio;
};

struct myled_dev *pleddev = NULL;

int led_open(struct inode *pnode,struct file *pfile)
{
    pfile->private_data = (void *)(container_of(pnode->i_cdev, struct myled_dev, mydev));

    return 0;
}

int led_close(struct inode *pnode,struct file *pfile)
{
    return 0;
}

void led_on(struct myled_dev *pleddev, int whitch_led)
{
    switch(whitch_led)
    {
        case 2:
            gpio_set_value(pleddev->led2gpio, 1);
            break;
        case 3:
            gpio_set_value(pleddev->led3gpio, 1);
            break;
        case 4:
            gpio_set_value(pleddev->led4gpio, 1);
            break;
        case 5:
            gpio_set_value(pleddev->led5gpio, 1);
            break;
    }
}

void led_off(struct myled_dev *pleddev, int whitch_led)
{
    switch(whitch_led)
    {
        case 2:
            gpio_set_value(pleddev->led2gpio, 0);
            break;
        case 3:
            gpio_set_value(pleddev->led3gpio, 0);
            break;
        case 4:
            gpio_set_value(pleddev->led4gpio, 0);
            break;
        case 5:
            gpio_set_value(pleddev->led5gpio, 0);
            break;
    }
}

long led_ioctl(struct file *pfile,unsigned int cmd,unsigned long arg)
{
    struct myled_dev *pleddev = (struct myled_dev *)pfile->private_data;

    /*led2-led5*/
    if(arg < 2 || arg >5)
    {
        return -1;
    }

    switch(cmd)
    {
        case MY_LED_ON:
            led_on(pleddev, arg);
            break;
        case MY_LED_OFF:
            led_off(pleddev, arg);
            break;
        default:
            return -1;
    }
    return 0;
}

struct file_operations myops = {
    .owner = THIS_MODULE,
    .open = led_open,
    .release = led_close,
    .unlocked_ioctl = led_ioctl,
};

/*向内核申请GPIO*/
void request_leds_gpio(struct myled_dev *pleddev, struct device_node *pnode)
{
    /**
    * include/of_gpio.h
    * of_get_named_gpio - 从设备树中提取gpio口
    * @np - 设备节点指针
    * @propname - 属性名
    * @index - gpio口引脚标号
    * 成功:得到GPIO口编号;失败:负数,绝对值是错误码
    */
    pleddev->led2gpio = of_get_named_gpio(pnode, "led2-gpio", 0);
    /*其实就是让内核检查一下该GPIO引脚是否被其它设备占用,如果没有占用则返回0并用label做一下标记,表示被本设备占用,否则返回负数*/
    gpio_request(pleddev->led2gpio, "led2");

    pleddev->led3gpio = of_get_named_gpio(pnode, "led3-gpio", 0);
    gpio_request(pleddev->led3gpio, "led3");

    pleddev->led4gpio = of_get_named_gpio(pnode, "led4-gpio", 0);
    gpio_request(pleddev->led4gpio, "led4");

    pleddev->led5gpio = of_get_named_gpio(pnode, "led5-gpio", 0);
    gpio_request(pleddev->led5gpio, "led5");
}

/*配置相应GPIO为输出模式*/
void set_led_gpio_output(struct myled_dev *pleddev)
{
    /*在GPIO口写上0的同时,把端口设置为输出模式*/
    gpio_direction_output(pleddev->led2gpio, 0);
    gpio_direction_output(pleddev->led3gpio, 0);
    gpio_direction_output(pleddev->led4gpio, 0);
    gpio_direction_output(pleddev->led5gpio, 0);
}

/*向内核归还对该GPIO引脚的使用权*/
void free_leds_gpio(struct myled_dev *pleddev)
{
    gpio_free(pleddev->led2gpio);
    gpio_free(pleddev->led3gpio);
    gpio_free(pleddev->led4gpio);
    gpio_free(pleddev->led5gpio);
}


int __init led_init(void)
{
    int ret = 0;
    dev_t devno = MKDEV(major, minor);
    struct device_node *pnode = NULL;           //对应设备树中的一个节点

    /*通过路径查找指定节点*/
    pnode = of_find_node_by_path("/fs4412-leds");
    if(NULL == pnode)
    {
        printk("fine node failed\n");
        return -1;
    }

    /*申请设备号*/
    ret = register_chrdev_region(devno,myled_num,"myled");
    if(ret)
    {
        ret = alloc_chrdev_region(&devno,minor,myled_num,"myled");
        if(ret)
        {
            printk("get devno failed\n");
            return -1;
        }
        //更新主设备号
        major = MAJOR(devno);//容易遗漏,注意
    }
    /*动态申请内存空间*/
    //GFP_KERNEL —— 正常分配内存;
    pleddev = (struct myled_dev*)kmalloc(sizeof(struct myled_dev),GFP_KERNEL);
    if(NULL == pleddev)
    {   
        //申请失败,记得释放设备号
        unregister_chrdev_region(devno,myled_num);
        printk("kmallc for struct myled_dev failed\n");
        return -1;
    }
    memset(pleddev, 0, sizeof(struct myled_dev));

    /*给struct cdev指定操作对像*/
    cdev_init(&pleddev->mydev, &myops);

    /*将struct cdev添加到内核对应的数据结构里*/
    pleddev->mydev.owner = THIS_MODULE;
    cdev_add(&pleddev->mydev, devno, myled_num);

    /*向内核申请GPIO*/
    request_leds_gpio(pleddev, pnode);
    /*将寄存器设置为输出,led初始为灭*/
    set_led_gpio_output(pleddev);

    return 0;
}

void __exit led_exit(void)
{
    dev_t devno = MKDEV(major, minor);

    /*归还节点给内核*/
    free_leds_gpio(pleddev);

    cdev_del(&pleddev->mydev);

    unregister_chrdev_region(devno, myled_num);

    kfree(pleddev);
    pleddev = NULL;
}


MODULE_LICENSE("GPL");
module_init(led_init);
module_exit(led_exit);

3、CGI程序

#include <stdio.h> 
#include "cgic.h" 
#include <string.h> 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/ioctl.h>

#define mytype 'g'

typedef struct led_desc{
	int led_num;    //2 3 4 5
	int led_state;  //0 or 1
}led_desc_t;

#define FS_LED_ON  _IO(mytype,1)
#define FS_LED_OFF _IO(mytype,0)

#define LED "/dev/led_test"


int main(int argc, char const *argv[])
{
	int i = 0,j = 3;
	int nread;
	int led_control,led_state;
	int led_fd,fifo_fd;
	led_desc_t led;
	char *data;

	led_fd = open(LED,O_RDWR);
	if(led_fd < 0){
		printf("open failed !\n");
	}
	printf("open device success! led_fd: %d\n",led_fd);

    printf("Content-type: text/html;charset=utf-8\n\n");
    printf("<html>\n");
    printf("<head><title>web 点灯</title></head>\n");
    printf("<body>\n");
    printf("<p>led is setted successful! you can watch the led's change</p>\n");
    //printf("<p><a herf=http://192.168.1.100/led.html>go back</a></p>\n");
	printf("<a href=\"/led_test.html\">go back led control page </a>");
	printf("</body>\n");

    data = getenv("QUERY_STRING");   //getenv()读取环境变量的当前值的函数 

    if(sscanf(data,"led_control=%d&led_state=%d",&led_control,&led_state)!=2)
    {   //利用sscnaf()函数的特点将环境变量分别提取出led_control和led_state这两个值
        printf("<p>please input right"); 
        printf("</p>");
    } 
    printf("<p>led_control = %d,led_state =  %d</p>", led_control, led_state);
    if(led_control < 2 || led_control > 5) { 
        printf("<p>Please input 2<=led_control<=5!"); 
        printf("</p>");
    } 
    if(led_state>1) {
        printf("<p>Please input 0<=led_state<=1!"); 
        printf("</p>"); 
    }

	led.led_num   = led_control;
	led.led_state = led_state;
	
	if(led.led_state == 0){
		//关灯
		ioctl(led_fd,FS_LED_OFF, led.led_num);
	}else if(led.led_state == 1){
        //开灯
		ioctl(led_fd,FS_LED_ON, led.led_num);
	}else if(led.led_state == 2){
        //流水灯
		while(j --){
			for(i = 2; i <= 5; i ++ ){
				led.led_num = i;
				led.led_state = 0;
				ioctl(led_fd,FS_LED_OFF, led.led_num);
				usleep(500000);
				led.led_state = 1;
				ioctl(led_fd,FS_LED_ON, led.led_num);
				usleep(500000);
			}
		}
	}

	close(led_fd);
    printf("</html>\n");

	return 0;
}

arm-linux-gcc -o led_test.cgi led_test.c

编译生成cgi文件

4、HTML的编写

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<title>web点灯实验</title>
	</head>
		<body style="background-color: powderblue;">

		<td height="500">
			<div align="center">
				<h1 align="center">基于Cortex-A9的web控制LED灯</h1>
		<!--新建一个表单,动作链接到开发板的/cgi-bin/cgi_led.cgi,采用的方法为GET-->	
		<form action="/cgi-bin/led_test.cgi" method="get">  
			<p align="center">Web端的led的控制测试</p>
			<p align="center">请输入需要控制的led:<input type="text" name="led_control"/></p>
			<p align="center">请输入LED控制命令  :<input type="text" name="led_state"/></p>
			<h2 align="center"> (0熄灭-1点亮-2流水)</h2>   
			<p align="center"><input type="submit" value="sure"/>        
							  <input type="reset" value="back"/>
			</p>
		</form>
				</div>
			</td>
		</body>
	</html>

5、运行查看情况

4.文件拿到开发板执行

  1. 拷贝ko文件到开发板
    cp led_test.ko /opt/4412/rootfs/drv/
  2. 拷贝cgi文件到开发板
    cp led_test.cgi /opt/4412/rootfs/boa/cgi-bin/
  3. 拷贝HTML文件到开发板
    cp led_test.html /opt/4412/rootfs/boa/www/
  4. 加载驱动模块
    insmod led_test.ko
    查看主设备号:cat /proc/devices/ | grep led_test
    创建设备:mknod /dev/led_test c 主设备号 0
  5. boa服务器运行
    ./boa
  6. 网页端运行查看现象
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值