當前位置:首頁 > IT技術(shù) > 系統(tǒng)服務(wù) > 正文

Linux應(yīng)用開發(fā)【第十一章】PWM編程應(yīng)用開發(fā)
2021-12-13 17:44:44

@[TOC]

11 PWM編程應(yīng)用開發(fā)

11.1 PWM概述

? PWM,英文名Pulse Width Modulation,是脈沖寬度調(diào)制縮寫,它是通過對一系列脈沖的寬度進行調(diào)制,等效出所需要的波形(包含形狀以及幅值),對模擬信號電平進行數(shù)字編碼,也就是說通過調(diào)節(jié)占空比的變化來調(diào)節(jié)信號、能量等的變化,占空比就是指在一個周期內(nèi),信號處于高電平的時間占據(jù)整個信號周期的百分比,例如方波的占空比就是50%。是利用微處理器的數(shù)字輸出來對模擬電路進行控制的一種非常有效的技術(shù)。

Linux應(yīng)用開發(fā)【第十一章】PWM編程應(yīng)用開發(fā)

? PWM信號把模擬信號轉(zhuǎn)化為數(shù)字電路所需要的編碼,現(xiàn)在基本是采用數(shù)字電路,因此在很多場合都采用PWM信號,我們經(jīng)常見到的就是交流調(diào)光電路,也可以說是無級調(diào)速,高電平占多一點,也就是占空比大一點亮度就亮一點,占空比小一點亮度就沒有那么亮,前提是PWM的頻率要大于我們?nèi)搜圩R別頻率,要不然會出現(xiàn)閃爍現(xiàn)象。除了在調(diào)光電路應(yīng)用,還有在直流斬波電路、蜂鳴器驅(qū)動、電機驅(qū)動、逆變電路、加濕機霧化量等都會有應(yīng)用。

Linux應(yīng)用開發(fā)【第十一章】PWM編程應(yīng)用開發(fā)

11.1.1 PWM的參數(shù)說明

https://www.kernel.org/doc/Documentation/pwm.txt
period
PWM信號的總周期(讀/寫)。
值以納秒為單位,是活動和非活動的總和
PWM的時間。

duty_cycle(占空比)
PWM信號的有效時間(讀/寫)。
值以納秒為單位,且必須小于周期。
在NORMAL模式下,表示一個周期內(nèi)高電平持續(xù)的時間
在INVERTED模式下,表示一個周期中低電平持續(xù)的時間

polarity
改變PWM信號的極性(讀/寫)。
寫入此屬性僅在PWM芯片支持更改時才有效
極性。只有PWM不能改變極性
啟用。值是字符串“normal”或“inversed”。

enable
啟用/禁用PWM信號(讀/寫)。

  • 0 - 禁用
  • 1 - 啟用

11.2 用戶層查看PWM

? 如果在內(nèi)核配置中啟用了CONFIG_SYSFS,則會提供一個簡單的sysfs接口來使用用戶空間的PWM。它在/ sys / class / pwm /中公開。每個被探測的PWM控制器/芯片將被輸出為pwmchipN,其中N是PWM芯片的基礎(chǔ)。你在目錄里面會發(fā)現(xiàn):

 1 echo 0 > /sys/class/pwm/pwmchip0/export /*設(shè)置PWM4輸出,調(diào)出pwm0目錄下設(shè)備節(jié)點,用于以下配置 */
 2 echo 1000000 >/sys/class/pwm/pwmchip0/pwm0/period /*設(shè)置PWM4一個周期的持續(xù)時間,單位為ns,即1K Hz */
 3 echo 500000 >/sys/class/pwm/pwmchip0/pwm0/duty_cycle /*設(shè)置一個周期中的”O(jiān)N”時間,單位為ns,即占空比=duty_cycle/period=50% */
 4 echo 1 >/sys/class/pwm/pwmchip0/pwm0/enable /*設(shè)置PWM4使能 */

11.3 PWM的SYSFS使用

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>

#define dbmsg(fmt, args ...) printf("%s[%d]: "fmt"
", __FUNCTION__, __LINE__,##args)

#define DUTY              "duty"
#define PERIOD            "1000000"
#define DUTYCYCLE         "500000"
#define LENGTH            100

int fd_period = 0,fd_duty = 0,fd_enable = 0,duty_m = 0;

int usage()
{
    printf("usage:
");
    printf("./pwm-sysfs-test duty <0/1> : 0-->static; 1-->dynamic 
");   
    return 0;
}

int pwm_setup()
{
  int fd,ret;

  fd = open("/sys/class/pwm/pwmchip0/export", O_WRONLY);
  if(fd < 0)
  {
      dbmsg("open export error
");
      return -1;
  }
  ret = write(fd, "0", strlen("0"));
  if(ret < 0)
  {
      dbmsg("creat pwm0 error
");
      return -1;
  }else
  dbmsg("export pwm0 ok
");

  fd_period = open("/sys/class/pwm/pwmchip0/pwm0/period", O_RDWR);
  fd_duty = open("/sys/class/pwm/pwmchip0/pwm0/duty_cycle", O_RDWR);
  fd_enable = open("/sys/class/pwm/pwmchip0/pwm0/enable", O_RDWR);

  if((fd_period < 0)||(fd_duty < 0)||(fd_enable < 0))
  {
      dbmsg("open error
");
      return -1;
  }

  ret = write(fd_period, PERIOD,strlen(PERIOD));
  if(ret < 0)
  {
      dbmsg("change period error
");
      return -1;
  }else
    dbmsg("change period ok
");

  ret = write(fd_duty, DUTYCYCLE, strlen(DUTYCYCLE));
  if(ret < 0)
  {
      dbmsg("change duty_cycle error
");
      return -1;
  }else
    dbmsg("change duty_cycle ok
");

  ret = write(fd_enable, "1", strlen("1"));
  if(ret < 0)
  {
      dbmsg("enable pwm0 error
");
      return -1;
  }else
  dbmsg("enable pwm0 ok
");

  duty_m = atoi(DUTYCYCLE)/2;
  printf("duty_m: %d 
",duty_m);

  return 0;
}

int main ( int argc, char *argv[] )
{
  int ret;
  int num;
  if(argc < 2)
  {
    usage();
    return -1;
  }

  if(strncmp(argv[1],DUTY, sizeof(DUTY)) == 0)
  {
    dbmsg("%s", DUTY);
    if(argc != 3)
    {
      usage();
      return -1;
    }
    pwm_setup();
  }

  return 0;
}

11.4 PWM應(yīng)用編程

The main useful user API are the following:
devm_pwm_get() or pwm_get() / pwm_put(): this API is used to look up, request, then free a PWM device.
pwm_init_state(),pwm_get_state(), pwm_apply_state(): this API is used to initialize, retrieve and apply the current PWM device state.
pwm_config(): this API updates the PWM device configuration (period and duty cycle).

11.4.1 修改設(shè)備樹

beeper {
compatible = "pwm-beeper";
pwms = <&pwm 0 1000000 0>;
pinctrl-names = "default";
pinctrl-0 = <&pwm0_pin>;
};

11.4.2 修改配置文件

Activate PWM framework in the kernel configuration through the Linux menuconfig tool, Menuconfig or how to configure kernel (CONFIG_PWM=y):
Device Drivers  --->
   [*] Pulse-Width Modulation (PWM) Support  --->

11.4.3 添加驅(qū)動

#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <asm/gpio.h>
#include <linux/pwm.h>

//#include <plat/gpio-cfg.h>

#define PWM_ON  0x100001
#define PWM_OFF 0x100002

struct pwm_device *pwm_dev_2;
struct pwm_device *pwm_dev_3;

static long pwm_ioctl(struct file *file,
                        unsigned int cmd,
                        unsigned long arg)
{
    int ret;
    switch(cmd) {
        case PWM_ON:
                ret = pwm_config(pwm_dev_2,200000,500000);
                if(ret < 0){
                    printk("pwm_dev_2 ioctl fail");
                    return 0;
                }
                ret = pwm_config(pwm_dev_3,300000,500000);
                if(ret < 0){
                    printk("pwm_dev_3 ioctl fail");
                }
                pwm_enable(pwm_dev_2);
                pwm_enable(pwm_dev_3);
            break;
        case PWM_OFF:
                ret = pwm_config(pwm_dev_2,0,500000);
                if(ret < 0){
                    printk("pwm_dev_2 ioctl fail");
                    return 0;
                }
                ret = pwm_config(pwm_dev_3,0,500000);
                if(ret < 0){
                    printk("pwm_dev_3 ioctl fail");
                }
                pwm_disable(pwm_dev_2);
                pwm_disable(pwm_dev_3);
            break;
    }
    return 0;
}

//定義初始化硬件操作方法
static struct file_operations pwm_fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = pwm_ioctl
};

//定義初始化混雜設(shè)備對象
static struct miscdevice pwm_misc = {
    .minor = MISC_DYNAMIC_MINOR, //動態(tài)分配次設(shè)備號
    .name = "mypwm",             //dev/mypwm
    .fops = &pwm_fops 
};

static int pwm_init(void)
{
    int ret;
    printk("regisger pwm_misc device
");
    //1.申請pwm資源,設(shè)置輸出為0
    pwm_dev_2 = pwm_request(1,"pwm_2");
    if(pwm_dev_2 == NULL){
        printk("pwm_dev_2 register fail
");
    }
    pwm_dev_3 = pwm_request(2,"pwm_3");
    if(pwm_dev_3 == NULL){
        printk("pwn_dev_3 register fail
");
    }

    ret = pwm_config(pwm_dev_2,0,500000);
    if(ret < 0){
        printk("pwm_config_2 init fail
");
        return 0;
    }
    ret = pwm_config(pwm_dev_3,0,500000);
    if(ret < 0){
        printk("pwm_config_3 init fail
");
        return 0;
    }

    ret = pwm_enable(pwm_dev_2);
    if(ret == 0){
        printk("pwm_enable_dev_2 init success
");
    }
    if(ret < 0 ){
        printk("pwm_enable_dev_2 init fail
");
        return 0;
    }
    ret = pwm_enable(pwm_dev_3);
    if(ret == 0){
        printk("pwm_enable_dev_3 init success
");
    }
    if(ret < 0 ){
        printk("pwm_enable_dev_3 init fail
");
        return 0;
    }
    //2.注冊混雜設(shè)備
    misc_register(&pwm_misc);
    return 0;
}

static void pwm_exit(void)
{
    printk("unregister pwm_misc device
");
    //1.卸載混雜設(shè)備
    misc_deregister(&pwm_misc);
    //2.釋放pwm資源
    pwm_config(pwm_dev_2,0,500000);
    pwm_disable(pwm_dev_2);
    pwm_free(pwm_dev_2);

    pwm_config(pwm_dev_3,0,500000);
    pwm_disable(pwm_dev_3);
    pwm_free(pwm_dev_3);
}
module_init(pwm_init);
module_exit(pwm_exit);
MODULE_LICENSE("GPL");

11.4.4 運行測試

#include <stdio.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <fcntl.h> 

#define PWM_ON  0x100001 
#define PWM_OFF 0x100002 

int main(void) 
{
    int fd; 
    int a; 

    fd = open("/dev/mypwm", O_RDWR); 
    if (fd < 0) 
        return -1; 

    while(1) { 
            ioctl(fd, PWM_ON); 
    } 
    close(fd); 
    return 0; 
}

本文摘自 :https://blog.51cto.com/w

開通會員,享受整站包年服務(wù)立即開通 >