樹莓派的接口:
大而簡單的類別:IO口,input和output是相對于主控芯片來說的,是根據MCU和外設之間的關系將IO口的功能分為output和input。當IO作為input使用時外設有:人體傳感器、煙霧傳感器、火焰傳感器、振動傳感器等等;當IO作為output使用時的外設有:繼電器、蜂鳴器等等。 PWM輸出IO口用來電機調速、燈光調亮度等等、串口、IIC、SPI、IIS和其他特定硬件的接口等等。 像我們之前接觸過的C51、STM32、Arduino等等這類的單片機是直接基于裸機的開發,而像樹莓派、Nanopi、Tiny210這些設備是基于操作系統的,裸機的驅動和操作系統的驅動還是有很大的區別的。 樹莓派外設開發接口庫:WiringPi庫(就是別人幫你做好的很多的接口很多的API你只需要了解如何調用這些API和了解這些API如何使用就好,他就是特定平臺特定功能的接口組成的庫)至于API是如何驅動硬件工作的,后面會在驅動這一塊詳細講解。
WiringPi庫詳解: wiringPi是一個很棒的樹莓派IO控制庫,使用C語言開發,提供了豐富的接口:GPIO控制,中斷,多線程,等等。自己的樹莓派可能會有這個庫也有可能沒有,在樹莓派終端輸入指令:gpio -v查看有沒有裝WiringPi庫,出現下圖所示表示已經有WiringPi庫了(這里的版本是2.50) 如果沒有裝的話,它會提示指令不認識,可以根據以下步驟安裝:
進入 wiringPi 下載安裝包。然后進入安裝包所在的目錄執行以下命令:
tar xfz wiringPi-98bcb20.tar.gz //98bcb20為版本標號,可能不同 cd wiringPi-98bcb20 ./build
當然也可以通過終端命令來安裝WiringPi庫,安裝Git如果你的系統還沒有安裝Git版本控制工具,請先安裝Git:輸入命令:sudo apt-get install git-core下載wiringPi庫輸入命令:git clone git://git.drogon.net/wiringPi安裝輸入命令:cd wiringPi和./build安裝完成后,測試是否安裝成功輸入命令:gpio -v 接下來就是WringPi庫的使用了,使用gpio readall可以查看樹莓派GPIO的功能分布,還有就是使用樹莓派的時候如果用到WringPi庫編譯時要鏈上樹莓派的WringPi庫就像之前的使用多線程編程一樣,-lwiringPi
WringPi庫API大全:
硬件初始化函數,使用wiringPi時,你必須在執行任何操作前初始化樹莓派,否則程序不能正常工作。可以調用下表函數之一進行初始化,它們都會返回一個int , 返回 -1 表示初始化失敗。 在使用wiringPi庫時,你需要包含頭文件 #include<wiringPi.h>。凡是寫wiringPi的程序,都包含這個頭文件。
int wiringPiSetup ( void )
說明:當使用這個函數初始化樹莓派引腳時,程序使用的是wiringPi 引腳編號表。引腳的編號為
0 ~ 16 需要root權限返回值:返回
: 執行狀態,
- 1 表示失敗
int wiringPiSetupGpio ( void )
說明:當使用這個函數初始化樹莓派引腳時,程序中使用的是BCM GPIO 引腳編號表。需要root權限返回值:返回執行狀態,
- 1 表示失敗
wiringPiSetupPhys ( void ) 和
wiringPiSetupSys ( void ) 不太常用,不做介紹。
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.3 v
功能:對一個設置IO模式為 INPUT 的輸入引腳設置拉電阻模式。與Arduino不同的是,樹莓派支持的拉電阻模式更豐富。樹莓派內部的拉電阻達
50 K歐姆
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 ) )
功能:注冊的函數會在中斷發生時執行和
51 單片機不同的是:這個注冊的中斷處理函數會和main函數并發執行(同時執行,誰也不耽誤誰)當本次中斷函數還未執行完畢,這個時候樹莓派又觸發了一個中斷,那么這個后來的中斷不會被丟棄,它仍然可以被執行。但是wiringPi最多可以跟蹤并記錄后來的僅僅
1 個中斷,如果不止
1 個,則他們會被忽略,得不到執行。
參數:pin:接受中斷信號的引腳edgeType:觸發的方式。INT_EDGE_FALLING:下降沿觸發INT_EDGE_RISING:上升沿觸發INT_EDGE_BOTH :上下降都會觸發INT_EDGE_SETUP:編程時用不到。 function:中斷處理函數的指針,它是一個無返回值,無參數的函數。
多線程:wiringPi提供了簡單的Linux系統下的通用的 Posix threads線程庫接口來支持并發。因為之前學習過linux多線程的開發,所以一般不用這個WringPi庫里面的多線程函數,他這里面的函數也是機=基于linux線程封裝的
int piThreadCreate ( name
)
參數:name
: 被包裝的線程執行函數
返回值:狀態碼。返回
0 表示成功啟動,反之失敗。
源代碼:
int piThreadCreate ( void * ( * fn
) ( void * ) )
{ pthread_t myThread
; return pthread_create ( & myThread
, NULL , fn
, NULL ) ;
}
包裝一個用PI_THEEAD定義的函數為一個線程,并啟動這個線程。
首先你需要通過以下方式創建一個特特殊的函數。這個函數中的代碼就是在新的線程中將執行的代碼。myTread是你自己線程的名字,可自定義。
PI_THREAD ( myThread
)
{
}
在wiringPi
. h中,我發現這樣一個宏定義:#define
PI_THREAD ( X
) void * X ( void * dummy
)
那么,被預處理后我們寫的線程函數會變成下面這個樣子,請注意返回值,難怪我每次寫都會警告,因為沒有返回一個指針,
那么,以后注意返回
NULL ,或者
( void * ) 0
void * myThread ( void * dummy
)
{
} piLock ( int keyNum
)
功能:使能同步鎖。wiringPi只提供了
4 把鎖,也就是keyNum只能取
0 ~ 3 的值,官方認為有這
4 把鎖就夠了。
參數:keyNum:
0 , 1 , 2 , 3 每一個數字就代表一把鎖。
源代碼:
void piLock ( int keyNum
)
{ pthread_mutex_lock ( & piMutexes
[ keyNum
] ) ;
} piUnlock ( int keyNum
)
功能:解鎖,或者說讓出鎖。
參數:keyNum
: 0 - 3 的值,每一個值代表一把鎖
解鎖,或者說讓出鎖。
源代碼:
void piUnlock ( int key
)
{ pthread_mutex_unlock ( & piMutexes
[ key
] ) ;
} int piHiPri ( int priority
)
功能:設定線程的優先級,設定線程的優先級變高,不會使程序運行加快,但會使這個線程獲得相當更多的時間片。priority是相對的。比如你的程序只用到了主線程和另一個線程A,主線程設定優先級為
1 ,A線程設定為
2 ,那也代表A比main線程優先級高。
參數:priority:優先級指數,
0 ~ 99
返回值:
0 :成功
, - 1 : 失敗。
softPwm,軟件實現的PWM,樹莓派硬件上支持的PWM輸出的引腳有限,為了突破這個限制,wiringPi提供了軟件實現的PWM輸出API。需要包含頭文件:#include <softPwm.h>編譯時需要添pthread庫鏈接 -lpthread
int softPwmCreate ( int pin
, int initialValue
, int pwmRange
)
功能:使用一個指定的pin引腳創建一個模擬的PWM輸出引腳
參數:pin:用來作為軟件PWM輸出的引腳initalValue:引腳輸出的初始值pwmRange:PWM值的范圍上限,建議使用
100.
返回:
0 表示成功。
void softPwmWrite ( int pin
, int value
)
功能:更新引腳輸出的PWM值
參數:pin:通過softPwmCreate創建的引腳value: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
, …
)
功能:像使用C語言中的printf一樣發送數據到串口
參數:fd:文件描述符message:格式化的字符串
int serialDataAvail ( int fd
)
功能:獲取串口緩存中可用的字節數。
參數:fd:文件描述符
返回:串口緩存中已經接收的,可讀取的字節數,
- 1 代表錯誤
int serialGetchar ( int fd
)
功能:從串口讀取一個字節數據返回。如果串口緩存中沒有可用的數據,則會等待
10 秒,如果
10 后還有沒,返回
- 1 所以,在讀取前,做好通過serialDataAvail判斷下。
參數:fd:文件描述符
返回:讀取到的字符
void serialFlush ( int fd
)
功能:刷新,清空串口緩沖中的所有可用的數據。
參數:fd:文件描述符
* size_t write ( int fd
, const void * buf
, size_t count
)
功能:這個是Linux下的標準IO庫函數,需要包含頭文件#include
< unistd
. h
> 當要發送到的數據量過大時,wiringPi建議使用這個函數。
* size_t read ( int fd
, void * buf
, size_t count
) ;
功能:這個是Linux下的標準IO庫函數,需要包含頭文件#include
< unistd
. h
> 當要接收的數據量過大時,wiringPi建議使用這個函數。
參數:fd:文件描述符buf:接受的數據緩存的數組count
: 接收的字節數
.
返回:實際讀取的字符數。
> 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
> cd
/ etc
/
> sudo vim inittab
注釋掉最后一行內容
: ,在前面加上 # 號
# T0: 23 : respawn: / sbin/ getty - L ttyAMA0 115200 vt100
sudo reboot 重啟
shift移位寄存器芯片API,需要包含頭文件 #include <wiringShift.h>,用過595的都知道還有一個引腳:12腳,Rpin,用于把移位寄存器中的數據更新到存儲寄存器中,然后wiringPi的API中沒有使用這個引腳。我建議使用的時候自己加上。
void shiftOut ( uint8_t dPin
, uint8_t cPin
, uint8_t order
, uint8_t val
)
功能:將val串化,通過芯片轉化為并行輸出,如常見的
74 HC595
參數:dPin:移位芯片的串行數據入口引腳,比如
74 HC595的SER腳cPin:移位芯片的時鐘引腳。如
74 HC595的
11 腳order:LSBFIRST 先發送數據的低位MSBFIRST先發送數據的高位
val:要發送的
8 位數據
uint8_t shiftIn ( uint8_t dPin
, uint8_t cPin
, uint8_t order
)
功能:將并行數據,通過芯片轉化為串行輸出。
參數同上。
樹莓派硬件平臺特有的API,并沒有列全,我只是列出了相對來說有用的,其他的,都基本不會用到。pwmSetMode、pwmSetRange、pwmSetClock函數應該都是硬件PWM的函數。
pwmSetMode ( int mode
)
功能:設置PWM的運行模式。pwm發生器可以運行在
2 種模式下,通過參數指定:PWM_MODE_BAL:樹莓派默認的PWM模式PWM_MODE_MS:傳統的pwm模式
參數:mode:PWM運行模式
pwmSetRange ( unsigned int range
)
功能:設置pwm發生器的數值范圍,默認是
1024
參數:range,范圍的最大值,
0 ~ range
pwmSetClock ( int divisor
)
功能:這設置了PWM時鐘的除數默認是
32 分頻,也就是
19.2 / 32 = 600 KHZ,因此不調用此函數,pwm的默認工作時鐘為
600 KHz
. piBoardRev ( void )
返回:樹莓派板子的版本編號,
1 或者
2 。
Wringpi庫部分參考博客:https://ww.cnblogs.com/lulipro/p/5992172.html
使用指令uname -r查看樹莓派的版本,下載linux內核源碼的時候可以使用。
使用樹莓派控制第一個外設——繼電器模塊:
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <wiringPi.h>
int main ( )
{ int initReturn
; char * cmd
; cmd
= ( char * ) malloc ( 128 ) ; initReturn
= wiringPiSetup ( ) ; if ( initReturn
== - 1 ) printf ( "init fail\n" ) ; pinMode ( 1 , OUTPUT
) ; while ( 1 ) { memset ( cmd
, '\0' , 128 ) ; printf ( "please input cmd\n" ) ; scanf ( "%s" , cmd
) ; if ( strcmp ( cmd
, "open" ) == 0 ) digitalWrite ( 1 , LOW
) ; else if ( strcmp ( cmd
, "close" ) == 0 ) digitalWrite ( 1 , HIGH
) ; memset ( cmd
, '\0' , 128 ) ; } return 0 ;
}
上面是控制繼電器的代碼,編譯的時候要使用指令gcc switch.c -o switch -lwiringPi注意:要加上wiringPi庫
樹莓派外設——超聲波模塊:
超聲波模塊上面通常有兩個超聲波元器件,一個用于發射,一個用于接收。電路板上有四個引腳:VCC(正極)、Trig(觸發)、Echo(接收)、GND(接地) 超聲波的主要參數:工作電壓與電流:5V、15mA;測距范圍:2~400cm;感測角度:不大于15°;被測物的面積不要小于50平方厘米并且盡量平整;具備溫度補償電路 工作原理:在超聲波的觸發腳位輸入10微妙以上的高電位,即可發射超聲波,發射超聲波以后與接收傳回的超聲波之前,“接收引腳”呈現高電位,因此,程序可以從“接收引腳”的高電位脈沖持續時間,換算出被測物的距離。
# include <stdio.h>
# include <wiringPi.h>
# define Echo 4
# define Trige 5
int main ( )
{ int timeone
, timetwo
; float distance
; wiringPiSetup ( ) ; pinMode ( Trige
, OUTPUT
) ; pinMode ( Echo
, INPUT
) ; while ( 1 ) { digitalWrite ( Trige
, LOW
) ; delayMicroseconds ( 2 ) ; digitalWrite ( Trige
, HIGH
) ; delayMicroseconds ( 10 ) ; digitalWrite ( Trige
, LOW
) ; while ( digitalRead ( Echo
) != HIGH
) ; timeone
= micros ( ) ; while ( digitalRead ( Echo
) == HIGH
) ; timetwo
= micros ( ) ; distance
= ( float ) ( timetwo
- timeone
) / 58 ; printf ( "distance is %0.2f cm\n" , distance
) ; delay ( 100 ) ; } return 0 ;
}
上面那個超聲波測距的程序是我自己寫的,下面這個是從網上查找的,感覺比我寫的高大上。
# include <wiringPi.h>
# include <stdio.h>
# include <sys/time.h>
# define Trig 4
# define Echo 5 void ultraInit ( void )
{ pinMode ( Echo
, INPUT
) ; pinMode ( Trig
, OUTPUT
) ;
} float disMeasure ( void )
{ struct timeval tv1
; struct timeval tv2
; long start
, stop
; float dis
; digitalWrite ( Trig
, LOW
) ; delayMicroseconds ( 2 ) ; digitalWrite ( Trig
, HIGH
) ; delayMicroseconds ( 10 ) ; digitalWrite ( Trig
, LOW
) ; while ( digitalRead ( Echo
) != 1 ) ) ; gettimeofday ( & tv1
, NULL ) ; while ( ! ( digitalRead ( Echo
) == 0 ) ) ; gettimeofday ( & tv2
, NULL ) ; start
= tv1
. tv_sec
* 1000000 + tv1
. tv_usec
; stop
= tv2
. tv_sec
* 1000000 + tv2
. tv_usec
; dis
= ( float ) ( stop
- start
) / 1000000 * 34000 / 2 ; return dis
;
} int main ( void )
{ float dis
; if ( wiringPiSetup ( ) == - 1 ) { printf ( "setup wiringPi failed !" ) ; return 1 ; } ultraInit ( ) ; while ( 1 ) { dis
= disMeasure ( ) ; printf ( "distance = %0.2f cm\n" , dis
) ; delay ( 1000 ) ; } return 0 ;
}
# include "sys/time.h"
struct timeval
{
__time_t tv_sec
;
__suseconds_t tv_usec
;
} ;
用法很簡單,先定義時間結構體變量,然后使用gettimeofday(&tv_b,NULL)函數獲取當前時間,然后就可以計算出來時間差。示例如下:
gettimeofday ( & tv_b
, NULL ) ;
gettimeofday ( & tv_d
, NULL ) ;
timeconsumed
= tv_d
. tv_sec
- tv_b
. tv_sec
+ ( tv_d
. tv_usev
- tv_b
. tv_usec
) / 1000000 ;
總結
以上是生活随笔 為你收集整理的树莓派GPIO口的使用(外设相关开发WringPi库的使用,超声波、继电器) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。