如何使用ARM7-LPC2148微控制器中的PWM控制LED的亮度

众所周知,微控制器从模拟传感器获取模拟输入,并使用adc(模数转换器)来处理这些信号。但是,如果微控制器想要产生模拟信号来控制伺服电机、直流电机等模拟操作设备怎么办?微控制器不会产生像 1v、5v 这样的输出电压,而是使用一种称为 pwm 的技术来操作模拟设备。pwm的一个例子是我们笔记本电脑的冷却风扇(直流电机)需要根据温度进行速度控制,这也是通过在主板中使用脉宽调制(pwm)技术来实现的。
在本教程中,我们将使用 arm7-lpc2148 微控制器中的 pwm 控制 led 的亮度。
pwm(脉冲宽度调制)
pwm 是一种使用数字值控制模拟设备的好方法,例如控制电机的速度、led 的亮度等。虽然 pwm 不提供纯模拟输出,但它会产生不错的模拟脉冲来控制 analog devices。pwm 实际上调制矩形脉冲波的宽度,以便得到结果波平均值的变化。
pwm 的占空比
pwm 信号保持高电平(开启时间)的时间百分比称为占空比。如果信号始终打开,则占空比为 100%,如果始终关闭,则占空比为 0%。
占空比=开启时间/(开启时间+关闭时间)
arm7-lpc2148 中的 pwm
arm7-lpc2148 有 6 个 pwm 引脚和 14 个 adc 引脚。它具有 8 位 pwm 分辨率(2 8),即计数器和变量可以高达 255,因此:
255 的数字值可提供 led 的全亮度(100% 占空比)
同样,数字值 127 可提供 50% 的 led 亮度(占空比为 50%)
数字值 64 提供 25% 的 led 亮度(25% 占空比)
arm7-lpc2148 中的 pwm 引脚
下图显示了arm7-lpc2148 的 pwm 输出引脚。pwm共有 6 个引脚。
arm7-lpc2148 中的 pwm 寄存器
在进入我们的项目之前,我们需要了解 lpc2148 中的 pwm 寄存器。
这是 lpc2148 中用于 pwm 的寄存器列表
1. pwmpr : pwm 预分频寄存器
用途:它是一个 32 位寄存器。它包含在递增 pwm 定时器计数器之前 pclk 必须循环的次数(减 1)(它实际上保存了预分频计数器的最大值)。
2. pwmpc: pwm 预分频计数器
用途:它是一个 32 位寄存器。它包含递增的计数器值。当该值等于 pr 值加 1 时,pwm 定时器计数器 (tc) 递增。
3. pwmtcr : pwm 定时器控制寄存器
用途:它包含计数器使能、计数器复位和 pwm 使能控制位。它是一个 8 位寄存器。
4. pwmtc : pwm 定时器计数器
用途:它是一个 32 位寄存器。它包含递增 pwm 定时器的当前值。当预分频器计数器 (pc) 达到预分频器寄存器 (pr) 的值加 1 时,该计数器递增。
5. pwmir: pwm中断寄存器
用途:它是一个 16 位寄存器。它包含 pwm 匹配通道 0-6 的中断标志。当该通道(mrx 中断)发生中断时,将设置一个中断标志,其中 x 是通道号(0 到 6)。
6. pwmmr0-pwmmr6: pwm匹配寄存器
用途:它是一个 32 位寄存器。 实际上,匹配通道组允许设置 6 个单边沿控制或 3 个双边沿控制 pwm 输出。您可以修改七个匹配通道来配置这些 pwm 输出以满足您在 pwmpcr 中的要求。
7. pwmmcr : pwm 匹配控制寄存器
用途:它是一个 32 位寄存器。它包含控制所选匹配通道的中断、复位和停止位。pwm 匹配寄存器和 pwm 定时器计数器之间发生匹配。
8. pwmpcr : pwm 控制寄存器
用途:它是一个 16 位寄存器。它包含启用 pwm 输出 0-6 并为每个输出选择单边沿或双边沿控制的位。
9. pwmler: pwm 锁存器使能寄存器
用途:它是一个 8 位寄存器。它包含每个匹配通道的匹配 x 锁存位。
现在让我们开始构建硬件设置来演示 arm 微控制器中的脉冲宽度调制。
所需组件
电路图和连接
lcd和arm7-lpc2148之间的连接
led与arm7-lpc2148之间的连接
led 的 anode 连接到 lpc2148 的 pwm 输出 (p0.0),而 led 的 cathode 引脚连接到 lpc2148 的 gnd 引脚。
arm7-lpc2148与带3.3v稳压器的电位器连接
需要注意的点
1. 这里使用 3.3v 的稳压器为 lpc2148 的 adc 引脚 (p0.28) 提供模拟输入值,因为我们使用的是 5v 电源,我们需要使用 3.3v 的稳压器来调节电压。
2. 电位器用于在(0v 至 3.3v)之间改变电压,以向 lpc2148 引脚 p0.28 提供模拟输入(adc)
为 pwm 和 adc 编程 lpc2148 所涉及的步骤
第 1 步:-首先是配置 pll以生成时钟,因为它根据程序员的需要设置 lpc2148 的系统时钟和外设时钟。lpc2148 的最大时钟频率为 60mhz。以下行用于配置 pll 时钟生成。
void initilizepll (void) //使用 pll 产生时钟的函数
{
pll0con = 0x01;
pll0cfg = 0x24;
pll0feed = 0xaa;
pll0feed = 0x55;
而(!(pll0stat&0x00000400));
pll0con = 0x03;
pll0feed = 0xaa;
pll0feed = 0x55;
vpbdiv = 0x01;
}
第 2 步:-接下来是使用 pinsel 寄存器选择 lpc2148 的 pwm 引脚和 pwm 功能。我们使用 pinsel0,因为我们使用 p0.0 作为 lpc2148 的 pwm 输出。
pinsel0 = 0x00000002;//设置引脚p0.0为pwm输出
第 3 步:-接下来我们需要使用 pwmtcr(定时器控制寄存器)重置定时器。
pwmtcr = (1<<1); //设置pwm定时器控制寄存器为计数器复位
然后,设置决定 pwm 分辨率的预分频值。我将它设置为零
pwmpr = 0x00;//设置pwm预分频值
第 4 步:-接下来我们需要设置 pwmmcr(pwm 匹配控制寄存器),因为它设置了复位等操作,pwmmr0 的中断。
pwmmcr = (1<<0)|(1<<1); //设置pwm匹配控制寄存器
第 5 步:-使用 pwmmr 设置 pwm 通道的最大周期。
pwmmr0 = pwm值;//给pwm值最大值
在我们的例子中,最大值是 255(对于最大亮度)
第 6 步:-接下来我们需要使用 pwmler 将 latch enable 设置为相应的匹配寄存器
pwmler = (1<<0); //启用pwm锁存器
(我们使用 pwmmr0)所以通过在 pwmler 中设置 1 来启用相应的位
第 7 步:-要使 pwm 输出到引脚,我们需要使用 pwmtcr 来启用 pwm 定时器计数器和 pwm 模式。
pwmtcr = (1<<0) | (1<<3); //启用pwm和pwm计数器
第 8 步:-现在我们需要从 adc 引脚 p0.28 获取用于设置 pwm 占空比的电位器值。因此,我们使用 lpc2148 中的 adc 模块将电位器模拟输入(0 至 3.3v)转换为 adc 值(0 至 1023)。
在这里,我们通过将其除以 4 将值从 0-1023 转换为 0-255,因为 lpc2148 的 pwm 具有 8 位分辨率 (2 8 )。
第 9 步:-为了选择 lpc2148 中的 adc 引脚 p0.28,我们使用
pinsel1 = 0x01000000;//设置p0.28为adc input
ad0cr = (((14)<<8) | (1<<21)); //为a/d转换设置时钟和pdn
以下行捕获模拟输入(0 到 3.3v)并将其转换为数字值(0 到 1023)。然后将此数字值除以 4 以将它们转换为(0 到 255),最后作为pwm 输出馈送到连接 led 的 lpc2148 的 p0.0 引脚。
ad0cr |= (1<<1);
//在adc寄存器delaytime(10)
中选择ad0.1通道;ad0cr |= (1<<24); //开始a/d转换
while( (ad0dr1 & (16) & 0x3ff; //从 adc 数据寄存器中获取 result
dutycycle = adcvalue/4; //从 (0 到 255) 获取占空比值的公式
pwmmr1 = dutycycle; //设置占空比值到 pwm 匹配寄存器
pwmler |= (1<<1); //使用占空比值启用 pwm 输出
第 10 步:-接下来我们在 lcd (16x2) 显示模块中显示这些值。所以我们添加以下行来初始化 lcd 显示模块
void lcd_initilize(void) //准备 lcd 的函数
{
io0dir = 0x0000fff0; //设置引脚p0.12,p0.13,p0.14,p0.15,p0.4,p0.6为output
delaytime(20);
lcd_send(0x02); // 以 4 位操作模式初始化 lcd
lcd_send(0x28); // 2 行 (16x2)
lcd_send(0x0c); // 光标关闭时显示
lcd_send(0x06); // 自动递增光标
lcd_send(0x01); // 显示清除
lcd_send(0x80); // 第一行第一个位置
}
当我们将4 位模式的 lcd 与 lpc2148连接时,我们需要发送值以逐个半字节(上半字节和下半字节)显示。所以使用以下几行。
void lcd_display (char* msg) //函数将发送的字符一一打印
{
uint8_t i=0;
while(msg[i]!=0)
{
io0pin = ( (io0pin & 0xffff00ff) | ((msg[i] & 0xf0)<<8) ); //发送高半字节
io0set = 0x00000050; //rs high & enable high 打印数据
io0clr = 0x00000020; //rw low 写模式
延迟时间(2);
io0clr = 0x00000040;// en = 0,rs 和 rw 不变(即 rs = 1,rw = 0)
delaytime(5);
io0pin = ( (io0pin & 0xffff00ff) | ((msg[i] & 0x0f)<<12) ); //发送低半字节
io0set = 0x00000050; //rs & en high
io0clr = 0x00000020;
延迟时间(2);
io0clr = 0x00000040;
延迟时间(5);
我++;
}
}
为了显示这些 adc 和 pwm 值,我们在int main()函数中使用以下行。
lcd_send(0x80);
sprintf(displayadc, adcvalue=%f, adcvalue);
lcd_display(displayadc); //显示adc值(0到1023)
lcd_send(0xc0);
sprintf(ledoutput,“pwm op=%.2f”,亮度);
lcd_display(led输出);//显示从(0到255)的占空比值
无效初始化pll(无效);
无效初始化pwm(无符号整数周期pwm);
无效延迟时间(uint16_t j);
void initilizepll (void) //使用pll产生时钟的函数
{
pll0con = 0x01;
pll0cfg = 0x24;
pll0feed = 0xaa;
pll0feed = 0x55;
而(!(pll0stat&0x00000400));
pll0con = 0x03;
pll0feed = 0xaa;
pll0feed = 0x55;
vpbdiv = 0x01;
}
void delaytime(uint16_t j) // 产生 1 毫秒延迟的函数
{
uint16_t x,i;
for(i=0;i{
对于(x=0;x<6000;x++);
}
}
无效初始化pwm(无符号整数pwm值)
{
pinsel0 = 0x00000002;//设置引脚p0.0为pwm输出
pwmtcr = (1<<1); //设置pwm定时器控制寄存器为计数器复位
pwmpr = 0x00;//设置pwm预分频值
pwmmcr = (1<<0)|(1<<1); //设置pwm匹配控制寄存器
pwmmr0 = pwm值;//给pwm值最大值
pwmler = (1<<0); //启用pwm锁存器
pwmtcr = (1<<0) | (1<<3); //启用pwm和pwm计数器
}
void lcd_send(char command) //发送十六进制命令的函数
{
io0pin = ( (io0pin & 0xffff00ff) | ((命令 & 0xf0)<<8) ); //发送命令的上半字节
io0set = 0x00000040;//使启用高
io0clr = 0x00000030;//使 rs & rw 低
延迟时间(5);
io0clr = 0x00000040;//使启用低
延迟时间(5);
io0pin = ( (io0pin & 0xffff00ff) | ((命令 & 0x0f)<<12) ); //发送命令的低半字节
io0set = 0x00000040;//启用高
io0clr = 0x00000030;//rs & rw 低
延迟时间(5);
io0clr = 0x00000040;//启用低
延迟时间(5);
}
void lcd_initilize(void) //准备lcd的函数
{
io0dir = 0x0000fff0;//设置引脚p0.12,p0.13,p0.14,p0.15,p0.4,p0.6为output
延迟时间(20);
lcd_send(0x02); // 以 4 位操作模式初始化 lcd
lcd_send(0x28); // 2 行 (16x2)
lcd_send(0x0c); // 光标关闭时显示
lcd_send(0x06); // 自动递增光标
lcd_send(0x01); // 显示清晰
lcd_send(0x80); // 第一行第一个位置
}
void lcd_display (char* msg) //函数将发送的字符一一打印
{
uint8_t i=0;
而(味精[i]!=0)
{
io0pin = ( (io0pin & 0xffff00ff) | ((msg[i] & 0xf0)<<8) ); //发送上半字节
io0set = 0x00000050;//rs high & enable high 打印数据
io0clr = 0x00000020;//rw low 写模式
延迟时间(2);
io0clr = 0x00000040;// en = 0,rs 和 rw 不变(即 rs = 1,rw = 0)
延迟时间(5);
io0pin = ( (io0pin & 0xffff00ff) | ((msg[i] & 0x0f)<<12) ); //发送低半字节
io0set = 0x00000050;//rs & en 高
io0clr = 0x00000020;
延迟时间(2);
io0clr = 0x00000040;
延迟时间(5);
我++;
}
}
主函数()
{
lcd_initilize(); //调用函数准备lcd显示
字符显示adc[18];
浮动亮度;
字符 led 输出[18];
lcd_display(电路摘要);
延迟时间(900);
lcd_send(0xc0);
lcd_display(lpc2148 中的 pwm);
延迟时间(900);
占空比;
浮动 adc 值;
初始化pll();//调用函数initilizepll
pinsel1 = 0x01000000;//设置p0.28为adc input
ad0cr = (((14)<<8) | (1<<21)); //为a/d转换设置时钟和pdn
初始化pwm(255);//调用函数initilizepwm,值为255
pwmpcr |= (1<<9); //在lpc2148的p0.0引脚启用pwm1输出
而(1)
{
ad0cr |= (1<<1); //选择adc寄存器中的ad0.1通道
延迟时间(10);
ad0cr |= (1<<24); //开始a/d转换
而( (ad0dr1 & (16) & 0x3ff; //从adc数据寄存器中获取result
占空比 = adcvalue/4;//从 (0 到 255) 获取占空比值的公式
pwmmr1 = 占空比;//设置占空比值到pwm匹配寄存器
pwmler |= (1<<1); //使用占空比值启用 pwm 输出
亮度 = 占空比;
lcd_send(0x80);
sprintf(displayadc, adcvalue=%f, adcvalue);
lcd_display(displayadc); //显示adc值(0到1023)
lcd_send(0xc0);
sprintf(ledoutput,“pwm op=%.2f”,亮度);
lcd_display(led输出);//显示从(0到255)的占空比值
}
}

华为HMS的生态新跑道 HMS的生态基建为全球开发者铺路
3G手机射频集成障碍
Yolov3&amp;Yolov4核心基础知识
ios10.3.2公测版发布,是良心还是挖坑?重新支持32位设备,神速关闭ios10.2.1和ios10.3的系统验证通道
智能化汽车如何发展,四维智联提出智能座舱交互思考
如何使用ARM7-LPC2148微控制器中的PWM控制LED的亮度
MSH二级补全API使用示例
基于TMS320VC5402处理器实现无线定位模拟系统的设计
免驱动即插即用HDMI转VGA转换器的介绍
MAX3669 低功耗622Mbps激光驱动器
ADI携最新低功耗主动降噪芯片亮相蓝牙耳机展
中商北斗和币安中国区块链研究院合作 助力中国数字经济发展
盘古大模型和混元模型的区别
机器人零拷贝数据传输编程开发
华勤H8230 4U8卡AI服务器,助力企业数字化转型价值提升
踏歌智行参编的《智能化矿山数据融合共享规范》正式发布
CNR插槽
英菲尼迪将推首款纯电动跑车 使用新平台打造
面向现场 三相永磁无刷电机的技术研究
能优异导热填料粉:片状氮化铝导热高于球形氮化铝吗?