pwm归根到底就是调整高低电平在一个周期信号里的比例时间.
占空比: 指有效电平(通常高电平)在周期信号里的持续时间.
周期信号: 如从上升沿到下一个上升沿的时间。 100HZ表示1秒钟内有100个时钟周期。
pwm常用于调节LCD背光和对比度, 舵机, 调速马达,也可用于作时钟信号产生器。
如上图,就是四种在相同周期信号里的不同的占空比(每个周期里的高电平持续时间)
pwm调节LCD背光原理:
LCD背光通常是由LED作背光源, 调节LED的工作电压值可以改变LED的工作电流大小,从而改变了LCD的亮度.
但通过I/O口只能控制输出高(如3.3v)和低(0v)两种电平, 没法输出其它电压值. 所以通过pwm里的占空比,表示要输出的电压值大小, 再由芯片MP3202根据提供的pwm信号里的占空比输出相应比例的电压值.
如下图就是相应的电路:
一般的芯片都会提供pwm控制器,而全志H3里只提供了一个pwm控制器(电路上标的pwm1是不存在的)
在H3 linux 核里pwm控制器相关的配置:
make menuconfig ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
Device Drivers —>
[*] Pulse-Width Modulation (PWM) Support —>
sunxi pwm support
驱动代码在drivers/pwm/pwm-sunxi.c, 源文件里已实现相应的struct platform_device和platform_driver, 只需通过script.bin里打开pwm控制器功能即可.
同时需要注意的是, H3 pwm控制器的信号输出引脚PA05与uart0的rx脚是复用的, 所以PA05作pwm输出时就不可以使用uart0, 需要把其它的uart控制器作调试口使用,请参考http://blog.csdn.net/jklinux/article/details/79579145
在script.fex里pwm的配置:
[pwm0_para]
pwm_used = 1
pwm_positive = port:PA05<3><0>
修改script.bin和重编并使用新内核镜像后,pwm控制器应就驱动好了.
控制器驱动好的,就可以在设备驱动里通过下面相关的函数来调用控制器即可:
#include
struct pwm_device *pwm_request(int pwm_id, const char *label);
//请求使用pwm控制器, pwm_id是指第几个控制器
void pwm_free(struct pwm_device *pwm);
//释放请求的pwm控制器
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
//duty_ns表示占空比时间, period_ns表示信号周期时间
int pwm_enable(struct pwm_device *pwm);
//启用pwm控制器
void pwm_disable(struct pwm_device *pwm);
//停用pwm控制器
enum pwm_polarity {
PWM_POLARITY_NORMAL, //占空比为高电平
PWM_POLARITY_INVERSED, //低电平
};
int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity);
//设置pwm的有效电平是高电平/低电平
调用流程:
1 初始化
pwm_request
pwm_config
pwm_set_polarity
pwm_enable
2 修改占空比
pwm_disable
pwm_config
pwm_enable
3 停止pwm信号输出
pwm_disable
pwm_free
舵机:
红色线接电源, 棕色线接地, 橙色线接pwm
舵机控制原理, 通过一个为20ms(即50HZ)的周期信号,不同的占空比(0.5ms ~ 2.5ms)控制舵机的转向角度.
0.5ms————–舵机转动到0度
1.0ms————–舵机转动到45度
1.5ms————–舵机转动到90度
2.0ms————–舵机转动到135度
2.5ms————–舵机转动到180度
借用别人的一张动图,可以完整展示出转动到的角度与pwm信号的关系.
控制舵机的测试代码:
#include
#include
#include
#include
struct pwm_device *pwm;
static int __init test_init(void)
{
int ret = -ENODEV;
pwm = pwm_request(0, “mypwmdev”);
if (NULL == pwm)
goto err0;
pwm_config(pwm, 500000, 20000000); // 0.5ms
pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);
pwm_enable(pwm);
msleep(3000);
printk(“change …\n”);
pwm_disable(pwm);
pwm_config(pwm, 1000000, 20000000); // 1ms
pwm_enable(pwm);
return 0;
err0:
return ret;
}
static void __exit test_exit(void)
{
pwm_disable(pwm);
pwm_free(pwm);
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE(“GPL”);