首先要瞭解wiringPi庫
wiringPi是一個很棒的樹莓派IO控制庫,使用C語言開發,提供了豐富的介面:GPIO控制,中斷,多執行緒,等等。
驗證wiringPi的是否安裝成功,輸入gpio -v,會在終端中輸出相關wiringPi的資訊。
檢視樹莓派的引腳編號
gpio readall
在使用wiringPi庫時,你需要包含標頭檔案 #include<wiringPi.h>。凡是寫wiringPi的程式,都包含這個標頭檔案。
硬體初始化函數
|int wiringPiSetup (void)| 返回:執行狀態,-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歐姆 |
還有很多函數可以參考:https://www.cnblogs.com/lulipro/p/5992172.html
#include <stdio.h>
#include <wiringPi.h>
#define SWITCH 7
int main()
{
int cmd;
int ret = wiringPiSetup();//初始化硬體介面
if(ret == -1){
printf("硬體介面初始化失敗\n");
return -1;
}
//void pinMode (int pin, int mode) pin:設定的引腳 mode:指定引腳的IO模式 可取的值:INPUT、OUTPUT、PWM_OUTPUT,GPIO_CLOCK
pinMode(SWITCH,OUTPUT);//把樹莓派7引腳設定爲輸出引腳
digitalWrite(SWITCH,HIGH);//剛上電繼電器保持斷開狀態
while(1){
printf("請輸入0或1 0是給個高電平,1是給個低電平\n");
scanf("%d",&cmd);
if(cmd == 0){
//void digitalWrite (int pin, int value) pin:控制的引腳 value:引腳輸出的電平值。 可取的值:HIGH,LOW分別代表高低電平
digitalWrite(SWITCH,HIGH);//高電平繼電器斷開
}else if(cmd == 1){
digitalWrite(SWITCH,LOW);//低電平繼電器閉合
}else{
printf("輸入的指令不正確\n");
}
}
return 0;
}
當輸入1的時候,給了個低電平,繼電器裏面吸片閉合,成導通狀態
當輸入0的時候,給了個高電平,繼電器裏面吸片鬆開 ,成斷開狀態
接線
程式碼
#include <stdio.h>
#include <wiringPi.h>
#include <string.h>
#define SWITCH4 26
#define SWITCH3 27
#define SWITCH2 28
#define SWITCH1 29
int initPin()
{
int ret = wiringPiSetup();//初始化樹莓派引腳
if(ret == -1){
printf("初始化失敗\n");
return -1;
}
pinMode(SWITCH4,OUTPUT);//設定引腳爲輸出引腳
pinMode(SWITCH3,OUTPUT);
pinMode(SWITCH2,OUTPUT);
pinMode(SWITCH1,OUTPUT);
digitalWrite(SWITCH4,HIGH);//一上電保持斷開狀態
digitalWrite(SWITCH3,HIGH);
digitalWrite(SWITCH2,HIGH);
digitalWrite(SWITCH1,HIGH);
}
void allOn()
{
digitalWrite(SWITCH4,LOW);//一上電保持斷開狀態
digitalWrite(SWITCH3,LOW);
digitalWrite(SWITCH2,LOW);
digitalWrite(SWITCH1,LOW);
}
void allOff()
{
digitalWrite(SWITCH4,HIGH);//一上電保持斷開狀態
digitalWrite(SWITCH3,HIGH);
digitalWrite(SWITCH2,HIGH);
digitalWrite(SWITCH1,HIGH);
}
int main()
{
char cmd[32]={'\0'};
initPin();
while(1){
memset(cmd,'\0',sizeof(cmd));
printf("請輸入指令\n");
gets(cmd);
if(strcmp(cmd,"1 on") == 0){
digitalWrite(SWITCH1,LOW);
}else if(strcmp(cmd,"1 off") == 0){
digitalWrite(SWITCH1,HIGH);
}
if(strcmp(cmd,"2 on") == 0){
digitalWrite(SWITCH2,LOW);
}else if(strcmp(cmd,"2 off") == 0){
digitalWrite(SWITCH2,HIGH);
}
if(strcmp(cmd,"3 on") == 0){
digitalWrite(SWITCH3,LOW);
}else if(strcmp(cmd,"3 off") == 0){
digitalWrite(SWITCH3,HIGH);
}
if(strcmp(cmd,"4 off") == 0){
digitalWrite(SWITCH4,LOW);
}else if(strcmp(cmd,"4 off") == 0){
digitalWrite(SWITCH4,HIGH);
}
if(strcmp(cmd,"all on") == 0){
allOn();
}else if(strcmp(cmd,"all off") == 0){
allOff();
}
}
return 0;
}
效果和上方單個繼電器一樣不做比較了
超聲波的工作原理
接線
程式碼
#include <stdio.h>
#include <sys/time.h>
#include <wiringPi.h>
#define Trig 4
#define Echo 5
void initUltra()
{
pinMode(Trig,OUTPUT);//把Trig設定爲輸出引腳
pinMode(Echo,INPUT);//把Echo設定爲輸入引腳
}
int initWringPiSetup()
{
int ret = wiringPiSetup();//初始化樹莓派的引腳
if(ret == -1){
printf("樹莓派引腳初始化失敗\n");
return -1;
}
}
float disMeasure()
{
/*struct timeval
{
__time_t tv_sec; //秒
__suseconds_t tv_usec; //微妙
};*/
struct timeval t1;
struct timeval t2;
long start;
long stop;
float dis;
digitalWrite(Trig,LOW);
delayMicroseconds(2);//延時兩微秒
digitalWrite(Trig,HIGH);
delayMicroseconds(10);//發出超聲波脈衝
digitalWrite(Trig,LOW);
while(!(digitalRead(Echo)== 1));
gettimeofday(&t1, NULL);//獲取當前時間 ,等待接受返回信號
while(!(digitalRead(Echo) == 0));
gettimeofday(&t2, NULL);//獲取當前時間,接收到返回信號的時候
start = t1.tv_sec * 1000000 + t1.tv_usec;//算出是多少微妙
stop = t2.tv_sec * 1000000 + t2.tv_usec;
dis = (float)(stop - start) / 1000000 * 34000 / 2; //計算距離
return dis;
}
int main(int argc, char const *argv[])
{
float dis;
initWringPiSetup();//初始化樹莓派引腳
initUltra();//初始化超聲波
while(1){
dis = disMeasure();
printf("距離是:%0.2f cm\n",dis);//保留兩位小數
delay(1000);//延時
}
return 0;
}
結果
串列埠通訊
使用時需要包含標頭檔案:#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 重新啓動
程式碼例子
發送字元每隔一秒
#include <wiringSerial.h>
#include <stdio.h>
#include <wiringPi.h>
int initWiringPiSetuo()
{
int ret = wiringPiSetup();
if(ret == -1){
printf("樹莓派初始化失敗\n");
return -1;
}
}
int main()
{
int fd;//Linux 的思想是:將一切IO裝置,都看做 檔案,fd就是代表串列埠抽象出來的檔案
initWiringPiSetuo();
fd = serialOpen("/dev/ttyAMA0",9600);
if( fd == -1){
printf("開啓串列埠失敗\n");
return -1;
}
while(1){
serialPutchar(fd,'j');
delay(1000);
}
return 0;
}
發送字串
#include <wiringSerial.h>
#include <stdio.h>
#include <wiringPi.h>
int initWiringPiSetuo()
{
int ret = wiringPiSetup();
if(ret == -1){
printf("樹莓派初始化失敗\n");
return -1;
}
}
int main()
{
int fd;//Linux 的思想是:將一切IO裝置,都看做 檔案,fd就是代表串列埠抽象出來的檔案
initWiringPiSetuo();
fd = serialOpen("/dev/ttyAMA0",9600);
if( fd == -1){
printf("開啓串列埠失敗\n");
return -1;
}
while(1){
serialPuts(fd,"hello world\r\n");
delay(1000);
}
return 0;
}
串列埠向樹莓派發送資訊
程式碼
#include <wiringSerial.h>
#include <stdio.h>
#include <wiringPi.h>
int initWiringPiSetuo()
{
int ret = wiringPiSetup();
if(ret == -1){
printf("樹莓派初始化失敗\n");
return -1;
}
}
int main()
{
int fd;//Linux 的思想是:將一切IO裝置,都看做 檔案,fd就是代表串列埠抽象出來的檔案
int cmd;
initWiringPiSetuo();
fd = serialOpen("/dev/ttyAMA0",9600);
if( fd == -1){
printf("開啓串列埠失敗\n");
return -1;
}
while(1){
while(serialDataAvail(fd) != -1){
cmd = serialGetchar(fd);
printf("get data:%d\n",cmd);
}
}
return 0;
}
這把發送的是3的ASCLL碼
實現雙方通訊
#include <wiringSerial.h>
#include <stdio.h>
#include <wiringPi.h>
int initWiringPiSetuo()
{
int ret = wiringPiSetup();
if(ret == -1){
printf("樹莓派初始化失敗\n");
return -1;
}
}
int main()
{
int fd;//Linux 的思想是:將一切IO裝置,都看做 檔案,fd就是代表串列埠抽象出來的檔案
int cmd;
initWiringPiSetuo();
fd = serialOpen("/dev/ttyAMA0",9600);
if( fd == -1){
printf("開啓串列埠失敗\n");
return -1;
}
while(1){
while(serialDataAvail(fd) != -1){
cmd = serialGetchar(fd);
if(cmd == '2'){
serialPuts(fd,"hello world 2\r\n");
printf("get data : %d\n",cmd);
}else if(cmd == '3'){
serialPuts(fd,"hello world 3\r\n");
printf("get data : %d\n",cmd);
}else if(cmd == '4'){
serialPuts(fd,"hello world 4\r\n");
printf("get data : %d\n",cmd);
}else{
serialPuts(fd,"sorry\r\n");
printf("get data : %d\n",cmd);
}
}
}
return 0;
}
語音模組在這裏不作詳細介紹了
選擇其中一些程式碼
case CODE_DMCS: /*命令「測試」*/
//PrintCom("收到\r\n"); /*text.....*/
break;
case CODE_KFBYZ: /*命令「全開」*/
//PrintCom("「開發板驗證」命令識別成功\r\n"); /*text.....*/
break;
case CODE_KD: /*命令「復位」*/
PrintCom("turn on light\r\n"); /*text.....*/
break;
case CODE_GD: /*命令「復位」*/
PrintCom("guan deng\r\n"); /*text.....*/
break;
case CODE_KFS: /*命令「復位」*/
PrintCom("open fengshan\r\n"); /*text.....*/
break;
case CODE_GFS: /*命令「復位」*/
PrintCom("close fengshan\r\n"); /*text.....*/
break;
uint8 code sRecog[DATE_A][DATE_B] = {
"xiao ai",\
"kai fa ban yan zheng",\
"dai ma ce shi",\
"kai deng",\
"guan deng",\
"kai feng shan",\
"guan feng shan",\
"kai dian shi"
}; /*新增關鍵詞,使用者修改*/
樹莓派程式碼
#include <stdio.h>
#include <string.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <unistd.h>
#define SWITCH4 26
#define SWITCH3 27
#define SWITCH2 28
#define SWITCH1 29
int initwiringPiSetup()
{
int ret = wiringPiSetup();
if(ret == -1){
printf("樹莓派初始化失敗\n");
return -1;
}
}
void initPin()
{
pinMode(SWITCH4,OUTPUT);//設定引腳爲輸出引腳
pinMode(SWITCH3,OUTPUT);//設定引腳爲輸出引腳
pinMode(SWITCH2,OUTPUT);//設定引腳爲輸出引腳
pinMode(SWITCH1,OUTPUT);//設定引腳爲輸出引腳
digitalWrite(SWITCH4,HIGH);//一上點保持斷開狀態
digitalWrite(SWITCH3,HIGH);//一上點保持斷開狀態
digitalWrite(SWITCH2,HIGH);//一上點保持斷開狀態
digitalWrite(SWITCH1,HIGH);//一上點保持斷開狀態
}
int main(int argc, char const *argv[])
{
int fd;
int n_read;
char cmd[128]={'\0'};
initwiringPiSetup();
initPin();
fd = serialOpen("/dev/ttyAMA0",9600);//開啓串列埠通訊
while(1){
n_read = read(fd,cmd,sizeof(cmd));
if(strlen(cmd) == 0){
printf("超時。。。。。\n");
continue;
}
if(strstr(cmd,"turn") != NULL){
digitalWrite(SWITCH4,LOW);//導通繼電器4(開燈)
printf("開燈\n");
}
if(strstr(cmd,"guan") != NULL){
digitalWrite(SWITCH4,HIGH);//阻塞繼電器4(關燈)
printf("關燈\n");
}
if(strstr(cmd,"open") != NULL){
digitalWrite(SWITCH3,LOW);//導通繼電器3(開風扇)
printf("開風扇\n");
}
if(strstr(cmd,"close") != NULL){
digitalWrite(SWITCH3,HIGH);//阻塞繼電器3(關風扇)
printf("關風扇\n");
}
memset(cmd,'\0',sizeof(cmd)/sizeof(char));
}
return 0;
}
接線
樹莓派和語音模組
電機組合器
執行效果應該視訊最好,我這邊沒有上傳。目前我只連線了一個led燈和一個usb插口的電風扇,應該還有很多東西可以控制,後期會繼續去做。語音模組的全部程式碼後期我會放上去