@

1.流水灯在电子电路中的地位

记得第一次接触单片机时,还是用的AT89S52单片机,第1个程序就是点亮一个LED,然后再实现LED流水灯的效果。在这个过程中,可以了解整个程序的结构,GPIO的使用,延时的使用等。可以说单片机学习中的点灯,就相当于C语言中的"Hello World"!好的,我们来看一下在ARM Linux下如何控制GPIO。

2.硬件电路分析

点灯的根本是控制LED对应GPIO输出高低电平,那要控制哪个GPIO呢?这就需要查看原理图,看LED是连接到了哪个GPIO管脚。

iMX287的扩展板AP-283Demo原理图中,LED的驱动电路:



与连接器的连接关系:



这里我们把:4个LED的管脚和J8C的4个管脚使用跳线帽短接起来,即

  1. J8A_1=LED1 -> J8C_1=IO3.26
  2. J8A_2=LED2 -> J8C_2=IO3.22
  3. J8A_3=LED3 -> J8C_3=IO3.20
  4. J8A_4=LED4 -> J8C_4=IO2.7

即:

  1. GPIO3_26 = LED1
  2. GPIO3_22 = LED2
  3. GPIO3_20 = LED3
  4. GPIO2_7 = LED4

所以,我们只需要控制这几个GPIO的高低电平,可以控制LED了。

连接方式:

3.先点个灯吧

iMX28 系列处理器的 IO 端口分为 7 个 BANK,其中 BANK0~4 具有 GPIO 功能,每个BANK 具有 32 个 I/O。iMX283 部分 BANK 的引脚不支持 GPIO 功能,具体需要参考《IMX28CEC_Datasheet.pdf》手册。在导出 GPIO 功能引脚时,需要先计算 GPIO 引脚的排列序号,其序号计算公式:

  1. GPIO序号 = Bank * 32 + N
  2. #LED对应的序号
  3. LED1 -> GPIO3_26 = 3 * 32 + 26 = 122
  4. LED2 -> GPIO3_22 = 3 * 32 + 22 = 118
  5. LED3 -> GPIO3_20 = 3 * 32 + 20 = 116
  6. LED4 -> GPIO2_7 = 2 * 32 + 7 = 71

串口或SSH登录开发板之后,通过如下过程可导出对应GPIO的功能,以LED1对应的122为例:

  1. #进入到gpio驱动所在的文件夹
  2. cd /sys/class/gpio
  3. #生成LED1操作的相关文件
  4. echo 122 > export
  5. #进入到LED1控制文件夹
  6. cd gpio122
  7. #设置GPIO为输出方向
  8. echo out > direction
  9. #查看当前GPIO的输入输出方向
  10. cat direction
  11. #设置GPIO输出0点亮LED
  12. echo 0 > value
  13. #查看当前GPIO的输出状态
  14. cat value
  15. #设置GPIO输出1熄灭LED
  16. echo 1 > value
  17. #查看当前GPIO的输出状态

在这里,就体现了Linux系统下一切皆文件的含义。



这样,就实现了某个GPIO输出高低电平的目的,其他LED的控制,只需要修改对应的序号即可。

如果想取消LED1的GPIO功能,可以通过如下命令实现:

  1. echo 122 > unexport



当然,如果是读取输入,如按键等,就设置方向为in输入,通过cat value来读取输入的状态。

4.shell脚本实现流水灯

好了,知道了如何实现GPIO的控制,那么如何方便、快捷的执行以上步骤呢?我们这里先介绍一种通过shell脚本的方式控制LED实现流水灯的效果:

  1. #在home目录新建led_blink.sh脚本文件
  2. touch led_blink.sh
  3. #输入控制LED实现流水灯效果的代码
  4. vi led_blink.sh

led_blink.sh的文件内容:

  1. #!/bin/bash
  2. #LED对应的GPIO
  3. led1_pin=122
  4. led2_pin=118
  5. led3_pin=116
  6. led4_pin=71
  7. #echo $led1_pin $led2_pin $led3_pin $led4_pin
  8. #GPIO操作文件如果不存在则创建,否则不创建
  9. for pin in $led1_pin $led2_pin $led3_pin $led4_pin
  10. do
  11. #如果文件夹存在
  12. if [ ! -d "/sys/class/gpio/gpio$pin/" ];
  13. then
  14. echo $pin > /sys/class/gpio/export
  15. else
  16. echo "$pin dir exist!"
  17. fi
  18. done
  19. #GPIO方向设置为输出
  20. for pin in $led1_pin $led2_pin $led3_pin $led4_pin
  21. do
  22. echo out > /sys/class/gpio/gpio$pin/direction
  23. done
  24. #死循环
  25. while true
  26. do
  27. #GPIO输出0/1
  28. for pin in $led1_pin $led2_pin $led3_pin $led4_pin
  29. do
  30. echo "点亮$pin"
  31. echo 0 > /sys/class/gpio/gpio$pin/value
  32. sleep 1
  33. echo "熄灭$pin"
  34. echo 1 > /sys/class/gpio/gpio$pin/value
  35. done
  36. done

保存退出之后,通过如下命令执行这个脚本:

  1. #添加可执行权限
  2. chmod +x led_blink.sh
  3. #执行脚本文件
  4. ./led_blink.sh

然后就可以看到流水灯效果了:



这种方式,没什么高深的技术,就是把之前通过一行一行的命令,转换成了自动化的脚本文件。为了写这种shell脚本,需要学习一些基本的shell语法。下面我们来介绍两种比较通用的方法,通过C语言文件读写的方式来实现流水灯效果。

5.ANSI C文件操作实现流水灯

只使用标准ANSI C文件操作来实现流水灯效果。标准C语言操作,常用的函数有

fopen/fclose/fwrite/fread/fseek等。无论是Linux还是Windows都是通用的。

  1. /* ANSI C文件操作实现流水灯 By whik */
  2. //包含printf和sleep等
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #define LED1_PIN 122
  7. #define LED2_PIN 118
  8. #define LED3_PIN 116
  9. #define LED4_PIN 71
  10. #define GPIO_PATH "/sys/class/gpio/"
  11. int main(void)
  12. {
  13. int led_table[4] = {LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN};
  14. char path[100];
  15. char cmd_export[100];
  16. int i;
  17. char *str;
  18. FILE *fp; //文件指针
  19. int cnt_w; //写入的字节数
  20. //判断LED对应的操作文件夹是否存在,不存在自动创建
  21. for(i = 0; i < 4; i++)
  22. {
  23. sprintf(path, "%sgpio%d", GPIO_PATH, led_table[i]); //sys/class/gpio/gpio122
  24. if (!access(path, 0))
  25. printf("%s 文件夹存在\n", path);
  26. else
  27. {
  28. printf("%s 文件夹不存在\n", path);
  29. sprintf(cmd_export, "echo %d > %sexport", led_table[i], GPIO_PATH);//echo 122 > /sys/class/gpio/export
  30. system(cmd_export); //执行export命令
  31. if(!access(path, 0)) //访问文件夹,确认创建成功
  32. printf("%s 导出成功\n", path);
  33. else
  34. return -1;
  35. }
  36. }
  37. //设置输出方向
  38. for(i = 0; i < 4; i++)
  39. {
  40. sprintf(path, "%sgpio%d/direction", GPIO_PATH, led_table[i]);
  41. fp = fopen(path, "r+");
  42. if(fp != NULL) //打开成功
  43. {
  44. printf("%s 打开成功\n", path);
  45. cnt_w = fwrite("out", 3, 1, fp);
  46. if(cnt_w == EOF)
  47. {
  48. printf("方向写入失败\n");
  49. return -1;
  50. }
  51. else
  52. printf("方向写入成功\n");
  53. fclose(fp); //文件关闭
  54. }
  55. else
  56. {
  57. printf("%s 文件打开失败\n", path);
  58. return -1;
  59. }
  60. }
  61. //流水灯效果
  62. while(1)
  63. {
  64. for(i = 0; i < 4; i++)
  65. {
  66. sprintf(path, "%sgpio%d/value", GPIO_PATH, led_table[i]);
  67. fp = fopen(path, "w+");
  68. if(fp != NULL)
  69. {
  70. fwrite("0", 1, 1, fp);
  71. fseek(fp, 0, SEEK_SET); //重新定位到文件起始
  72. printf("%s 写入0\n", path);
  73. sleep(1);
  74. fwrite("1", 1, 1, fp);
  75. printf("%s 写入1\n", path);
  76. fseek(fp, 0, SEEK_SET);
  77. fclose(fp);
  78. }
  79. else
  80. {
  81. printf("%s 文件打开失败\n", path);
  82. }
  83. }
  84. }
  85. return 0;
  86. }

实现原理和之前的shell脚本也是一样的思路:

  • 先判断LED对应的GPIO操作文件是否导出,如果没有导出则执行导出命令,否则不执行。
  • 循环的方式,依次设置4个LED的方向为输出
  • 循环的方式,控制4个GPIO的输出高低电平,外面是一个死循环

6.Linux 系统调用实现流水灯

Linux系统调用,常用的文件IO操作函数有open/close/read/write/lseek/ulink等。函数用法也很简单,和标准C语言用法几乎一样,这里不再介绍。

  1. /* Linux 系统函数实现流水灯 */
  2. //涉及到设备操作的,需包含以下头文件
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <fcntl.h>
  6. //包含close/read/write/lseek等函数
  7. #include <unistd.h>
  8. //包含printf/sprintf函数
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #define LED1_PIN 122
  13. #define LED2_PIN 118
  14. #define LED3_PIN 116
  15. #define LED4_PIN 71
  16. #define GPIO_PATH "/sys/class/gpio/"
  17. int main(void)
  18. {
  19. int led_table[4] = {LED1_PIN, LED2_PIN, LED3_PIN, LED4_PIN};
  20. char path[100];
  21. char cmd_export[100];
  22. int i;
  23. char *str;
  24. int fd;
  25. int cnt_w; //写入的字节数
  26. //判断LED对应的操作文件夹是否存在,不存在自动创建
  27. for(i = 0; i < 4; i++)
  28. {
  29. sprintf(path, "%sgpio%d", GPIO_PATH, led_table[i]); //sys/class/gpio/gpio122
  30. if (!access(path, 0))
  31. printf("%s 文件夹存在\n", path);
  32. else
  33. {
  34. printf("%s 文件夹不存在\n", path);
  35. sprintf(cmd_export, "echo %d > %sexport", led_table[i], GPIO_PATH);//echo 122 > /sys/class/gpio/export
  36. system(cmd_export); //执行export命令
  37. if(!access(path, 0)) //访问文件夹,确认创建成功
  38. printf("%s 导出成功\n", path);
  39. else
  40. return -1;
  41. }
  42. }
  43. //设置输出方向
  44. for(i = 0; i < 4; i++)
  45. {
  46. sprintf(path, "%sgpio%d/direction", GPIO_PATH, led_table[i]);
  47. fd = open(path, O_RDWR); //linux系统函数,失败返回-1
  48. if(fd != -1) //打开成功
  49. {
  50. printf("%s 打开成功\n", path);
  51. cnt_w = write(fd, "out", 3); //linux系统函数
  52. if(cnt_w <= 0)
  53. {
  54. printf("方向写入失败\n");
  55. return -1;
  56. }
  57. else
  58. printf("方向写入成功\n");
  59. close(fd); //linux系统函数,成功返回0
  60. }
  61. else
  62. {
  63. printf("%s 文件打开失败\n", path);
  64. return -1;
  65. }
  66. }
  67. //流水灯效果
  68. while(1)
  69. {
  70. for(i = 0; i < 4; i++)
  71. {
  72. sprintf(path, "%sgpio%d/value", GPIO_PATH, led_table[i]);
  73. fd = open(path, O_RDWR); //linux系统函数
  74. if(fd != -1)
  75. {
  76. write(fd, "0", 1);
  77. lseek(fd, 0, SEEK_SET); //重新定位到文件起始
  78. printf("%s 写入0\n", path);
  79. sleep(1);
  80. write(fd, "1", 1);
  81. printf("%s 写入1\n", path);
  82. lseek(fd, 0, SEEK_SET);
  83. close(fd);
  84. }
  85. else
  86. {
  87. printf("%s 文件打开失败\n", path);
  88. }
  89. }
  90. }
  91. return 0;
  92. }

实现过程也很简单,就是对文件的读写,Linux下一切皆文件的含义你理解了吗?

我的公众号:mcu149

iMX287A多种方法实现流水灯效果的更多相关文章

  1. CSS(3)多种方法实现水平垂直居中效果

    CSS实现水平垂直居中对齐 在CSS中实现水平居中,会比较简单.常见的,如果想实现inline元素或者inline-block元素水平居中,可以在其父级块级元素上设置text-align: cente ...

  2. S5PV210_流水灯

    1.整体思路:把相应的配置数据写入相应的寄存器,控制GPIO电平(Led.s)——运用工程管理Makefile编译.链接文件(由Led.s编译得到led.bin,该文件用于USB启动方式点亮LED,若 ...

  3. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】【实验一】流水灯模块

    实验一:流水灯模块 对于发展商而言,动土仪式无疑是最重要的任务.为此,流水灯实验作为低级建模II的动土仪式再适合不过了.废话少说,我们还是开始实验吧. 图1.1 实验一建模图. 如图1.1 所示,实验 ...

  4. Tiny4412之C语言实现流水灯,Tiny4412裸机程序[3]

    在前边我们使用汇编完成了一个流水灯实验: Tiny4412汇编流水灯代码,Tiny4412裸机LED操作 ---- - -- -- -- - -- -- 修改: # ${MKBL2} ${SOURCE ...

  5. Tiny4412汇编流水灯代码,Tiny4412裸机LED操作[1]

    从今天开始就正式进入到tiny4412的开发学习中了,今天主要看了一下Tiny4412的启动流程及存储器映射及Exynos4412数据手册,用汇编写了一个跑马灯程序(后续会有C语言版本的出来),先说一 ...

  6. Tiny4412汇编流水灯代码,Tiny4412裸机LED操作【转】

    本转载自:http://www.techbulo.com/1313.html Tiny4412汇编流水灯代码,Tiny4412裸机LED操作 2014年10月20日 ⁄ 裸机程序 ⁄ 共 4171字 ...

  7. cc2530的第三次实验,按键中断控制流水灯

    cc2530的第三次实验:按键中断控制流水灯 效果为按一次按键,流水灯亮一次 实验相关电路图: 实验相关寄存器: 初始化函数 //初始化LED灯 //设置P1SEL,通用为0,外设为1 1111110 ...

  8. [51单片机] EEPROM 24c02 [I2C代码封装-保存实现流水灯]

    这里把EEPROM 24c02封装起来,今后可以直接调用,其连线方式为:SDA-P2.1;SCL-P2.0;WP-VCC >_<:i2c.c /*--------------------- ...

  9. Xilinx Vivado的使用详细介绍(4):Zedboard+vivado之流水灯(加SDK)

    Vivado+zedboard之初学流水灯 Author:zhangxianhe 环境:vivado 2016.3(已验证适用于2015.4) 开发板:Zedboard version xc7z020 ...

随机推荐

  1. win下PowerShell的簡單使用

  2. 基于Redis的Service缓存实现

    项目中有使用到缓存,每次需要将缓存代码和业务代码杂糅在一起,以及分散各处的key,严重影响代码的可读性.以下是使用AOP对其简单尝试.直接上代码: 1.定义缓存注解: @Target(ElementT ...

  3. 关于VLC无法播放rtsp的问题分析

    我之前有一篇博客说,怎么通过vlc查日志,方法不知道是不是特别好,传送门:https://www.cnblogs.com/132818Creator/p/11136714.html 虽然在调试窗口上提 ...

  4. 让Spring不再难懂-mvc篇

    spring mvc简介与运行原理 Spring的模型-视图-控制器(MVC)框架是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器 ...

  5. EXAM-2018-7-27

    EXAM-2018-7-27 未完成 [ ] F A 要用ll,然后注意正方形的情况,细心一点 E 有点动态规划的感觉,状态的转移,不难,要注意不要漏掉状态 K 正解是DFS 然后用贪心数据弱的话能过 ...

  6. php获取服务器和mysql等信息输出到页面(基于ci框架)

    function show($varName) {    switch($result = get_cfg_var($varName)) {     case 0:      return '< ...

  7. [LC] 53. Maximum Subarray

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...

  8. Spring Boot集成全局唯一ID生成器

    流水号生成器(全局唯一 ID生成器)是服务化系统的基础设施,其在保障系统的正确运行和高可用方面发挥着重要作用.而关于流水号生成算法首屈一指的当属 Snowflake雪花算法,然而 Snowflake本 ...

  9. python语法基础-面向对象-基础-长期维护

    ###############    类的基本操作    ############## """ 类的基本认识: 1,类就是一个模子 2,dict,list都是类,具体的一 ...

  10. python与模块的导入方式

    今日所得 模块 import from...import... 循环导入 相对导入 绝对导入 软件开发目录规范 模块 模块:是一系列功能的集合体 模块的三种来源:1.内置模块(Python解释器自带的 ...