Linux-PWM

Linux-PWM

在应用层进行Linux-PWM的开发,关于驱动开发可以查看嵌入式Linux-PWM 子系统

调用应用层接口

  • 验证PWM设备存在

    
    root@ATK-IMX6U:/sys/class/pwm# ls
    pwmchip0  pwmchip1  pwmchip2  pwmchip3  pwmchip4  pwmchip5  pwmchip6  pwmchip7
    
  • pwmchip0-7对应着PWM1-8这8个PWM输出口

  • 导出pwmchip2(PWM3)的0号通道的的操作目录,则会看到pwm0这个操作接口

    在I.MX6ULL中,每个pwm控制器下只有一路pwm输出口。均只有通道0是有效的

    root@ATK-IMX6U:/sys/class/pwm# echo 0 > /sys/class/pwm/pwmchip2/export # 在 pwmchip2 这个PWM控制器上导出第0号PWM通道
    root@ATK-IMX6U:/sys/class/pwm# ls /sys/class/pwm/pwmchip2/
    device  export  npwm  power  pwm0  subsystem  uevent  unexport
    root@ATK-IMX6U:/sys/class/pwm#
    
    
  • 基于pwmchip2/pwm0操作接口实现设置

    root@ATK-IMX6U:/sys/class/pwm/pwmchip2/pwm0# ls
    duty_cycle  enable  period  polarity  power  uevent
    
    • 使能

      echo 1 > /sys/class/pwm/pwmchip2/pwm0/enable
      
    • 设置频率: 设置周期时间(ns)来设置频率

      echo 20000 > /sys/class/pwm/pwmchip2/pwm0/period
      
    • 设置占空比: 设置高电平时间来设置占空比

      echo 500 > /sys/class/pwm/pwmchip2/pwm0/duty_cycle
      
  • 在外设上使用指定的PWM

    • 对于需要使用pwm的外设例如lcd屏幕,可以使用内置的pwn驱动来进行设置。需要修改设备树

    • 以已有的背光节点作为参考

      compatible​属性必须为“pwm-backlight​用于匹配内核驱动。pwms​用于指定具体使用的哪一路pwm。brightness-levels​用于设置背光等级,范围0-255,首个值必须为0power-supply属性可以不设置,其用于设置支持的电压。

      	backlight {
      		compatible = "pwm-backlight";
      		pwms = <&pwm1 0 5000000>; #imx6每个pwn只有1个通道 因此通道为0 设置200Hz
      		brightness-levels = <0 4 8 16 32 64 128 255>;
      		default-brightness-level = <7>;
      		status = "okay";
      	};
      
      

在Qt中调用Linux的PWM接口

  • 程序

    以下程序中使用硬编码的pwm通道,可以考虑进行修改。

    static bool SetupPWMDevice(int frequencyHz, float dutyCycle) {
      // 检查sys/class/pwm/pwmchip2目录是否存在
      const char* pwmChipPath = "/sys/class/pwm/pwmchip2";
      if (!QFile::exists(pwmChipPath)) {
        qWarning() << "PWM芯片路径不存在:" << pwmChipPath;
        return false;
      }
      // 导出PWM通道0
      QFile exportFile(QString("%1/export").arg(pwmChipPath));
      if (!exportFile.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开PWM导出文件:" << exportFile.errorString();
        return false;
      }
      QTextStream exportStream(&exportFile);
      exportStream << "0";  // 写入0 ,也就是导出通道0
      exportFile.close();
    
      // 设置PWM频率
      QFile periodFile(QString("%1/pwm0/period").arg(pwmChipPath));
      if (!periodFile.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开PWM周期文件:" << periodFile.errorString();
        return false;
      }
      qint64 periodNs = static_cast<qint64>(1e9 / frequencyHz);  // 周期,单位纳秒
      QTextStream periodStream(&periodFile);
      periodStream << periodNs;
      periodFile.close();
    
      // 设置PWM占空比
      QFile dutyFile(QString("%1/pwm0/duty_cycle").arg(pwmChipPath));
      if (!dutyFile.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开PWM占空比文件:" << dutyFile.errorString();
        return false;
      }
      qint64 dutyNs = static_cast<qint64>(periodNs * dutyCycle);
      QTextStream dutyStream(&dutyFile);
      dutyStream << dutyNs;
      dutyFile.close();
    
      // 使能
      QFile enableFile(QString("%1/pwm0/enable").arg(pwmChipPath));
      if (!enableFile.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开PWM使能文件:" << enableFile.errorString();
        return false;
      }
      QTextStream enableStream(&enableFile);
      enableStream << "1";  // 写入1 ,也就是使能
      enableFile.close();
    
      return true;
    }
    
    static bool DeinitPWMDevice() {
      // 检查sys/class/pwm/pwmchip2目录是否存在
      const char* pwmChipPath = "/sys/class/pwm/pwmchip2";
      if (!QFile::exists(pwmChipPath)) {
        qWarning() << "PWM芯片路径不存在:" << pwmChipPath;
        return false;
      }
    
      // 关闭使能
      QFile enableFile(QString("%1/pwm0/enable").arg(pwmChipPath));
      if (!enableFile.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开PWM使能文件:" << enableFile.errorString();
        return false;
      }
      QTextStream enableStream(&enableFile);
      enableStream << "0";  // 写入0 ,也就是关闭使能
      enableFile.close();
    
      // 取消导出PWM通道0
      QFile unexportFile(QString("%1/unexport").arg(pwmChipPath));
      if (!unexportFile.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开PWM取消导出文件:" << unexportFile.errorString();
        return false;
      }
      QTextStream unexportStream(&unexportFile);
      unexportStream << "0";  // 写入0 ,也就是取消导出通道0
      unexportFile.close();
      return true;
    }
    static bool SetPWMDutyCycle(float dutyCycle) {
      // 检查sys/class/pwm/pwmchip2目录是否存在
      const char* pwmChipPath = "/sys/class/pwm/pwmchip2";
      if (!QFile::exists(pwmChipPath)) {
        qWarning() << "PWM芯片路径不存在:" << pwmChipPath;
        return false;
      }
    
      // 读取当前周期
      QFile periodFile(QString("%1/pwm0/period").arg(pwmChipPath));
      if (!periodFile.open(QIODevice::ReadOnly)) {
        qWarning() << "无法打开PWM周期文件:" << periodFile.errorString();
        return false;
      }
      QTextStream periodStream(&periodFile);
      qint64 periodNs;
      periodStream >> periodNs;
      periodFile.close();
    
      // 设置新的占空比
      QFile dutyFile(QString("%1/pwm0/duty_cycle").arg(pwmChipPath));
      if (!dutyFile.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开PWM占空比文件:" << dutyFile.errorString();
        return false;
      }
      qint64 dutyNs = static_cast<qint64>(periodNs * dutyCycle);
      QTextStream dutyStream(&dutyFile);
      dutyStream << dutyNs;
      dutyFile.close();
    
      // 重新使能PWM以应用新设置
      QFile enableFile(QString("%1/pwm0/enable").arg(pwmChipPath));
      if (!enableFile.open(QIODevice::WriteOnly)) {
        qWarning() << "无法打开PWM使能文件:" << enableFile.errorString();
        return false;
      }
      QTextStream enableStream(&enableFile);
      enableStream << "1";
      enableFile.close();
    
      return true;
    }
    
    

验证

  • 基于上述配置,设置生成周期为20KHz,占空比为20%的PWM波。

  • 而后,使用Slogic Commbo8 的逻辑分析仪功能实现验证。

    逻辑分析仪显示按照设置的值进行了输出。20KHz,20%占空比

    image

  • 结合Qt UI进行验证

    • UI设计

      image

    • 槽函数绑定

       // 连接PWM滑动条信号到槽函数
          connect(this,&sensorgui::sendPWMValueToControl,sensorOp,&SensorOperation::onSetPWMDutyCycle);
      
    • 事件响应

      void sensorgui::on_pwm3ValueSlidrBar_valueChanged(int value)
      {
          //获取最大值和最小值
          int minValue = ui->pwm3ValueSlidrBar->minimum();
          int maxValue = ui->pwm3ValueSlidrBar->maximum();
          //计算占空比
          float dutyCycle = static_cast<float>(value - minValue) / (maxValue - minValue);
          //发送信号
          emit sendPWMValueToControl(dutyCycle);
      }
      static bool SetPWMDutyCycle(float dutyCycle)
      {
          //检查sys/class/pwm/pwmchip2目录是否存在
          const char *pwmChipPath = "/sys/class/pwm/pwmchip2";
          if (!QFile::exists(pwmChipPath)) {
              qWarning() << "PWM芯片路径不存在:" << pwmChipPath;
              return false;
          }
      
          //读取当前周期
          QFile periodFile(QString("%1/pwm0/period").arg(pwmChipPath));
          if (!periodFile.open(QIODevice::ReadOnly)) {
              qWarning() << "无法打开PWM周期文件:" << periodFile.errorString();
              return false;
          }
          QTextStream periodStream(&periodFile);
          qint64 periodNs;
          periodStream >> periodNs;
          periodFile.close();
      
          //设置新的占空比
          QFile dutyFile(QString("%1/pwm0/duty_cycle").arg(pwmChipPath));
          if (!dutyFile.open(QIODevice::WriteOnly)) {
              qWarning() << "无法打开PWM占空比文件:" << dutyFile.errorString();
              return false;
          }
          qint64 dutyNs = static_cast<qint64>(periodNs * dutyCycle);
          QTextStream dutyStream(&dutyFile);
          dutyStream << dutyNs;
          dutyFile.close();
      
          return true;
      }
      
      
    • 效果验证

      image

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值