Arduino中国 | Flamingo EDA

Archive for June 2009

Jun/09

30

用Arduino与EasyDriver驱动步进电机

与其它普通直流电机相比,步进电机最大的特点就是它可以通过输入脉冲信号来进行控制的,也就是说电机的总转动角度可以由输入脉冲数决定,而电机的转速由脉冲信号频率决定。正因如此,你可以用Arduino来为步进电机产生相应的脉冲信号,来精确地控制电机转动的角度和速度!

步进电机是机电控制中一种常用的执行机构,实际使用时通常会用到一个驱动电路来对其进行驱动,这里我们使用的是EasyDriver,使用它能够很方便地控制一个两相混合式步进电机。电路在工作时由Arduino负责给EasyDriver发送相应的控制脉冲信号,来驱动步进电机转动相应的角度。由于EasyDriver一边要接收Arduino的控制信号,一边要控制电机转过相应的角度,因此接线其实也可以分成两个部分。

一部分是同Arduino相连的GND, STEP, DIR三根接线,分别为地、步进脉冲引脚和方向控制引脚步,STEP和DIR使用Arduino上普通的数字I/O引脚即可:

另一部分则是为电机供电的GND和+V引脚(这里我使用的9V外接电源),以及与两相步进电机相连接的MA和MB这4个个引脚(分别同电机的一个相连接起来):

为了演示的方便,我们还在A0和A1两个引脚上接上了两个按钮来分别控制电机的方向。顺便提一句,Arduino的A0 ~ A6在需要的时候也可以当成数字I/O引脚使用,其中A0对应的数字I/O为14,A1对应的数字I/O为15,依次类推。

接线并不算太复杂,最后电路接线的效果图:

相应的程序也比较简单:

int dirPin = 6;
int stepperPin = 5;
int switch1  = 14;
int switch2 = 15;
int value;

void setup() {
  pinMode(dirPin, OUTPUT);
  pinMode(stepperPin, OUTPUT);
  pinMode(switch1, INPUT);
  pinMode(switch2, INPUT);
}

void step(boolean dir,int steps){
  digitalWrite(dirPin,dir);
  for(int i=0; i < steps; i ++) {
    digitalWrite(stepperPin, HIGH);
    delayMicroseconds(50);
    digitalWrite(stepperPin, LOW);
    delayMicroseconds(50);

    // speed control
    delayMicroseconds(100);
  }
}

void loop(){
  value = digitalRead(switch1);
  if (HIGH == value) {
    step(true,1600 * 5);
  }

  value = digitalRead(switch2);
  if (HIGH == value) {
      step(false,1600*5);
  }

}

按照前面的连线,控制电机转动的脉冲信号是通过Arduino上的数字I/O引脚5来提供的,而电机转动方向的控制则是通过数字I/O引脚6来实现的。两个按钮开关分别接在A0和A1号引脚上,对于数字I/O引脚14和15:

int dirPin = 6;
int stepperPin = 5;
int switch1  = 14;
int switch2 = 15;

步进电机的转动主要是通过step()函数来实现,该函数有两个参数:第一个是转动的方向,分别代表正转和反转;第二个是步进数目,即给的控制脉冲的数目。通过修改每个脉冲间隔之间的时间长度,可以非常容易地调整电机转动的速度:

    // speed control
    delayMicroseconds(100);

两个对step()函数的调用,分别控制电机正转/反转相应的圈数,由于每种电机步进的角度数不同,旋转一圈所需要的脉冲数也是不一样的:

  step(true,1600 * 5);
  step(false,1600 * 5);

最后提醒一下,EasyDriver上的R6是用来限流的,调节它可以设置经过驱动芯片的电流大小。

·

在之前的文章中,曾经介绍了如何使用RF模块实现对Arduino的无线控制,其原理非常类似于遥控器,能够实现4个按钮的RF无线遥控。不过,对于要进行数据传输的场合,这样的解决办法就显得不太适合了,比如你要将Arduino采集到的光线传感器的数值,无线传输到PC机那端的时候。这种情况技术上称为无线数据传输,或者简称为无线数传。实现无线数传目前有不少解决方案,但最容易同Arduino连接使用的是类似于APC220这样通过串口来实现的无线数传,虽然数据传输的速度可能慢点(受限于串口的波特率),但的确不失为一种简单易用的方式,难怪很多网友都建议为Arduino加上这样的模块支持。

今天找出点时间来摆弄摆弄这个APC220了,厂家寄给我的模块没有任何说明,好在网络上能找到一些说明,另外就得自己摸索了。首先发现的问题是厂家给的USB适配器似乎于APC220不是很匹配:引脚的数目不一样。这个嘛,似乎不难理解,可能为了兼容不同的产品,或者至少可以说这一适配器不是为APC220专门设计的。USB适配器上用的芯片是CP2102,于是先到Silicon Laboratories网站下载相应的驱动程序,我下载的文件为cp210x_vcp_win2k_xp_s2k3.zip,解压缩后是一个exe文件,直接执行然后按照提示一步一步完成驱动的安装。

驱动安装完成之后,将USB适配器插入到PC机的USB接口中,Windows会提示找到相应的硬件,并对其进行相应的安装和配置:

当Windows提示你硬件已经可以使用之后,在设备管理器的“端口(COM 和 LPT)”下面可以找到CP2102虚拟出来的串口:

现在可以将一个APC220模块连接到USB适配器上了,由于USB适配器与APC220的引脚数目并不一致,连接时要注意插入的位置:

打开APC220厂家提供的设置程序RF-ANET,之前CP2102默认找到的串口为COM87,但RF-ANET程序似乎不能正常地打开这一端口。

在设备管理器中将串口设置成COM4后,重新插入USB适配器并打开RF-ANET,单击“Read R”按钮,一切正常,状态栏上显示“read succeed!”,表明已经能够正常地跟APC220通讯上了!

这样PC端APC220的测试环境就建议好了,现在来看Arduino这一端端。APC220模块与Arduino之间的连线有4条:5V, GND, TX和RX,需要注意的是,APC220和Arduino都是单独的串口设备,因此Arduino上的发送端TX应该与APC220上的接收端RX连接起来,同理Arduino上的RX应该与APC220上的TX连接起来:

APC220模块的默认波特率设置为9600,因此先用下面的代码来进行测试,注意在向Aduino下载程序时,先断开同APC220模块TX和RX上的连线,否则会出现下载无法正常的情况。

int val = 0;
int ledPin = 13;
void setup()
{
  Serial.begin(9600);
}

void loop()
{
  val = Serial.read();
  if (-1 != val) {
   if ('A' == val || 'a' == val) {
     Serial.println("Hello from Arduino!");
   }else if ('B' == val || 'b' == val) {
      digitalWrite(ledPin, HIGH);
      delay(500);
      digitalWrite(ledPin, LOW);
    }
  }
}

总结一下,现在我们已经分别在PC和Arduino上连接了一个APC220模块,并且已经向Arduino里面写入了相应的测试代码。一切都准备好之后,现在我们来进行相应的测试。首先要注意的是我们必须用外接电源的方式对Arduino进行供电,这是因为如果连接上USB线的话,相应的FT232模块会被激活,这样FT232实现的串口和ACP220上的串口就会因为冲突导致通信不正常:

在将加电后的Arduino放到房间里的一个角落之后,现在来配置PC端。APC220模块通过其USB适配器之后,其原理上也相当于一个串口,因此我们可以用Arduino自带的开发环境来进行测试,只是这一情况下你的PC上连接的不再是Arduino,而是APC220 USB适配器。连接好APC220 USB适配器后,打开Arduino,在“Tools” -> “Serial Ports”菜单下选择USB适配器虚拟出来的“COM4”(与之前的设置一致)。接着打开Arduino里的“Serial Monitor”,发送A字符,会收到Arduino传回来的“Hello from Arduino!”,发送B字符可以点亮Arduino上的13号LED(持续0.5秒):

Jun/09

6

STM32环境准备:JLink + OpenOCD

终于忍不住要开始玩ARM了!虽然AVR单片机是个好东西,Arduino也是个好东西,但无奈其速度对于某些需要大量计算的应用来讲还是有点低。当然,其实这只是一个借口,因为现在做的项目也没有复杂到那个程度,主要还是为了满足自己喜新厌旧的本性罢了;-)

虽然以前也玩过ARM,但那时候都是成形的系统了已经,自己无非是写写驱动做做应用,底层硬件对我来讲基本也就是一个“黑匣子”。这回我的目的自然不是移植一个操作系统,然后跑几个应用这么简单啦,所以在挑选开发板的时候自然就有所考虑了。这所谓的考虑说到底就只有一个原则:越简单越好,因为我要从最小系统玩开始!

最后挑选的是一块基于STM32F103 VET6芯片的最小系统开发板,板子上就只带一个JTAG接口,以及用来给芯片供电的USB接口和电源插座,其它所有引脚均通过2.54插针的方式引出,正好满足虐待自己的目的。当然,为了能够向开发板中下载程序,一条编程电缆自然是少不了的,与这个板配套使用的是JLink(估计应该是clone的)。

板子拿到手后,第一感觉就是做工比较细致,算是自己下一步追求的目标:) 前两天忙了点别的,昨天才正式开始给板子上电,试着装了开发板自带的JLink驱动,没有费什么劲系统就找到了该下载线,于是立即转向OpenOCD。OpenOCD是德国人的一个开源项目,主要目的是实现一个在线调试器,同时也能够实现程序烧写等目的,目前支持很多种编程线,这与我对想像中的STM32环境构想一致,所以很快就决定使用它了。

现在的问题是怎么让手头的这个JLink能够与OpenOCD通信上。首先按照YAGARTO网站上介绍的步骤在Windows下安装好了OpenOCD,可惜这个好像并没有编译进对JLink的支持。于是从OpenOCD的官方网址下了一个最新的安装文件安装后,并按照网友在Mac下的步骤启动OpenOCD,毫无悬念地得到了如下的出错信息(玩家第一规律:出错是必然的,出什么错是偶然的):

Error: Cannot find jlink Interface! Please check connection and permission.

好了,开始猜原因吧!Google依然是最好的助手,先把出错信息Search一把,发现Sparkfun上有人也在讨论类似的问题,但没有给出解来。同时也有人非常肯定地指出说OpenOCD是支持JLink的,至少在Linux系统上是没有问题。从各种收集到的信息来看,我想可能会是下面几个原因:

  • OpenOCD不支持clone的JLink
  • 需要重新编译OpenOCD的代码
  • Windows下OpenOCD对JLink的支持不完备

第二条很快经过实践检验之后被证明是不对的,但自己也不是完全没有收获,至少整理出了OpenOCD在Cygwin下的编译过程:

$ svn co http://svn.berlios.de/svnroot/repos/openocd openocd
$ cd openocd/trunk/
$ ./bootstrap
$ ./configure --enable-jlink
$ make

编译完成之后,使用下面的配置文件stm32cfg运行openocd命令:

$ ./openocd.exe -f stm32.cfg

得到的错误依然是无法找到JLink。好在开源虽然有层出不穷的问题,但不管什么时候你都可以拿到代码去寻找问题所在。OpenOCD是拿C语言写的,在做了一些简单的分析和调试之后,确认应该是通过libusb无法得到USB设备所至的,也就是jtag/jlink.c文件中的这一条语句:

	busses = usb_get_busses();

接着Google,原来这个是LibUsb-Win32库,有人在讨论说Vista64下这个库没法用,但显然不属于我的情况。由于怀疑可能是libusb库版本导致的问题,把之前安装的OpenOCD全部删除,但编译依然能够通过,原因是Cygwin的/bin/cygusb0.dll文件似乎就是这个库。抱着试试看的态度,下载了LibUsb-Win32官方的安装包重新安装,安装完后运行其测试程序,终于能够顺利找到J-Link这个设备了:

此时再运行openocd命令,看起来就一切正常了:

$ ./openocd.exe -f stm32.cfg
Open On-Chip Debugger 0.2.0-in-development (2009-06-06-01:25) svn:2076

BUGS? Read http://svn.berlios.de/svnroot/repos/openocd/trunk/BUGS

$URL: http://svn.berlios.de/svnroot/repos/openocd/trunk/src/openocd.c $
500 kHz
Info : J-Link ARM V6 compiled Apr  1 2009 11:56:10
Info : JLink caps 0x19ff7bbf
Info : JLink hw version 60000
Info : JLink max mem block 8832
Info : Vref = 3.287 TCK = 1 TDI = 0 TDO = 1 TMS = 0 SRST = 1 TRST = 1

Info : J-Link JTAG Interface ready
Info : JTAG tap: stm32.cpu tap/device found: 0x3ba00477 (Manufacturer: 0x23b, Part: 0xba00, Version: 0x3)
Info : JTAG Tap/device matched
Info : JTAG tap: stm32.bs tap/device found: 0x06414041 (Manufacturer: 0x020, Part: 0x6414, Version: 0x0)
Info : JTAG Tap/device matched

试着用telnet连接到OpenOCD

C:\Documents and Settings\Administrator>telnet localhost 4444
Open On-Chip Debugger
>

再按照STM32 Primer programming with OpenOCD on GNU/Linux中的说明执行了几个测试命令:

> halt
target was in unknown state when halt was requested

这个命令像是挂起CPU?

> flash probe 0
device id = 0x10016414
flash size = 512kbytes
flash 'stm32x' found at 0x08000000

这个命令是用来检测Flash类型的。

> flash erase_check 0

这个是命令是检查Flash中特定块是否擦除,这就算开始对ARM动刀了已经;-)

> flash erase_check 0

过了一把擦除Flash的瘾!

中间有一个小的插曲,开始的时候将stm32.cfg中的JTAG时钟设置成自动识别的,似乎不是很稳定。刚开始的时候还能够正常地跟STM32通信上,后来就一直报错,并且需要重新启动计算机,再能够再次工作。

jtag_khz 0

这一问题一直困扰了我一个晚上,今天早上把这一频率设置成固定值后,稳定了不少:

jtag_khz 500

目前暂时先宣告JLink + OpenOCD部分正常工作吧,接下去硬件要实现的目标,是用基于FT2232的编程电缆,实现对STM32的控制,这还需要假以时日。软件上就相对明确多了:编译ARM上运行的HelloWorld,并下载到STM32中运行!

Theme Design by devolux.nh2.me