HonestQiao 发表于 2022-6-11 21:39

【国产RISC-V Linux板 昉·星光VisionFive试用报告】GPIO开发基础:从原理到实战

本帖最后由 HonestQiao 于 2022-6-11 22:01 编辑

<p>昉&middot;星光VisionFive开发板上,提供了40Pin IO口,可以供我们在实际开发中使用。</p>

<p></p>

<p>这些IO口的具体功能定义,可以通过官方的资料了解:</p>

<p></p>

<p>在Linux系统中,GPIO驱动启用后,对应的挂载点在/sys/class/gpio</p>

<p>这里需要说明一下,在Linux系统上,对于常规的文件,用文件路径来访问文件,这个很好理解。</p>

<p>同样的,对于内外设备,Linux系统上,也把这些各种设备,当成特殊形式的文件来访问。</p>

<p>例如,要查看cpu的信息,那么cat&nbsp;/proc/cpuinfo即可。</p>

<p>而GPIO设备的话,其挂载点就是/sys/class/gpio。</p>

<p>&nbsp;</p>

<p>通过官方40Pin的详细文档,我们可以了解每个引脚具体的挂载点:</p>

<p></p>

<p>从上图中,我们可以看到,GPIO0引脚,其对应的sys为448,那么,在系统中,其对应的挂载点,就是&nbsp;/sys/class/gpio/gpio448</p>

<p>依次类推,我们可以得到,GPIO2引脚,其对应的sys为450,那么其挂载点,就是/sys/class/gpio/gpio450</p>

<p>&nbsp;</p>

<p>但是在Linux系统中,具体GPIO的引脚,可能不会开机自动挂载,需要我们先激活,才能使用。</p>

<p>要激活具体的GPIO,也需要使用到一个特殊文件,那就是&nbsp;/sys/class/gpio/export</p>

<p>如果要激活GPIO1,也就是/sys/class/gpio/gpio448,我们只需要执行下面的命令,即可激活:</p>

<pre>
<code class="language-bash">echo 448 &gt; /sys/class/gpio/export</code></pre>

<p>该命令相当于告诉&nbsp;/sys/class/gpio/export,请帮我激活gpio448</p>

<p>执行完该命令后,ls -l /sys/class/gpio,就可以看到gpio448存在了。</p>

<p><strong>提醒:上述命令,需要在root权限下执行,否则执行时会提示没有权限。</strong></p>

<p>&nbsp;</p>

<p>激活GPIO0引脚后,我们还需要设置该引脚的功能,是输入,还是输出,那么使用下面的命令,操作/sys/class/gpio/gpio448/direction这个特殊文件即可:</p>

<p>如果是输出,也就是要输出高低电平,例如点亮LED,就使用:</p>

<pre>
<code class="language-bash">echo out &gt; /sys/class/gpio/gpio448/direction</code></pre>

<p>上面的命令,就相当于告诉&nbsp;/sys/class/gpio/gpio448/direction ,我要把你gpio448设置为out,也就是输出了。</p>

<p>&nbsp;</p>

<p>如果是输入,例如接按键,获取按键状态,就使用:</p>

<pre>
<code class="language-bash">echo in &gt; /sys/class/gpio/gpio448/direction</code></pre>

<p>上面的命令,就相当于告诉&nbsp;/sys/class/gpio/gpio448/direction ,我要把你gpio448设置为in,也就是输入了。</p>

<p>&nbsp;</p>

<p>设置好了GPIO0对应的功能后,我们就能具体使用了。</p>

<p>这个时侯,我们又要使用到&nbsp;/sys/class/gpio/gpio448/value 这个特殊文件了。</p>

<p>例如,如果设置好输出,已经在GPIO0上接好了LED,现在要点亮LED了,就执行:</p>

<pre>
<code class="language-bash">echo 1 &gt; /sys/class/gpio/gpio448/value</code></pre>

<p>这样就表示输出高电平</p>

<p>&nbsp;</p>

<p>如果要熄灭对应的LED,就执行:</p>

<pre>
<code class="language-bash">echo 0 &gt; /sys/class/gpio/gpio448/value</code></pre>

<p>这样就表示输出低电平了</p>

<p>&nbsp;</p>

<p>如果设置好输入,在GPIO0上接好了普通按键,现在要获取按键输入状态,就执行:</p>

<pre>
<code class="language-bash">cat /sys/class/gpio/gpio448/value</code></pre>

<p>那么,显示1,表示按键按下;显示0,则表示按键松开。</p>

<p>&nbsp;</p>

<p>在上面的讲解中,我们一共用到了下面的文件:</p>

<ul>
        <li>/sys/class/gpio/export:通知激活GPIO引脚对应的sys挂载点</li>
        <li>/sys/class/gpio/gpio448/direction:通知该GPIO是输入in还是输出out</li>
        <li>/sys/class/gpio/gpio448/value:输出或者输入高低电平</li>
</ul>

<p>我们对这几个特殊文件的操作,也就是使用了基础的echo、cat指令,这样的指令,对任何一个普通文件,也可以操作。</p>

<p>所以本质上,对Linux而言,普通文件是文件,而这些GPIO挂载点也是文件,只不过,具体的功能有所不同罢了。</p>

<p>&nbsp;</p>

<p>那么,如果你还懂一点bash脚本,会循环的,我命而已通过下面的方式,来闪烁GPIO0上连接的LED,具体指令如下:</p>

<pre>
<code class="language-bash"># 激活GPIO0 - 448
echo 448 &gt; /sys/class/gpio/export

# 设置GPIO0 - 448 为输出
echo out &gt; /sys/class/gpio/gpio448/direction

# 循环10次:点亮LED,延时1秒,在关闭LED,再延时1秒
for i in 1 2 3 4 5 6 7 8 9 10
do
echo 1 /sys/class/gpio/gpio448/value
sleep 1
echo 0 /sys/class/gpio/gpio448/value
sleep 1
done</code></pre>

<p>如果已经连接好LED到GPIO0,那么执行后,就能看到实际效果了。</p>

<p><strong>小作业:参考上面的讲解,在控制一个LED的基础上,控制3个LED,类似下面的效果:</strong></p>

<p>cc8f751e8b111805656f1bb22ca04e19</p>

<p>&nbsp;</p>

<p>在上面的讲解中,我们在bash环境下,用echo来写入数据到对应的GPIO对应的文件中,从而操控LED引脚。</p>

<p>那么,到了C语言中,我们要如何操作呢?</p>

<p>实际上,也非常简单,你就把他们当作普通的文件,打开,然后写入或者读取内容就好了。</p>

<p>以下为一段通过GPIO0来闪烁LED的代码,基本功能和上面演示的bash脚本闪烁LED类似:</p>

<pre>
<code class="language-cpp">#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;   //define O_WRONLY and O_RDONLY

//芯片复位引脚: P1_16
#define SYSFS_GPIO_EXPORT         "/sys/class/gpio/export"
#define SYSFS_GPIO_RST_PIN_VAL      "448"   
#define SYSFS_GPIO_RST_DIR          "/sys/class/gpio/gpio448/direction"
#define SYSFS_GPIO_RST_DIR_VAL      "OUT"
#define SYSFS_GPIO_RST_VAL          "/sys/class/gpio/gpio448/value"
#define SYSFS_GPIO_RST_VAL_H      "1"
#define SYSFS_GPIO_RST_VAL_L      "0"

int main()
{
    int fd;

         //打开端口/sys/class/gpio# echo 448 &gt; export
         fd = open(SYSFS_GPIO_EXPORT, O_WRONLY);
         if(fd == -1)
         {
                   printf("ERR: Radio hard reset pin open error.\n");
                   return EXIT_FAILURE;
         }
         write(fd, SYSFS_GPIO_RST_PIN_VAL ,sizeof(SYSFS_GPIO_RST_PIN_VAL));
         close(fd);

         //设置端口方向/sys/class/gpio/gpio448# echo out &gt; direction
         fd = open(SYSFS_GPIO_RST_DIR, O_WRONLY);
         if(fd == -1)
         {
                   printf("ERR: Radio hard reset pin direction open error.\n");
                   return EXIT_FAILURE;
         }
         write(fd, SYSFS_GPIO_RST_DIR_VAL, sizeof(SYSFS_GPIO_RST_DIR_VAL));
         close(fd);

         //输出复位信号: 拉高&gt;100ns
         fd = open(SYSFS_GPIO_RST_VAL, O_RDWR);
         if(fd == -1)
         {
                   printf("ERR: Radio hard reset pin value open error.\n");
                   return EXIT_FAILURE;
         }      
         while(1)
         {
                   write(fd, SYSFS_GPIO_RST_VAL_H, sizeof(SYSFS_GPIO_RST_VAL_H));
                   usleep(1000000);
                   write(fd, SYSFS_GPIO_RST_VAL_L, sizeof(SYSFS_GPIO_RST_VAL_L));
                   usleep(1000000);
         }
         close(fd);

         printf("INFO: Radio hard reset pin value open error.\n");
         return 0;

}</code></pre>

<p>上面C代码的步骤,和我们在bash脚本中操作的步骤一致,都是操作前面说的三个特殊GPIO挂载点对应的文件。</p>

<ul>
        <li>首先,是open了/sys/class/gpio/export,然后写入448,表示要激活GPIO0对应的sys挂载点</li>
        <li>其次,是open了/sys/class/gpio/gpio448/direction,写入了OUT,表示设置GPIO0为输入</li>
        <li>然后,是open了/sys/class/gpio/gpio448/value,准备循环写入0和1,来点亮和熄灭LED</li>
        <li>最后,是循环;再循环中,先写入1,点亮LED,然后延时1秒(usleep 1000000微秒),再写入0,熄灭LED,再延时1秒</li>
</ul>

<p>编译该c代码,并执行,就能看到和之前bash脚本执行,同样的结果了。</p>

<p><strong>提醒:上述编译结果的运行,需要在root权限下执行,否则执行时会提示没有权限。</strong></p>

<p><strong>小作业:参考上面的讲解,在控制一个LED的基础上,控制3个LED,达到类似上面bash脚本控制3个LED的效果。</strong><br />
&nbsp;</p>

<p>通过上面的讲解,我们能够学习到,如果控制GPIO0,同样的方法,你也可以控制GPIO2、GPIO4等所有你能控制的GPIO,他们无非是不同的文件而已。</p>

<p>不管是在bash脚本中,还是在C语言、C++语言,或者是Python中,都可以按照同样的操作文件的方式来进行操作即可。</p>

<p>&nbsp;</p>

<p><strong>小作业:通过控制LED点亮和熄灭的时间间隔,来实现LED灯的渐亮渐灭效果,也就是呼吸灯效果。</strong></p>

lugl4313820 发表于 2022-6-13 08:34

学习了,一篇基础的教学,感谢乔帮主的分享!希望有更精彩呈现!
页: [1]
查看完整版本: 【国产RISC-V Linux板 昉·星光VisionFive试用报告】GPIO开发基础:从原理到实战