Linux进阶-控制硬件设备

目录

驱动程序

应用程序

控制硬件设备步骤

找出硬件设备所对应的设备节点文件

找出驱动程序规定的设备文件使用方式

I.MX 6ULL开发板

LED控制

蜂鸣器控制

按键输入检测

树莓派GPIO

树莓派点亮LED的多种方式

UART


驱动程序

为硬件设备创建相应的设备节点文件。创建设备文件时,规定好设备文件的使用方式。

应用程序

根据驱动程序规定的设备文件使用方式去控制硬件。

控制硬件设备步骤

找出硬件设备所对应的设备节点文件

/dev目录下:对驱动程序熟悉的工程师可以使用,一个设备节点文件控制硬件全部特性。

/sys目录下:业余工程师使用,一个设备节点文件只控制硬件的一个特性。严格来说,它下面的文件是Linux内核导出到用户空间的硬件操作接口。

找出驱动程序规定的设备文件使用方式

Linux系统引脚编号规则(针对i.MX6ull):(组号-1)*32+组内引脚编码。

例如GPIO1_19,组号为1,组内引脚编码为19。所有GPIO1_19再Linux内核的引脚编号为19。

/sys/class/gpio/export:导出GPIO子系统硬件操作接口。 

/sys/class/gpio/gpio19/direction:控制芯片引脚的输入输出模式。in代表输入,out代表输出。

/sys/class/gpio/gpio19/value:控制芯片引脚的输出电平。1代表高电平,0代表低电平。

sudo echo 19 > /sys/class/gpio/export
sudo sh -c 'sudo echo out > /sys/class/gpio/gpio19/direction'
sudo sh -c 'sudo echo 1 > /sys/class/gpio/gpio19/value'

I.MX 6ULL开发板

LED控制

led.c

#include 
#include 
#include 
#include 
#include 
#include 

//ARM 开发板LED设备的路径
#define RLED_DEV_PATH "/sys/class/leds/red/brightness"
#define GLED_DEV_PATH "/sys/class/leds/green/brightness"
#define BLED_DEV_PATH "/sys/class/leds/blue/brightness"

int main(int argc, char* argv[])
{
        int red_fd, green_fd, blue_fd;
        int res = 0;

        printf("This is the led demo\n");

        //获取红灯的设备文件描述符
        red_fd = open(RLED_DEV_PATH, O_WRONLY);
        if(r_fd < 0)
        {
                printf("Fail to Open %s device\n", RLED_DEV_PATH);
                exit(1);
        }

        //获取绿灯的设备文件描述符
        green_fd = open(GLED_DEV_PATH, O_WRONLY);
        if(r_fd < 0)
        {
                printf("Fail to Open %s device\n", GLED_DEV_PATH);
                exit(1);
        }

        //获取蓝灯的设备文件描述符
        blue_fd = open(BLED_DEV_PATH, O_WRONLY);
        if(r_fd < 0)
        {
                printf("Fail to Open %s device\n", BLED_DEV_PATH);
                exit(1);
        }

        while(1)
        {
                write(red_fd, "255", 3);
                sleep(1);
                write(red_fd, "0", 1);

                write(green_fd, "255", 3);
                sleep(1);
                write(green_fd, "0", 1);

                write(blue_fd, "255", 3);
                sleep(1);
                write(blue_fd, "0", 1);
        }
}

蜂鸣器控制

beep.h

#ifndef _BSP_BEEP_H
#define _BSP_BEEP_H

//蜂鸣器的GPIO引脚号
//i.mx 6ull 计算方式:GPIOn_IOx = (n-1)*32 + x
//如GPIO1_IO19 = (1-1)*32 + 19 = 19
#define BEEP_GPIO_INDEX "19"

/**
 * @brief 初始化蜂鸣器GPIO
 * @return
 *      @arg 0:正常
 *      @arg 1:export文件打开错误
 *      @arg 2:direction文件打开错误
 **/
extern int beep_init(void);

/**
 * @brief 关闭蜂鸣器GPIO的export输出
 * @return
 *      @arg  0:正常
 *      @arg !0:value文件打开错误
 **/
extern int beep_deinit(void);

/**
 * @brief 蜂鸣器响
 * @return
 *      @arg  0:正常
 *      @arg !0:value文件打开错误
 **/
extern int beep_on(void);

/**
 * @brief 关闭蜂鸣器GPIO的export输出
 * @return
 *      @arg  0:正常
 *      @arg !0:unexport文件打开错误
 **/
extern int beep_off(void);

#endif

beep.c

#include 
#include 
#include 
#include 
#include 
#include "../include/beep.h"

int beep_init(void)
{
        int fd;
        char gpio_path_direction[40] = {0};

        /*******************索引配置********************/
        fd = open("/sys/class/gpio/export", O_WRONLY);
        if(fd < 0)
                return 1;

        write(fd, BEEP_GPIO_INDEX, strlen(BEEP_GPIO_INDEX));
        close(fd);
        /*******************索引配置********************/

        /*******************方向配置********************/
        sprintf(gpio_path_direction, "/sys/class/gpio/gpio%d/direction", BEEP_GPIO_INDEX);
        fd = open(gpio_path_direction, O_WRONLY);
        if(fd < 0)
                return 2;

        write(fd, "out", strlen("out"));
        close(fd);
        /*******************方向配置********************/

        return 0;
}

int beep_deinit(void)
{
        int fd;

        fd = open("/sys/class/gpio/unexport", O_WRONLY);
        if(fd < 0)
                return 1;

        write(fd, BEEP_GPIO_INDEX, strlen(BEEP_GPIO_INDEX));
        close(fd);

        return 0;
}

int beep_on(void)
{
        int fd;
        char gpio_value[40] = {0};

        sprintf(gpio_value, "/sys/class/gpio/gpio%d/value", BEEP_GPIO_INDEX);
        fd = open(gpio_value, O_WRONLY);
        if(fd < 0)
                return 1;

        write(fd, "1", 1);
        close(fd);
}

int beep_off(void)
{
        int fd;
        char gpio_value[40] = {0};

        sprintf(gpio_value, "/sys/class/gpio/gpio%d/value", BEEP_GPIO_INDEX);
        fd = open(gpio_value, O_WRONLY);
        if(fd < 0)
                return 1;

        write(fd, "0", 1);
        close(fd);

        rerurn 0;
}

main.c

#include 
#include 
#include 
#include 
#include 
#include "../include/beep.h"

int main(int argc, char* argv[])
{
        int res = 0;
        char buf[10];

        printf("This is the beep demo\n");

        res = beep_init();
        if(res)
        {
                printf("beep init error, code = %d\n", res);
                return 0;
        }

        while(1)
        {
                printf("please input the value: 0--off 1--on q--exit\n");
                scanf("%10s", buf);

                switch(buf[0])
                {
                        case '0':
                                beep_off();
                                break;
                        case '1':
                                beep_on();
                                break;
                        case 'q':
                                beep_deinit();
                                printf("Exit\n");
                                return 0;
                        default:
                                break;
                }
        }
}

按键输入检测

key按键的设备文件:/dev/input/by-path/platform-gpio-keys-event

struct input_event

{

        struct timeval time;        //记录输入时间的时间戳

        __u16 type;                   //记录输入事件的类型,比如按键输入、坐标输入、特殊类型(EV_SYN,同步事件,提醒我们及时处理已经发生的完成输入事件)

        __u16 code;                  //记录输入类型的具体事件代号,比如键盘发生按键输入类型事件时,记录键盘哪个值被按下

        __s32 value;                 //记录事件的具体值,比如按键输入类型事件里,value--1表示按键被按下,value--0表示按键被弹起

};

input子系统:按键、键盘、鼠标、触摸屏等。

main.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//开发板的KEY按键,请根据实际情况修改
const char default_path[] = "/dev/input/by-path/platform-gpio-keys-event";

int main(int argc, char* argv[])
{
        int fd;
        struct input_event event;
        char *path;

        printf("This is a input device demo\n");

        //若无输入参数则使用默认事件设备
        if(argc > 1 )
                path = argv[1];
        else
                path = (char *)default_path;

        fd = open(path, O_RDONLY);
        if(fd < 0)
        {
                printf("Fail to open device:%s\n", path);
                exit(1);
        }

        printf("Test device:%s\n", input);

        while(1)
        {
                if( read(fd, &event, sizeof(event)) == sizeof(event))
                {
                        //EV_SYN是事件分隔标志,不打印
                        if(event.type != EV_SYN)
                        {
                                printf("Event:time %ld.%ld,type %d,code %d,value %d\n",
                                                event.time.tv_sec, event.time.tv_usec,
                                                event.type,
                                                event.code,
                                                event.value);
                        }
                }
        }

        close(fd);
        return 0;
}

树莓派

树莓派的GPIO引脚为40个,树莓派的引脚共有三种编码:板载编码、BCM编码、Wiring编码。

板载编码:按照树莓派主板上引脚排针编号顺序排序1~40号引脚。

BCM编码:python语言常用编码。

Wiring编码:c语言常用编码。

终端查看引脚编码:pinout-查看板载编码。gpio readall-查看全部编码。

//支持gpio readall
cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb
gpio -g mode 4 out //设置管脚为输出模式,-g表示是以BCM编码为编码方式。默认为wiringPi编码方式
gpio -g read 4     //读取管脚当前状态
gpio -g write 4 1  //设置管脚为高电平
gpio -g write 4 0  //设置管脚为低电平

树莓派点亮LED的多种方式

方式一是直接通过终端命令进行控制,从内核空间找到引脚直接控制GPIO引脚。

//选定GPIO目录
cd /sys/class/gpio
ls
echo BCM引脚编码 > export //GPIO操作接口从内核空间暴露到用户空间,执行后该目录会增加一个引脚文件
ls                       //加入多了gpio26
//使用GPIO开始控制
cd gpio26
echo out > diretion      
echo 1 > value
echo 0 > value
//注销GPIO引脚
cd ..
echo 26 > unexport       //注销GPIO26接口

方式二是使用Python来控制LED灯,使用RPi.GPIO库。新建文件vim led.py。

import RPi.GPIO as GPIO
from time import sleep

GPIO.setmode(GPIO.BCM)            //采用BCM编号方式
GPIO.setup(26,GPIO.OUT)           //指定使用26号端口
for i in range(1,10):
    GPIO.output(26,GPIO.HIGH)
    sleep(1)
GPIO.cleanup()

python3 led.py执行程序。

方式三是使用C来控制LED灯,使用wiringPi.h库。新建文件vim led.c。

#include 
#define Pin 25
int main()
{
    if(wiringPiSetup()<0)
            return 1;
    pinMode(Pin,OUTPUT);
    for(int i=0;i<10;i++)
    {
        digitalWrite(Pin,1);
        delay(200);
        digitalWrite(Pin,0);
        delay(200);
    }
    return 0;
}

gcc -o led led.c -lwiringPi

sudo ./led

UART

硬件串口:/dev/ttyAMA0。

mini串口:/dev/ttyS0。

主UART:可以通过引脚实现通讯。/dev/serial0。

辅助UART:不能使用GPIO引脚通讯,默认被分配给蓝牙端。/dev/serial1。

默认情况下,mini串口是禁用的,无论将它指定为主UART还是辅助UART。在树莓派上,TxD和RxD是作为主串口的收发端。

串口通讯步骤

第一步是准备待调试的硬件串口。将硬件串口设置为主串口。因为主串口可以使用引脚通讯。

输入ls /dev -al查看串口打开情况。只有serial1 -> ttyAMA0 ,没找到serial0。

然后打开mini UART。命令行可输入sudo raspi-config进入树莓派配置,Interfacing Options是接口选项菜单,可启用/禁用:Camera、SSH、VNC、SPI、I2C、Serial、1-Write和远程访问GPIO。我们Enable Serial Port,Disable Serial Console。完成更改后选中Finish按钮,系统会询问是否重新启动,选择重新启动。

输入ls /dev -al查看串口打开情况。有serial1 -> ttyAMA0 ,serial0 -> ttyS0。

然后将硬件串口设置为主串口。命令行输入sudo vim /boot/config.txt打开文件,在末行添加:

dtoverlay=pi3-miniuart-bt

force_turbo=1

reboot重启生效。输入ls /dev -al查看串口打开情况。有serial0 -> ttyAMA0 ,serial1 -> ttyS0。

第二步是树莓派安装minicom串口助手。

输入sudo apt-get install minicom。

第三步是PC端安装串口调试工具。使用USB转TTL工具连接电脑和树莓派,开始通讯。

第四步是输入minicom -D /dev/ttyAMA0 -b 9600

你可能感兴趣的:(#,linux基础之路,linux)