在本教程中,我们将使用 ARM7-LPC2148 控制伺服电机。伺服电机比步进电机具有低功耗的优势。当到达所需位置时,伺服电机停止其功耗,但步进电机继续消耗功率以将轴锁定在所需位置。伺服电机主要用于 机器人项目 ,因为它们的准确性和易于操作性。
伺服电机
伺服电机 是直流电机、位置控制系统和齿轮的组合。 伺服电机的旋转是通过向其施加PWM信号来控制的,PWM信号的宽度决定了电机的旋转角度和方向。在这里,我们将在本教程中使用 SG90 伺服电机 ,它是最受欢迎和最便宜的电机之一。SG90 是 180 度伺服。所以有了这个伺服,我们可以将轴定位在 0-180 度之间:
工作电压:+5V
齿轮类型:塑料
旋转角度:0 至 180 度
重量:9克
扭矩:2.5kg/cm
在我们开始为伺服电机编程之前,我们应该知道要发送什么类型的信号来控制伺服电机。我们应该对 MCU 进行编程以将 PWM 信号发送到伺服电机的信号线。伺服电机内部有一个控制电路,它读取 PWM 信号的占空比并将伺服电机轴定位在相应的位置,如下图所示
伺服电机每 20 毫秒检查一次脉冲。因此,调整信号的脉冲宽度以旋转电机的轴。
1 毫秒(1 毫秒)脉冲宽度,用于伺服旋转到0 度
1.5ms 脉冲宽度旋转到90 度(中性位置)
2 ms 脉冲宽度用于伺服旋转到180 度。
在 将伺服连接到 ARM7-LPC2148之前,您可以借助此 伺服电机测试仪电路测试您的伺服。
使用 LPC2148 PWM 和 ADC 控制伺服电机
LPC2148 可以使用 PWM 控制伺服电机。通过以 20ms 的周期和 50Hz 的频率向 SERVO 的 PWM 引脚提供 PWM 信号,我们可以将伺服电机的轴定位在 180 度左右(-90 到 +90)。
电位器用于改变PWM信号的占空比并旋转伺服电机的轴,这种方法是通过使用LPC2148中的ADC模块来实现的。因此,我们需要在本教程中实现 PWM 和 ADC 概念。所以请参考我们之前的教程来学习 ARM7-LPC2148 中的 PWM 和 ADC。
ARM7-LPC2148 中的 PWM 和 ADC 引脚
下图显示了 LPC2148 中的 PWM 和 ADC 引脚。黄色框表示 (6) 个 PWM 引脚,黑框表示 (14) 个 ADC 引脚。
所需组件
ARM7-LPC2148
LCD (16x2) 显示模块
伺服马达 (SG-90)
3.3V稳压器
10k电位器(2个)
面包板
连接电线
软件
凯尔uVision5
闪光魔法工具
电路图和连接
下表显示了伺服电机与 ARM7-LPC2148 之间的连接:
引脚 P0.1 是 LPC2148 的 PWM 输出。
下表显示了LCD 和 ARM7-LPC2148 之间的电路连接。
下表显示了ARM7 LPC2148 和带 3.3V 稳压器的电位器之间的连接。
注意事项
1. 这里使用一个 3.3V 的稳压器为 LPC2148 的 ADC 引脚(P0.28)提供模拟输入值。由于我们使用的是 5V 电源,我们需要使用 3.3V 的稳压器来调节电压。
2. 电位器用于在(0V 至 3.3V)之间改变电压,以向 LPC2148 引脚 P0.28 提供模拟输入(ADC)
3、LPC2148的P0.1引脚为伺服电机提供PWM输出,控制电机的位置。
4. 根据模拟输入 (ADC) 值,伺服电机的位置通过 LPC2148 的 P0.1 处的 PWM 输出引脚从(0 到 180 度)变化。
为 PWM 和 ADC 配置 LPC2148 以控制伺服电机的步骤
第 1 步:-包括编码 LPC2148 所需的头文件
#include
#include
#include
#include
第 2 步:-下一步是配置 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;
}
第 3 步:-接下来要做的是使用 PINSEL 寄存器选择 LPC2148 的 PWM 引脚和 PWM 功能。我们使用 PINSEL0,因为我们使用 P0.1 作为 LPC2148 的 PWM 输出。
PINSEL0 |= 0x00000008; // 将 LPC2148 的 P0.1 引脚设置为 PWM3
第 4 步:-接下来,我们需要使用 PWMTCR(定时器控制寄存器)重置定时器。
PWMTCR = 0x02;// 重置和禁用 PWM 计数器
然后设置决定 PWM 分辨率的预分频值。
PWMPR = 0x1D;// 预分频寄存器值
第 5 步:-接下来,设置 PWMMCR(PWM 匹配控制寄存器),因为它设置复位、PWMMR0 和 PWMMR3 的中断等操作。
PWMMCR = 0x00000203;// MR0 匹配时复位并中断,MR3 匹配时中断
第 6 步:- PWM 通道的最大周期使用 PWMMR0 设置,PWM 占空比的 Ton 初始设置为 0.65msec
PWMMR0 = 20000;// PWM波的时间周期,
20msec PWMMR3 = 650; // 吨 PWM 波 0.65 毫秒
第 7 步:-接下来,我们需要使用 PWMLER 将 Latch Enable 设置为相应的匹配寄存器
PWMLER = 0x09;// PWM3 和 PWM0 的锁存使能
(我们使用 PWMMR0 和 PWMMR3)所以通过在 PWMLER 中设置 1 来启用相应的位
第 8 步:-要使 PWM 输出到引脚,我们需要使用 PWMTCR 来启用 PWM 定时器计数器和 PWM 模式。
PWMPCR = 0x0800;// 使能 PWM3 和 PWM 0,单边沿控制 PWM
PWMTCR = 0x09; // 启用 PWM 和计数器
第 9 步:-现在我们需要从 ADC 引脚 P0.28 获取用于设置 PWM 占空比的电位器值。因此,我们使用 LPC2148 中的 ADC 模块将电位器模拟输入(0 至 3.3V)转换为 ADC 值(0 至 1023)。
第 10 步:-为了 选择 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 输出馈送到 LPC2148 的 P0.1 引脚 。在这里,我们 通过将其除以 4 将值从 0-1023 转换为 0-255,因为 LPC2148 的 PWM 具有 8 位分辨率 (28)。
AD0CR |= (1<<1);
//在ADC寄存器delaytime(10)
中选择AD0.1通道;AD0CR |= (1<<24); //开始A/D转换
while( (AD0DR1 & (1<<31)) == 0 ); //检查ADC数据寄存器中的DONE位
adcvalue = (AD0DR1>>6) & 0x3ff; //从 ADC 数据寄存器中获取 RESULT
dutycycle = adcvalue/4; //从 (0 到 255) 获取占空比值的公式
PWMMR1 = dutycycle; //设置占空比值到 PWM 匹配寄存器
PWMLER |= (1<<1); //使用占空比值启用 PWM 输出
第 11 步:-接下来,我们在 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”,占空比);
LCD_DISPLAY(displayadc); //显示ADC值(0到1023)
angle = (adcvalue/5.7); //公式将ADC值转换为角度(o到180度)
LCD_SEND(0xC0);
sprintf(角度值,“角度=%.2f 度”,角度);
LCD_DISPLAY(角度值);
//连接伺服电机与ARM7-LPC2148
//由 Pramoth.T 编写的代码
#include
#include
#include
#include
无效初始化PLL(无效);
void initilizePLL (void) //使用PLL产生时钟的函数
{
PLL0CON = 0x01;
PLL0CFG = 0x24;
PLL0FEED = 0xAA;
PLL0FEED = 0x55;
而(!(PLL0STAT&0x00000400));
PLL0CON = 0x03;
PLL0FEED = 0xAA;
PLL0FEED = 0x55;
VPBDIV = 0x01;
}
void delay_ms(uint16_t z) // 使用 Cclk (60MHz) 产生 1 毫秒延迟的函数
{
uint16_t x,i;
for(i=0;i
{
对于(x=0;x<6000;x++);
}
}
__irq 无效 PWM_ISR (无效)
{
如果(PWMIR & 0x0001)
{
PWMIR = 0x0001;
}
如果(PWMIR & 0x0008)
{
PWMIR = 0x0008;
}
VICVectAddr = 0x00000000;
}
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];
浮动ADC;
浮动角度;
字符角度值[18];
LCD_DISPLAY("电路摘要");
延迟毫秒(900);
LCD_SEND(0xC0);
LCD_DISPLAY("伺服 LPC2148");
延迟毫秒(900);
PINSEL0 |= 0x00000008; // 将 LPC2148 的 P0.1 引脚设置为 PWM3
VICVectAddr0 =(无符号)PWM_ISR;// PWM ISR 地址
VICVectCntl0 = (0x00000020 | 8); // 启用 PWM IRQ 插槽
VICIntEnable = VICIntEnable | 0x00000100; // 启用 PWM 中断
VICIntSelect = VICIntSelect | 0x00000000; // PWM 配置为 IRQ
PWMTCR = 0x02;// 重置和禁用 PWM 计数器
PWMPR = 0x1D;// 预分频寄存器值
PWMMR0 = 20000;// PWM波的时间周期,20msec
PWMMR3 = 650;// 吨 PWM 波 0.65 毫秒
PWMMCR = 0x00000203;// MR0 匹配时复位并中断,MR3 匹配时中断
PWMLER = 0x09;// PWM3 和 PWM0 的锁存使能
PWMPCR = 0x0800;// 启用 PWM3 和 PWM 0,单边沿控制 PWM
PWMTCR = 0x09;// 启用 PWM 和计数器
浮动占空比;
unsigned short int adcvalue;
PINSEL1 = 0x01000000;//设置P0.28为ADC INPUT(来自电位器)
AD0CR = (((14)<<8) | (1<<21)); //为A/D转换设置时钟和PDN
PWMPCR |= (1<<9); //在LPC2148的P0.1引脚启用PWM3输出用于伺服(橙色线)
而(1)
{
AD0CR |= (1<<1); //选择ADC寄存器中的AD0.1通道
AD0CR |= (1<<24); //开始A/D转换
而( (AD0DR1 & (1<<31)) == 0 ); //检查ADC数据寄存器中的DONE位
adcvalue = (AD0DR1>>6) & 0x3ff; //从ADC数据寄存器中获取RESULT
占空比 = (adcvalue/4); //从 (0 到 255) 获取占空比值的公式
PWMMR3 = 占空比;//设置占空比值到PWM匹配寄存器
PWMLER = 0x08;//使用占空比值启用 PWM 输出
延迟毫秒(50);
LCD_SEND(0x80);
sprintf(displayadc,“adcvalue=%f”,占空比);
LCD_DISPLAY(displayadc); //显示ADC值(0到1023)
角度 = (adcvalue/5.7); //将ADC值转换为角度的公式(o到180度)
LCD_SEND(0xC0);
sprintf(角度值,“角度=%.2f 度”,角度);
LCD_DISPLAY(角度值); //显示角度值
}
}
评论
查看更多