之前有些過一篇文章講arduino的PWM輸出,請參考下文:
現在有了示波器之後可以進行更進一步的觀察與深入了解的機會。
Arduino官網有一篇文章是深入解說PWM的詳細說明,文章如下:
重點在於說明PWM可以透過timer的使用由一般GPIO腳座交替high low輸出來達成,
但這樣很沒有效率,同時做其他事情時也會影響到PWM的準確性跟穩定度,
所以Arduino透過內建的函數,只要簡單的設定即可使用PWM,就如本文最上面的範例。
而Arduino有兩種PWM模式:
第一種叫fast PWM,原理如下圖:
Timer由0數到255然後歸零重數,這樣的輸出頻率為:
16 MHz / 64 / 256 = 976.5625Hz
16MHz是系統的OSC晶震頻率
64是prescaler(預除器)的數值,預設值為64
256是8位元counter從0到255的計數次數
所以輸出是976.5625Hz
這是Arduino UNO的pin 3與pin 11用的。
第二種叫Phase-Correct PWM,原理如下圖:
Timer由0到255之後再遞減到0,這樣的輸出頻率為:
16 MHz / 64 / 256 / 2 = 490.196Hz
因為timer跑了兩次,所以頻率就是fast PWM的一半。
prescaler是可以改變的,改變之後會改變PWM的頻率,但有些修改會動到系統底層的計數函數功能,沒必要不建議隨意修改。
底下是用Arduino UNO加上VR可變電阻的實驗照片:
這是用CH1接到A6的照片:
可以看到讀值為976Hz,正占比為46%。
底下是用示波器截圖功能所擷取的一些圖片,這是CH1接A6腳量的資料,PWM由小調到大的波形:
這是A9的輸出訊號量測:
後來修改程式後讓A9跟A6同時輸出,接線照片:
接線與量測照片:
示波器截圖:
底下是我修改後雙PWM輸出的程式:
//PWM輸出頻率與佔空比的實驗程式--PWM01
//經由讀取可變電阻VR上的電壓值,然後等比例於PWM腳輸出的變化
//因Arduino PWM 輸出頻率有兩種,所以利用此程式配合示波器量測以確認輸出頻率的差別
//本程式由LUYAKU於2022.02.18寫作修改
const byte analogPin = A0; //設定可變電阻VR 中間抽頭的輸入腳,設定為A0
int PWM0_Out = 9; //設定 Arduino PWM0輸出腳位在 9 pin
int PWM1_Out = 6; //設定 Arduino PWM1輸出腳位在 6 pin
int VR_Value;
int PWM_Map;
int Percent_Map;
void setup() {
Serial.begin(9600);
pinMode(PWM0_Out, OUTPUT); //定義 pinmode 為 pin 9 OUTPUT 輸出
pinMode(PWM1_Out, OUTPUT); //定義 pinmode 為 pin 6 OUTPUT 輸出
}
void loop() {
VR_Value = analogRead(analogPin); //讀取VR可變電阻值
PWM_Map = map(VR_Value,0,1023,0,255); //Arduino的類比輸入為10bit,範圍由0到1023
Percent_Map = map(VR_Value,0,1023,0,99); //將ADC的讀取值map到百分比0到99
analogWrite(PWM0_Out,PWM_Map); //將map後的值(0-255)由9 pin pwm0 輸出
analogWrite(PWM1_Out,PWM_Map); //6 pin pwm1 輸出一樣的map值
Serial.println(PWM_Map); //將結果輸出到電腦的com port上顯示
Serial.println(Percent_Map); //顯示百分比
Serial.println(VR_Value); //顯示VR的ADC讀取值
Serial.print(VR_Value*0.0048828125);
Serial.println("V""\n"); //以上兩行將ADC瀆值轉換為電壓
delay(500); //500毫秒更新一次
}
修改程式後把PWM百分比顯示到1602A LCD螢幕上:
/*
* 重新改寫Analog input & PMW out程式,輸出到1602A LCD螢幕
*
* VR可變電阻輸入,輸入腳為A0,PWM由Arduino UNO的pin9輸出到N MOS-FET
* 2022.02.18 Luyaku
* 程式名稱 2PWM_out_to_LCD.ino
*/
#include <LiquidCrystal_PCF8574.h>
LiquidCrystal_PCF8574 lcd(0x27); // 設定i2c位址,一般情況就是0x27和0x3F兩種,我的是0x27
const byte analogPin = A0;
int PWM0_Out = 9; //設定 Arduino PWM輸出腳位在 9 pin
int PWM1_Out = 6; //設定 Arduino PWM輸出腳位在 6 pin
int VR_Value;
int PWM_Map;
int Percent_Map;
float Volt_res = 0.0048828125;
void setup() {
Serial.begin(9600);
pinMode(PWM0_Out, OUTPUT); //定義 pinmode 為 pin 9 PWM OUTPUT 輸出
pinMode(PWM1_Out, OUTPUT); //定義 pinmode 為 pin 6 PWM OUTPUT 輸出
lcd.begin(16, 2); // 初始化LCD
// 閃爍三次
for(int i = 0; i < 3; i++) {
lcd.setBacklight(1); // 開啟背光
delay(250);
lcd.setBacklight(0); // 關閉背光
delay(250);
}
lcd.setBacklight(1);
delay(1000);
lcd.clear();
lcd.setCursor(0, 0); //設定游標位置 (字,行)
lcd.print("Hello, world!");
lcd.setCursor(0, 1);
lcd.print("LCD is Working!");
delay(2000);
}
void loop() {
VR_Value = analogRead(analogPin); //由A0腳讀入VR值
PWM_Map = map(VR_Value,0,1023,00,255); //用map函數將類比值0-1023轉為0-255
Percent_Map = map(VR_Value,0,1023,0,99);
analogWrite(PWM0_Out,PWM_Map); //我們設定pin 9為PWM輸出,輸出值為map轉換後的值
analogWrite(PWM1_Out,PWM_Map); //我們設定pin 6為PWM輸出,輸出值為map轉換後的值
Serial.println(PWM_Map);
Serial.println(Percent_Map);
Serial.println(VR_Value);
Serial.print(VR_Value*Volt_res);
Serial.println("V""\n");
lcd.clear();
lcd.setCursor(0, 0); //設定游標位置 (第0字,第0行)
lcd.print("PWM :"); //輸出PWM的百分比到LCD上
lcd.setCursor(7,0);
lcd.print(Percent_Map);
lcd.print("%");
delay(200); //延遲200mS,也就是每秒讀取5次
}
輸出波形,單ch:
雙ch:
LCD上的顯示與史波器量的占空比幾乎一樣,頂多數值差1而已。
PWM以後就可以視專案需求來決定用哪個PWM輸出,需要反應時間快一點的就用pin5 6,
不然就用其他慢一點的PWM接腳即可,可以增加設計彈性。
用示波器觀察波形並驗證程式,真的很方便。
實驗日期:2022.02.18
文章日期:2022.02.18
留言列表