树莓派01 ------- 基于orangepi学习 静态动态库、交叉编译、软链接

目录

静态库和动态库

 静态库

静态库优缺点

动态库

动态库优缺点

静态库的制作

 静态库的使用

动态库的制作

动态库的使用

外设库wiringPi

继电器

超声波

串口通信

 serialTool.c

serialTool.h

uart.c

通过语音模块发送数据给串口控制开关灯

orangepi交叉编译

orangepi 交叉编译的工具

下载工具到Windows上并上传到Ubuntu虚拟机

解压

设置环境变量临时有效 

设置永久有效

 测试

 带wiringpi库的交叉编译

1.带wiringpi库的交叉编译如何进行

2.将库所需的文件拷贝到上位机

3.创建软链接

4.将wiringpi上传到上位机

5. 编写脚本

 树莓派交叉编译

1. 交叉编译是什么,为什么要交叉编译

2. 交叉编译工具链的安装

3. 交叉编译服务端客户端

4. 带wiringPi库的交叉编译如何进行


静态库和动态库

 静态库

静态库优缺点

静态函数库,是在程序执行前(编译)就加入到目标程序中去了 ;

优点: 运行快

   发布程序无需提供静态库,因为已经在app中,移植方便

缺点:大

动态库

动态库优缺点

动态函数库,是在程序执行时动态(临时)由目标程序去调用

缺点: 运行慢

优点: 小

静态库的制作

  1. gcc  func.c  -c                                 生成func.o文件
  2. ar rcs libfunc.a  func.o                    func.o文件生成libfunc.a静态库文件

 静态库的使用

    3.  gcc mainfunc.c   -lfunc   -L  ./  -o mainProStatic        

解释:-lfunc   -l是制定要用的静态库,库名砍头去尾 原是libfunc.a 

-L告诉gcc编译器从-L制定的路径去找静态库。默认是从/usr/lib  /usr/local/lib去找

动态库的制作

a.    gcc -shared -fpic func.c -o libcalc.so           //编译func.c 生成动态库 名字叫libfunc.so

解释:-shared 指定生成动态库  -fpic 标准,fPIC 选项作用于编译阶段,在生成目标文件时就得使用该选项,以生成位置无关的代码。

动态库的使用

b.    gcc mainfunc.c  -lfunc   -L  ./  -o mainDongtai   

c. 会找不到 需要配置环境为了方便 用脚本执行  mainDongtai.sh   ----chmod +x mainDongtai.sh

export LD_LIBRARY_PATH="/home/orangepi/prppr/raspberryPi/jingTaiDongTaiKu"
./mainDongtai.

 解释:编译mainfunc.c 和libfunc.so  -L在当前目录查找 当前目录生成mainDongtai可执行文件


外设库wiringPi

编译 gcc demo.c -lwiringPi    有线程的要链lpthread

继电器

#include <stdio.h>
#include <wiringPi.h>
#include <stdlib.h>
#include <string.h>

#define switch1  0
#define switch2  1
#define switch3  2
#define switch4  5
int main()
{
        char cmd[32] = {'\0'};

        if(wiringPiSetup() == -1){
                printf("wiringPiSetup faile!!\n");
                exit(-1);
        }
        pinMode(switch1,OUTPUT);//模式为输出
        digitalWrite(switch1,HIGH);//初始化该引脚为高电平 不导通

        pinMode(switch2,OUTPUT);//模式为输出
        digitalWrite(switch2,HIGH);//初始化该引脚为高电平 不导通

        pinMode(switch3,OUTPUT);//模式为输出
        digitalWrite(switch3,HIGH);//初始化该引脚为高电平 不导通

        pinMode(switch4,OUTPUT);//模式为输出
        digitalWrite(switch4,HIGH);//初始化该引脚为高电平 不导通

        while(1){
                printf("请输入s1/2/3/4 no 或 off\n");
                memset(cmd,'\0',sizeof(cmd));

                gets(cmd);//scanf 回车会干扰
                if(strstr(cmd,"s1 no") != NULL){ //如果输入为s1 no 则给引脚 继电器1 写入高电平
                        digitalWrite(switch1,LOW);//该继电器高电平触发
                }
                else if(strstr(cmd,"s1 off") != NULL){
                        digitalWrite(switch1,HIGH);//低电平断开
                }


                else if(strstr(cmd,"s2 no") != NULL){ //如果输入为s1 no 则给引脚 继电器1 写入高电平
                        digitalWrite(switch2,LOW);//该继电器高电平触发
                }
                else if(strstr(cmd,"s2 off") != NULL){
                        digitalWrite(switch2,HIGH);//低电平断开
                }

                else if(strstr(cmd,"s3 no") != NULL){ //如果输入为s1 no 则给引脚 继电器1 写入高电平
                        digitalWrite(switch3,LOW);//该继电器高电平触发
                }
                else if(strstr(cmd,"s3 off") != NULL){
                        digitalWrite(switch3,HIGH);//低电平断开
                }

                else if(strstr(cmd,"s4 no") != NULL){ //如果输入为s1 no 则给引脚 继电器1 写入高电平
                        digitalWrite(switch4,LOW);//该继电器高电平触发
                }
                else if(strstr(cmd,"s4 off") != NULL){
                        digitalWrite(switch4,HIGH);//低电平断开
                }
                else if(strstr(cmd,"all no") != NULL){ //如果输入为s1 no 则给引脚 继电器1 写入高电平
                        digitalWrite(switch1,LOW);//该继电器高电平触发
                        digitalWrite(switch2,LOW);//该继电器高电平触发
                        digitalWrite(switch3,LOW);//该继电器高电平触发
                        digitalWrite(switch4,LOW);//该继电器高电平触发
                }
                else if(strstr(cmd,"all off") != NULL){
                        digitalWrite(switch1,HIGH);//低电平断开
                        digitalWrite(switch2,HIGH);//低电平断开
                        digitalWrite(switch3,HIGH);//低电平断开
                        digitalWrite(switch4,HIGH);//低电平断开
                }
                else{
                        printf("输入错误!!\n");
                }


        }

        return 0;
}
    

超声波

#include <stdio.h>
#include <wiringPi.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#define trig  0
#define echo  1


double disHandler()
{
        double dis;
        struct timeval start;
        struct timeval stop;

        digitalWrite(trig,LOW);
        usleep(2);
        digitalWrite(trig,HIGH);
        usleep(12);

        digitalWrite(trig,LOW);
        while(!digitalRead(echo));
        gettimeofday(&start,NULL);
        while(digitalRead(echo));
        gettimeofday(&stop,NULL);
        long time = 1000000*(stop.tv_sec - start.tv_sec) + (stop.tv_usec - start.tv_usec);
        dis = (double)time*0.000001*34000/2;
        return dis;
}

int main()
{
        double dis = 0;

        if(wiringPiSetup() == -1){
                printf("wiringPiSetup faile!!\n");
                exit(-1);
        }

        pinMode(trig,OUTPUT);
        pinMode(echo,INPUT);

        while(1){
                dis = disHandler();
                printf("dis:%.2lf cm\n",dis);
                sleep(1);
        }
        return 0;
}

串口通信

根据wiringPi库下的serialTest.c  自己封装了一个serialTool.c   ---》 serialTool.h 在串口中使用

解释:find -iname serial* 查找

编译:gcc uart.c  serialTool.c  有线程的要链线程

 serialTool.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "wiringSerial.h"


int myserialOpen (const char *device, const int baud)//根据硬件地址和波特率打开串口
{
        struct termios options ;
        speed_t myBaud ;
        int status, fd ;
        switch (baud){
                case    4800:   myBaud =    B4800 ; break ;
                case    9600:   myBaud =    B9600 ; break ;
                case  115200:   myBaud =  B115200 ; break ;
                default:
                return -2 ;
        }
        if ((fd = open (device, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK)) == -1)
                return -1 ;

        fcntl (fd, F_SETFL, O_RDWR) ;

        // Get and modify current options:

        tcgetattr (fd, &options) ;

        cfmakeraw   (&options) ;
        cfsetispeed (&options, myBaud) ;
        cfsetospeed (&options, myBaud) ;

        options.c_cflag |= (CLOCAL | CREAD) ;
        options.c_cflag &= ~PARENB ;
        options.c_cflag &= ~CSTOPB ;
        options.c_cflag &= ~CSIZE ;
        options.c_cflag |= CS8 ;
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
        options.c_oflag &= ~OPOST ;

        options.c_cc [VMIN]  =   0 ;
        options.c_cc [VTIME] = 100 ;    // Ten seconds (100 deciseconds)

        tcsetattr (fd, TCSANOW, &options) ;

        ioctl (fd, TIOCMGET, &status);

        status |= TIOCM_DTR ;
        status |= TIOCM_RTS ;

        ioctl (fd, TIOCMSET, &status);

        usleep (10000) ;        // 10mS

        return fd ;

}

void myserialClose (const int fd)//关闭串口
{
        close (fd) ;
}


void myserialSendstring (const int fd, const char *s)//串口发送字符串
{
        int ret;
        ret = write (fd, s, strlen (s));
        if (ret < 0)
                printf("Serial Puts Error\n");
}

int myserialGetchar (const int fd)//串口接收单个字符
{
        char x ;

        if (read (fd, &x, 1) != 1)
                return -1 ;

        return x;
}
int myserialGetstring (const int fd,char *buffer)//串口接收字符串
{
        int n_read;
        n_read = read(fd,buffer,32);
        return n_read;
}

serialTool.h
int myserialOpen (const char *device, const int baud);//打开函数
void myserialClose (const int fd);//关闭函数
void myserialSendstring (const int fd, const char *s);//发送字符串
int myserialGetchar (const int fd);//获取单个字符
int myserialGetstring (const int fd,char *buffer);//获取字符串
uart.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "wiringSerial.h"
#include <pthread.h>
#include <unistd.h>
#include "serialTool.h"//-----“”先找该目录下三个函数 open write read

int fd;
void* readSerial()
{
        char buff[32];
        while(1){
                memset(buff,'\0',sizeof(buff));//清空
                myserialGetstring(fd,buff);
                printf("Get-->%s\n",buff);//创建线程1 调用seriaTool.h中的接收函数 并打印
        }
}

void* sendSerial()
{
        char buff[32];
        while(1){
                memset(buff,'\0',sizeof(buff));//清空
                scanf("%s",buff);
                myserialSendstring(fd,buff);//创建线程2 输入内容放到buff中 调用serialTool.h中的发送函数 把buff传过去
        }
}


int main(int argc,char **argv)
{


        char deviceName[32] = {'\0'};

        pthread_t readt;//线程读 接收
        pthread_t sendt;//线程写 发送

        if(argc < 2){
                printf("usage:%s xxx /dev/ttyS?\n",argv[0]);
                exit(-1);
        }

        strcpy(deviceName,argv[1]);
        if((fd = myserialOpen(deviceName,115200)) == -1){
                printf("serialopen faile!!\n");
                exit(-1);
        }


        pthread_create(&readt,NULL,(void*)readSerial,NULL);//--4--读取线程  调用readSerial函数读取
        pthread_create(&sendt,NULL,(void*)sendSerial,NULL);//--5--发送线程  调用sendSerial函数发送

        pthread_join(readt,NULL);
        pthread_join(sendt,NULL);

        return 0;
}
     
通过语音模块发送数据给串口控制开关灯
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "wiringSerial.h"
#include <pthread.h>
#include <unistd.h>
#include "serialTool.h"//-----“”先找该目录下三个函数 open write read
//因为用的自己封装的库 所以不用wiringPiSetup

int main()
{

        int fd;
        char readBuff[128] = {'\0'};
        int n_read = 0;

        if((fd = myserialOpen("/dev/ttyS5",115200)) == -1){//打开串口
                printf("serialopen faile!!\n");
                exit(-1);
        }


        while(1){//不断读取
                n_read = read(fd,readBuff,sizeof(readBuff));
                if(n_read == 0){//不会一直阻塞读取 当没有读到数据则不往后执行
                        printf("coertime!!\n");
                        continue;
                }
                else if(strstr(readBuff,"open") != NULL){//如果读到数据含有open 则开灯并清空
                        printf("open light\n");
                }
                else if(strstr(readBuff,"close") != NULL){
                        printf("close light\n");
                }
                memset(readBuff,'\0',128);
        }
        return 0;
}

orangepi交叉编译

 //参考   : 全志H616交叉编译工具链的安装与使用_C有点难。的博客-CSDN博客

orangepi 交叉编译的工具

a.  电脑:Ubuntu 18.04  和VMwere Tools
//参考博文:VM Tools安装过程_vmtools安装_闫渭丘的博客-CSDN博客
//vmware tools无效_vmware tools安装后重启仍不生效_天空之城Aloha2020的博客-CSDN博客

b. 开发板:orangepi-zero2

c. 交叉编译器:aarch64-none-linux-gnu-
 

下载工具到Windows上并上传到Ubuntu虚拟机

地址:索引 /armbian-releases/_toolchain/ |清华大学开源软件镜像站 |清华开源镜像 (tsinghua.edu.cn)https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/_toolchain/?C=N&O=A

解压

cp /home/ygl/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz    /home/orangpiZero2

tar -xf gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz

cd gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin

设置环境变量临时有效 

输出环境变量 echo $PATH

输出结果为:

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

pwd显示当前路径

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/ygl/orangePiZero2/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin
 

设置永久有效

修改工作目录的 .bashrc 是一个隐藏文件,用来配置命令终端

vi /home/ygl/.bashrc

在最后一行加入

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/ygl/orangePiZero2/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin
 

 保存并推出  source /home/ygl/.bashrc 使其生效

 测试

在虚拟机编写hello.c并用交叉编译工具编译为 test可执行文件

 查看文件类型 

把test上传到orangepiZer2上 

指令:scp test orangepi@192.168.1.5:/home/orangepi/prppr


 带wiringpi库的交叉编译

1.带wiringpi库的交叉编译如何进行

(1)正常我们要先交叉编译wiringpi库,编译出的库适合开发板,这时交叉编译可执行程序的时候,链接库的格式也是正确的。

(2)通过 -I 指定头文件-L指定库

2.将库所需的文件拷贝到上位机

进入开发板/usr/local/lib目录下拷贝libwiringPi.so.2.46到上位机的/home/ygl/orangePiZero2目录下

进入开发板/usr/local/lib目录下拷贝libwiringPiDev.so.2.46到上位机的/home/ygl/orangePiZero2目录下

scp libwiringPi.so.2.46 prppr@192.168.1.9:/home/prppr/orangePiZero2

scp libwiringPiDev.so.2.46 prppr@192.168.1.9:/home/prppr/orangePiZero2

3.创建软链接

参考文章: https://www.cnblogs.com/zhangna1998517/p/11347364.html

概念 :软链接相当于一个快捷方式,实际上是一个文本文件存放的是另外一个文件的位置信息。软链接就是在你选定的位置上生成一个镜像,不占用磁盘空间。

ln -s 源文件 目标文件

ln -s libwiringPi.so.2.46 libwiringPi.so

ln -s libwiringPiDev.so.2.46 libwiringPiDev.so

        ln -s libwiringPi.so.2.50 libwiringPi.so 
        指令 参数   要被链接的文件    软链接文件名字

 硬链接:

硬链接会在你选定的位置上生成一个和源文件相同大小的文件

ln 源文件 目标文件

4.将wiringpi上传到上位机

将orangepiZero2上的wiringpi-master.zip上传到上位机并解压

5. 编写脚本

编写build.sh脚本 交叉编译带wiringPi库的文件:把wiringOP-master在当前目录解压并通过软链接找到外设库

aarch64-none-linux-gnu-gcc $1 -I ./wiringOP-master/wiringPi -L. -lwiringPi -lwiringPiDev -lpthread -lm -lcrypt -lrt -g -o $2
 

 给予其执行权限:chmod +x build.sh

执行:./build.sh demo2.c  jiaoChaDemo

上位机软链接交叉编译后上传到开发板:scp test orangepi@192.168.1.5:/home/orangepi/prppr

脚本相当于 : aarch64-none-linux-gnu-gcc demo2.c -I ./wiringOP-master/wiringPi -L. -lwiringPi -lwiringPiDev 

  1. -I ./wiringOP-master/wiringPi:这个选项告诉编译器在给定的路径中查找头文件(包含文件)。在这个例子中,编译器将在./wiringOP-master/wiringPi路径中查找所需的头文件。

  2. -L.:这个选项告诉编译器在当前目录(.)中查找库文件。编译器将在当前目录中查找后面指定的库文件。


 树莓派交叉编译

1. 交叉编译是什么,为什么要交叉编译


    ======================================是什么?
        交叉编译 是在一个平台上生成另一个平台上的可执行代码。
                我们再windows上面编写C51代码,并编译成可执行代码,如xx.hex,
                是在c51上面运行,不是在windows上面运行

                我们在ubuntu上面编写树莓派的代码,并编译成可执行代码,如a.out,
                是在树莓派上面运行,不是在ubuntu linux上面运行

        编译:是在一个平台上生成在该平台上的可执行代码

        C51 交叉编译的发生在keil(集成环境上面)
        stm32 

    =============================为什么要交叉编译?
        平台上不允许或不能够安装我们所需要的编译器比如C51
        1.因为目的平台上的资源贫乏,无法运行我们所需要编译器
        2.树莓派是不是就不需要交叉编译?
            错。也要  树莓派有时又是因为目的平台还没有建立,连操作系统都没有,根本谈不上运行什么编译器。
            操作系统也是代码,也要编译!

            平台运行需要两样至少东西:bootloader(启动引导代码)以及操作系统核心

    宿主机(host) :编辑和编译程序的平台,一般是基于X86的PC机,通常也被称为主机。
    目标机(target):用户开发的系统,通常都是非X86平台。host编译得到的可执行代码在target上运行。

    ===========================交叉编译需要用到什么工具?
        交叉编译器、交叉编译工具链


****************************************************************************************************************************


2. 交叉编译工具链的安装


    https://github.com/raspberrypi/

    从共享文件夹拷贝到工作目录
     cp /mnt/hgfs/share/tools-master.zip .
     解压
     unzip tools-master.zip 
     cd /home/CLC/lessonPI/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
     pwd获得路径

     echo $PATH 获得当前环境变量的值


    2.1 临时有效,配置环境变量
        PATH 环境变量
        export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/CLC/lessonPI/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
    2.2 永久有效,配置环境变量

        修改工作目录下的.bashrc 隐藏文件,配置命令终端的
         vi /home/CLC/.bashrc 
         在文件最后一行加入:
             export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/CLC/lessonPI/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
         source /home/CLC/.bashrc 加载配置文件,马上生效配置。


****************************************************************************************************************************

3. 交叉编译服务端客户端


        交叉编译:
            检查下交叉编译工具对不对:
                arm-linux-gnueabihf-gcc -v
                4.8.3

        arm-linux-gnueabihf-gcc  xxx.c -o xxx

        如何把编译生成的可执行文件下载到开发板:
        scp clientInPi pi@192.168.43.30:/home/pi
        指令  文件名  开发板用户名@开发板地址:开发板的绝对路径
 
****************************************************************************************************************************


4. 带wiringPi库的交叉编译如何进行


        1. 正常我们先要交叉编译wiringPi库,编译出的库适合树莓派,这时候交叉编译可执行程序的试试,链接库的格式也是正确的。
        2. 通过-I -L来指定
         
         因为链接的库的格式不对,是宿主机的平台,出现以下错误
          arm-linux-gnueabihf-gcc demo2.c -I /home/CLC/lessonPI/WiringPi/wiringPi -lwiringPi
        /home/CLC/lessonPI/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/../lib/gcc/arm-linux-gnueabihf/4.8.3/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lwiringPi
        collect2: error: ld returned 1 exit status

        把树莓派的wringPI库拿上来用

        软链接:
        参考文章: https://www.cnblogs.com/zhangna1998517/p/11347364.html
        概念:
             1. 软链接文件有类似于Windows的快捷方式。
             2. 在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。
             3. 你选定的位置上生成一个文件的镜像,不会占用磁盘空间
        如何生成:
        ln -s libwiringPi.so.2.50 libwiringPi.so 
        指令 参数   要被链接的文件    软链接文件名字

        硬链接:ln libwiringPi.so.2.50 libwiringPi.so 
                它会在你选定的位置上生成一个和源文件大小相同的文件

********************************************************************************************************************************

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值