wiringPi是一個很棒的樹莓派IO控制庫,使用C語言開發,提供了豐富的接口:GPIO控制,中斷,多線程,等等。java 的pi4j項目也是基於wiringPi的,我最近也在看源代碼,到時候整理好了會放出來的。
下面開始wiringPi之旅吧!
安裝
進入 wiringPi的github (https://git.drogon.net/?p=wiringPi;a=summary) 下載安裝包。點擊頁面的第一個鏈接的右邊的snapshot,下載安裝壓縮包。
然后進入安裝包所在的目錄執行以下命令:
>tar xfz wiringPi-98bcb20.tar.gz //98bcb20為版本標號,可能不同 >cd wiringPi-98bcb20 >./build
驗證wiringPi的是否安裝成功,輸入gpio -v,會在終端中輸出相關wiringPi的信息。否則安裝失敗。
編譯 和運行
假如你寫了一個LEDtest.c 的項目,則如下。
編譯: g++ -Wall -o LEDtest LEDtest.cpp -lwiringPi //使用C++編程 , -Wall 是為了使能所有警告,以便發現程序中的問題 gcc -Wall -o LEDtest LEDtest.c -lwiringPi //使用C語言編程 運行: sudo ./LEDtest
查看引腳編號表格
使用如下控制台下命令
> gpio readall
也可以查看下面的圖。
注意:查看時,將樹莓派的USB接口面對自己,這樣看才是正確的。
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
|
只有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 不啟用任何拉電阻。關閉拉電阻。 |
對一個設置IO模式為 INPUT 的輸入引腳設置拉電阻模式。 與Arduino不同的是,樹莓派支持的拉電阻模式更豐富。 樹莓派內部的拉電阻達50K歐姆 |
LED閃爍程序

#include<iostream> #include<cstdlib> #include<wiringPi.h> const int LEDpin = 1; int main() { if(-1==wiringPiSetup()) { cerr<<"setup error\n"; exit(-1); } pinMode(LEDpin,OUTPUT); for(size_t i=0;i<10;++i) { digitalWrite(LEDpin,HIGH); delay(600); digitalWrite(LEDpin,LOW); delay(600); } cout<<"------------bye-------------"<<endl; return 0; }
PWM輸出控制LED呼吸燈的例子

#include<iostream> #include<wiringPi.h> #include<cstdlib> using namespace std; const int PWMpin = 1; //只有wiringPi編號下的1腳(BCM標號下的18腳)支持 void setup(); int main() { setup(); int val = 0; int step = 2; while(true) { if(val>1024) { step = -step; val = 1024; } else if(val<0) { step = -step; val = 0; } pwmWrite(PWMpin,val); val+=step; delay(10); } return 0; } void setup() { if(-1==wiringPiSetup()) { cerr<<"setup error\n"; exit(-1); } pinMode(PWMpin,PWM_OUTPUT); }
時間控制函數
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:下降沿觸發 function:中斷處理函數的指針,它是一個無返回值,無參數的函數。 |
注冊的函數會在中斷發生時執行 和51單片機不同的是:這個注冊的中斷處理函數會和main函數並發執行(同時執行,誰也不耽誤誰) 當本次中斷函數還未執行完畢,這個時候樹莓派又觸發了一個中斷,那么這個后來的中斷不會被丟棄,它仍然可以被執行。但是wiringPi最多可以跟蹤並記錄后來的僅僅1個中斷,如果不止1個,則他們會被忽略,得不到執行。 |
通過1腳檢測 因為按鍵按下引發的 下降沿,觸發中斷,反轉11控制的LED

#include<iostream> #include<wiringPi.h> #include<cstdlib> using namespace std; void ButtonPressed(void); void setup(); /********************************/ const int LEDPin = 11; const int ButtonPin = 1; /*******************************/ int main() { setup(); //注冊中斷處理函數 if(0>wiringPiISR(ButtonPin,INT_EDGE_FALLING,ButtonPressed)) { cerr<<"interrupt function register failure"<<endl; exit(-1); } while(1) ; return 0; } void setup() { if(-1==wiringPiSetup()) { cerr<<"wiringPi setup error"<<endl; exit(-1); } pinMode(LEDPin,OUTPUT); //配置11腳為控制LED的輸出模式 digitalWrite(LEDPin,LOW); //初始化為低電平 pinMode(ButtonPin,INPUT); //配置1腳為輸入 pullUpDnControl(ButtonPin,PUD_UP); //將1腳上拉到3.3v } //中斷處理函數:反轉LED的電平 void ButtonPressed(void) { digitalWrite(LEDPin, (HIGH==digitalRead(LEDPin))?LOW:HIGH ); }
多線程
wiringPi提供了簡單的Linux系統下的通用的 Posix threads線程庫接口來支持並發。
int piThreadCreate(name) | name:被包裝的線程執行函數 返回:狀態碼。返回0表示成功啟動,反之失敗。 |
包裝一個用PI_THEEAD定義的函數為一個線程,並啟動這個線程。 首先你需要通過以下方式創建一個特特殊的函數,這個函數中的代碼就是在新的線程中將執行的代碼。,myTread是你自己線程的名字,可自定義。 |
piLock(int keyNum) | keyNum:0-3的值,每一個值代表一把鎖 | 使能同步鎖。wiringPi只提供了4把鎖,也就是keyNum只能取0~3的值,官方認為有這4把鎖就夠了。 keyNum:0,1,2,3 每一個數字就代表一把鎖。 源代碼: void piLock (int keyNum)
|
piUnlock(int keyNum) | keyNum:0-3的值,每一個值代表一把鎖 | 解鎖,或者說讓出鎖。 源代碼: void piUnlock (int key) |
int piHiPri (int priority) | priority:優先級指數,0~99 返回值:0,成功 -1:,失敗 |
設定線程的優先級,設定線程的優先級變高,不會使程序運行加快,但會使這個線程獲得相當更多的時間片。priority是相對的。比如你的程序只用到了主線程, 和另一個線程A,主線程設定優先級為1,A線程設定為2,那也代表A比main線程優先級高。 |
凡是涉及到多線程編程,就會涉及到線程安全的問題,多線程訪問同一個數據,需要使用同步鎖來保障數據操作正確性和符合預期。
當A線程鎖上 鎖S 后,其他共用這個鎖的競爭線程,只能等到鎖被釋放,才能繼續執行。
成功執行了piLock 函數的線程將擁有這把鎖。其他線程想要擁有這把鎖必須等到這個線程釋放鎖,也就是這個線程執行piUnlock后。
同時要擴展的知識是:volatile 這個C/C++中的關鍵字,它請求編譯器不緩存這個變量的數據,而是每次都從內存中讀取。特別是在多線程下共享放變量,必須使用volatile關鍵字聲明才是保險的。
softPwm,軟件實現的PWM
樹莓派硬件上支持的PWM輸出的引腳有限,為了突破這個限制,wiringPi提供了軟件實現的PWM輸出API。
需要包含頭文件:#include <softPwm.h>
編譯時需要添pthread庫鏈接 -lpthread
int softPwmCreate (int pin, int initialValue, int pwmRange) | pin:用來作為軟件PWM輸出的引腳 initalValue:引腳輸出的初始值 pwmRange:PWM值的范圍上限 建議使用100. 返回:0表示成功。 |
使用一個指定的pin引腳創建一個模擬的PWM輸出引腳 |
void softPwmWrite (int pin, int value) | pin:通過softPwmCreate創建的引腳 value:PWM引腳輸出的值 |
更新引腳輸出的PWM值 |
串口通信
使用時需要包含頭文件:#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建議使用這個函數。 |
初次使用樹莓派串口編程,需要配置。我開始搞了很久,以為是程序寫錯了 還一直在調試。。。(~ ̄— ̄)~
/* 修改 cmdline.txt文件 */ >cd /boot/ >sudo vim cmdline.txt
刪除【】之間的部分 dwc_otg.lpm_enable=0 【console=ttyAMA0,115200】 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait /*修改 inittab文件 */ >cd /etc/ >sudo vim inittab 注釋掉最后一行內容:,在前面加上 # 號 #T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100 sudo reboot 重啟
下面是雙機通信的一個例子
C51代碼,作為串口通信的接發送。serial庫請看另一篇文章

#include<reg52.h> #include"serial.h" /**********function****************/ bit isOpenPressed(void); bit isClosePressed(void); void delay(unsigned int t); /*********************************/ sbit closeButton = P2^0; //與關閉按鍵相連的引腳 sbit openButton = P2^1; //與打開按鍵相連的引腳 void main(void) { closeButton = 1; //拉高 openButton = 1; //拉高 EA =1; //打開總中斷 serial_init(9600); //初始化51串口 while(1) { if(isClosePressed()) //如果關閉按鈕按下 { serial_write(0); //發送數據 0給樹莓派 delay(10); } else if(isOpenPressed()) //如果打開按鈕按下 { serial_write(1); //發送數據 1給樹莓派 delay(10); } } } bit isOpenPressed(void) { bit press =0; if(0==openButton) { delay(5); if(0==openButton) { while(!openButton) ; press = 1; } } return press; } bit isClosePressed(void) { bit press =0; if(0==closeButton) { delay(5); if(0==closeButton) { while(!closeButton) ; press = 1; } } return press; } void delay(unsigned int t) { unsigned int i ; unsigned char j; for(i = t;i>0;i--) for(j=120;j>0;j--) ; }
樹莓派代碼,作為串口通信的接收方

#include<iostream> #include<cstdlib> #include<wiringPi.h> #include<wiringSerial.h> using namespace std; void setup(); const int LEDPin = 11; int main() { setup(); int fd; //Linux 的思想是:將一切IO設備,都看做 文件,fd就是代表串口抽象出來的文件 if((fd = serialOpen("/dev/ttyAMA0",9600))==-1) //初始化串口,波特率9600 { cerr<<"serial open error"<<endl; exit(-1); } while(true) { if(serialDataAvail(fd) >= 1) //如果串口緩存中有數據 { int data = serialGetchar(fd); if(data==0) //接受到51發送的 數據 0 { // close led digitalWrite(LEDPin,LOW); } else if(data==1) //接受到51發送的 數據 1 { //open led digitalWrite(LEDPin,HIGH); } } } return 0; } void setup() { if(-1==wiringPiSetup()) { cerr<<"set up error"<<endl; exit(-1); } pinMode(LEDPin,OUTPUT); digitalWrite(LEDPin,HIGH); }
shift移位寄存器芯片API
需要包含頭文件 #include <wiringShift.h>
void shiftOut (uint8_t dPin, uint8_t cPin, uint8_t order, uint8_t val) | dPin:移位芯片的串行數據入口引腳,比如74HC595的SER腳 cPin:移位芯片的時鍾引腳。如74HC595的11腳 order: LSBFIRST 先發送數據的低位 MSBFIRST先發送數據的高位
val:要發送的8位數據 |
將val串化,通過芯片轉化為並行輸出 如常見的74HC595 |
uint8_t shiftIn (uint8_t dPin, uint8_t cPin, uint8_t order) |
同上。 | 將並行數據,通過芯片轉化為串行輸出。 |
用過595的都知道還有一個引腳:12腳,Rpin,用於把移位寄存器中的數據更新到存儲寄存器中,然后wiringPi的API中沒有使用這個引腳。我建議使用的時候自己加上。

#include<iostream> #include<wiringPi.h> #include <wiringShift.h> #include<cstdlib> using namespace std; const int SERpin = 1; //serial data input const int SCKpin = 2; //shift register clock const int RCKpin = 3; // storage register clock /************************/ void setup(); /*************************/ int main() { setup(); for(int i=0;i<8;++i) { digitalWrite(RCKpin,LOW); shiftOut(SERpin,SCKpin,LSBFIRST,1<<i); digitalWrite(RCKpin,HIGH); delay(800); } return 0; } void setup() { if(-1==wiringPiSetup()) { cerr<<"setup error\n"; exit(-1); } pinMode(SERpin,OUTPUT); pinMode(RCKpin,OUTPUT); pinMode(SCKpin,OUTPUT); }
樹莓派硬件平台特有的API
並沒有列全,我只是列出了相對來說有用的,其他的,都基本不會用到。
pwmSetMode (int mode) | mode:PWM運行模式 |
設置PWM的運行模式。 pwm發生器可以運行在2種模式下,通過參數指定: |
pwmSetRange (unsigned int range) | range,范圍的最大值 0~range |
設置pwm發生器的數值范圍,默認是1024 |
pwmSetClock (int divisor) | This sets the divisor for the PWM clock. To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual. |
|
piBoardRev (void) | 返回:樹莓派板子的版本編號 1或者2 |
/ |
就這樣,以后會更新。
歡迎轉載,請注明出處:www.cnblogs.com/lulipro
為了獲得更好的閱讀體驗,請訪問原博客地址。
限於本人水平,如果文章和代碼有表述不當之處,還請不吝賜教。
代碼鋼琴家