☰
ARM裸机开发-PWM
2026/10/7 10:10:37 网站建设 项目流程

目录

一.背景

PWM原理

二.寄存器

PWMCR

FWM(bit27:26):

POUTC(bit19:18):

CLKSRC(bit17:16):

PRESCALER(bit15:4):

REPEAT(bit2:1):

EN(bit0):

PWMSR

FE(bit3):

PWMIR

FIE(bit0):

PWMSAR

PWMPR

三.代码实现


一.背景

不管是使用显示器还是手机,其屏幕背光都是可以调节的,通过调节背光就可以控制屏幕的亮度。在户外阳光强烈的时候可以通过调高背光来看清屏幕,在光线比较暗的地方可以调低背光,防止伤眼睛并且省电。 我们使用的开发板LCD 有一个背光控制引脚,给这个背光控制引脚输入高电平就会点亮背光,输入低电平就会关闭背光。假如我们不断的打开和关闭背光,当速度足够快的时候就不会感觉到背光关闭这个过程了。这个正好可以使用 PWM 来完成,PWM 全称是 Pulse Width Modulation,也就是脉冲宽度调制,本质上来说PWM的目的就是产生一个方波。
PWM 信号有两个关键的术语:频率和占空比,频率就是开关速度,把一次开关算作一个周期,那么频率就是 1 秒内进行了多少次开关。占空比就是一个周期内高电平时间和低电平时间的比例,一个周期内高电平时间越长占空比就越大,反之占空比就越小。占空比用百分之表示,如果一个周期内全是低电平那么占空比就是 0%,如果一个周期内全是高电平那么占空比就是100%。
我们给 LCD 的背光引脚输入一个 PWM 信号,这样就可以通过调整占空比的方式来调整LCD 背光亮度了。提高占空比就会提高背光亮度,降低占空比就会降低背光亮度。重点就在于PWM 信号的产生和占空比的控制,很幸运的是,I.MX6U 提供了 PWM 外设,因此我们可以配置 PWM 外设来可以方便地产生PWM 信号。

imx6ull将PWM封装为外设

PWM原理

此图有三个中断,周期寄存器的回滚中断,采样寄存器的比较中断,以及FIFO缓冲区的空槽中断。此处只用FIFO中断,每次从FIFO中取数到采样寄存器,决定了占空比(该FIFO深度为4,即存放4个16位数),当FIFO缓冲区的数据被取到空的阈值时产生中断,在中断处理函数中再往FIFO里重新装入数据,以下实现的代码基于此。

计数寄存器自增到和采样寄存器比较,相等则将PWM电平翻转,后续再和周期寄存器的值比较,相等则翻转电平,同时从0开始重新计数自增,重复此过程,和采样寄存器比较,再和周期寄存器的值比较,相等就翻转电平,并回滚为0.

二.寄存器

PWMCR

FWM(bit27:26):
FIFO 水位线,用来设置 FIFO 空余位置为多少的时候表示 FIFO 为空。设置为 0 的时候表示 FIFO 空余位置大于等于 1 的时候 FIFO 为空;设置为 1 的时候表示 FIFO 空余位置大于等于 2 的时候 FIFO 为空;以此类推。

队列有四个数,设置FWM位为01,当队列有两个空槽时置1

POUTC(bit19:18):

00表示回滚点高电平,比较点低电平,01相反,即设置起始的默认电平。

我们设置为 0,也就是一开始输出高电平,当计数器值和采样值相等的话就改为低电平,这样采
样值越大高电平时间就越长,占空比就越大;

如下图

CLKSRC(bit17:16):
PWM 时钟源选择,为 0 的话关闭;为 1 的话选择 ipg_clk 为时钟源;为 2 的话选择 ipg_clk_highfreq 为时钟源;为 3 的话选择 ipg_clk_32k 为时钟源。我们设置为 1,也就是选择ipg_clk 为 PWM 的时钟源,因此 PWM 时钟源频率为 66MHz;
PRESCALER(bit15:4):
分频值,可设置为 0~4095,对应着 1~4096 分频。我们设置为65,就是66分频,PWM实际工作频率为1MHz;
REPEAT(bit2:1):
重复采样设置,此位用来设置 FIFO 中的每个数据能用几次。可设置 0~3分别表示 FIFO
中的每个数据能用 1~4 次。本章我们设置为 3,即 FIFO 中的每个数据用8次;

EN(bit0):
PWM 使能位,为 1 的时候使能 PWM,为 0 的时候关闭 PWM

PWMSR

这个寄存器是状态及标志寄存器
FE(bit3):
FIFO 到达水位线标志,为 1 的时候表示 FIFO 已到达水位线。我们主要在中断中关注这个标志,
并及时清零;

PWMIR

这个是 PWM 的中断控制寄存器
FIE(bit0):
FIFO 空中断,为 1 的时候使能,为 0 的时候关闭。我们需要使能这个中断

PWMSAR

设置PWM的占空比,即采样寄存器

PWMPR

设置PWM周期,即周期寄存器

三.代码实现

float global_ratio = 1.0; // 设置占空比 void set_ratio(void) { int i = 0 ; for (i = 0; i < 4; i++) { PWM1->PWMSAR = PWM1->PWMPR * global_ratio; } } void pwm1_interrupt_handler(void) { if ((PWM1->PWMSR & (1 << 3)) != 0) { set_ratio(); PWM1->PWMSR |= (1 << 3); } } // pwm1初始化 void pwm1_init(void) { // 1. pwm引脚复用 IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_PWM1_OUT, 0); // 2. pwm引脚电气属性 IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_PWM1_OUT, 0xB9); PWM1->PWMCR = 0; PWM1->PWMCR |= (1 << 26) | (1 << 16) | (65 << 4) | (3 << 1); PWM1->PWMIR |= (1 << 0); PWM1->PWMPR = 998; set_ratio(); // 注册pwm中断 system_interrupt_register(PWM1_IRQn, pwm1_interrupt_handler); // 设置pwm中断优先级 GIC_SetPriority(PWM1_IRQn, 0); // 使能pwm中断 GIC_EnableIRQ(PWM1_IRQn); // 使能PWM PWM1->PWMCR |= (1 << 0); }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询