机械臂是令人着迷的工程创造之一,看着这些东西倾斜和平移以像人类手臂一样完成复杂的事情总是令人着迷。这些机械臂常见于装配线上进行焊接、钻孔、喷漆等高强度机械工作的行业中,最近还开发了高精度的先进机械臂来执行复杂的外科手术。因此,在本教程中,让我们使用 ARM7-LPC2148 微控制器构建一个简单的机械臂,通过手动控制几个电位器来拾取和放置物体。
所需组件
3D 打印机机械臂
ARM7-LPC2148
SG-90 伺服电机 (4)
10k 电位器 (4)
按钮 (4)
发光二极管 (4)
5V (1A) 直流电源适配器
电阻器(10k (4)、2.2k(4))
面包板
连接电线
准备好 3D 打印机械臂
本教程中使用的 3D 打印机械臂是按照Thingiverse中提供的EEZYbotARM给出的设计制作的。制作 3D 打印机械臂的完整程序和带有视频的组装细节都在上面分享的 thingiverse 链接中。
这是我的 3D 打印机械臂与 4 个伺服电机组装后的图像。
电路原理图
下图显示了基于 ARM 的机械臂的电路连接。
该项目的电路连接很简单。确保使用单独的 5V DC 电源适配器为伺服电机供电。对于电位器和按钮,我们可以使用LPC2148 微控制器提供的 3.3V 电压。
这里我们使用 LPC2148 的 4 个 ADC 引脚和 4 个电位器。LPC2148 的 4 个 PWM 引脚与伺服电机的 PWM 引脚相连。我们还连接了 4 个按钮来选择要操作的电机。因此,按下按钮后,电位器会变化以改变伺服电机的位置。
与LPC2148的GPIO连接的按钮一端通过10k的电阻下拉,另一端连接3.3V。还连接了 4 个 LED 以指示选择哪个伺服电机来改变位置。
为机械臂编程 LPC2148 所涉及的步骤
在为这个机械臂编程之前,我们需要了解如何在 LPC2148 中生成 PWM 以及在 ARM7-LPC2148 中使用 ADC。为此,请参阅我们之前关于将伺服电机与 LPC2148连接以及如何在 LPC2148 中使用 ADC 的项目。
使用 LPC2148 进行 ADC 转换
因为我们需要提供 ADC 值来设置占空比值,以生成用于控制伺服电机位置的 PWM 输出。我们需要找到电位器的 ADC 值。由于我们有四个电位器来控制四个伺服电机,因此我们需要 LPC2148 的 4 个ADC 通道。在本教程中,我们使用 LPC2148 中分别存在的 4、1、2、3 ADC 通道的 ADC 引脚(P0.25、P0.28、P0.29、P0.30)。
使用 LPC2148 为伺服电机生成 PWM 信号
因为我们需要生成 PWM 信号来控制伺服电机的位置。我们需要设置 PWM 的占空比。我们有四个伺服电机连接到机械臂,所以我们需要 LPC2148 的 4 个 PWM 通道。在本教程中,我们使用LPC2148 中分别存在的 3、2、4、5 PWM 通道的 PWM 引脚(P0.1、P0.7、P0.8、P0.21)。
将十六进制文件编程和闪存到 LPC2148
要对 ARM7-LPC2148 进行编程,我们需要keil uVision 并将HEX 代码闪存到 LPC2148 需要 Flash Magic 工具。此处使用 USB 电缆通过微型 USB 端口对ARM7 Stick进行编程。我们使用 Keil 编写代码并创建一个 hex 文件,然后使用Flash Magic将 HEX 文件闪存到 ARM7 棒。要了解有关安装 keil uVision 和 Flash Magic 以及如何使用它们的更多信息,请点击链接 Getting Started With ARM7 LPC2148 Microcontroller and Program it using Keil uVision。
编码说明
该机械臂项目的完整程序在教程的最后给出。现在让我们详细看看编程。
配置 LPC2148 的 PORT 以使用 GPIO、PWM 和 ADC:
使用 PINSEL1 寄存器为引脚 P0.25、P0.28、P0.29、P0.30 启用 ADC 通道 - ADC0.4、ADC0.1、ADC0.2、ADC0.3。此外,对于引脚 P0.21 (1<<10) 的 PWM5。
#define AD04 (1<<18) //为 P0.25 选择 AD0.4 函数 #define AD01 (1<<24) //为 P0.28 选择 AD0.1 函数 #define AD02 (1<<26) / /为 P0.29 选择 AD0.2 函数 #define AD03 (1<<28) //为 P0.30 选择 AD0.3 函数 PINSEL1 |= AD04 | AD01 | AD02 | AD03 | (1<<10);
使用 PINSEL0 寄存器来使能 LPC2148 的引脚 P0.1、P0.7、P0.8 的 PWM 通道 PWM3、PWM2、PWM4。
PINSEL0 = 0x000A800A;
使用 PINSEL2 寄存器启用 PORT1 中所有用于连接 LED 和按钮的引脚的 GPIO 引脚功能。
PINSEL2 = 0x00000000;
为了使 LED 引脚作为输出和按钮引脚作为输入,使用 IODIR1 寄存器。(输入为 0,输出为 1)
IODIR1 = ((0<<17)|(0<<18)|(0<<19)|(0<<20)|(1<<28)|(1<<29)|(1<<30 )|(1<<31));
虽然引脚号定义为
#define SwitchPinNumber1 17 //(与P1.17相连) #define SwitchPinNumber2 18 //(与P1.18相连) #define SwitchPinNumber3 19 //(与P1.19相连) #define SwitchPinNumber4 20 //(与P1相连。 20) #define LedPinNumber1 28 //(与P1.28相连) #define LedPinNumber2 29 //(与P1.29相连) #define LedPinNumber3 30 //(与P1.30相连) #define LedPinNumber4 31 //(与P1相连。 31)
配置 ADC 转换设置
接下来使用 AD0CR_setup 寄存器设置 ADC 转换模式和 ADC 时钟。
无符号长 AD0CR_setup = (CLKDIV<<8) | BURST_MODE_OFF | 充电; //设置ADC模式
而 CLCKDIV、Burst Mode 和 PowerUP 被定义为
#define CLKDIV (15-1) #define BURST_MODE_OFF (0<<16) // 1 表示开启,0 表示关闭 #define PowerUP (1<<21)
设置 ADC 转换的时钟 (CLKDIV)
这用于为 ADC 生成时钟。4Mhz ADC 时钟 (ADC_CLOCK=PCLK/CLKDIV) 实际使用“CLKDIV-1”,在我们的例子中 PCLK=60mhz
Burst Mode (Bit-16):该位用于 BURST 转换。如果该位置位,ADC 模块将对在 SEL 位中选择 (SET) 的所有通道进行转换。将此位设置为 0 将禁用 BURST 转换。
断电模式(Bit-21):用于打开或关闭 ADC。该位设置 (1) 使 ADC 退出掉电模式并使其运行。清零该位将关闭 ADC。
配置 PWM 转换设置
首先使用 PWMTCR 寄存器复位和禁用 PWM 计数器,并使用预分频器值设置 PWM 定时器预分频寄存器。
PWMTCR = 0x02; PWMPR = 0x1D;
接下来设置一个循环中的最大计数数。这是在匹配寄存器 0 ( PWMMR0 ) 中完成的。因为我们有 20000,因为它是 20 毫秒的 PWM 波
PWMMR0 = 20000;
在匹配寄存器中设置占空比值之后,我们使用 PWMMR4、PWMMR2、PWMMR3、PWMMR5。这里我们将初始值设置为 0 毫秒 (Toff)
PWMMR4 = 0; PWMMR2 = 0; PWMMR3 = 0; PWMMR5 = 0;
之后,设置 PWM 匹配控制寄存器以在匹配寄存器发生时导致计数器复位。
PWMMCR = 0x00000002;// 在 MR0 匹配时重置
之后,PWM 锁存器使能寄存器使能使用匹配值(PWMLER)
PWMLER = 0x7C;// PWM2、PWM4、PWM4 和 PWM5 的锁存使能
使用 PWM 定时器控制寄存器 ( PWMTCR )中的一个位来复位定时器计数器,并启用 PWM。
PWMTCR = 0x09;// 启用 PWM 和计数器
接下来启用 PWM 输出并在 PWM 控制寄存器 ( PWMPCR ) 中将 PWM 设置为单边沿控制模式。
PWMPCR = 0x7C00;// 使能 PWM2、PWM4、PWM4 和 PWM5,单边沿控制 PWM
使用按钮选择要旋转的伺服电机
我们有四个按钮,用于旋转四个不同的伺服电机。通过选择一个按钮并改变相应的电位器,ADC值设置占空比,相应的伺服电机改变其位置。获取按钮开关的状态
switchStatus1 = (IOPIN1>>SwitchPinNumber1) & 0x01 ;
因此,根据哪个开关值是高电平,会发生 ADC 转换,然后在成功转换 ADC(0 到 1023)值后,将其映射为(0 到 2045),然后将占空比值写入(PWMMRx) PWM 引脚连接到伺服电机。而且,LED 会变高以指示按下了哪个开关。以下是第一个按钮的示例
if(switchStatus1 == 1) { IOPIN1 = (1<>6) & 0x3ff; //获取ADC值 result1 = map(convert1,0,1023,0,2450); //将 ADC 值转换为 PWM 的 占空比 PWMMR5 = result1; //设置占空比值为 PWM5 PWMLER = 0x20; //启用 PWM5 delay_ms(2); } } 其他 { IOPIN1 = (0<
取放机械臂的工作
将代码上传到 LPC2148 后,按下任意开关并改变相应的电位器来改变机械臂的位置。
每个开关和电位器控制每个伺服电机的运动,即底座向左或向右运动,向上或向下运动,向前或向后运动,然后夹具保持和释放运动。
//使用LPC2148的机器人ARM
#include
#include
#define SwitchPinNumber1 17
#define SwitchPinNumber2 18
#define SwitchPinNumber3 19
#define SwitchPinNumber4 20
#define LedPinNumber1 28
#define LedPinNumber2 29
#define LedPinNumber3 30
#define LedPinNumber4 31
#define AD04 (1<<18) //为 P0.25 选择 AD0.4 功能
#define AD01 (1<<24) //为 P0.28 选择 AD0.1 功能
#define AD02 (1<<26) //为 P0.29 选择 AD0.2 功能
#define AD03 (1<<28) //为 P0.30 选择 AD0.3 功能
#define SEL_AD04 (1<<4) //选择ADC通道4
#define SEL_AD01 (1<<1) //选择ADC通道1
#define SEL_AD02 (1<<2) //选择ADC通道2
#define SEL_AD03 (1<<3) //选择ADC通道3
#define CLKDIV (15-1) // 4Mhz ADC 时钟 (ADC_CLOCK=PCLK/CLKDIV) 实际使用“CLKDIV-1”,在我们的例子中 PCLK=60mhz
#define BURST_MODE_OFF (0<<16) // 1 表示开启,0 表示关闭
#define 上电 (1<<21)
#define START_NOW ((0<<26)|(0<<25)|(1<<24)) //001 立即开始转换
#define ADC_DONE (1UL<<31)
#define VREF 3.3 //VREF 引脚的参考电压
易失性int结果1 = 0;
易失性int结果2 = 0;
易失性int结果3 = 0;
易失性int结果4 = 0;
易失性 int 转换 1=0;
易失性int转换2 = 0;
易失性 int 转换 3=0;
易失性 int convert4=0;
volatile unsigned int switchStatus1;
volatile unsigned int switchStatus2;
volatile unsigned int switchStatus3;
volatile unsigned int switchStatus4;
long map(long x, long in_min, long in_max, long out_min, long out_max) // 映射函数来转换范围
{
返回 (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void delay_ms(uint16_t j) /* 循环产生 1 毫秒延迟,Cclk = 60MHz */
{
uint16_t x,i;
for(i=0;i
{
对于(x=0;x<6000;x++);
}
}
主函数()
{
PINSEL0 = 0x000A800A;// 将 P0.1,P0.7,P0.8 配置为 PWM3,PWM2,PWM4 引脚
PINSEL2 = 0x00000000;//将PORT1引脚配置为GPIO;
PINSEL1 |= AD04 | AD01 | AD02 | AD03 | (1<<10); // 配置 P0.25,P0.28,P0.29,P0.30 为 ADC0.4, ADC0.1, ADC0.2, ADC0.3 引脚 & P0.21 为 PWM5
IODIR1 = ((0<<17)|(0<<18)|(0<<19)|(0<<20)|(1<<28)|(1<<29)|(1<<30 )|(1<<31)); //配置LED管脚为输出,开关管脚为输入
无符号长 AD0CR_setup = (CLKDIV<<8) | BURST_MODE_OFF | 充电; //设置ADC模式
PWMTCR = 0x02;// 重置和禁用 PWM 计数器
PWMPR = 0x1D;// 预分频寄存器值
PWMMR0 = 20000;// PWM波的时间周期,20msec
PWMMR4 = 0;// PWM 波的初始值 0 ms
PWMMR2 = 0;
PWMMR3 = 0;
PWMMR5 = 0;
PWMMCR = 0x00000002;// 在 MR0 匹配时重置
PWMLER = 0x7C;// PWM2、PWM4、PWM4 和 PWM5 的锁存使能
PWMPCR = 0x7C00;// 使能 PWM2、PWM4、PWM4 和 PWM5,单边沿控制 PWM
PWMTCR = 0x09;// 启用 PWM 和计数器
而(1)
{
switchStatus1 = (IOPIN1>>SwitchPinNumber1) & 0x01 ; // 读取开关状态
switchStatus2 = (IOPIN1>>SwitchPinNumber2) & 0x01; // 读取开关状态
switchStatus3 = (IOPIN1>>SwitchPinNumber3) & 0x01 ; // 读取开关状态
switchStatus4 = (IOPIN1>>SwitchPinNumber4) & 0x01; // 读取开关状态
if(switchStatus1 == 1) //根据开关状态打开/关闭 LED 并开始 ADC 转换
{
IOPIN1 = (1<
AD0CR = AD0CR_setup | SEL_AD01; //为通道1设置ADC
AD0CR |= START_NOW; //在ADC1开始新的转换
while( (AD0DR1 & ADC_DONE) == 0 ) //检查 ADC 转换
{
转换1 = (AD0DR1>>6) & 0x3ff; //获取ADC值
结果 1 = 地图(转换 1,0,1023,0,2450);//根据占空比为 PWM 转换 ADC 值
PWMMR5 = 结果1;//将占空比值设置为PWM5
PWMLER = 0x20;//启用PWM5
延迟毫秒(2);
}
}
别的
{
IOPIN1 = (0<
}
if(switchStatus2 == 1) //根据开关状态打开/关闭 LED 并开始 ADC 转换
{
IOPIN1 = (1<
AD0CR = AD0CR_setup | SEL_AD02; //设置通道2的ADC
AD0CR |= START_NOW; //在ADC2开始新的转换
while( (AD0DR2 & ADC_DONE) == 0 ) //检查 ADC 转换
{
转换2 = (AD0DR2>>6) & 0x3ff; //获取ADC值
结果 2 = 地图(转换 2,0,1023,0,2450);//根据占空比为 PWM 转换 ADC 值
PWMMR4 = 结果2;//将占空比值设置为PWM4
PWMLER = 0x10;//启用PWM4
延迟毫秒(2);
}
} 别的
{
IOPIN1 = (0<
}
if(switchStatus3 == 1) //根据开关状态打开/关闭 LED 并开始 ADC 转换
{
IOPIN1 = (1<
AD0CR |= START_NOW; //在ADC3开始新的转换
while( (AD0DR3 & ADC_DONE) == 0 ) //检查 ADC 转换
{
转换3 = (AD0DR3>>6) & 0x3ff; //获取ADC值
结果 3 = 地图(转换 3,0,1023,0,2450);//根据占空比为 PWM 转换 ADC 值
PWMMR3 = 结果3;//将占空比值设置为PWM3
PWMLER = 0x08;//启用PWM3
延迟毫秒(2);
}
} 别的
{
IOPIN1 = (0<
}
if(switchStatus4 == 1) //根据开关状态打开/关闭 LED 并开始 ADC 转换
{
IOPIN1 = (1<
AD0CR = AD0CR_setup | SEL_AD04; //设置通道4的ADC
AD0CR |= START_NOW; //在ADC4开始新的转换
while( (AD0DR4 & ADC_DONE) == 0 ) //检查 ADC 转换
{
转换4 = (AD0DR4>>6) & 0x3ff; //获取ADC值
结果4 =地图(转换4,0,1023,0,2450);//根据占空比为 PWM 转换 ADC 值
PWMMR2 = 结果4;//将占空比值设置为 PWM PWMLER = 0x04; //启用PWM2
延迟毫秒(2);
}
} 别的
{
IOPIN1 = (0<
}
}
}
评论
查看更多