杭州手机网站,域名类型,广州海珠区最新通告,跨境电商关键词工具PWM PWM简介⭕
**PWM#xff08;Pulse Width Modulation#xff0c;脉冲宽度调制#xff09;**是一种利用微处理器的数字输出对模拟电路进行控制的技术。通过改变脉冲的占空比#xff0c;可以控制模拟电路的输出电压或电流。PWM技术广泛应用于电机控制、灯光调节、音频信号…PWM PWM简介⭕
**PWMPulse Width Modulation脉冲宽度调制**是一种利用微处理器的数字输出对模拟电路进行控制的技术。通过改变脉冲的占空比可以控制模拟电路的输出电压或电流。PWM技术广泛应用于电机控制、灯光调节、音频信号生成等领域。
PWM频率和占空比⭕
周期PWM信号的重复周期即一个PWM信号从高电平到低电平再到高电平的时间间隔。
频率PWM信号的重复频率即每秒钟PWM信号的重复次数。频率与周期成反比频率 1 / 周期。
占空比PWM信号的脉冲宽度与周期的比值即高电平时间占整个周期的比例。占空比可以取0到1之间的任意值。
PWM的应用⭕
面积等效原理 冲量相等而形状不同的窄宽脉冲加在具有惯性的环节上其效果基本相同
冲量相等而形状不同是指面积相等惯性环节在电路和系统分析中当输入信号发生变化时其输出不会立即跟随变化而是需要经过一段时间后才能逐渐达到新的稳态值。
通俗的说:电压不同时间不同的俩个信号当他们的电压和时间的乘积相等的时候输出的波形信号是相同的 pwm的子系统框架图 两种驱动方法
直接在应用层操作sys/class/pwm编写驱动程序后在应用层调用
PWM驱动编写⭕
Linux内描述一个PWM控制器的结构体
struct pwm_chip {struct device *dev;const struct pwm_ops *ops;int base;unsigned int npwm;struct pwm_device * (*of_xlate)(struct pwm_chip *pc,const struct of_phandle_args *args);unsigned int of_pwm_n_cells;/* only used internally by the PWM framework */struct list_head list;struct pwm_device *pwms;ANDROID_KABI_RESERVE(1);
};
PWM常有API
pwm_config函数
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) //改变pwm配置参数作用*pwmpwm_deviceduty_ns占空比period_ns周期
成功返回0失败返回负数
pwm_set_polarity函数
int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity) //设置pwm极性参数作用*pwmpwm_devicepolaritypwm极性
成功返回0失败返回负数
pwm_enable函数
int pwm_enable(struct pwm_device *pwm) //使能pwm参数作用*pwmpwm_device
成功返回0失败返回负数
pwm_disable函数
int pwm_disable(struct pwm_device *pwm) //禁止pwm参数作用*pwmpwm_device
成功返回0失败返回负数
pwm_request函数
struct pwm_device *pwm_request(int pwm, const char *label) //申请pwm参数作用pwmpwm号labelpwm标签
成功返回pwm_device失败返回NULL
pwm_free函数
void pwm_free(struct pwm_device *pwm) //释放pwm参数作用*pwmpwm_device
无返回
devm_pwm_get函数
int devm_pwm_get(struct device *dev, const char *con_id)//获取PWM设备句柄参数作用*dev设备con_idpwm标签
成功返回pwm_device句柄失败返回负数
driver层的使用⭕
使用platform_driver的实现驱动注册匹配设备树节点即可。
#include linux/of.h
#include linux/of_gpio.h
#include linux/module.h
#include linux/platform_device.h
#include linux/gpio.h
#include linux/delay.h
#include linux/pwm.hstruct pwm_device *pwm_dev;dev_t dev_num; // 设备号static int major 0; /* 主设备号, 0 表示由系统分配 */struct class *class; // 类和对象static int pwm_driver_open(struct inode *, struct file *)
{pwm_config(pwm_dev, 500000, 2000000); // 周期2000000ns,占空比500000nspwm_set_polarity(pwm_dev, PWM_POLARITY_NORMAL); // 设置极性pwm_enable(pwm_dev); // 启动PWMreturn 0;
}
static int pwm_driver_release(struct inode *, struct file *)
{pwm_free(pwm_dev);return 0;
}static struct file_operations pwm_fops {.owner THIS_MODULE,.open pwm_driver_open,.release pwm_driver_release};static int pwm_driver_probe(struct platform_device *pdev)
{int ret 0;pwm_dev devm_of_pwm_get(pdev-dev, dev-dev.of_node, NULL);if (IS_ERR(pwm_dev)){printk(get pwm device failed\n);return -1;}// 添加字符设备节点int err;major register_chrdev(0, hello, pwm_fops);class class_create(THIS_MODULE, hello_class);err PTR_ERR(class);if (IS_ERR(class)){printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, hello);return -1;}device_create(class, NULL, MKDEV(major, 0), NULL, hello); /* 设备节点/dev/hello创建 */return 0;
}static int pwm_remove(struct platform_device *pdev)
{unregister_chrdev(major, hello);class_destroy(class);if (!pwm_dev){pwm_free(pwm_dev);}return 0;
}static const struct of_device_id pwm_of_match[] {{.compatible pwm_test},{},
};
MODULE_DEVICE_TABLE(of, pwm_of_match);static struct platform_driver pwm_driver {.driver {.name pwm_test,.of_match_table pwm_of_match,},.probe pwm_driver_probe,.remove pwm_remove,
};static int __init pwm_init(void)
{return platform_driver_register(pwm_driver);
}static void __exit pwm_exit(void)
{platform_driver_unregister(pwm_driver);
}
module_init(pwm_init);
module_exit(pwm_exit);
MODULE_LICENSE(GPL);模拟PWM
使用模拟PWM即使用定时器来模拟PWM信号。给GPIO配置为输出模式然后通过定时器来控制GPIO的电平变化从而实现PWM信号的产生。 配置设备树指定一个LED的GPIO引脚
led {compatible gpio-led;gpios gpio0 9 GPIO_ACTIVE_LOW;
};在驱动中通过与设备树probe获取GPIO引脚然后配置为输出模式并使用定时器来控制GPIO的电平变化从而实现PWM信号的产生。
高精度定时器
普通定时器的时钟频率可以设置在 100Hz 到 1000Hz 之间所以精度只能限制在毫秒级别。所以无法满足精度较高的场景当中为此 Linux 提供了高精度定时器可以提供纳秒级别的精度。
struct hrtimer结构体
// include/linux/hrtimer.h高精度定时器
struct hrtimer {struct timerqueue_node node;ktime_t _softexpires;//定时时间enum hrtimer_restart (*function)(struct hrtimer *);//超时服务函数struct hrtimer_clock_base *base;u8 state;u8 is_rel;u8 is_soft;u8 is_hard;ANDROID_KABI_RESERVE(1);
};
// include/linux/timer.h普通定时器
struct timer_list {struct list_head entry;unsigned long expires; //定时时间void (*function)(unsigned long);//超时服务函数unsigned long data;unsigned int flags;int slack;
};hrtimer_init函数
//初始化一个定时器
void hrtimer_init(struct hrtimer *timer, clockid_t which_clock,enum hrtimer_mode mode);参数作用timer要初始化的定时器which_clock定时器所使用的时钟类型比如 CLOCK_REALTIME、CLOCK_MONOTONIC 等hrtimer_mode定时器模式比如 HRTIMER_MODE_REL、HRTIMER_MODE_ABS 等
ktime_set函数
//设置定时时间
ktime_t ktime_set(const error-type secs, const unsigned long nsecs);参数作用secs秒nsecs纳秒
hrtimer_start函数
//启动定时器
int hrtimer_start(struct hrtimer *timer, ktime_t time, const enum hrtimer_mode mode);参数作用timer要启动的定时器time定时时间mode定时器模式
hrtimer_forward函数
//定时器延时
void hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval);参数作用timer要延时的定时器now当前时间interval延时时间
hrtimer_cancel函数
//取消定时器
int hrtimer_cancel(struct hrtimer *timer);参数作用timer要取消的定时器
Source_code
#include linux/of.h
#include linux/of_gpio.h
#include linux/module.h
#include linux/platform_device.h
#include linux/gpio.h
#include linux/delay.h
#include linux/pwm.hstruct pwm_data{int sum_conut; // 总计数int high_count; // 高电平计数struct gpio_desc *gpio; // GPIOstruct hrtimer pwm_timer; // 定时器int time; // 定时时间
};
struct pwm_data *data;
struct pwm_device *pwm_dev;dev_t dev_num; // 设备号static int major 0; /* 主设备号, 0 表示由系统分配 */struct class *class; // 类和对象
enum hrtimer_restart pwm_timer_func(struct hrtimer *timer){//container_of 宏来从一个结构体成员的指针中获取包含它的结构体指针/*timer 是指向 pwm_timer 成员的指针。struct pwm_data 是包含 pwm_timer 成员的结构体类型。pwm_timer 是 struct pwm_data 结构体中的一个成员。*/static int timer_count 0;struct pwm_data *mydata container_of(timer, struct pwm_data, pwm_timer); if(timer_count mydata-sum_conut){gpiod_set_value(mydata-gpio, 1);timer_count 0;}if(timer_count mydata-high_count){gpiod_set_value(mydata-gpio, 0);}timer_countif(mydata-high_count 0){timer_count 0;}hrtimer_forward(timer, timer-_softexpires, mydata-time); // 定时器重新启动, 调整定时器的到期时间为当前时间加上mydata-timereturn HRTIMER_RESTART; // 重启定时器
}
static int pwm_driver_open(struct inode *, struct file *)
{return 0;
}
static int pwm_driver_release(struct inode *, struct file *)
{return 0;
}
static long pwm_driver_ioctl(struct file *file, unsigned int cmd, unsigned long arg){}
static ssize_t pwm_driver_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos){int ret 0;int kbuf[2];ret copy_from_user(kbuf, buf, count);data-sum_conut kbuf[0]; //总计数,周期data-high_count kbuf[1];//高电平计数占空比return ret;
}
static struct file_operations pwm_fops {.owner THIS_MODULE,.open pwm_driver_open,.release pwm_driver_release,.unlocked_ioctl pwm_driver_ioctl,.write pwm_driver_write,
};static int pwm_driver_probe(struct platform_device *pdev)
{data kmalloc(sizeof(struct pwm_data), GFP_KERNEL);data-sum_conut 20;data-high_count 10;// 添加字符设备节点int err;major register_chrdev(0, hello, pwm_fops);class class_create(THIS_MODULE, hello_class);err PTR_ERR(class);if (IS_ERR(class)){printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, hello);return -1;}device_create(class, NULL, MKDEV(major, 0), NULL, hello); /* 设备节点/dev/hello创建 */data-gpio gpiod_get(pdev-dev,gpio-led,GPIOF_OUT_INIT_HIGH) //获取GPIOgpiod_set_value(data-gpio, 1);//设置GPIO高电平data-time ktime_set(0,1000000); //定时器时间1ms,返回总时间hrtimer_init(data-pwm_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);//初始化定时器,CLOCK_MONOTONIC表示定时器从系统启动开始计时,HRTIMER_MODE_REL表示定时器从当前时间开始计时data-pwm_timer.function pwm_timer_func;//定时器回调函数hrtimer_start(data-pwm_timer, data-time, HRTIMER_MODE_REL);//启动定时器return 0;
}static int pwm_remove(struct platform_device *pdev)
{return 0;
}static const struct of_device_id pwm_of_match[] {{.compatible pwm_test},{},
};
MODULE_DEVICE_TABLE(of, pwm_of_match);static struct platform_driver pwm_driver {.driver {.name pwm_test,.of_match_table pwm_of_match,},.probe pwm_driver_probe,.remove pwm_remove,
};static int __init pwm_init(void)
{return platform_driver_register(pwm_driver);
}static void __exit pwm_exit(void)
{hrtimer_cancel(data-pwm_timer);kfree(data);platform_driver_unregister(pwm_driver);device_destroy(class, MKDEV(major, 0));class_destroy(class);unregister_chrdev(major, hello);}
module_init(pwm_init);
module_exit(pwm_exit);
MODULE_LICENSE(GPL);