嵌入式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子系統支持把引腳用於基本的輸入輸出功能,其中輸入功能還支持中斷檢測。

米爾的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間隔切換.

微信公衆號

歡迎掃描關注我的微信公衆號, 及時獲取最新文章:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章