這次給瓦力配的大腦是 ardiuno ,是不是聽起來很高貴冷的樣子,其實就是一塊avr單片機而已.....
arduino是意大利人發明的,把底層的代碼全部都封裝好了,所以程序寫起來就跟搭積木一樣,灰常簡單明了,沒有電子基礎的人都能用的來。而且它是開源的,人家寫好的東西很多可以直接用,翻個墻還可以看到很多好東西,不過妥妥的注釋全是英文,這個時候就很明顯看到了國內國外在個人做電設上的差距,先不說人家的模塊各種高大上,也不說人家的比賽各種多各種神奇,技術上咱們比不上人家。只是光是拿做模型模具的條件來說,國內的發展水平差太多了,木有辦法,神馬機械條件的使用都是要錢滴。
扯偏了,我給兒子duby一號初步要實現的功能是,語音識別,語音播放,超聲避障。暫時使用的模塊是LD3320語音識別,WTV020-SD語音播放,HC-SR04超聲測距,以及電機驅動,兩個直流減速電機和三個舵機,用的是 arduino nano V3.0控制器,arduino家族里面最小的一款,因為我兒子實在太小了放不下太多東西......還好性能不錯。
想做個兒子純粹是心血來潮= = ,有人證!!!不是為了泡妞好嗎。
許久沒有碰過電設了,連中斷定時器IO口神馬的知識都忘得差不多了。而且還腦殘選的一款木有很熟悉的單片機,要用的模塊也是一個都沒上手過,好吧,真的是一切從頭開始。依稀記得去年搭過一輛會唱歌的車子,用的也是arduino ,依稀記得當時用的代碼好像也是這里抄抄那里抄抄......結果本來想實現能寫字功能的沒實現就送掉了

demo,這次造兒子要認真一點,不可以再那么隨便。
接下來是技術貼,先上舵機程序,arduino有自己的庫,灰常簡單好用,去官網上看了人家的技術手冊,拿過來改改就可以用了。
#include<Servo.h>
char buffer[10];
Servo servo1;
void setup()
{
servo1.attach(5);
Serial.begin(9600); //波特率不是高頻通信時9600足矣
Serial.flush();
servo1.write(90); // 舵機打到90度!get !是不是很方便!!!
Serial.println("starting.....");
}
void loop()
{
if(Serial.available()>0)
{
int index=0;
delay(100);
int numchar=Serial.available();
if(numchar>10)
{
numchar=10;
}
while(numchar--)
{
buffer[index++]=Serial.read();
}spliString(buffer);
}
}
void spliString(char*data)
{
Serial.print("Data entered:");
Serial.println(data);
char*parameter;
parameter=strtok(data,",");
while(parameter!=NULL)
{
setServo(parameter);
parameter=strtok(NULL,","); //long int strtol(const char *nptr,char **endptr,int base); 我一直覺得這種突然出現的
自帶函數都是來給我添堵的。這個函數會將參數nptr字符串根據參數base來轉換
成長整型數。 新函數!get!
自帶函數都是來給我添堵的。這個函數會將參數nptr字符串根據參數base來轉換
成長整型數。 新函數!get!
}
for(int x=0;x<9;x++)
{
buffer[x]='\0';
}
Serial.flush();
}
void setServo(char*data)
{
if((data[0]=='L')||(data[0]=='l'))
{
int firstval=strtol(data+1,NULL,10);
firstval=constrain(firstval,0,180); // 限制!
servo1.write(firstval);
Serial.print("Servo1 is set to:");
Serial.println(firstval);
}
if((data[0]=='R')||(data[0]=='r'))
{
int secondval=strtol(data+1,NULL,10);
secondval=constrain(secondval,0,255);
servo1.write(secondval);
Serial.print("servo1 is set to:");
Serial.println(secondval);
}
}
這是控制單個舵機的程序,通過串口通信在PC端控制舵機。紅色線接6V電源,褐色線接地,橙色信號線接在D5口,因為要輸出的是PWM信號,在nano中只有3,5,6,9,10,11和13腳具有該功能,可以輸出模擬量,即固定脈沖。舵機轉動范圍是0~180度,現在的程序是上電時直接打到90度的位置。我用兩個18650供電,7806和7805穩壓。
改完這個程序瞬間覺得成就感滿滿有木有,接著就準備弄電機。我買的是uln2003,三毛五一片,用不起八塊一片的mos。依稀記得我很久很久以前用uln2003成功驅動過,所以我把自己給坑了。芯片搭好以后特么的就是木有輸出,查了各種之后,我笑了。它確實是能驅動....可是這玩意只適合驅動步進電機.....驅動直流電機的話只能走一個方向和停止,不能反轉.....要想反轉要用三極管加兩個臂,構成類似H橋的東西,或者是用它兩個口的反相器構建。早知這么麻煩,當時一定會買一個別的現成的,比如L298n.... 這是亂憑經驗的教訓。
ULN2003的接法為,8腳接地,9腳懸空,其他是input和outpu,一共七路,負載一端接電源,另一端接輸出。好像原理是集電極開路導通神馬的= = ,原諒我當年模電沒學好.......
程序木有寫,因為就一句digitalWrite(x,HIGH或者LOW)
x是arduino的信號輸出腳,輸出的是數字量,控制通斷。HIGH對應的是51里的高電平1,LOW對應的是低電平0,注意是要大寫。補充一點,所有的口都可以做數字口,都可以輸出HIGH 或者LOW。并不是標著A就只能做模擬口,模擬口只是那個腳特有的功能。
池老師突然覺得這篇日志好適合入門......
(⊙_⊙),困了,明天再寫。
昨天說到被電機驅動坑了,今天去實驗室轉悠的時候小城給了一個我心心念念的L298n,妥妥的正傳反轉180度360度隨意轉了好嗎。附程序:
int a1=3;
int b1=5;
int zuo1=0;
int zuo2=1;
int you1=2;
int you2=4;
void setup()
{
pinMode(0,OUTPUT);
pinMode(1,OUTPUT);
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
}
void loop()
{
qianjin(100,100,8000);
tingzhi();
houtui(100,100,8000);
tingzhi();
}
void qianjin(int zuo,int you,int chang)
{
digitalWrite(zuo1,HIGH);
digitalWrite(you1,HIGH);
digitalWrite(zuo2,LOW);
digitalWrite(you2,LOW);
analogWrite(a1,zuo);
analogWrite(b1,you);
delay(chang);
}
void tingzhi()
{analogWrite(a1,0);
analogWrite(b1,0);
digitalWrite(zuo1,LOW);
digitalWrite(you1,LOW);
digitalWrite(zuo2,LOW);
digitalWrite(you2,LOW);
delay(1000);
}
void houtui(int zuo,int you,int chang)
{
digitalWrite(zuo1,LOW);
digitalWrite(you1,LOW);
digitalWrite(zuo2,HIGH);
digitalWrite(you2,HIGH);
analogWrite(a1,zuo);
analogWrite(b1,you);
delay(chang);
}
void zuozhuan(int zuo)
{
analogWrite(b1,0);
digitalWrite(you2,LOW);
digitalWrite(you1,LOW);
digitalWrite(zuo1,HIGH);
digitalWrite(zuo2,LOW);
analogWrite(a1,100);
delay(zuo*50);
tingzhi();
}
void youzhuan(int you)
{
analogWrite(a1,0);
digitalWrite(zuo2,LOW);
digitalWrite(zuo1,LOW);
digitalWrite(you1,HIGH);
digitalWrite(you2,LOW);
analogWrite(b1,100);
delay(you*50);
tingzhi();
}
這個程序毫無修飾一看就知道是我寫的.....粗糙得一逼啊。
L298N可以驅動兩路直流電機或者步進電機,程序中a1,b1對應為模塊上的使能端A,B,使用pwm口輸出可以控制電機轉動的速度(即車速) ,值0~255,255代表5V,0代表0V,加1時步長為0.02V增量,此處取100可改。zuo1,zuo2和you1,you2是兩個電機各自的方向控制口,兩相不同時電機正反轉,同為低電平時電機不轉。
小記:nano 板上 pwm輸出口只有 3,5,6,7,9,10,11,13 ,用analogWrite()函數輸出,板上所有口均可做數字口輸出。
電機舵機這兩部分木有難的地方,畢竟這玩意上電就可以動彈。
接著我就開搞超聲波檢測距離的模塊。
這個程序毫無修飾一看就知道是我寫的.....粗糙得一逼啊。
L298N可以驅動兩路直流電機或者步進電機,程序中a1,b1對應為模塊上的使能端A,B,使用pwm口輸出可以控制電機轉動的速度(即車速) ,值0~255,255代表5V,0代表0V,加1時步長為0.02V增量,此處取100可改。zuo1,zuo2和you1,you2是兩個電機各自的方向控制口,兩相不同時電機正反轉,同為低電平時電機不轉。
小記:nano 板上 pwm輸出口只有 3,5,6,7,9,10,11,13 ,用analogWrite()函數輸出,板上所有口均可做數字口輸出。
電機舵機這兩部分木有難的地方,畢竟這玩意上電就可以動彈。
接著我就開搞超聲波檢測距離的模塊。

這東西長這樣,五塊一個。
這東西原理是,我們聲音發出去是會彈回來的對吧,就是基于這個原理。控制口發一個10US 以上的高電平,就可以在接收口等待高電平輸出.一有輸出就可以開定時器計時,當此口變為低電平時就可以讀定時器的值,此時就為此次測距的時間,方可算出距離.如此不斷的周期測,就可以達到你移動測量的值了。
找到的參考例程都是51之類的,還好這東西原理不難,憑我這樣子半吊子水平還能改改用,上程序
#define ECHOPIN 8
#define TRIGPIN 9
void setup()
{
Serial.begin(9600);
pinMode(ECHOPIN, INPUT);
pinMode(TRIGPIN, OUTPUT);
}
void loop()
{
digitalWrite(TRIGPIN, LOW);
delayMicroseconds(2); //制造脈沖
digitalWrite(TRIGPIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGPIN, LOW);
float distance = pulseIn(ECHOPIN, HIGH);
distance= distance/58;
Serial.println(distance);
delay(500);
}
} 這東西一共四個腳 ,一個是5V電源,一個是地,一個是ECHO一個是TRIG,這兩個是數據的收發口,連到單片機上。我們通過TRIG發送一個10us以上的脈沖,就是一個有高有低的方波,然后就可以檢測ECHO口的返回數據了,我們不用關心超聲波是如何發送又是如何接收的,只要知道我們給一個脈沖,就可以在ECHO口守株待兔,讀到一個高電平為止,然后把這中間的時間拿去處理就對了。
我們看到一個函數:
pulseIn()函數用來讀取一個引腳的脈沖(HIGH或LOW)。例如,如果value是HIGH,pulseIn()會等待引腳變為HIGH,開始計時,再等待引腳變為LOW并停止計時。返回脈沖的長度,單位毫秒。如果在指定的時間內無脈沖函數返回。
計時范圍從10微秒至3分鐘。(1秒=1000毫秒=1000000微秒)
語法:
pulseIn(pin, value)
pulseIn(pin, value, timeout)
參數:
pin:你要進行脈沖計時的引腳號(int)。
value:要讀取的脈沖類型,HIGH或LOW(int)。
timeout (可選):指定脈沖計數的等待時間,單位為微秒,默認值是1秒(unsigned long) 這是一個灰常方便的函數,我愛arduino。
讀到的東西是英寸單位,所以要除以58,這樣一來就能化成厘米了,數據手冊是這么說的,別問我為什么。得出來的數據通過串口監視器可以查看,精度不是很高,超過四米基本瞎了,低于二十厘米反應也遲鈍了。但是用來做避障神馬的妥妥地足夠了,預計日后會用舵機配合它進行組合掃描探測,現在先放著吧。
然后就剩兩個模塊了,下次再來。