标题:
单片机串口通信控制步进电机,为什么每次上电只能接收一次数据控制一次?
[打印本页]
作者:
ttaniscy
时间:
2019-9-10 18:10
标题:
单片机串口通信控制步进电机,为什么每次上电只能接收一次数据控制一次?
求助,上面的程序我单片机上电后可以正常串口通信收到数据,也可以按照设定返回给串口助手相应信息,电机也可以转动指定的脉冲数,但接下来接不能正常通信了,再发数据串口助手就没有反映了,电机也不转了,单片机关掉再上电就又可以正确接收一次数据。我想不明白哪里的问题,特来求助,望指导。
单片机源程序如下:
#include<reg52.h> //共阳极接法
#define uint unsigned int
#define uchar unsigned char
#define N 8 //可一次接收数据量 帧头(# ascii码)0x23 帧头(+/-号)+——0x2b --0x2d 5位数据 帧尾(* ascii码)0x2a
sbit dula=P2^6;
sbit wela=P2^7;
sbit pul=P1^0; //脉冲端
sbit dir=P1^2; //方向端
sbit ena=P1^1; // 电机轴使能端
sbit limita=P1^3; //起始端极限位
sbit limitb=P1^4;//远端极限位
sbit origin=P1^5;//原点位
sbit led=P1^1;
sbit led2=P1^3;
uchar forward=0,backward=0,flag,i,w,j=0,serial_con;
uint n,m,l,k,r,a,b,c,d,e,sum;
uchar code table[]={ //数码管编码组
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
uchar code table1[]="MCU gets ";
uchar code table2[]=" pluses!\r\n";
uchar code table3[]="Error 1!\r\n"; //帧头错误反馈代码
uchar code table4[]="Error 2!\r\n"; //帧尾错误反馈代码
uchar code table5[]="Error 3!\r\n";//脉冲数超过38500
uchar rectable[N]; //用于接收串口通信数据的数组
void delayms(uint xms) //延时子程序
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void display(uchar num) //显示子函数
{
P0=table[num];
dula=1;
dula=0;
}
void tmod(uint m) //设置定时器0中断时间的子函数
{
TMOD=0x01;//设定定时器0 工作方式1(16位定时/计数器)
TH0=(65536-m)/256; //设定中断发生时间
TL0=(65536-m)%256;
ET0=1; //开定时器0中断
EA=1; //开总中断
TR0=1; //开启定时器0
}
void rs232_init() //串口通信初始化子程序
{
TMOD=0x20;
TH1=0xfd; //9600波特率
TL1=0xfd;
TR1=1; //波特率的发生利用定时器1
SM0=0;
SM1=1;
REN=1; //先设定好工作方式,再打开允许接收
EA=1; //打开总中断
ES=1; //打开串口中断
}
void serial_control() //根据串口通信收到脉冲数转动子程序
{
if(serial_con==1)
{
r=0; //进入几次定时器0中断计数用
serial_con=0;
/* a=rectable[2]-'0';
b=rectable[3]-'0';
c=rectable[4]-'0';
d=rectable[5]-'0';
e=rectable[6]-'0';
sum=a*10000+b*1000+c*100+d*10+e; //把输入的脉冲数的字符型字转变成数字 */
if(limita==1&&limitb==1)
{
switch(rectable[1]) //判断方向 +号ASC码 0x2b
{
case 0x2b:
dir=0;
tmod(500);
n=2;
forward=1;
break;
case 0x2d: ////判断方向 -号ASC码 0x2d
dir=1;
tmod(500);
n=2;
backward=1;
break;
}
}
serial_con=0;
}
}
void serial_com() //串口通信子程序
{
if(flag==1)
{
a=rectable[2]-'0';
b=rectable[3]-'0';
c=rectable[4]-'0';
d=rectable[5]-'0';
e=rectable[6]-'0';
sum=a*10000+b*1000+c*100+d*10+e; //把输入的脉冲数的字符型字转变成数字
if(sum<=38500) //判断是否超限,如果没有超限
{
ES=0; //关闭串口中断
for(i=0;i<9;i++) //发送既定字符
{
SBUF=table1[i];
while(!TI);
TI=0;
}
for(j=2;j<(N-1);j++) //发送接收数组
{
SBUF=rectable[j];
while(!TI);
TI=0;
}
for(i=0;i<12;i++) //发送既定字符
{
SBUF=table2[i];
while(!TI);
TI=0;
}
j=0;
ES=1;
flag=0;
serial_con=1; //进入根据收到脉冲数运动的子函数的标志位
}
if(sum>38500) //如果输入脉冲超限
{
ES=0;
for(i=0;i<12;i++)
{
SBUF=table5[i];
while(!TI);
TI=0;
}
}
j=0;
ES=1;
flag=0;
}
if(flag==2) //帧头不正确的报错
{
ES=0;
for(i=0;i<12;i++)
{
SBUF=table3[i];
while(!TI);
TI=0;
}
ES=1;
flag=0;
}
if(flag==3) //帧尾不正确的报错
{
ES=0;
for(i=0;i<12;i++)
{
SBUF=table4[i];
while(!TI);
TI=0;
}
ES=1;
flag=0;
}
}
void time0() interrupt 1 //定时器0中断子程序 中断频率在此函数内设置不同的频率,即不同的转速
{
switch(n)
{
// case 0:
// TH0=(65536-12500)/256; //n=12500 频率为40Hz 400脉冲/圈时转速为 6r/m
// TL0=(65536-12500)%256;
// break;
case 0:
TH0=(65536-5000)/256; //n=5000 频率为100Hz 400脉冲/圈时转速为 15r/m
TL0=(65536-5000)%256;
break;
// case 0:
// TH0=(65536-2500)/256; //n=2500 频率为200Hz 400脉冲/圈时转速为 30r/m
// TL0=(65536-2500)%256;
// break;
case 1:
TH0=(65536-1250)/256; //n=1250 频率为400Hz 400脉冲/圈时转速为 60r/m
TL0=(65536-1250)%256;
break;
// case 0:
// TH0=(65536-1000)/256; //n=1000 频率为500Hz 400脉冲/圈时转速为 75r/m
// TL0=(65536-1000)%256;
// break;
// case 0:
// TH0=(65536-800)/256; //n=800 频率为625Hz 400脉冲/圈时转速为 93.75r/m
// TL0=(65536-800)%256;
// break;
case 2:
TH0=(65536-500)/256; //n=500 频率为1KHz 400脉冲/圈时转速为 150r/m
TL0=(65536-500)%256;
break;
// case 2:
// TH0=(65536-312)/256; //n=312 频率为1.6KHz 400脉冲/圈时转速为 240r/m
// TL0=(65536-312)%256;
// break;
case 3:
TH0=(65536-200)/256;//根据调整n的数值,n为200时,速度较快且可正常运行,n为150时启动不正常(n=150时,频率为3.33KHz,可能这个频率对于起步太快了)
TL0=(65536-200)%256; //n为200 频率为2.5KHz 400脉冲/圈时转速为 375r/m
break;
//case 1:
// TH0=(65536-175)/256; //n=175 频率为2.86KHz 400脉冲/圈时转速为 430r/m
// TL0=(65536-175)%256;
// break;
// case 4:
// TH0=(65536-150)/256; //n=150 频率为3.33KHz 400脉冲/圈时转速为 500r/m
// TL0=(65536-150)%256;
// break;
case 4:
TH0=(65536-125)/256; //n=125 频率为4KHz 400脉冲/圈时转速为 600r/m
TL0=(65536-125)%256;
break;
case 5:
TH0=(65536-100)/256; //n=100 频率为5KHz 400脉冲/圈时转速为 750r/m
TL0=(65536-100)%256;
break;
case 6:
TH0=(65536-75)/256; //n=75 频率为6.67KHz 400脉冲/圈时转速为 1000r/m
TL0=(65536-75)%256;
break;
case 7:
TH0=(65536-50)/256; //n=50 频率为10KHz 400脉冲/圈时转速为 1500r/m
TL0=(65536-50)%256;
break;
}
// REN=0;//禁止串口接收数据
ES=0;
pul=~pul; //进入中断后,开始高低电平变换以产生脉冲
r++;
if(r==(sum*2))
{
pul=1;
TR0=0;
r=0;
n=0; //0档最慢速度
forward=0;
backward=0;
// REN=1;
ES=1;
}
if(limita==0||limitb==0) //如果起始方向极限或远端极限被触发,pul输出高电平,停止转动并关闭定时器0
{
pul=1;
TR0=0;
n=0; //0档最慢速度
forward=0;
backward=0;
// REN=1;
ES=1;
}
}
void ser()interrupt 4 //串口中断子程序
{
RI=0;
rectable[j++]=SBUF; //存数据到接收缓存
if(rectable[0]!=0x23) //帧头验证
{
flag=2;
}
if(j==N) //数组满时,验证帧尾再把flag置相应数值
{
if(rectable[7]!=0x2a) //帧尾验证
{
flag=3;
}
else
{
flag=1;
}
}
}
void main()
{
P0=0;
dula=1;
dula=0;
P0=0xc0;
wela=1;
wela=0;
rs232_init(); //串口通信初始化设置
while(1)
{
serial_com();
serial_control();
}
}
复制代码
作者:
ttaniscy
时间:
2019-9-11 11:55
根据我的试验,问题是在void serial_control()这个函数相关的地方,因为在主程序中如果屏蔽掉这个子程序,就可以实现连续正确接收。但我分析不出来这个子程序的问题在哪了,特在此求助。
作者:
yzwzfyz
时间:
2019-9-11 22:17
经验不足,
1、排除电机的电磁干扰。
2、排除程序的错误。
慢慢找吧。
作者:
ttaniscy
时间:
2019-9-12 08:25
我找到原因了,因为在主函数中我先进行串口通信接收串口助手的脉冲数信息时,TMOD设定的时定时器1的工作方式,然后在驱动步进电机是TMOD是设定定时器0的工作方式,所以在后续接收串口通信时就无法正常接受了。而修改也很简单,在269行下面加一行代码 rs232_init(); 就可以实现后续的正常接收了。
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1