
用单片机同时是不可能的,当然,时间间隔小到可以接受,跑几个任务,那也可以视为同时。要实现真正意义上的同时,用FPGA/CPLD是可以完成的。 话说回来,也许你的同时并不是说一定严格地同时工作,只是说一个单片机去控制四个步进电机,那就好办多了。 一个步进电机,比如四相5线那种,四个IO口可控制一个,四个步进电机就要一陆个,驱动芯片用ULN二00三即可。 当然,如果你的IO口不允许使用这么多,那也可以通过串转并的方法,扩展IO口,比如用漆四HC595,三根IO口控制它,它可以级联,三根线可以控制很多片。一片为吧位,两片就为一陆位,三片为二四位 …… 只要加些三极管驱动那三根控制线,三个IO口可控制一串级联的漆四HC595,得到的扩展IO口,那是相当多的。我用三个IO口控制过5片漆四HC595,三个IO口一下子就扩展成了四0个IO口!!
C语言程序如下:
#include<reg 51h>
#define uint unsigned int
Sbit k1=p34;//启动开关
Sbit k2=p35;//换向开关
Sbit s2=p32;//加速按钮
Sbit s3=p33;//减速按钮
Void idr_int0(void);//外部中断0中断服务函数声明
Void idr_int1(void);
Void zd_t0ist(void);
Uint speed,count,r1,I,t,k;
Main()
{k=0;
T=0;
r1=0x11;
speed=0;
count=1;
tmod=0x01;
et0=1;
ea=1;
ex0=1;
ex1=1;
if(k2==0)
p0=0xbf;
else p0=0xf9;
if (speed==0)
{p2=0xc0;
Tr0=0;
}
Else tr0=1;
}
}
}
Void isr_int0(void)interrupt();
{
If(speed<7)
Speed=speed+1;
While(s2==0)
{For(i=0;i<10;i++);}
}
Void isr_int0(void)interrupt2;
Th0=0xcf;
Tl0=0x2c;
For(;;)
{
If (k1==0)
{p0=0xff;
P2=0xff;
Speed=0;
Tr0=0}
Else
{
If(k2==0)
P0=0xbf;
Else p0=0xf9;
If(speed==0)
{p2=0xc0;
Tr0=0;
}
Else tr0=1;
}
}
}
Void isr_int0(void)interrupt()
{
If(speed<7)
Speed=speed+1;
While(s2==0)
{for(i=0;i<10;i++);}
}
Void isr_int1(void)interrupt2
{
If(speed>0)
Speed=speed-1;
While(s3==0)
{for(i=0;;i<10;i++);}
}
Void zd_t0ist(void)interrupt 1
{
Th0=0xd8;
Tl0=0xf0;
Switch(speed)
{
Case0;p2=0xc0;count=0;break;
Case1;p2=0xf9;count=60;break;
Case2;p2=0xa4;count=40;break;
Case3;p2=0xb0;count=35break;
Case4;p2=0x99;count=30;break;
Case5;p2=0x92;count=28;break;
Case6;p2=0x82;count=25;break;
Case7;p2=0xf8;count=21;break;
Default:break;
}
If(t==0)
T=count;
If(t>0)
T=t-1;
If(k2==0)
{
If(t==0)
{
Switch(k)
{
Case0;p1=0x01;break;
Case1;p1=0x02;break;
Case2;p1=0x04;break;
Case3;p1=0x08;break;
Default:break;
}
k=k+1;
if(k==4)
k=0;
}
}
Else
{
If(t==0)
{
Switch(k)
{
Case0;p1=0x08;break;
Case1;p1=0x04;break;
Case2;p1=0x02;break;
Case3;p1=0x01;break;
Default:break;
}
K=k+1;
If(==4)
K=0;
}
}
}
一、S1为单片机复位开关,按下此开关并释放,单片机从ORG 0000H这一句开始执行命令
二、至于步进电机第一步转多少角度,这个应该跟步进电机停止前的状态有关,在编程的时候可以先让步进电机复位一次,下次启动之前先查询下步进电机的位置变量就可以了。在实际应用中可以忽略不计,因为步进电机通常要接减速器的,角度一步只有几度,所以不会产生影响
三、Vcc和com端都是步进电机的两个公共抽头,实际的步进电机这两根也是接电源的
四、以上汇编程序几乎每句都有注释,真的再不好解释了,呵呵
#include "reg52h"
#include "INTRINSH"
#include <absacch>
#include <mathh>
#define uint unsigned int
#define uchar unsigned char
void check_addr(void); /
地址核对
/
uchar code slave_addr[4]={00, 01, 02, 255};
/
从机地址
/
uchar idata T0low, T0high,common_count,input_order,cmd_in_permit,interval;
uchar sent_ok,speed_change,start_up,start_end,address_true,i;
uint y1;
uint
code
add[100]={60006,62771,63693,64154,64430,64614,64746,64845,64922,64983,65033,65075,651
11,65141,65167,65190,65211,65229,65245,65260,65273,65285,65296,65306,65315,65323,65331
,65339,65345,65352,65358,65363,65368,65373,65378,65382,65387,65390,65394,65398,65401,6
5404,65407,65410,65413,65416,65418,65421,65423,65425,65428,65430,65432,65434,65435,654
37,65439,65441,65442,65444,65445,65447,65448,65450,65451,65452,65453,65455,65456,65457
,65458,65459,65460,65461,65462,65463,65464,65465,65466,65467,65468,65469,65469,65470,6
5471,65472,65472,65473,65474,65475,65475,65476,65477,65477,65478,65478,65479,65480,654
80,65481};
sbit P2_0=P2^0;
/
作输入步进电机的脉冲信号发送口
/
sbit P2_2=P2^2;
/
作输入步进电机的旋转方向信号发送口
/
sbit P1_0=P1^0;
/
作串口输出信号的使能口
, P1_0=0
时接通串口
,
输出信号
/
sbit WD=P1^7;
/
看门狗
/
main()
{
P2_0=0;
P2_2=0;
/
步进电机的旋转方向待试验后确定
/
P1_0=1;
/
开机时需要关断
,
串口发送功能
,
需要时再接通
/
WD=1;
/
看门狗先为
1
,电平翻转为喂狗
/
i=0;
common_count=0;
cmd_in_permit=0;
input_order=0;
interval=0;
address_true=1;
speed_change=0;
start_up=0;
2
start_end=0;
sent_ok=0;
//
允许发送
EA=1;
/
开放总中断
/
TMOD=0x21;
TH1 = 0xFD;
//
波特率
9600
TL1 = 0xFD;
SCON = 0xd0;
//
设定串行口工作方式
PCON &= 0x00;
//
波特率不倍增
SM2=1;
TR1 = 1;
ES=1;
//
启动定时器
1
T2MOD=00;
T2CON=0x00;
RCAP2H
=0xEE;
//
赋
T2
的预置值
0xA600,25MS
,
0xB800
,
20MS,0xCA00
,
15MS,0xDC00
,
10MS
,
0xEE00
,
5MS
RCAP2L =0x00;
TR2=1;
//
启动定时器
ET2=1;
//
打开定时器
2
中断
do
{
if(address_true==1)
{
address_true=0;
check_addr();
}
if(start_up==1&&start_end==0)
//
第一次启动
{
y1=add[common_count];
T0high = (uchar)(y1>>8)
/
取
y1
的高
8
位
/
T0low = (uchar)(y1&0x00ff);
/
取
y1
的低
8
位
/
TR0 = 1;
ET0=1;
/
允许
T/C0
中断
/
start_end=1;
}
if(speed_change==1)
{
if(interval>=0&&interval<=0x63)
{
if(interval>common_count)
{common_count=common_count+1; }
if(interval<common_count)
{common_count=common_count-1; }
}
3
speed_change=0;
}
if(sent_ok==1)
{
sent_ok=0;
P1_0=0;
for(i=0;i<=20;i++) {_nop_();}
TI=0; SBUF=T0high;
while(TI==0);TI=0;
TI=0; SBUF=T0low;
while(TI==0);TI=0;
P1_0=1;
for(i=0;i<=20;i++) {_nop_();}
SM2=1;
}
}
while(1);
}
void timer0(void) interrupt 1 using 3
{
P2_0=~P2_0;
y1=add[common_count];
T0high = (uchar)(y1>>8)
/
取
y1
的高
8
位
/
T0low = (uchar)(y1&0x00ff);
/
取
y1
的低
8
位
/
TH0=T0high;
/
高
8
位
T0high
送定时器
0
的
TH0/
TL0=T0low;
/
低
8
位
T0low
送定时器
0
的
TL0/
}
void timer2(void) interrupt 5 using 2
{
TF2=0;
/T2
溢出中断需软件清
0/
speed_change=1;
//
速度可以改变标示,以便主程序处理
WD=!WD; /MAX813
喂狗
/
}
void inte_SERIAL() interrupt 4 using 1
/
串口
0
中断服务子程序
/
{
uchar key_in
key_in=0;
if(RI)
{
C语言程序源代码
#include <REGX51H> // 51寄存器定义
#include "intrinsh"
#define control P1 //P1_0:A相,P1_1:B相,P1_2:C相,P1_3:D相
#define discode P0 //显示代码控制端口
#define uchar unsigned char //定义无符号型变量
#define uint unsigned int
sbit en_dm=P3^0; //显示代码锁存控制
sbit en_wk=P3^1; //位控锁存控制
uchar code corotation[4]= {0x03,0x06,0x0c,0x09};//电机正转
uchar code rollback[4]={0x0c,0x06,0x03,0x09}; //电机反转
uchar code tab[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//显示字段
uint code Levspeed[5]={500,400,300,200,100};//电机速度等级
uchar Hscan,speedcount;//Hscan行扫描,speedcount 速度等级计数
uint uu; //频率计数
uint step,setstep; //step:电机步伐计数,setstep:手动设置电机步伐
uint speed=500; //电机初始速度
uchar count;
uchar flag[5];
uchar butcount; //按键次数
//
//flag[0] 正转标志
//flag[1] 反转标志
//flag[2] 加速标志
//flag[3] 减速标志
//flag[4] 设置标志
//
Delay1mS(unsigned int tt) //延时1ms “Delay1mS”延时子程序,用循环语句延时。
{
unsigned char i;
while(tt--)
for(i=113;i>0;i--);
}
keyscan() //键盘扫描 “keyscan”键盘扫描子程序,用于寻找是否有按键按下。
{
P2=0xf0; //把oxfe赋值给P2口 //将按键控制口置于未按键的状态单片机输出//口假设不是按键按下状态
if(P2!=0xf0) //如果P2口的值不等于0xfe //检查是否有按键按下如果有,处理{}内的事
{ //有按键按下
Delay1mS(150);//调用延时函数//有按键按下,避开无效读码值的时间,或者是脉冲长度
Hscan=0xfe; //将Hscan赋值,初始遥控值是要置高电平的
P2=Hscan; //
while((Hscan&0x10)!=0) //检查X10口是否有键按下。未按下是1,
//在这显示出你的按键口是P2_4即检查P2_4是高电平,无//键按下,低电平有键按下。
{
P2=Hscan;
if((P2&0xf0)!=0xf0) //检查按键脉冲是否是变化,
return P2;
else Hscan=(Hscan<<1)|0x01; //这里在存码值,应该是遥控输入。将码值存入Hscan
//这里是读取码值的关键,如果来的脉冲不管是高电平//还是低电平,靠左移一位保存脉冲的状态值
}
}
else return 0;
}
key_val() //按键处理函数 //这里是读取将存好的码值进行处理看是什么代码值
{
uchar key;
key= keyscan(); //这里是读取码值并存放在key里
switch(key) //这里是对比读取的码值
{
case 0xee: //按键‘7’ //读取的码值=0xEE,则是按键“7”的代码
//while(P2==0xee);
setstep=setstep10+7; //步伐数 //这里是输入”setstep +7” 步伐数对比读取的码值, //setstep原来可能是有数字的。
step=setstep;
butcount++; //计数,看输入拉几个数字
if(butcount>=5) //输入的数字超过5个就置0,无效
{
butcount=0;
setstep=0;
}
break;
case 0xde: //按键‘8’ //读取的码值=0xdE,则是按键“8”的代码
//其他同”7”
//while(P2==0xde);
setstep=setstep10+8;
butcount++;
step=setstep;
if(butcount>=5)
{
butcount=0;
setstep=0;
}
break;
case 0xbe: //按键‘9’ //同上”7”
//while(P2==0xbe);
setstep=setstep10+9;
butcount++;
step=setstep;
if(butcount>=5)
{
butcount=0;
setstep=0;
}
break;
case 0x7e: //按键‘正转 //正转按键识别
while(P2==0x7e); //等待按键松开//一值按住电机是不转的,放开后才转有检查//P2口的状态值
flag[0]=0xff; //开启正转标志,关闭反转//置正转标志
flag[1]=0x00; //清除反转标志
butcount=0;
speedcount=0;
speed=500; //置电机的转速
if(!flag[4]) step=0;
TR0=1;
break;
case 0xed: //按键‘4’ //同上”7”
while(P2==0xed);
setstep=setstep10+4;
butcount++;
step=setstep;
if(butcount>=5)
{
butcount=0;
setstep=0;
}
break;
case 0xdd: //按键‘5’ //同上”7”
//while(P2==0xdd);
setstep=setstep10+5;
step=setstep;
butcount++;
if(butcount>=5)
{
butcount=0;
setstep=0;
}
break;
单片机控制步进电机,我想你说的是两相步进电机,一般是控制其相序分配的顺逆从而控制正反转,一般而言,步进电机相序分配你可以做成一个数组比如step[]={0x03,0x06,0x0c,0x09},这样来说可以假设P0口是步进电机控制口,那么可以按如下方式来控制: while(1) { for(i=0;i<4;i++) { if(fx==1)P0=step[i]; //正向 else P0=step[3-i]; //反向 delay(x); //x大小决定电机速度。
根据电机相数买个驱动器。然后用单片机产生脉冲来控制电机的转动以及正反转。单片机产生脉冲的方法和单片机控制流水灯是一样的。ULN2003D 是驱动步进电机的驱动芯片,主要是匹配电机所需的电流。 由于是四相电机,步进电机之所以可以转动就需要给相绕组提供连续的脉冲,所以需要4个端口来控制四相绕组的工作状态(P15应该是不需要的),具体的编码要看电机的拍数; 一旦明白这些,你就可以很容易编写代码来控制电机的转动了,还有在脉冲间你可以设置不同的延时时间来调节电机的转速。
#includeunsignedchari[]={0x00,0x01,0x02,0x04,0x08};voiddelay(unsignedints){while(s--);}main(){while(1){unsignedchara;for(a=1;a0;a--){P2=i[a];delay(50000);}}}记得给好评吆、、、
先看步进电机控制电机转动原理,把时序搞清楚,单片机控制驱动按照时序置管脚就OK
1、本程序用于测试4相步进电机常规驱动
2、需要用跳帽或者杜邦线把信号输出端和对应的步进电机信号输入端连接起来
3、速度不可以调节的过快,不然就没有力矩转动了
4、按s4(设置成独立按键模式)可以控制正反转
------------------------------------------------/
#include <reg52h>
bit Flag;//定义正反转标志位
unsigned char code F_Rotation[4]={0xf1,0xf2,0xf4,0xf8}; //正转表格
unsigned char code B_Rotation[4]={0xf8,0xf4,0xf2,0xf1}; //反转表格
//
/ 延时函数 /
//
void Delay(unsigned int i)//延时
{
while(--i);
}
//
/ 主函数 /
//
main()
{
unsigned char i;
EX1=1; //外部中断0开
IT1=1; //边沿触发
EA=1; //全局中断开
while(!Flag)
{
P0=0x71;//显示 F 标示正转
for(i=0;i<4;i++) //4相
{
P1=F_Rotation[i]; //输出对应的相 可以自行换成反转表格
Delay(500); //改变这个参数可以调整电机转速 ,数字越小,转速越大
}
}
while(Flag)
{
P0=0x7C;//显示 b 标示反转
for(i=0;i<4;i++) //4相
{
P1=B_Rotation[i]; //输出对应的相
Delay(500); //改变这个参数可以调整电机转速 ,数字越小,转速越大
}
}
}
//
/ 中断入口函数 /
//
void ISR_Key(void) interrupt 2 using 1
{
Delay(300);
Flag=!Flag; //s3按下触发一次,标志位取反
}
以上就是关于如何用一个单片机控制多个步进电机全部的内容,包括:如何用一个单片机控制多个步进电机、求单片机控制步进电机简单的c程序、四相步进电机单片机控制程序等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)