本節(jié)內(nèi)容:
一、什么是PWM荒椭?有何用途谐鼎?
二、Arduino產(chǎn)生PWM信號的兩種方式?
三趣惠、串口輸入輸出的基本方法 ?
四狸棍、串口控制變色燈的實(shí)現(xiàn)?
一、什么是PWM味悄?有何用途草戈?
(一)什么是PWM
? ? 1.PWM介紹
PWM,全稱:Pulse Width Modulation侍瑟,通常中文翻譯為:脈沖寬度調(diào)制唐片,通過將一段數(shù)字信號編碼為方波信號,在外部作用事物上達(dá)到擬輸出效果的一種手段涨颜。實(shí)際上费韭,就是通過數(shù)字控制產(chǎn)生不同占空比的方波來模擬輸出。也就是使用PWM輸出模擬信號庭瑰。
圖中的高電平和低電平所占比例都不同星持,我們知道,電壓信號是離散的弹灭,在這里我們只能輸出0V或者5V電壓督暂,那么想要連續(xù)輸出3.7V或者其他介于0-5V之間的電壓怎么辦呢揪垄?
? ?(1)通過一系列的計(jì)算我們得到,高電平信號占持續(xù)時間占這個周期得百分比決定了輸出電壓信號的大小逻翁。
? (2)這里說百分比饥努,就是下面要說的,占空比八回。
? ?2.占空比
占空比就是在一個調(diào)制周期內(nèi)酷愧,某個信號持續(xù)的時間占這個時間段的百分比。在前一個圖中缠诅,占空比就是不同的伟墙,并且是高電平的占空比。因此滴铅,低占空比意味著輸出的能量低,因?yàn)樵谝粋€周期內(nèi)大部分時間信號處于關(guān)閉狀態(tài),如果PWM控制的負(fù)載為LED,則具體表現(xiàn)例如LED燈很暗就乓。高占空比意味著輸出的能量高汉匙,在一個周期內(nèi),大部分時間信號處于on狀態(tài),具體表現(xiàn)為LED比較亮。
綜上生蚁,我們大概可以了解PWM究竟是什么了:脈寬調(diào)制噩翠,也就是高電平信號在一個調(diào)制周期中持續(xù)時間長短,它可以用占空比去衡量邦投,占空比越大伤锚,脈沖寬度越寬。
(二)PWM用途
? ? ?1.PWM軟件法控制充電電流
該方法的基本思想就是利用單片機(jī)具有的PWM端口志衣,在不改變PWM方波周期的前提下屯援,通過軟件的方法調(diào)整單片機(jī)的PWM控制寄存器來調(diào)整PWM的占空比,從而控制充電電流念脯。
? ? 2.PWM在推力調(diào)制中的應(yīng)用
1962年狞洋,Nicklas等提出了脈沖調(diào)制理論,指出利用噴氣脈沖對航天器控制是簡單有效的控制方案绿店,同時能使時間或能量達(dá)到最優(yōu)控制吉懊。
脈寬調(diào)制發(fā)動機(jī)控制方式是在每一個脈動周期內(nèi),通過改變閥門在開或關(guān)位置上停留的時間來改變流經(jīng)閥門的氣體流量假勿,從而改變總的推力效果借嗽,對于質(zhì)量流率不變的系統(tǒng),可以通過脈寬調(diào)制技術(shù)來獲得變推力的效果转培。?
? 3.在LED中的應(yīng)用
在LED控制中PWM作用于電源部分恶导,脈寬調(diào)制的脈沖頻率通常大于100Hz,人眼就不會感到閃爍堡距。
二甲锡、產(chǎn)生PWM信號的兩種方式
先確定哪些引腳支持PWM兆蕉,ATmega328的3, 5, 6, 9, 10, 和 11引腳支持PWM
(一)適用于所有GPIO的純軟件編程方式
void setup(){?
pinMode(11, OUTPUT);//設(shè)定11號端口為輸出
}
void loop(){
digitalWrite(11, HIGH);? //11號引腳輸出高電平
delayMicroseconds(100); // 大約10%占空比的1KHz方波? digitalWrite(10, LOW);? //10號引腳輸出低電平
delayMicroseconds(900);//延時900微秒
}
? ? 適用于所有GPIO的純軟件編程方式的優(yōu)缺點(diǎn)
? ? ? ?PWM 的比例可以更精確;
? ? ? ?周期和頻率可控制缤沦;
? ? ? ?所有的 pin 腳都可以輸出虎韵,不局限于那幾個腳;
? ? ? ?缺點(diǎn):CPU 干不了其他事情了缸废;
(二)通過analogWrite函數(shù)來完成PWM信號輸出
analogWrite(pin,value)
作用:讓一個支持PWM輸出的引腳持續(xù)輸出指定脈沖寬度的方波包蓝。
參數(shù):pin:PWM輸出的引腳編號。Pin可以等于3企量、5测萎、6、9届巩、10硅瞧、11? ? ? ?
? ? ? ? ? ?value:用于控制占空比,范圍:0~255恕汇。值為0表示占空比為0腕唧,值為255表示占空比為100%,值為127表示占空比為50%瘾英。
void setup()??{
?? pinMode(9,OUTPUT);//設(shè)定9號端口為輸出端口
void loop()??{
?? analogWrite(9, led);//將led的值寫入9號端口
?? if (value==0)
{
? ? digitalWrite(pin,LOW);//輸出低電平
}
else if (value==255)
{
? ? ? digitalWrite(pin,HIGH);?//輸出高電平? ?? ?? ?? ?? ?? ???
}
二枣接、串口輸入輸出的基本方法
(一)Arduino串口的使用——與計(jì)算機(jī)交流
??Arduino與計(jì)算機(jī)通信最常用的方式就是串口通信
??我們使用USB線連接Arduino Uno與計(jì)算機(jī)時,Arduino Uno會在計(jì)算機(jī)上虛擬出一個串口設(shè)備缺谴,此時兩者之間便建立了串口連接但惶。通過此連接,Arduino Uno便可與計(jì)算機(jī)互傳數(shù)據(jù)湿蛔。
(二)串口初始化
??使用串口與計(jì)算機(jī)通信膀曾,需要先使用Serial.begin() 初始化Arduino的串口通信功能。
??參數(shù)speed是指串口通信波特率阳啥,這是設(shè)定串口通信速率的參數(shù)妓肢。串口通信的雙方必須使用同樣的波特率,方能正常進(jìn)行通信苫纤。
??波特率是一個衡量通信速度的參數(shù)碉钠。它表示每秒鐘傳送的bit的個數(shù)。例如9600波特表示每秒發(fā)送9600bit的數(shù)據(jù)卷拘。通信雙方需要使用一致的的波特率才能正常通信喊废。Arduino串口通信通常會使用以下波特率:
??300、600栗弟、1200污筷、2400、4800、9600瓣蛀、14400陆蟆、19200、28800惋增、38400叠殷、57600、115200 (單位:bps)
??波特率越大诈皿,說明串口通信的速率越快林束。
(三)串口輸出
串口初始化完成后,我們便可以使用Serial.print() 或Serial.println() 向計(jì)算機(jī)發(fā)送信息了稽亏。
??參數(shù)val是你要輸出的數(shù)據(jù)壶冒,各種類型的數(shù)據(jù)均可。
??Serial.println(val) 語句也是使用串口輸出數(shù)據(jù)截歉,不同的是println() 函數(shù)會在輸出完指定數(shù)據(jù)后胖腾,再輸出一組回車換行符。
??使用串口輸出數(shù)據(jù)到計(jì)算機(jī):
上傳該程序到Arduino Uno瘪松,然后可以通過Arduino IDE右上角的圖標(biāo)打開串口監(jiān)視器胸嘁。
注意保證串口監(jiān)視器右下方的波特率和上傳程序中的一致,才能保證正常運(yùn)行凉逛。
(四)串口輸入
除了輸出,串口同樣可以接收由計(jì)算機(jī)輸出的數(shù)據(jù)群井。接收串口數(shù)據(jù)需要使用Serial.read()函數(shù)状飞。
??調(diào)用該語句,每次都會返回一個字節(jié)的數(shù)據(jù)书斜,這個返回值便是當(dāng)前串口讀取到的數(shù)據(jù)诬辈。
??上傳以下程序到Arduino:
上傳成功后,運(yùn)行串口監(jiān)視器荐吉,在發(fā)送按鍵左側(cè)的文本框中輸入要發(fā)送的信息焙糟,如"arduino",你會看到Arduino在輸出了你輸入的信息同時样屠,還輸出了很多亂碼穿撮,這些亂碼是因?yàn)榇诰彌_區(qū)中沒有可讀數(shù)據(jù)造成的。當(dāng)緩沖區(qū)中沒有可讀數(shù)據(jù)時痪欲,read()函數(shù)會返回int型值-1悦穿,而int型-1對應(yīng)的char型數(shù)據(jù)便是該亂碼。
在使用串口時业踢,Arduino Uno會在SRAM中開辟一段大小為256 bytes的空間栗柒,串口接收到的數(shù)據(jù)都會被暫時存放進(jìn)這個空間中,這個存儲空間知举,我們稱之為緩沖區(qū)瞬沦。當(dāng)你調(diào)用Serial.read()語句時太伊,Arduino便會從緩沖區(qū)取出一個字節(jié)的數(shù)據(jù)。
通常使用串口讀取數(shù)據(jù)時逛钻,需要搭配Serial.available() 語句使用僚焦。
Serial.available() 的返回值便是當(dāng)前緩沖區(qū)中接收到的數(shù)據(jù)字節(jié)數(shù)。
Serial.available() 可以搭配if 或者while使用绣的,先檢測緩沖區(qū)中是否有可讀數(shù)據(jù)叠赐,如果有數(shù)據(jù),再讀取屡江,沒有數(shù)據(jù)便跳過讀取或等待讀取芭概。如:
上傳完成后,打開串口監(jiān)視器惩嘉,鍵入并發(fā)送任意信息罢洲。你會看到Arduino輸出了你發(fā)送過去的信息,并且不會再出現(xiàn)亂碼了文黎。
需要注意的是惹苗,在串口監(jiān)視器右下角有兩個選項(xiàng),一個是設(shè)置結(jié)束符耸峭,一個是設(shè)置波特率桩蓉。如果你設(shè)置了結(jié)束符,則在你最后發(fā)送完數(shù)據(jù)后劳闹,串口監(jiān)視器會自動發(fā)送一組你設(shè)定的結(jié)束符院究,如回車符和換行符。
四本涕、串口控制變色燈的實(shí)現(xiàn)
(一)簡單回顧下之前的內(nèi)容:
? ? ?1.什么是PWM业汰?
脈沖寬度調(diào)制技術(shù),通過對一系列脈沖的寬度進(jìn)行調(diào)制菩颖,來等效地獲得所需要波形(含形狀和幅值)样漆。
? ? 2.analogWrite(pin,value)函數(shù)
參數(shù):pin:整型,要寫入的引腳編號晦闰;
? ? ? ? ? value:占空比放祟,在0~255之間。(0時候?yàn)殛P(guān)呻右,即LOW舞竿;255為開,即HIGH)
返回值:無
(二)本節(jié)所需的組件:
共陰極 RGB LED燈
3個470歐電阻
Arduino Nano開發(fā)板
面包板和跳線
(三)認(rèn)識一下RGB LED:
RGB LED燈可以通過混合紅色窿冯、綠色和藍(lán)色這三種基本顏色來發(fā)出不同的顏色骗奖。所以它實(shí)際上由3個獨(dú)立的LED組成,紅色、綠色和藍(lán)色包裝在一個盒子里执桌。這就是為什么它有4個引腳鄙皇,3種顏色中的每一種都有一根引線,而RGB LED類型則有共用陰極或陽極仰挣。在本篇文章中伴逸,我使用的是共陰極。
共陽極和共陰極在使用上是有區(qū)別的膘壶,區(qū)別分為以下兩點(diǎn):
(1)接線中的改變错蝴,共陽的話,共用端需要接5V颓芭,而不是GND顷锰,否則LED不能被點(diǎn)亮。
(2)在顏色的調(diào)配上亡问,共陽極與共陰極是完全相反的官紫。
? ? ? ? 舉個例子:共陰RGB顯示紅色為R-255,G-0州藕,B-0束世。然而共陽則完全相反,RGB數(shù)值是R-0,G-255,B-255床玻。
(四)工作原理
RGB只是簡單的把三個顏色的LED燈封裝在一個LED中毁涉。只要當(dāng)做三個燈使用就可以了。我們都知道紅色锈死、綠色贫堰、藍(lán)色是三原色,通過組合這些基本顏色可以得到任何色調(diào)馅精。我們將使用PWM模擬輸出,這將為LED提供不同的電壓電平粱檀,通過串口得到數(shù)值洲敢,再使Arduino通過PWM口對三種顏色明暗的調(diào)節(jié),也就analogWrite(value)語句茄蚯,就能讓LED調(diào)出任何你想要的顏色压彭。
(五)電路原理圖
我們將陰極接地,3個陽極通過470歐姆電阻連接到Arduino開發(fā)板上的3個數(shù)字引腳渗常,這些引腳可提供PWM信號壮不。我們將使用PWM模擬模擬輸出,這將為LED提供不同的電壓電平皱碘,以便我們可以獲得所需的顏色询一。
(六)源代碼
我使用的是引腳9、10和11,分別將它們命名為RedPin健蕊、GreenPin和BluePin菱阵。并定義一個字符串變量str和一個整形數(shù)組RGB。
String str;? //定義字符串變量str
? ? ? int RedPin = 9;? //紅燈連接引腳為9的接口
? ? ? int GreenPin = 10;? //綠燈連接10接口
? ? ? int BluePin = 11;? //藍(lán)燈連接11接口
int RGB[3];? //定義整形數(shù)組RGB
在setup部分缩功,我們需要將它們定義為輸出晴及。開啟串口。
void setup(){//創(chuàng)建函數(shù)
? Serial.begin(9600);? // 打開串口
? pinMode(RedPin, OUTPUT);? //設(shè)定紅燈引腳為輸出模式
? pinMode(GreenPin, OUTPUT);//設(shè)定綠燈引腳為輸出模式
? pinMode(BluePin, OUTPUT);//設(shè)定藍(lán)燈引腳為輸出模式
}
現(xiàn)在在loop函數(shù)中我們將制作程序嫡锌,它將根據(jù)串口輸入的數(shù)值改變LED的顏色虑稼。
void loop(){//創(chuàng)建循環(huán)函數(shù)
? if (Serial.available() > 0) {? // 當(dāng)串口接收到數(shù)據(jù)時
? ? str = Serial.readString();? //將串口接收到數(shù)據(jù)賦給str變量
? }
? if (str != "") {? //當(dāng)接收到數(shù)據(jù)時
? ? //對輸入的數(shù)字分割讀取并賦給數(shù)組
? ? RGB[0] = str.substring(0, str.indexOf(',')).toInt();
? ? RGB[1] = str.substring(str.indexOf(',')+1, str.lastIndexOf(',')).toInt();
? ? RGB[2] = str.substring(str.lastIndexOf(',')+1).toInt();
? }
? setcolor(RGB[0], RGB[1], RGB[2]);? //調(diào)用setcolor函數(shù)
}
函數(shù)參考:
① 變量.Substring(參數(shù)1,參數(shù)2);
截取字串的一部分,參數(shù)1為左起始位數(shù)势木,參數(shù)2為截取幾位蛛倦。
如:string s1 = str.Substring(0,2); //截取第0位到第2位三位字節(jié)賦給s1
② 變量.IndexOf()
查找字串中指定字符或字串首次出現(xiàn)的位置,返首索引值。
如:str1.IndexOf("字")跟压; //查找“字”在str1中的索引值(位置)
③變量 .toInt()
可以將字符串轉(zhuǎn)換成整型
如:上述代碼將字符串轉(zhuǎn)化為整型
然后我定義了一個名為setcolor()的自定義函數(shù)胰蝠,它接受3個不同的參數(shù)red、green和blue震蒋。這些參數(shù)表示LED的亮度或使用analogWrite()函數(shù)創(chuàng)建的PWM信號的占空比茸塞,在0到255之間變化。
void setcolor(int red, int green, int blue){//創(chuàng)建setColor函數(shù)
? ? analogWrite(RedPin,redValue);//analogWrite函數(shù)通過PWM的方式在引腳上輸出一個模擬量查剖,控制LED亮度
? ? analogWrite(GreenPin,greenValue);//analogWrite函數(shù)通過PWM的方式在引腳上輸出一個模擬量钾虐,控制LED亮度
? analogWrite(BluePin,blueValue);//analogWrite函數(shù)通過PWM的方式在引腳上輸出一個模擬量,控制LED亮度
}
(七)實(shí)驗(yàn)步驟
電路的連接非常簡單:
? 1.? 將RGB LED插入面包板笋庄。
? 2.? 將共陰極的公共端效扫,與Arduino中的GND引腳連接。
? 3.? 將每個LED引線(紅色直砂、綠色和藍(lán)色)與Arduino中的數(shù)字引腳相連菌仁, 每個引腳與470歐姆電阻串聯(lián)。
? 4.? 利用USB連至計(jì)算機(jī)静暂。
? 5.? 輸入代碼济丘,上傳即可實(shí)現(xiàn)。
(八)實(shí)驗(yàn)結(jié)果
(九)map函數(shù)的用法
1.函數(shù)原型:map(value, fromLow, fromHigh, toLow, toHigh)
2.功能: 將數(shù)字從一個范圍重新映射到另一個范圍洽蛀。
3.參數(shù):value: 要映射的數(shù)字
? ? ? ? ? ? ? ? ? fromLow: 值當(dāng)前范圍的下限
? ? ? ? ? ? ? ? ? fromHigh: 值當(dāng)前范圍的上限
? ? ? ? ? ? ? ? ? toLow: 值的目標(biāo)值范圍的下限
? ? ? ? ? ? ? ? ? toHigh: 值的目標(biāo)值范圍的上限
4.返回值:映射的值
5.例如:val = map(analogRead(0),0,1023,100, 200); // 將analog0 所讀取到的訊號對等轉(zhuǎn)換至100 – 200之間的數(shù)值摹迷。
以上實(shí)現(xiàn)了如 輸入255,0,0 得到紅色 等? 輸入對應(yīng)值RGB 呈現(xiàn)相應(yīng)顏色 的過程。