![369dac94ac577927d53739295f51a394.png](https://i-blog.csdnimg.cn/blog_migrate/3cdf1bed5fd111378532d17b4e5d666f.jpeg)
大家好,我是兔子。
是一个嵌入式软硬件工程师。
正在从单片机开发转岗Linux开发。
这次,上一节,我们把流水灯点亮了。这一节,我们再来控制数码管,让数码管显示我们需要的数字。
1.操作大纲
1)使用上一节编写的gpio驱动,即gpio_driver.ko(i.MX283及i.MX287也一样,驱动配置稍微调整)。
加载驱动。
2)看原理图,知道如何得知数码管是共阳还是共阴。如何通过锁存器74HC595控制。
3)写数码管程序。
4)开发板运行数码管,观看效果。
2.调整驱动及驱动编译
使用上一节编译好的gpio驱动gpio_driver.ko,直接在开发板上加载驱动即可。
(如果对gpio驱动不清楚的,可以移步教程5)
兔子MCU:从51单片机到Linux Linux操控流水灯(教程5)zhuanlan.zhihu.com![95ce8f52f9dd94d1f60caf1250586cef.png](https://i-blog.csdnimg.cn/blog_migrate/340a23ba441d41ee0163147ce7c6f0bc.jpeg)
需要通过NFS共享文件服务传输到开发板中加载。
(如果对NFS服务不清楚,可以移步教程3)
兔子MCU:从51单片机到Linux 开发板传文件利器-NFS(教程3)zhuanlan.zhihu.com![95ce8f52f9dd94d1f60caf1250586cef.png](https://i-blog.csdnimg.cn/blog_migrate/340a23ba441d41ee0163147ce7c6f0bc.jpeg)
1)首先先开启NFS服务,将虚拟机的共享文件夹挂载在开发板的/mnt目录下
2)使用cd /mnt命令,进入/mnt目录
3)使用ls命令,看到是否有gpio驱动文件,即gpio_driver.ko。发现有的。
4)使用insmod gpio_driver.ko加载驱动。
5)可以看到后面打印了很多文件信息,表示驱动加载成功。
![31fc6e0993699cac80ab9b30762e13d0.png](https://i-blog.csdnimg.cn/blog_migrate/e1b7f053d904a7f59f0ba3cec924e06d.jpeg)
3.看原理图接线
首先看的是扩展板上的数码管部分的原理图。
可以看到是使用了3根线,通过控制2片74HC595锁存器芯片,来间接控制数码管。和很多的51开发板一样的电路。
![483edff3f83b695029f6a6f2472ace7d.png](https://i-blog.csdnimg.cn/blog_migrate/0c8b1062934bca040d297523a73a69f0.jpeg)
1)确认数码管是共阳还是共阴数码管。
原理图上已经注明数码管型号,是LN3461BS。
兔子我在搜索引擎上搜索一番,就有人告诉我是共阳的。
![7e5e2d5f52a36c927f085aeec4f5bafe.png](https://i-blog.csdnimg.cn/blog_migrate/7174c84bca134f29e3934e395212080c.jpeg)
共阳就是表示:数码管段选位给高电平,位选位给低电平。对应的数码管就能被点亮。
2)接入跳线
一共用到3根线。一个是数据线,一个是时钟线,还有一个是锁存线。
![3d2d8441d0884a98b74ca535ae63f7a6.png](https://i-blog.csdnimg.cn/blog_migrate/fa9b59dfd0c127a8152d8d597c62071f.jpeg)
原理图上,实际的3根线通过跳线帽是这样接的。
可以得知:
<1>锁存线RCK,在扩展板内是接到了IO3.21电气网络上。
<2>数据线SPI_CLK,在扩展板内是接到了SCK电气网络上。
<3>时钟线SPI_DIN,在扩展板内是接到了MOSI电气网络上。
![5c5712afe9f53134ae72109926d26f42.png](https://i-blog.csdnimg.cn/blog_migrate/090bcedcbfce44a546c96704b6f1f5db.jpeg)
可以追根溯源,在扩展板上,最终和主控板相连的3个脚分别为。
IDC-B的4脚(即RCK,锁存线)。
IDC-A的15脚(即SPI_SCK,时钟线)。
IDC-A的16脚(即SPI_DIN,数据线)。
![4d99e2ea5e575ed240c5b48093f07954.png](https://i-blog.csdnimg.cn/blog_migrate/637314be2469f67d7ae8aa8ca89ba630.jpeg)
如下图所示,可以看到,最终接到ARM的为
PWM4(锁存线)。
RX2(时钟线)。
TX2(数据线)。
![7779ab1fc7636010de3aee8932f9e08a.png](https://i-blog.csdnimg.cn/blog_migrate/40acc13ab7804fe6e4acce3f32b66774.jpeg)
故接线已经分析完成。
(详细的接线分析,可以移步教程5,参考教程5的接线分析)
兔子MCU:从51单片机到Linux Linux操控流水灯(教程5)zhuanlan.zhihu.com![95ce8f52f9dd94d1f60caf1250586cef.png](https://i-blog.csdnimg.cn/blog_migrate/340a23ba441d41ee0163147ce7c6f0bc.jpeg)
4.写数码管程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h> //个人添加,字符转数字
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <limits.h>
#include <asm/ioctls.h>
#include <time.h>
#include <pthread.h>
#include "gpio.h"
static int fd_RCK,fd_SPI_DIN,fd_SPI_CLK;
const char code[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
static void show_help(void)
{
printf("example:n");
printf("./gpio_595 0 &n");
//printf(" gpio_test /dev/gpio-xxx H #set gpio output higth n");
//printf(" gpio_test /dev/gpio-xxx L #set gpio output low n");
//printf(" gpio_test /dev/gpio-xxx R #read gpio input status(H/L) n");
}
static void data(uint CH,uint num)
{
int i;
char tmp_1,tmp_2;
ioctl(fd_RCK,SET_GPIO_LOW);
tmp_1 = code[num];
tmp_2 = tmp_1 & 0x80;
for(i=0;i<8;i++)
{
if(tmp_2 == 0x80)
{
ioctl(fd_SPI_DIN,SET_GPIO_LOW);
ioctl(fd_SPI_CLK,SET_GPIO_HIGHT);
//usleep(500);
ioctl(fd_SPI_CLK,SET_GPIO_LOW);
//usleep(500);
}
else
{
ioctl(fd_SPI_DIN,SET_GPIO_HIGHT);
ioctl(fd_SPI_CLK,SET_GPIO_HIGHT);
//usleep(500);
ioctl(fd_SPI_CLK,SET_GPIO_LOW);
//usleep(500);
}
tmp_1 = tmp_1 << 1;
tmp_2 = tmp_1 & 0x80;
}
for(i=0;i<8;i++)
{
if(i == (8 - CH))
{
ioctl(fd_SPI_DIN,SET_GPIO_HIGHT);
ioctl(fd_SPI_CLK,SET_GPIO_HIGHT);
//usleep(500);
ioctl(fd_SPI_CLK,SET_GPIO_LOW);
//usleep(500);
}
else
{
ioctl(fd_SPI_DIN,SET_GPIO_LOW);
ioctl(fd_SPI_CLK,SET_GPIO_HIGHT);
//usleep(500);
ioctl(fd_SPI_CLK,SET_GPIO_LOW);
//usleep(500);
}
}
ioctl(fd_RCK,SET_GPIO_HIGHT);
}
int main(int argc, char *argv[])
{
int cnt;
if (argc != 2) {
show_help();
return -1;
}
fd_RCK = open("/dev/gpio-PWM4", O_RDWR);
if (fd_RCK < 0) {
printf("faile to open RCK,file :/dev/gpio-RCK n");
return -1;
}
fd_SPI_DIN = open("/dev/gpio-TX2", O_RDWR);
if (fd_SPI_DIN < 0) {
printf("faile to open SPI_DIN,file :/dev/gpio-TX2I n");
return -1;
}
fd_SPI_CLK = open("/dev/gpio-RX2", O_RDWR);
if (fd_SPI_CLK < 0) {
printf("faile to open SPI_CLK,file :/dev/gpio-RX2 n");
return -1;
}
cnt = atoi(argv[1]);
while(1)
{
data(1,cnt / 1000);
usleep(100);
data(2,cnt /100 % 10);
usleep(100);
data(3,cnt /10 % 10);
usleep(100);
data(4,cnt % 10);
usleep(100);
}
return 0;
}
程序说明:
1)open("/dev/gpio-PWM4", O_RDWR);表示打开开发板的/dev目录下的gpio-PWM3文件。O_RDWR表示对这个文件是可读可写操作。
开发板的/dev/gpio-PWM3文件是操作ARM的IO管脚的文件。
(只有加载驱动才会在开发板生成这个文件,故运行数码管程序之前,需要首先加载第2步的驱动)
Linux操作,都是对文件的操作。所以在进行相关操作之前,都是需要open对应的文件。
2)const char code[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
为兔子我验证过的数码管显示编码,从0开始到9.共10个编码。
即0x3F对应显示数字0。
3)if (argc != 2) {
show_help();
return -1;
}
表示验证传入程序的参数是否为2个。如果不为2个,则打印帮助信息。
(即最终运行,会输入./gpio_595_cmd 2,第一个参数为./gpio_595_cmd。表示运行的程序名称。第二个参数为2,表示数码管显示的数字。范围可以使0~9999)
4)ioctl(fd_SPI_DIN,SET_GPIO_LOW);
Ioctl表示直接操作文件,具体操作需要和驱动对应。这里简单器件直接写明。
SET_GPIO_LOW表示对应的IO输出低电平
SET_GPIO_HIGHT表示对应的IO输出高电平
SET_GPIO_LOW和SET_GPIO_HIGHT是头文件gpio.h里的宏定义。
5)sleep(1);
表示延时1秒(在当前内核2.26.35.3里表示1秒,其他版本内核可能表示为毫秒)
如果想延时小于1秒,可以使用微秒延时函数。
usleep(500*1000);
表示延时500毫秒。
sleep();以及usleep();延时函数推荐使用。因为这不是软件延时,不会占用CPU的资源。
将数码管程序命名为gpio_595_cmd.c存到路径~/XW_Linux/ZLG/2、gpio_driver/test目录下。
同时修改该目录下的数码管应用程序的Makefile。调整如下图所示。
![0dcf15ffc70401a9fbf3202486315687.png](https://i-blog.csdnimg.cn/blog_migrate/d956ef3465d7688b0efbeaa3bf410c1f.jpeg)
然后使用终端,make一下,进行点灯应用程序的编译。
![530d471e8377b68acb6c535aa8676178.png](https://i-blog.csdnimg.cn/blog_migrate/3d3a9e9099249d57429afcb69ce44f6f.jpeg)
可以看到,无报错。生成的数码管应用文件在bin文件夹里。
将生成的数码管程序和之前的gpio驱动拷贝到NFS共享目录里。
(如何使用NFS共享目录,请移步至教程3)
兔子MCU:从51单片机到Linux 开发板传文件利器-NFS(教程3)zhuanlan.zhihu.com![95ce8f52f9dd94d1f60caf1250586cef.png](https://i-blog.csdnimg.cn/blog_migrate/340a23ba441d41ee0163147ce7c6f0bc.jpeg)
![3aecfbfb19189172221139c8727cc854.png](https://i-blog.csdnimg.cn/blog_migrate/59dc2c1b8faefd7b223c4998b5bd776f.jpeg)
至此,数码管程序编译完成。
5.运行程序
1)开发板上电,并挂载NFS共享目录。
(具体操作可移步教程3)
兔子MCU:从51单片机到Linux 开发板传文件利器-NFS(教程3)zhuanlan.zhihu.com![95ce8f52f9dd94d1f60caf1250586cef.png](https://i-blog.csdnimg.cn/blog_migrate/340a23ba441d41ee0163147ce7c6f0bc.jpeg)
2)进入开发板的NFS挂载点/mnt文件夹下。通过ls命令能查看到我们编译好的点灯程序和驱动。
![7e378c0433f8f2dc0a5a775402416f36.png](https://i-blog.csdnimg.cn/blog_migrate/c89660e4f07518ab3318c1e17920f59a.jpeg)
3)首先,先加载驱动。
使用insmod gpio_driver.ko指令。
![11904b11a63eef49106c932a3962f2ae.png](https://i-blog.csdnimg.cn/blog_migrate/03012567519837c29fcc6ccc3ba9eca0.jpeg)
可以看到,打印了很多生成的文件。表示驱动加载成功。
4)运行数码管程序
使用./gpio_595_cmd 234 表示让数码管显示234这个数字。
![007c0ec6f1068a7ca4d3f8f81f1c5ff5.png](https://i-blog.csdnimg.cn/blog_migrate/4023bca38b7f4eead328be1ed4d5776a.jpeg)
效果图:
![b85331263cf4a8223ab1cdb8c4ba5739.png](https://i-blog.csdnimg.cn/blog_migrate/bd3b343d5b96f25ee1b7f0e5688722af.jpeg)
至此,数码管程序已经成功使用IO口来控制。
6.效果视频
![401b9ab2b165c48ebb4272df5c73659f.png](https://i-blog.csdnimg.cn/blog_migrate/d80e5e3085003eba92220f7984378093.jpeg)
![736c821e718ea5b6a4b273275a6908c0.png](https://i-blog.csdnimg.cn/blog_migrate/d5717c92c8c1fd0ee1087e7dfccf7c92.jpeg)