所需要硬件:
TQ2440开发板一块
28BYJ-48步进电机两个
ULN2003驱动模块两个
杜邦线若干
5号电池4节
一、首先设计用CPU的哪些引脚来驱动步进电机
用五线四线步进电机连接ULN2003驱动模块,每个驱动模块需要4个GPIO,要想驱动两个步进电机所以需要用到8个GPIO口。
我选择用了4个LED灯口和4个中断口
二、修改GPIO的驱动LED的驱动为我们需要的驱动。
下面上一部分主要的修改后的GPIO驱动,主要是把这8个引脚设置成GPIO的功能,提供接口用以上层应用调用控制输入高电平或低电平。
#define DEVICE_NAME "GPIO-Control"
/* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
#define IOCTL_GPIO_ON 1
#define IOCTL_GPIO_OFF 0
/* 用来指定LED所用的GPIO引脚 */
static unsigned long gpio_table [] =
{
S3C2410_GPB5, //LED1
S3C2410_GPB6, //LED2
S3C2410_GPB7, //LED3
S3C2410_GPB8, //LED4
S3C2410_GPG5, //EINT13
S3C2410_GPG6, //EINT14
S3C2410_GPG7, //EINT15
S3C2410_GPG11, //EINT19
};
/* 用来指定GPIO引脚的功能:输出 */
static unsigned int gpio_cfg_table [] =
{
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
S3C2410_GPG5_OUTP,
S3C2410_GPG6_OUTP,
S3C2410_GPG7_OUTP,
S3C2410_GPG11_OUTP,
};
static int tq2440_gpio_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
unsigned long arg)
{
if (arg > 8)
{
return -EINVAL;
}
switch(cmd)
{
case IOCTL_GPIO_ON:
// 设置指定引脚的输出电平为0
s3c2410_gpio_setpin(gpio_table[arg], 0);
return 0;
case IOCTL_GPIO_OFF:
// 设置指定引脚的输出电平为1
s3c2410_gpio_setpin(gpio_table[arg], 1);
return 0;
default:
return -EINVAL;
}
}
三、编写程序来简单的控制电机正转和反转
程序很简单只是简单的控制两个电机同时正转、反转或停止。
moto.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
int setGPIO(int led_no,int on)
{
int fd;
fd = open("/dev/GPIO-Control", 0);
if (fd < 0) {
perror("open device leds");
exit(1);
}
ioctl(fd, on, (led_no-1));
close(fd);
return 0;
}
#define uchar unsigned char
#define uint unsigned int
uchar CCW[8]={0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09}; //逆时钟旋转相序表
uchar CW[8]={0x09,0x01,0x03,0x02,0x06,0x04,0x0c,0x08}; //正时钟旋转相序表
int K1=0;
int K2=1;
int K3=1;
void switchPort(char value,int flag){
#if 1
int p1,p2,p3,p4;
if(flag==1){
p1=1;
p2=2;
p3=3;
p4=4;
}else if(flag==2){
p1=5;
p2=6;
p3=7;
p4=8;
}
setGPIO(p1,value&1);
setGPIO(p2,(value >> 1) & 1);
setGPIO(p3,(value >> 2) & 1);
setGPIO(p4,(value >> 3) & 1);
#endif
}
void beep(){
#if 1
int fd,i;
unsigned long temp = 0;
fd=open("dev/PWM-Test",0);
if(fd<0){
perror("open device error\n");
exit(1);
}
ioctl(fd,1,3);
usleep(500);
ioctl(fd,0);
close(fd);
#endif
}
void motor_ccw(void)
{
uchar i,j;
for(j=0;j<8;j++) //电机旋转一周,不是外面所看到的一周,是里面的传动轮转了一周
{
for(i=0;i<8;i++) //旋转45度
{
switchPort(CCW[i],1);
switchPort(CCW[i],2);
usleep(1);//调节转速
}
}
}
void motor_cw(void)
{
uchar i,j;
for(j=0;j<8;j++)
{
for(i=0;i<8;i++) //旋转45度
{
switchPort(CW[i],1);
switchPort(CW[i],2);
usleep(1);//调节转速
}
}
}
void switchDir(uint key){
if(key==0){ //ting
K1=1;
K2=1;
}else if(key==1){ //zheng
K1=0;
K2=1;
}else if(key==2){ //fan
K1=1;
K2=0;
}else
printf("please put 0|1|2 \n");
}
int main(int argc,char **argv)
{
uint tmp;
uchar r;
uchar N=64; //因为步进电机是减速步进电机,减速比的1/64,
//所以N=64时,步进电机主轴转一圈
printf("Please enter the direction number (0 is stop) :\n");
scanf("%d",&tmp);
switchDir(tmp);
while(1)
{
if(K1==0)
{
beep();
for(r=0;r<N;r++)
{
motor_ccw(); //电机逆转
if(K3==0)
{
beep();
printf("break ccw!\n");
break;
}
}
}
else if(K2==0)
{
beep();
for(r=0;r<N;r++)
{
motor_cw(); //电机反转
if(K3==0)
{
beep();
printf("break cw!\n");
break;
}
}
}
else{
switchPort(0xf0,1);//电机停止
switchPort(0xf0,2);//电机停止
}
}
return 0;
}
四、重新编译内核和moto.c
将内核烧到开发板,并将moto.c生成的moto放到文件系统中,在串口运行./moto。
最后上一张电机成功转动的图片。
仅仅只是在下班后做着玩的,功能很简单,有时间后期还会慢慢完善的,文章写得很简单,不足之处请见谅。
致我们逝去的不眠夜