嵌入式Linux LED GPIO

前言

这是前3篇:

Linux 中的三大类驱动:字符设备驱动、块设备驱动和网络设备驱动. LED, GPIO属于字符设备, 驱动在买的板子上一般厂家都已改好, 当然如果扩展或者自己画新板子的话可以改设备树. 本篇介绍下GPIO, 以LED, GPIO子系统为例, 采用板子出厂配置的系统, 暂不涉及设备树的改动.

LED

终端

# 查看LED
root@mys6ull14x14:~# ls /sys/class/leds
cpu     mmc0::  user
# 米尔的MYS-6ULX板子上有3颗LED, 分别命名为cpu, mmc0::, user
# user是闲置的LED, 用这个

# 查看LED设备属性
root@mys6ull14x14:~# ls /sys/class/leds/user
brightness      max_brightness  subsystem       uevent
device          power           trigger
# 这里主要用brightness, 取值范围0~brightness
# 如果不支持多级亮度, brightness取0灯灭, 非0灯亮(如1, 255)

# 点亮LED, 对应米尔MYS-6ULX板子上的D12
root@mys6ull14x14:~# echo 1 > /sys/class/leds/user/brightness

# 熄灭LED
root@mys6ull14x14:~# echo 0 > /sys/class/leds/user/brightness

脚本

此处可有脚本gpio_led.sh:

#!/bin/bash
echo "GPIO LED Test"

LED=/sys/class/leds/user/brightness

while (true)
do
    echo 1 > $LED
    sleep 1
    echo 0 > $LED
    sleep 1
done

加权限sudo chmod 777 gpio_led.sh, 执行./gpio_led.sh, 可以看到板子上LED间隔1s闪烁.

C语言

直接用系统调用的方式, 新建文件main.c:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>

#define USER_LED_DEV_PATH "/sys/class/leds/user/brightness"

int main()
{
    int led_fd;
    char cmd[128] = {0};

    printf("user led demo\r\n");

    led_fd = open(USER_LED_DEV_PATH, O_WRONLY);
    if (led_fd < 0)
    {
        printf("Fail to open %s device\n", USER_LED_DEV_PATH);
        exit(1);
    }

    while (1)
    {
        sprintf(cmd, "echo 1 > %s", USER_LED_DEV_PATH);
        system(cmd);
        sleep(1);
        sprintf(cmd, "echo 0 > %s", USER_LED_DEV_PATH);
        system(cmd);
        usleep(1000 * 300);
    }

    close(led_fd);
    return 0;
}

交叉编译arm-linux-gnueabihf-gcc -o led1 led1.c, 执行./led1, 可以看到板子user LED亮1s灭300ms循环…

while中也可以改成write的方式:

    while (1)
    {
        write(led_fd, "255", 3); //3: 3个字节
        sleep(1);
        write(led_fd, "0", 1);
        usleep(1000 * 300);
    }

交叉编译执行, 效果是一样的.

GPIO子系统

与LED子系统类似,Linux提供了GPIO子系统驱动框架,使用该驱动框架可以把CPU的GPIO引脚导出到用户空间,用户通过访问/sys文件系统进行控制,GPIO子系统支持把引脚用于基本的输入输出功能,其中输入功能还支持中断检测。

扫描二维码关注公众号,回复: 10048205 查看本文章

米尔的MYS-6ULX板子上留出了两个gpio, gpio5和gpio9:
在这里插入图片描述
这里以37引脚的GPIO_9为例, 接上万用表:
在这里插入图片描述

root@mys6ull14x14:~# ls /sys/class/gpio
export       gpiochip0    gpiochip32   gpiochip96
gpio131      gpiochip128  gpiochip64   unexport

# 向export文件写入GPIO编号可以向内核申请将该编号的GPIO导出到用户空间
# 注意: 板子复位后设置无效
# 反操作是unexport
root@mys6ull14x14:~# echo 9 > /sys/class/gpio/export
# 查看导出的gpio, 发现多了gpio9
root@mys6ull14x14:~# ls /sys/class/gpio
export       gpio9        gpiochip128  gpiochip64   unexport
gpio131      gpiochip0    gpiochip32   gpiochip96

# 查看gpio9属性
root@mys6ull14x14:~# ls /sys/class/gpio/gpio9
active_low  direction   power       uevent
device      edge        subsystem   value
# 使用GPIO子系统的设备则可以在用户空间灵活配置作为输入、输出或中断模式
# 查看gpio9的方向, 下面显示是输入
root@mys6ull14x14:~# cat /sys/class/gpio/gpio9/direction
in

# 设置gpio9为输出
root@mys6ull14x14:~# echo out > /sys/class/gpio/gpio9/direction

# gpio9输出高电平, 可用万用表检测米尔MYS-6ULX板子J2的37引脚, 应为3.3V
root@mys6ull14x14:~# echo 1 > /sys/class/gpio/gpio9/value

# gpio9输出低电平
root@mys6ull14x14:~# echo 0 > /sys/class/gpio/gpio9/value

# 取消gpio9的导出
root@mys6ull14x14:~# echo 9 > /sys/class/gpio/unexport

再回头看下米尔MYS-6ULX板子GPIO_9的定义, 实际引脚是GPIO1_IO09:
在这里插入图片描述
引用下 控制蜂鸣器(GPIO子系统)中的介绍:

i.MX6ULL芯片GPIO引脚名格式通常为GPIOn_IOx,如GPIO1_IO09,其 中n是端口号,x为该组端口的引脚号,开发板采用的芯片有1-5组端口,每组端口包含的引脚从0-31不等。

export文件使用的编号index与GPIO引脚名的转换关系:index = GPIOn_IOx = (n-1)*32 + x, 所以GPIO1_IO09对应的index是(1-1)*32+9 = 9, 直接在原理图中命名为GPIO_9.

用C语言编写文件gpio.c:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>

#define GPIO_INDEX "9"

int main()
{
    int fd;

    //echo 9 > /sys/class/gpio/export
    fd = open("/sys/class/gpio/export", O_WRONLY);
    if (fd < 0)
    {
        return 1;
    }
    write(fd, GPIO_INDEX, strlen(GPIO_INDEX));
    close(fd);

    //echo out > /sys/class/gpio/gpio9/direction
    fd = open("/sys/class/gpio/gpio" GPIO_INDEX "/direction", O_WRONLY);
    if (fd < 0)
    {
        return 2;
    }
    write(fd, "out", strlen("out"));
    close(fd);

    fd = open("/sys/class/gpio/gpio" GPIO_INDEX "/value", O_WRONLY);
    if (fd < 0)
    {
        return 3;
    }

    while (1)
    {
        write(fd, "1", 1);
        sleep(2);
        write(fd, "0", 1);
        sleep(2);
    }

    close(fd);
    return 0;
}

交叉编译: arm-linux-gnueabihf-gcc -o gpio1 gpio.c, 嵌入式板子上执行./gpio1, 可以看到万用表3.3V和0V之间以2s间隔切换.

微信公众号

欢迎扫描关注我的微信公众号, 及时获取最新文章:
在这里插入图片描述

发布了203 篇原创文章 · 获赞 105 · 访问量 38万+

猜你喜欢

转载自blog.csdn.net/weifengdq/article/details/104654079