樹莓派外設小開發(繼電器、語音模組、超聲波模組)

2020-08-10 10:03:23

wiringPi庫安裝與檢視

首先要瞭解wiringPi庫
wiringPi是一個很棒的樹莓派IO控制庫,使用C語言開發,提供了豐富的介面:GPIO控制,中斷,多執行緒,等等。
驗證wiringPi的是否安裝成功,輸入gpio -v,會在終端中輸出相關wiringPi的資訊。
在这里插入图片描述
檢視樹莓派的引腳編號

gpio readall

在这里插入图片描述

wiringPi庫API大全

在使用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插口的電風扇,應該還有很多東西可以控制,後期會繼續去做。語音模組的全部程式碼後期我會放上去