PWM介紹
- 專欄總目錄
- PWM是脈寬調制(Pulse Width Modulation)的縮寫。它是一種用于控制電子設備的技術,通過改變電信號的脈沖寬度來實現對設備的控制。
PWM基本概念
PWM信號由一個固定頻率的周期性脈沖序列組成,每個脈沖的寬度(持續時間)可以根據需要進行調節。調節脈沖寬度的比例可以改變平均電壓或電流的大小,從而實現對設備的控制。
當談論PWM時,以下三個關鍵術語經常被提及:
頻率(Frequency):PWM信號的頻率是指每秒鐘內脈沖的數量。
周期(Period):PWM信號的周期是指一個完整脈沖序列所花費的時間。它是頻率的倒數,以秒為單位表示。周期可以通過將頻率的倒數計算得到,例如,一個10kHz的PWM信號的周期為0.1毫秒(100微秒)。
占空比(Duty Cycle):占空比是指PWM信號中脈沖寬度與周期之間的比例關系。它表示了脈沖在一個周期中所占據的時間比例,通常以百分比表示。占空比為0%意味著脈沖不存在(完全低電平),而占空比為100%表示脈沖持續時間占據了整個周期(完全高電平)。在實際應用中,占空比可以在0%到100%之間任意調整,以實現所需的控制效果。
PWM驅動
pwm驅動是一個通用的驅動,SOC廠家都會在SDK里面默認打開
驅動文件
驅動文件所在位置:
drivers/pwm/pwm-rockchip.c
默認SDK已經加載好了PWM的驅動,下文我們主要注意PWM怎么使用
DTS 節點配置
DTS 配置參考文檔
Documentation/devicetree/bindings/pwm/pwm.txt
以下為一個例子的示例
Node name {
compatible = "Driver matching character";
pwms = < &pwmX 0 25000 0 >;
};
&pwmX {
status = "okay";
pinctrl-names = "active";
pinctrl-0 = < &pwmX_pin_pull_down >;
};
pwms的幾個參數說明如下:
參數 1,表示 index (per-chip index of the PWM to request),一般是 0,因為我們 Rockchip PWM 每個chip 只有一個。
參數 2,表示 PWM 輸出波形的時間周期,單位是 ns;例如下面配置的 25000 就是表示想要得到的
PWM 輸出周期是 40K 赫茲。
參數 3,表示極性,為可選參數;下面例子中的配置為負極性。
PWM使用
PWM 提供了用戶層的接口,在 /sys/class/pwm/ 節點下面,PWM 驅動加載成功后,會在/sys/class/pwm/ 目錄下產生 pwmchip0 目錄;向 export 文件寫入 0,就是打開 pwm 定時器 0,會產生一個 pwm0 目錄,相反的往 unexport 寫入 0 就會關閉 pwm 定時器了,同時 pwm0 目錄會
被刪除,該目錄下有以下幾個文件:
enable:寫入 1 使能 pwm,寫入 0 關閉 pwm;
polarity:有 normal 或 inversed兩個參數選擇,表示輸出引腳電平翻轉;
duty_cycle:在 normal 模式下,表示一個周期內高電平持續的時間(單位:納秒),在
reversed 模式下,表示一個周期中低電平持續的時間(單位:納秒);
period:表示 pwm 波的周期(單位:納秒);
以下是 pwmchip0 的例子,設置 pwm0 輸出頻率 100K,占空比 50%, 極性為正極性:
cd /sys/class/pwm/pwmchip0/
echo 0 > export
cd pwm0
echo 10000 > period
echo 5000 > duty_cycle
echo normal > polarity
echo 1 > enable
PWM應用實例
通常電子設備中應用pwm是比較常見的,比如風扇電機控制,電視背光控制, LED 照明調光、電動工具馬達控制、汽車加熱器等領域。
這里簡單介紹一下pwm控制LED燈實現呼吸燈效果。
呼吸燈需要燈的驅動與PWM的驅動結合,兩個驅動之間傳遞數據,我們可以在驅動中調用其他的驅動。
led是我需要的設備,這個設備用到了pwm,而pwm是用默認的驅動。
硬件上我們在開發板找到具有pwm功能的引腳
設備樹的修改如下:
/{
breathing_light {
compatible = "lhd,breathing_light_test";
backlight {
pwms = < &pwm8 0 25000 0 >;
pwm-names = "breathing_light";
};
};
};
&pwm8 {
status = "okay";
};
寫一個驅動。內部在使用PWM子系統。形成了包含驅動的驅動。
示例代碼
驅動程序
#include < linux/init.h >
#include < linux/module.h >
#include < linux/fs.h >
#include < linux/cdev.h >
#include < linux/uaccess.h >
#include < linux/types.h >
#include < linux/kernel.h >
#include < linux/delay.h >
#include < linux/ide.h >
#include < linux/errno.h >
#include < linux/gpio.h >
//#include < asm/mach/map.h >
#include < linux/of.h >
#include < linux/of_address.h >
#include < linux/of_gpio.h >
#include < asm/io.h >
#include < linux/device.h >
#include < linux/platform_device.h >
#include < linux/pwm.h >
#define RED_LED_DTS_COMPATIBLE "lhd,breathing_light_test" /* 設備樹節點匹配屬性 */
#define LED_PWM_CMD_SET_DUTY 0x01
#define LED_PWM_CMD_SET_PERIOD 0x02
#define LED_PWM_CMD_SET_BOTH 0x03
#define LED_PWM_CMD_ENABLE 0x04
#define LED_PWM_CMD_DISABLE 0x05
struct led_pwm_param {
int duty_ns;
int period_ns;
};
struct red_led_dev {
dev_t dev_no;
struct cdev chrdev;
struct class *led_class;
struct device_node *dev_node;
struct pwm_device *red_led_pwm;
};
static struct led_pwm_param led_pwm;
static struct red_led_dev led_dev;
static int red_led_drv_open (struct inode *node, struct file *file)
{
int ret = 0;
//pwm_set_periodnnn(led_dev.red_led_pwm, PWM_POLARITY_INVERSED);//設置PWM信號的極性
pwm_enable(led_dev.red_led_pwm);//啟用指定PWM設備,使其開始輸出PWM信號。
printk("red_led_pwm open
");
return ret;
}
static ssize_t red_led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)