使用ARM7-LPC2148控制伺服电机的教程

2023-05-29 18:30   370   0  

在本教程中,我们将使用 ARM7-LPC2148 控制伺服电机。伺服电机比步进电机具有低功耗的优势。当到达所需位置时,伺服电机停止其功耗,但步进电机继续消耗功率以将轴锁定在所需位置。伺服电机主要用于 机器人项目 ,因为它们的准确性和易于操作性。




伺服电机


伺服电机 是直流电机、位置控制系统和齿轮的组合。 伺服电机的旋转是通过向其施加PWM信号来控制的,PWM信号的宽度决定了电机的旋转角度和方向。在这里,我们将在本教程中使用 SG90 伺服电机 ,它是最受欢迎和最便宜的电机之一。SG90 是 180 度伺服。所以有了这个伺服,我们可以将轴定位在 0-180 度之间:




工作电压:+5V


齿轮类型:塑料


旋转角度:0 至 180 度


重量:9克


扭矩:2.5kg/cm


poYBAGMsH2OAbgcBAAIWv53GZgQ466.png


在我们开始为伺服电机编程之前,我们应该知道要发送什么类型的信号来控制伺服电机。我们应该对 MCU 进行编程以将 PWM 信号发送到伺服电机的信号线。伺服电机内部有一个控制电路,它读取 PWM 信号的占空比并将伺服电机轴定位在相应的位置,如下图所示


poYBAGMsH1-AEBCuAABd_qu6iT0564.png


伺服电机每 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 引脚。


pYYBAGMsH1yABFFEAAU11MlS-w0249.png


所需组件


硬件


ARM7-LPC2148


LCD (16x2) 显示模块


伺服马达 (SG-90)


3.3V稳压器


10k电位器(2个)


面包板


连接电线


软件


凯尔uVision5


闪光魔法工具


电路图和连接


poYBAGMsH1aAMEUIAAIx4J8i3i0748.pngpYYBAGMsH1KAKB3oAAlqWxRj20U554.png


下表显示了伺服电机与 ARM7-LPC2148 之间的连接:


poYBAGMsH0-AJrEFAAALWgGTx0c469.png


引脚 P0.1 是 LPC2148 的 PWM 输出。


下表显示了LCD 和 ARM7-LPC2148 之间的电路连接。


poYBAGMsH0qASmioAAAdq3a7Jn4259.png


下表显示了ARM7 LPC2148 和带 3.3V 稳压器的电位器之间的连接。


pYYBAGMsH0eAIoTlAAAWjYTiUBM502.png


注意事项


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(角度值);


pYYBAGMsHz2AIpZLAAlIh7VQBhw427.png


//连接伺服电机与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(角度值); //显示角度值

}

}




登录icspec成功后,会自动跳转查看全文
博客评论
还没有人评论,赶紧抢个沙发~
发表评论
说明:请文明发言,共建和谐网络,您的个人信息不会被公开显示。