Linux 开发示例
本页保留常用 Linux 命令和应用开发示例,删除其他产品介绍。
linux底层开发示例
播放mp3
注:登录账户为root 123456
将存放有mp3文件的TF卡插到主板的任意卡槽,使用如下命令挂载TF卡:
cd /
mkdir sdcard
mount /dev/mmcblk1p1 /sdcard
cd sdcard
使用如下命令播放:
./mplayer *.avi
./mplayer *.mp3
连接串口后,可以通过PC键盘的0或9调节音量。也可以使用madplayer播放音乐。
在后台运行程序
在上一节中给出了播放音乐的示例,但是这时候mplayer已经占据了终端控制台,在音乐播放完之前,我们无法再使用终端控制台了。又比如我们开发一款产品时,就需要在启动文件系统后运行一个应用程序,如果运行了一个程序,终端控制台就被占用了,那将极大的限制我们的功能。为止,我们可以将程序放在后台运行。使用方法很简单,我们只需在执行的指令后面添加一个”&”即可。如播放音乐时使用如下命令:
./mplayer *.mp3 &
中止程序的运行
中止程序的运行有多种方式,最直接的方式就是直接按ctrl+c。如前面我们正在播放一段音频文件,我们可以按ctrl+c退出程序。但是如果程序在后台运行,那么我们按ctrl+c就不管用了。这时我们可以使用kill命令。
kill+PID
kill+文件名
屏幕抓图
本文档中的各个图片,都是采用gsnap这个工具进行抓图的。进入QT图形界面后,我们能在LCD上看到丰富多彩的人机交互界面。通过gsnap可以抓取到图形界面精彩的瞬间。在控制台终端输入如下命令:
gsnap test_pic.jpg /dev/fb0
这时在当前目录将会保存test_pic.jpg图像文件。详细的gsnap移植步骤在后面会有详细描述。
挂载TF卡
进入QT图形界面后,在命令终端会有控制台出现,这时可以通过控制台查看文件系统的内容。将TF卡插到主板的任意卡槽,串口终端会有如下提示:
这时在文件系统的/dev目录将会自动生成一个名叫mmcblk1p1的块设备文件。它就是对应的TF卡的设备文件,使用如下命令挂载TF卡到/sdcard目录:
mkdir /sdcard
mount /dev/mmcblk1p1 /sdcard
查看/scard目录下的内容,即是我们TF卡中的内容,如下图所示:
挂载U盘
进入QT图形界面后,在命令终端会有控制台出现,这时可以通过控制台查看文件系统的内容。插入U盘后,串口终端会有如下提示:
这时在文件系统的/dev目录将会自动生成一个名叫sda4的块设备文件。它就是对应的U盘设备文件,使用如下命令挂载U盘到/udisk目录:
mkdir /udisk
mount /dev/sda4 /udisk
查看/udisk目录下的内容,即是我们U盘中的内容,如下图所示:
保存系统时钟
Linux可以使用date指令更改时间日期。例如:
date -s 201607211433 #设置为2016年7月21日14:33分
hwclock -w #把刚设置的时间存入RTC寄存器
hwclock -s #恢复linux系统时钟为RTC寄存器值,一般将该指令放在rcS中开机自动执行。
掉电保存数据到flash
由于本系统采用了ext4文件系统,因此可以很方便的保存数据,确保掉电后数据不丢失。如我们从U盘中拷备一首歌曲到/root目录:
cp /udisk/muyangqu.mp3 /
重启主板,我们发现在root目录仍然存在刚才拷备的这首歌曲,说明掉电后数据并没有丢失。
设置开机自动运行程序
借助启动脚本可以设置各种程序开机后自动运行,这点很类似于WINDOWS的Autobat自动批处理文件。启动脚本位于/etc/init.d/rcS中,我们可以将自己想要开机运行的程序或是开机执行的指令放在rcS里面。比如我们想制作一个简单的开机音乐,我们就完全可以在rcS中添加如下语句:
./mplayer start.mp3 &
这时,开机后就会播放名叫start.mp3的音乐了。注意start.mp3需要在当前执行指令所在目录。
查看主板内存信息
X3288主板默认配置2GB DDR3 SDRAM,在uboot启动时,打印信息上会给出RAM大小信息:
在进入文件系统后,可以通过cat命令查询Linux系统分配到的SDRAM大小。执行如下命令:
cat /proc/meminfo
linux应用开发示例
本手册给出的所有应用程序全部在九鼎创展x3288主板上运行,这里仅给出了一些比较基础,常用的应用程序,旨在为用户打开Linux世界奇妙的大门,用户定能举一反三,编写出属于自己的更加丰富完美的程序。
声明:以下所有应用程序全部为九鼎创展科技有限公司原创作品,所有内容全经我们严格测试,建议用户按照下面步骤动手编译一遍,以增强自己的理解,不推荐直接使用我们提供好的文件。另外,敬请商业人士勿侵犯版权。
Hello World
第一步:生成可执行文件
在x3288_lollipop目录新建app-ex目录,在app-ex目录新建hello目录,然后在hello目录下新建hello.c和makefile两个文件:
vim hello.c
这是一个最基础的应用程序,如果我们声明了交叉编译工具,可以直接敲入命令进行编译(由于主板环境缺少c库,编译时需要加上-static静态编译):
arm-linux-gcc-4.4.3 -o hello hello.c -static
说明:由于主板文件系统缺少标准函数库,编译时加上-static选项;使用的编译器为arm-linux-gcc-4.4.3。
编译完成后,在当前目录会生成hello可执行文件,我们可以使用file命令查询执行文件是否为ARM体系文件:
第二步:将可执行文件下载到主板运行
比较常用的方式有以下四种:
-
通过串口和sz/rz工具
-
复制到存储媒介,如SD卡,U盘等
-
通过NFS挂载文件系统,这时不用将可执行文件拷备到主板了,推荐调试使用这种方式!
-
通过ftp传输
这里介绍第二种方法,以TF卡为例,其他方法请读者自行尝试。
将生成的hello文件拷备到TF卡,再将TF卡插入主板的TF卡接口,将TF卡mount到/mnt目录:
cd /
mount /dev/mmcblk1p1 /mnt
进入mnt目录,可以看到刚才拷贝的hello文件了:
运行hello:
./hello
打印信息如下:
表明,程序已经成功运行。
前面编译文件我们需要通过手敲命令执行,我们可以通过编写makefile来代替手敲的动作。
在hello目录下新建makefile文件:
vim makefile
直接在hello目录下敲make就可以生成hello文件。运行的效果和前面的完全相同。
数学函数库调用
建立程序编译路径:
mkdir math
cd math
vim math.c
编辑如下内容:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(void)
{
double a=9.0;
printf("sqrt(%f)=%f\n",a,sqrt(a));
return 0;
}
编辑makefile文件,内容如下:
OBJS=math.o
LDFLAGS = -lm -static
CC = yourtoolchainpath/bin/arm-linux-gcc-4.4.3
math:${OBJS}
${CC} -o $@ $^ $(LDFLAGS)
clean:
rm -f math *.o
执行make,将生成的可执行文件math下载到主板上运行,如下图所示:
多线程编程示例
建立程序编译路径:
mkdir thread
cd thread
vim thread.c
编辑如下内容:
#include<stddef.h>
#include<stdio.h>
#include<unistd.h>
#include"pthread.h"
void function1(void);
void function2(void);
int func_flag=0;
pthread_mutex_t mutex;
main()
{
pthread_t reader;
pthread_mutex_init(&mutex,NULL);
pthread_create(&reader,NULL,(void*)&function1,NULL);
function2();
}
void function2(void)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(func_flag==0)
{
printf("excute function2.\n");
func_flag=1;
}
pthread_mutex_unlock(&mutex);
}
}
void function1(void)
{
while(1)
{
pthread_mutex_lock(&mutex);
if(func_flag==1)
{
printf("excute function1.\n");
func_flag=0;
}
pthread_mutex_unlock(&mutex);
}
}
编辑makefile文件,内容如下:
OBJS=thread.o
LDFLAGS = -lpthread -static
CC = yourtoolchainpath/bin/arm-linux-gcc-4.4.3
thread:${OBJS}
${CC} -o $@ $^ $(LDFLAGS)
clean:
rm -f thread *.o
执行make,将生成的可执行文件thread下载到主板上运行,如下图所示:
多进程编程示例
在Linux下通用调用fork函数创建新的进程。调用fork时,系统将产生一个与当前进程相同的进程。它与原有的进程具有相同的数据,连接关系和在程序同一处执行时的连续性。通常将原有的进程叫父进程,新创建的进程叫子进程。
fork调用将分两次返回,从父子进程返回。进程创建语法如下:
#include <unistd.h>
pid_t pid;
pid = fork();
如果pid返回0,表示说明从子进程返回,否则从父进程返回,此时返回的是进程的ID号。我们可以通过getpid()函数来获得进程的ID号。
首先建立程序编译目录:
mkdir process
cd process
vim process.c
编辑如下内容:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
main()
{
pid_t pid;
pid=fork();
if (pid<0)
{
printf("fork is error!\n");
return 1;
}
else if (pid == 0)
{
while (1)
{
printf("the child process is running now.pid=%d\n",getpid());
sleep(1);//linux延时函数,延时1秒
}
}
else
{
while (1)
{
printf("the perent process is running now.pid=%d\n",getpid());
sleep(1);
}
}
return 0;
}
编辑makefile文件,内容如下:
OBJS=process.o
LDFLAGS = -lpthread -static
CC = yourtoolchainpath/bin/arm-linux-gcc-4.4.3
process:${OBJS}
${CC} -o $@ $^ $(LDFLAGS)
clean:
rm -f process *.o
执行make编译,将生成的可执行文件下载到主板运行,仔细观察串口监控信息:
makefile编程示例
在上面的很多测试程序实例中,我们都编写了一些简单的makefile文件。下面我们介绍makefile的基本的语法。
makefile就好比批处理文件,里面写了一系列集合,当运行make编译时,便会按makefile提供的命令及顺序完成编译。
这里我们给出三个文件:main.c,func.c,func.h。主程序在main.c中,在main.c中程序会调用func.c中的函数,func.c中的函数又会用到func.h中定义的变量。
main.c文件内容如下:
#include "func.h"
extern int fd;
int main(int argc,char **argv)
{
fd = open(DEVICE_NAME,0);//打开设备
if(fd == -1)
{
printf("open device %s error \n",DEVICE_NAME);
return 0;
}
else
{
printf("open device %s ok! \n",DEVICE_NAME);
}
while(1)
{
glint_led();
}
close(fd);
return 0;
}
该文件会调用glint_led ()函数,这个函数在func.c中。func.c的内容如下:
#include "func.h"
void glint_led(void)
{
ioctl(fd,LED_ON);
sleep(1);
ioctl(fd,LED_OFF);
sleep(1);
}
这里仅仅是一个读取按键的函数,供main函数调用。该函数需要用到了一些变量,另外还需要一些头文件支持,这些都存放在func.h中,其内容如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#define DEVICE_NAME "/dev/vib"
#define LED_ON 0x11
#define LED_OFF 0x22
int fd;
很明显,这是基于LED测试程序,人为的分成的三个文件。我们的目的不在于分离代码,而在于学习makefile的编写方法。
当不使用makefile时,我们使用如下指令编译:
arm-none-linux-gnueabi-gcc -o mkfile main.c func.c
编译完成后,将会生成可执行文件mkfile。将它下载到主板上运行,和前面的按键测试完全相同。现在我们尝试编写第一个属于自己的makefile:
mkfile:main.o func.o
arm-linux-gcc-4.4.3 -o mkfilemain.o func.o
main.o:main.c
arm-linux-gcc-4.4.3 -c main.c -o main.o
func.o:func.c func.h
arm-linux-gcc-4.4.3 -c func.c -o func.o
clean:
rm -f mkfile *.o
执行make后,编译器会依次编译main.c和func.c文件,生成main.o和func.o文件,最后将这两个.o文件打包到可执行文件mkfile中。这时将mkfile文件下载到主板运行,效果和前面的是一样的。我们可以执行make clean指令清除生成的.o文件和可执行文件。
makefile具有很强大的推理功能,我们完全可以简化上面的代码。优化后的代码如下:
OBJS=main.o func.o
CC=arm-linux-gcc-4.4.3
mkfile:${OBJS}
${CC} -o $@ $^
main.o:
func.o:func.h
clean:
rm -f mkfile *.o
可见,这次比上面的完整版要简化多了。前面通过变量OBJS定义了要编译的源文件,变量CC给出了交叉编译工具。$@ 表示目标文件的全称,即mkfile,$^表示所有被依赖的文件,并以空格分开,即main.o func.o。后面的clean为清除指令,执行make clean后会执行 clean后面的指令。需要注意的是,rm指令后面千万不要使用$@符号来表征我们要删除的目标文件,因为这时候$@已经不再表示mkfile了,而表示clean。同样,使用make指令编译,一样能够生成我们需要的目录文件mkfile。
上面的makefile使用了变量以及预定义变量。第一句即定义了变量OBJS,将它赋值为main.o func.o,第二句定义了变量CC,将它赋值为一个交叉编译工具定义。引用变量时,通过${}表示,这里表示前面定义的变量。
上面使用了$@和$^两个预定义变量,GNU make主要有以下七种预定义变量:
对比以上几种编译方式,我们不然发现,其实最简的还是第一种,因为它就一句话就搞定了。那么在makefile中,我们是否也可以精简到只有一句话呢?答案是肯定的。我们继续利用makefile强大的推理功能进行简化,得到如下makefile代码:
OBJS=main.o func.o
CC=arm-linux-gcc-4.4.3
mkfile:${OBJS}
${CC} -o $@ $^
clean:
rm -f mkfile *.o
这次,makefile真正编译的代码,就只有上面红色部分一条指令了。和前面比较,不难发现,单独对main.c和func.c两个文件编译的指令已经去掉了。前面我们提到,makefile具有强大的推理功能,我们在生成目标文件mkfile时,makefile会推理出它需要main.c和func.c两个文件,因此它首先就会去编译这两个文件,最后再执行目标文件的生成。因此我们完全可以将它们省去。
这里只是makefile的一点基础,读者可以借助于其他书籍对makefile作更深一层的了解。
mplayer移植
有两种移植mplayer,第一种方法就是直接下载mplayer源码包,手动配置编译环境,再通过交叉编译环境编译。该方法比较传统,我们有更方便的方法,直接在buildroot中选中mplayer,再make即可,buildroot会自动下载mplayer源码包,自动配置编译环境并编译。
在buildroot的menuconfig配置选项中,进入Target packages-> Audio and video applications选项,选中mplayer,如下图所示:
保存退出,在buildroot下直接make,生成文件系统后更新到主板,mplayer就打包进文件系统了。
madplayer移植
madplayer的移植方法和mplayer的移植方法完全雷同,直接在buildroot中选中madplayer的选项,再make即可。
屏幕抓图工具gsnap移植
说明:以下步骤基于4.3.3的交叉编译工具,读者需修改成x3288对应的交叉编译工具,其他步骤雷同。
屏幕抓图的方法有多种,有不少爱好者自己动手写抓图小程序。这里我们使用JPEG库来处理。具体用到了jpegsrc.v6b.tar.gz和gsnap.tar.gz两个源码包。
一:安装libjpeg
解压jpeg库源码包,进入根目录:
tar zxf jpegsrc.v6b.tar.gz
cd jpeg-6b
二:配置编译环境:
./configure --prefix=/usr/local/arm/4.3.3/arm-none-linux-gnueabi
--exec-prefix=/usr/local/arm/4.3.3/arm-none-linux-gnueabi --enable-shared --enable-static
三:修改makefile
CC = gcc 修改为 CC = arm-none-linux-gnueabi-gcc
AR = ar ac 修改为 AR = arm-none-linux-gnueabi-ar ac
AR2=ranlib修改为 AR2= arm-none-linux-gnueabi-ranlib
确保—exec-prefix已经设置为/usr/local/arm/4.3.3/arm-none-linux-gnueabi,如果没有,手动设置。
四:在/usr/local/arm/4.3.3/arm-none-linux-gnueabi下建立man/man1目录:
cd /usr/local/arm/4.3.3/arm-none-linux-gnueabi
mkdir -p man/man1
五:编译,安装
make
make install
这时,在/usr/local/arm/4.3.3/arm-none-linux-gnueabi/man/man1目录下将会生成以下文件:
cjpeg.1 djpeg.1 jpegtran.1 rdjpgcom.1 wrjpgcom.1
在/usr/local/arm/4.3.3/arm-none-linux-gnueabi/lib目录下生成以下文件:
libjpeg.a libjpeg.la libjpeg.so libjpeg.so.62 libjpeg.so.62.0.0
六:解压gsnap
tar zxf gsnap.tar.gz
cd gsnap
七:修改makefile
all:
arm-none-linux-gnueabi-gcc -g gsnap.c -ljpeg -o gsnap
clean:
rm -f gsnap
八:编译,得到可执行文件gsnap
make
九:将jpeg库文件复制到文件系统的lib目录,注意保持文件的链接属性
cp -a libjpeg.s* “文件系统路径”/lib
十:将可执行文件gsnap复制到文件系统的sbin目录
cp gsnap “文件系统路径”/sbin
十一:重新制作文件系统,下载到主板上,使用如下命令即可截获图形界面:
gsnap 1.jpg /dev/fb0
同样可以将图片保持为bmp,png等其他格式。
安装ubuntu操作系统
x3288主板支持ubuntu14.04操作系统。
安装ubuntu源码包
默认我们已经将ubuntu的源码包整合到android4.4源码包中了,将android4.4的源码包解压到PC机的用户根目录,即完成了源码包的安装。
编译uboot
ubuntu的源码包和android4.4的源码包共用同一个uboot,如果已经编译过android4.4的uboot,以下步骤可省略。
执行如下指令编译uboot:
./mk -u
编译完成后,将会在out/release目录下生成uboot映像文件。
编译内核
ubuntu的源码包和android4.4的源码包共用同一个内核,如果已经编译过android4.4的内核,以下步骤可省略。
执行如下指令编译内核:
./mk -k
编译完成后,将会在out/release目录下生成内核映像文件。
生成统一固件update_ubuntu.img
执行如下指令生成统一ubuntu固件update_ubuntu.img:
./mk -us或./mk -su
编译完成后,将会在out/release目录下生成ubuntu映像文件update_ubuntu.img。
烧录固件update_ubuntu.img
烧录ubuntu系统的方法和烧写QT,android固件的方法完全相同,请参考相关章节。
ubuntu帐户
在x3288开发平台上,默认ubuntu操作系统的用户名如下: