浏览代码

点灯大师:红灯闪烁

xuxinyi 1 年之前
父节点
当前提交
930cda04a5
共有 5 个文件被更改,包括 143 次插入43 次删除
  1. 二进制
      开发笔记/img_17.png
  2. 5 1
      开发笔记/开发笔记.md
  3. 二进制
      开发笔记/点灯大师.mp4
  4. 26 23
      驱动文件/2024-11-6/led.c
  5. 112 19
      驱动文件/2024-11-6/ledByMySelf.c

二进制
开发笔记/img_17.png


+ 5 - 1
开发笔记/开发笔记.md

@@ -187,4 +187,8 @@
     4.执行
         ./led
     5.查看结果
-        ![img_16.png](img_16.png)
+        ![img_16.png](img_16.png)
+26.点灯大师
+    操作步骤参照25步
+    ![img_17.png](img_17.png)
+    MP4[点灯大师.mp4]

二进制
开发笔记/点灯大师.mp4


+ 26 - 23
驱动文件/2024-11-6/led.c

@@ -9,8 +9,8 @@
 int main()
 {
     int fd;
-    char write_buf[] = "Hello from user space!";
-    char read_buf[100];
+    char write_buf[2];
+    ssize_t written;
 
     // 打开设备文件
     fd = open(DEVICE_FILE, O_RDWR);
@@ -19,31 +19,34 @@ int main()
         return -1;
     }
 
-    // 向设备写入数据
-    ssize_t written = write(fd, write_buf, strlen(write_buf));
-    if (written < 0) {
-        perror("write");
-        close(fd);
-        return -1;
-    } else {
-        printf("Wrote %zd bytes to the device.\n", written);
-    }
+    // 在死循环中交替写入 0 和 1,控制 LED
+    int i = 0;
+    while (1) {
+        // 每次循环写入 1(开启 LED)或 0(关闭 LED)
+        if (i % 2 == 0) {
+            write_buf[0] = '1';  // LED 开
+        } else {
+            write_buf[0] = '0';  // LED 关
+        }
 
-    // 从设备读取数据
-    ssize_t read_bytes = read(fd, read_buf, sizeof(read_buf));
-    if (read_bytes < 0) {
-        perror("read");
-        close(fd);
-        return -1;
-    } else if (read_bytes == 0) {
-        printf("No data read from the device.\n");
-    } else {
-        read_buf[read_bytes] = '\0';
-        printf("Read from the device: %s\n", read_buf);
+        // 向设备写入数据
+        written = write(fd, write_buf, 1);
+        if (written < 0) {
+            perror("write");
+            close(fd);
+            return -1;
+        } else {
+            printf("Wrote %c to the device\n", write_buf[0]);
+        }
+
+        // 延迟 1 秒钟
+        sleep(1);
+
+        i++;
     }
 
     // 关闭设备文件
     close(fd);
 
     return 0;
-}
+}

+ 112 - 19
驱动文件/2024-11-6/ledByMySelf.c

@@ -3,45 +3,118 @@
 #include <linux/of.h>
 #include <linux/fs.h>
 #include <linux/cdev.h>
-#include <linux/uaccess.h>  // for copy_to_user() and copy_from_user()
-const char *TAG = "MYNEWNODE";\
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+const char *TAG = "MYNEWNODE";
 
 static int major_number = 0;  // 默认自动分配主设备号
 static struct cdev my_cdev;
 static struct class *my_class;
-
+static int gpio_pin = -1;  // GPIO 引脚号
 
 // 打开字符设备
 static int gpio_led_open(struct inode *inode, struct file *file)
 {
+    int ret;
+
     printk("%s:open!\n", TAG);
+
+    // 如果 GPIO 引脚没有初始化,先进行初始化
+    if (gpio_pin < 0) {
+        printk("%s:GPIO not initialized correctly.\n", TAG);
+        return -EINVAL;
+    }
+
+    // 设置 GPIO 为输出模式,初始化时设置为低电平(关闭 LED)
+    ret = gpio_direction_output(gpio_pin, 0);  // 默认设置为低电平(LED 关闭)
+    if (ret) {
+        printk("%s:Failed to set GPIO direction\n", TAG);
+        return ret;
+    }
+
+    // 可以根据需要设置 GPIO 的初始电平,比如点亮 LED
+    gpio_set_value(gpio_pin, 1);  // 设置为高电平,点亮 LED(假设低电平为关闭)
+
     return 0;
 }
 
-// 关闭字符设备
+// 释放字符设备
 static int gpio_led_release(struct inode *inode, struct file *file)
 {
     printk("%s:release!\n", TAG);
+
+    // 在设备释放时设置 GPIO 为低电平(关闭 LED)
+    gpio_set_value(gpio_pin, 0);  // 设置为低电平,关闭 LED
+
     return 0;
 }
 
 // 读取数据(此示例没有实际硬件操作)
+// 读取数据(控制 LED)
 static ssize_t gpio_led_read(struct file *file, char __user *buf, size_t len, loff_t *offset)
 {
+    int gpio_value = 0;
+    char read_buf[2];  // 用来存储读取的数据
+
     printk("%s:read!\n", TAG);
-    // 这里可以填充实际的读取逻辑,如果需要从硬件读取数据
-    return 0;
+
+    // 模拟 LED 状态控制,循环写入 '0' 和 '1'
+    if (*offset % 2 == 0) {
+        gpio_value = 0;  // 关闭 LED
+        read_buf[0] = '0';
+    } else {
+        gpio_value = 1;  // 点亮 LED
+        read_buf[0] = '1';
+    }
+
+    // 设置 GPIO 引脚电平,控制 LED 开关
+    gpio_set_value(gpio_pin, gpio_value);
+
+    // 将 LED 状态写入到用户空间
+    if (copy_to_user(buf, read_buf, 1)) {
+        return -EFAULT;
+    }
+
+    // 更新偏移量,每次切换一次
+    *offset += 1;
+
+    return 1;  // 返回读取的字节数
 }
 
-// 写入数据(此示例没有实际硬件操作)
+
+// 写入数据(控制 GPIO)
 static ssize_t gpio_led_write(struct file *file, const char __user *buf, size_t len, loff_t *offset)
 {
+    char user_buf[10];
+    int gpio_value = 0;
+
     printk("%s:write!\n", TAG);
-    // 这里可以填充实际的写入逻辑,如果需要控制硬件
-    return len;  // 返回实际写入的字节数
+
+    if (len > sizeof(user_buf) - 1) {
+        len = sizeof(user_buf) - 1;
+    }
+
+    if (copy_from_user(user_buf, buf, len)) {
+        return -EFAULT;
+    }
+
+    user_buf[len] = '\0';
+
+    if (user_buf[0] == '1') {
+        gpio_value = 1;
+    } else if (user_buf[0] == '0') {
+        gpio_value = 0;
+    } else {
+        return -EINVAL;
+    }
+
+    gpio_set_value(gpio_pin, gpio_value);
+
+    return len;
 }
 
-// 字符设备操作结构体
 static const struct file_operations gpio_led_fops = {
     .owner = THIS_MODULE,
     .open = gpio_led_open,
@@ -50,18 +123,34 @@ static const struct file_operations gpio_led_fops = {
     .write = gpio_led_write,
 };
 
+// 设备probe函数
 static int gpio_led_probe(struct platform_device *pdev)
-{   int ret;
-    // 这里可以添加初始化代码
-    printk("%s:probe!\n",TAG);
+{
+    int ret;
+
+    printk("%s:probe!\n", TAG);
+
+    // 获取设备树中的 GPIO 引脚
+    gpio_pin = of_get_named_gpio(pdev->dev.of_node, "gpios", 0);
+    if (gpio_pin < 0) {
+        printk("%s:Failed to get GPIO from device tree!\n", TAG);
+        return gpio_pin;
+    }
+
+    // 申请 GPIO 引脚
+    ret = gpio_request(gpio_pin, "gpio_led");
+    if (ret) {
+        printk("%s:Failed to request GPIO %d\n", TAG, gpio_pin);
+        return ret;
+    }
 
-    ret = alloc_chrdev_region(&major_number,0,1,"gpio_led");
-    if(ret < 0){
+    // 初始化设备文件
+    ret = alloc_chrdev_region(&major_number, 0, 1, "gpio_led");
+    if (ret < 0) {
         printk("%s:alloc_chrdev_region failed!\n", TAG);
         return ret;
     }
 
-    // 注册字符设备
     cdev_init(&my_cdev, &gpio_led_fops);
     my_cdev.owner = THIS_MODULE;
     ret = cdev_add(&my_cdev, major_number, 1);
@@ -89,7 +178,7 @@ static int gpio_led_probe(struct platform_device *pdev)
         return -ENOMEM;
     }
 
-    return 0; // 返回 0 表示成功
+    return 0;
 }
 
 // 设备remove函数
@@ -97,6 +186,9 @@ static int gpio_led_remove(struct platform_device *pdev)
 {
     printk("%s:remove!\n", TAG);
 
+    // 释放 GPIO 引脚
+    gpio_free(gpio_pin);
+
     // 注销字符设备
     device_destroy(my_class, major_number);
     class_destroy(my_class);
@@ -106,6 +198,7 @@ static int gpio_led_remove(struct platform_device *pdev)
     return 0;
 }
 
+// 关机处理函数
 static void gpio_led_shutdown(struct platform_device *pdev)
 {
     printk("%s:shutdown!\n", TAG);
@@ -123,7 +216,7 @@ static struct platform_driver gpio_led_driver = {
     .remove     = gpio_led_remove,
     .shutdown   = gpio_led_shutdown,
     .driver     = {
-        .name   = "led-user",
+        .name   = "gpio_led_driver",
         .of_match_table = of_gpio_leds_match,
     },
 };
@@ -132,4 +225,4 @@ module_platform_driver(gpio_led_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Your Name");
-MODULE_DESCRIPTION("Simple GPIO LEDs driver");
+MODULE_DESCRIPTION("GPIO control driver with character device");