• 當前位置:首頁 > IT技術 > 系統服務 > 正文

    Linux應用開發【第十一章】PWM編程應用開發
    2021-12-13 17:44:44

    @[TOC]

    11 PWM編程應用開發

    11.1 PWM概述

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

    Linux應用開發【第十一章】PWM編程應用開發

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

    Linux應用開發【第十一章】PWM編程應用開發

    11.1.1 PWM的參數說明

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

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

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

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

    • 0 - 禁用
    • 1 - 啟用

    11.2 用戶層查看PWM

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

     1 echo 0 > /sys/class/pwm/pwmchip0/export /*設置PWM4輸出,調出pwm0目錄下設備節點,用于以下配置 */
     2 echo 1000000 >/sys/class/pwm/pwmchip0/pwm0/period /*設置PWM4一個周期的持續時間,單位為ns,即1K Hz */
     3 echo 500000 >/sys/class/pwm/pwmchip0/pwm0/duty_cycle /*設置一個周期中的”ON”時間,單位為ns,即占空比=duty_cycle/period=50% */
     4 echo 1 >/sys/class/pwm/pwmchip0/pwm0/enable /*設置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應用編程

    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 修改設備樹

    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 添加驅動

    #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
    };
    
    //定義初始化混雜設備對象
    static struct miscdevice pwm_misc = {
        .minor = MISC_DYNAMIC_MINOR, //動態分配次設備號
        .name = "mypwm",             //dev/mypwm
        .fops = &pwm_fops 
    };
    
    static int pwm_init(void)
    {
        int ret;
        printk("regisger pwm_misc device
    ");
        //1.申請pwm資源,設置輸出為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.注冊混雜設備
        misc_register(&pwm_misc);
        return 0;
    }
    
    static void pwm_exit(void)
    {
        printk("unregister pwm_misc device
    ");
        //1.卸載混雜設備
        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

    開通會員,享受整站包年服務
    国产呦精品一区二区三区网站|久久www免费人咸|精品无码人妻一区二区|久99久热只有精品国产15|中文字幕亚洲无线码