树莓派外设开发
转载:https://www.cnblogs.com/lulipro/p/5992172.html
作者:lulipro
一、树莓派wiringPi库详解
wiringPi是一个很棒的树莓派IO控制库,使用C语言开发,提供了丰富的接口:GPIO控制,中断,多线程,等等。
- wiringPi库安装
因为树莓派镜像中自带wiringPi库,不用手动安装。如果没有手动安装。
1.1 wiringPi的github (https://git.drogon.net/?p=wiringPi;a=summary) 下载安装包。点击页面的第一个链接的右边的snapshot,下载安装压缩包。
1.2 然后进入安装包所在的目录执行以下命令:
1.3 验证wiringPi的是否安装成功,输入gpio -v,会在终端中输出相关wiringPi的信息。否则安装失败。>tar xfz wiringPi-98bcb20.tar.gz //98bcb20为版本标号,可能不同 >cd wiringPi-98bcb20 >./build
- 编译和运行
2.1 假如你写了一个LEDtest.c 的项目,则如下。
编译:gcc -o LEDtest LEDtest.c -lwiringPi //使用C语言编程
运行:sudo ./LEDtest - 查看引脚编号表格
gpio readall
二、wiringPi库API大全
-
在使用wiringPi库时,你需要包含头文件 #include<wiringPi.h>。凡是写wiringPi的程序,都包含这个头文件。
-
硬件初始化函数。使用wiringPi时,你必须在执行任何操作前初始化树莓派,否则程序不能正常工作。可以调用下表函数之一进行初始化,它们都会返回一个int , 返回 -1 表示初始化失败。
int wiringPiSetup (void) //返回:执行状态,-1表示失败 //当使用这个函数初始化树莓派引脚时,程序使用的是wiringPi 引脚编号表。引脚的//编号为 0~16 //需要root权限 int wiringPiSetupGpio (void) //返回执行状态,-1表示失败 //当使用这个函数初始化树莓派引脚时,程序中使用的是BCM GPIO 引脚编号表。 //需要root权限 wiringPiSetupPhys(void) //不常用,不做介绍 wiringPiSetupSys (void) //不常用,不做介绍
-
通用GPIO控制函数
void pinMode (int pin, int mode) /* pin:配置的引脚 mode:指定引脚的IO模式 可取的值:INPUT、OUTPUT、PWM_OUTPUT,GPIO_CLOCK 作用:配置引脚的IO模式 注意: 只有wiringPi 引脚编号下的1脚(BCM下的18脚) 支持PWM输出 只有wiringPi编号下的7(BCM下的4号)支持GPIO_CLOCK输出 */ void digitalWrite (int pin, int value) /* pin:控制的引脚 value:引脚输出的电平值。 可取的值:HIGH,LOW分别代表高低电平 让对一个已近配置为输出模式的 引脚 输出指定的电平信号 */ int digitalRead (int pin) /* pin:读取的引脚 返回:引脚上的电平,可以是LOW HIGH 之一 读取一个引脚的电平值 LOW HIGH ,返回 */ void analogWrite(int pin, int value) /* pin:引脚 value:输出的模拟量 模拟量输出 树莓派的引脚本身是不支持AD转换的,也就是不能使用模拟量的API,需要增加另外的模块 */ int analogRead (int pin) /* pin:引脚 返回:引脚上读取的模拟量模拟量输入树莓派的引脚本身是不支持AD转换的,也就是不能使用模拟量的API,需要增加另外的模块 */ void pwmWrite (int pin, int value) /* pin:引脚 value:写入到PWM寄存器的值,范围在0~1024之间。 输出一个值到PWM寄存器,控制PWM输出。 pin只能是wiringPi 引脚编号下的1脚(BCM下的18脚) */ void pullUpDnControl (int pin, int pud) /* pin:引脚 pud:拉电阻模式 可取的值:PUD_OFF 不启用任何拉电阻。关闭拉电阻。 PUD_DOWN 启用下拉电阻,引脚电平拉到GND PUD_UP 启用上拉电阻,引脚电平拉到3.3v 对一个设置IO模式为 INPUT 的输入引脚设置拉电阻模式。 与Arduino不同的是,树莓派支持的拉电阻模式更丰富。 树莓派内部的拉电阻达50K欧姆 */
-
时间控制函数
unsigned int millis (void) /*这个函数返回 一个 从你的程序执行 wiringPiSetup 初始化函数(或者wiringPiSetupGpio ) 到 当前时间 经过的 毫秒数。 返回类型是unsigned int,最大可记录 大约49天的毫秒时长。*/ unsigned int micros (void) /*这个函数返回 一个 从你的程序执行 wiringPiSetup 初始化函数(或者wiringPiSetupGpio ) 到 当前时间 经过的 微秒数。 返回类型是unsigned int,最大可记录 大约71分钟的时长。*/ void delay (unsigned int howLong) /*将当前执行流暂停 指定的毫秒数。因为Linux本身是多线程的,所以实际暂停时间可能会长一些。参数是unsigned int 类型,最大延时时间可达49天*/ void delayMicroseconds (unsigned int howLong) /*将执行流暂停 指定的微秒数(1000微秒 = 1毫秒 = 0.001秒)。 因为Linux本身是多线程的,所以实际暂停时间可能会长一些。参数是unsigned int 类型,最大延时时间可达71分钟*/
-
中断
wiringPi提供了一个中断处理注册函数,它只是一个注册函数,并不处理中断。他无需root权限。int wiringPiISR (int pin, int edgeType, void (*function)(void)) /* 返回值:返回负数则代表注册失败 pin:接受中断信号的引脚 edgeType:触发的方式。 INT_EDGE_FALLING:下降沿触发 INT_EDGE_RISING:上升沿触发 INT_EDGE_BOTH :上下降都会触发 INT_EDGE_SETUP:编程时用不到。 function:中断处理函数的指针,它是一个无返回值,无参数的函数。 注册的函数会在中断发生时执行 和51单片机不同的是:这个注册的中断处理函数会和main函数并发执行(同时执行,谁也不耽误谁) 当本次中断函数还未执行完毕,这个时候树莓派又触发了一个中断,那么这个后来的中断不会被丢弃,它仍然可以被执行。但是wiringPi最多可以跟踪并记录后来的仅仅1个中断,如果不止1个,则他们会被忽略,得不到执行。 */
-
串口通信
使用时需要包含头文件:#include <wiringSerial.h>int serialOpen (char *device, int baud) /*device:串口的地址,在Linux中就是设备所在的目录。 默认一般是"/dev/ttyAMA0",我的是这样的。 baud:波特率 返回:正常返回文件描述符,否则返回-1失败。 打开并初始串口*/ void serialClose (int fd) //fd:文件描述符 关闭fd关联的串口 void serialPutchar (int fd, unsigned char c) /*fd:文件描述符 c:要发送的数据 发送一个字节的数据到串口*/ void serialPuts (int fd, char *s) /*fd:文件描述符 s:发送的字符串,字符串要以'\0'结尾 发送一个字符串到串口*/ void serialPrintf (int fd, char *message, …) /*fd:文件描述符 message:格式化的字符串 像使用C语言中的printf一样发送数据到串口*/ int serialDataAvail (int fd) /*fd:文件描述符 返回:串口缓存中已经接收的,可读取的字节数,-1代表错误 获取串口缓存中可用的字节数。*/ int serialGetchar (int fd) /*fd:文件描述符 返回:读取到的字符 从串口读取一个字节数据返回。 如果串口缓存中没有可用的数据,则会等待10秒,如果10后还有没,返回-1 所以,在读取前,做好通过serialDataAvail判断下。*/ void serialFlush (int fd) /*fd:文件描述符 刷新,清空串口缓冲中的所有可用的数据。*/ *size_t write (int fd,const void * buf,size_t count) /*fd:文件描述符 buf:需要发送的数据缓存数组 count:发送buf中的前count个字节数据 返回:实际写入的字符数,错误返回-1 这个是Linux下的标准IO库函数,需要包含头文件#include <unistd.h> 当要发送到的数据量过大时,wiringPi建议使用这个函数。*/ *size_t read(int fd,void * buf ,size_t count); /*fd:文件描述符 buf:接受的数据缓存的数组 count:接收的字节数. 返回:实际读取的字符数。 这个是Linux下的标准IO库函数,需要包含头文件#include <unistd.h> 当要接收的数据量过大时,wiringPi建议使用这个函数。*/
三、程序源码
-
IO口控制Beep蜂鸣器
#include <wiringPi.h> #include <stdio.h> #define BEEP_PIN 7 int main() { int cmd=0; wiringPiSetup(); pinMode(BEEP_PIN, OUTPUT); digitalWrite(BEEP_PIN, HIGH); while(1) { printf("请输入控制开关,0-关,1-开\n"); scanf("%d",&cmd); getchar(); printf("cmd = %d\n",cmd); if(cmd == 1) { digitalWrite(BEEP_PIN, LOW); } else if(cmd == 0){ digitalWrite(BEEP_PIN, HIGH); } } return 0; }
-
超声波测距
#include <stdio.h> #include <wiringPi.h> #include <unistd.h> #include <sys/time.h> #include <stdlib.h> #define ECHO 28 //0PIN #define TRIG 29 //1PIN double getDistance(void) { double dis; long time; struct timeval start; struct timeval stop; digitalWrite (TRIG, LOW) ; usleep(20); digitalWrite (TRIG, HIGH) ; usleep(10); digitalWrite (TRIG, LOW) ; while(!digitalRead(ECHO)); gettimeofday(&start,NULL); while(digitalRead(ECHO)); gettimeofday(&stop,NULL); time = 1000000*(stop.tv_sec - start.tv_sec) + (stop.tv_usec - start.tv_usec); dis = (time/1000000.0)*340.0*100.0/2.0; return dis; } int main (void) { double dis; wiringPiSetup () ; pinMode (TRIG, OUTPUT) ; pinMode (ECHO, INPUT) ; while (1) { dis = getDistance(); printf("dis = %lf\n", dis); sleep(1); } return 0; }
-
串口通信
初次启动树莓派串口编程需要配置
输入指令: sudo vi /boot/cmdline.txt
树莓派的串口文件是/dev/ttyAMA0
#include <stdio.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <wiringPi.h> #include <wiringSerial.h> #include <pthread.h> #include <malloc.h> int fd; void *SendHandler() { char *str; str = (char *)malloc(128*sizeof(char)); while(1) { memset(str, '\0', 128*sizeof(char)); scanf("%s",str); while(*str) { serialPutchar (fd, *str) ; str++; } } } void *RevHandler() { while(1) { while (serialDataAvail (fd)) { printf ("%c", serialGetchar (fd)) ; } } } int main () { pthread_t send_t; pthread_t rev_t; if ((fd = serialOpen ("/dev/ttyAMA0", 115200)) < 0) { fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ; return 1 ; } if (wiringPiSetup () == -1) { fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ; return 1 ; } pthread_create(&send_t, NULL, SendHandler, NULL); pthread_create(&rev_t, NULL, RevHandler, NULL); while (1) { // usleep(1000); } return 0 ; }