求大哥帮小弟解决下问题。谢谢!单片机串口判断字符串问题。串口接收保存在数组里面只有第一个字节
时间:10-02
整理:3721RD
点击:
#include"STC_NEW_8051.H"
#include"delay.h"
#include"INTRINS.H"
#define uchar unsigned char
#define uint unsigned int
#define ON 0
#define OFF 1
#define LOW 0
#define HIGH 1
#define M_TIME 100//定义不进电机频率为75
/*-----------inductor-----------*/ //感应器端口定义
sbit G=P0^0; //用做步进电机原点感应器
sbit L = P0^4; //标志步进电机终点感应器
sbit zhengzhuan=P0^1; //手动 正转
sbit fanzhuan=P0^2; //手动 反转
sbit zidong=P0^3; //自动
/*----------motor_GPIO()---------*/ //马达输出口定义
sbit M_Z = P2^0 ; //脉冲正极,
sbit M_F = P2^1; //脉冲负极,
unsigned char date ,CHZT;
#define BUFSIZE 80//定义串口字节数组长度保存变量
uchar idata Rec_Buff[BUFSIZE]; //接收字符数组BUFSIZE长度
uchar Rec_cnt = 0;
bit Rec_ok;
uint Rec_timeout;
uchar stop_cnt = 0;
void zz_key_press();
void zd_key_press();
void fz_key_press();
void init_m();
void Send_Buf(uchar *p,uchar len) ;
void init_com() ;
void clear_rec();
void zd();
uint i , j = 300;
void main()
{
zhengzhuan = 1;
fanzhuan = 1;
G = 1;
L = 1;
M_Z = 0;
M_F = 0;
init_m(); // 初始化步进电机归初始状态
init_com();
Send_Buf("*******\r\n",9);
while(1)
{
if(Rec_ok == 1)
{
if(Rec_Buff[0]=='s') //start
{
Send_Buf("**s\r\n",5); //测试是否进入
if(Rec_Buff[1]=='t')
{
if(Rec_Buff[2]=='a')
{
if(Rec_Buff[3]=='r')
{
if(Rec_Buff[4]=='t')
{
zd();
Send_Buf("start_ok\n",9);
}
}
}
}
}
if(Rec_Buff[0]=='l') //left
{
Send_Buf("l\r\n",3); //测试是否进入
if(Rec_Buff[1]=='e')
{
Send_Buf("e\r\n",3); //测试是否进入
if(Rec_Buff[2]=='f')
{
Send_Buf("f\r\n",3); //测试是否进入
if(Rec_Buff[3]=='t')
{
Send_Buf("t\r\n",3); //测试是否进入
M_F = 0;
for(i=0;i<=j && L == 1;i++)
{
M_Z = 1;
delay_us(M_TIME);
M_Z = 0;
delay_us(M_TIME);
}
Send_Buf("left_ok\n",9);
}
}
}
}
if(Rec_Buff[0]=='r') //right
{
Send_Buf("r\r\n",3); //测试是否进入
if(Rec_Buff[1]=='i')
{
if(Rec_Buff[2]=='g')
{
if(Rec_Buff[3]=='h')
{
if(Rec_Buff[4]=='t')
{
M_F = 1;
for(i=0;i<=j && G == 1;i++)
{
M_Z = 1;
delay_us(M_TIME);
M_Z = 0;
delay_us(M_TIME);
}
Send_Buf("right_ok\n",10);
}
}
}
}
}
Rec_ok = 0;
clear_rec();
Rec_cnt = 0;
}
zz_key_press();
fz_key_press();
zd_key_press();
}
}
/**************初始化串口通讯函数********************/
void init_com() //COM初始化
{
AUXR=0x20;
SCON=0x50;
PCON=0x00;
TMOD=0x21;
TH1=0xfa;
TL1=0xfa;
PS=1;
EA=1;
ES=1;
TR1=1;
}
void send_byte(char date)
{
ES=0;
REN=0;
//TI = 0;
SBUF=date;
while(!TI);
TI = 0; //串口发送完毕后,将在标志位TI置0
REN=1;
ES=1;
}
void Send_Buf(uchar *p,uchar len) //发送函数 *P(字符串) len(字符串的长度)
{
while(len>0)
{
send_byte(*p);
p++;
len--;
}
}
void clear_rec() //清空 Rec_Buff[BUFSIZE]里面的数据
{
uchar i;
for(i=0;i<BUFSIZE;i++)
{
Rec_Buff[i] = 0;
}
}
//******************检测串行中断********************//
void RX_com() interrupt 4
{
//Send_Buf("test\r\n",6);
if(TI)
{
TI = 0;
}
if(RI)
{
RI=0;
Rec_timeout = 0;//超时函数
Rec_Buff[Rec_cnt] = SBUF; //循环把SBUF(串口接收的字符串)保存在数组 Rec_Buff[]里面 数组长度 BUFSIZE
Send_Buf("test_RI\r\n",9); //测试是否进入
if((Rec_Buff[0]=='s'))
{
stop_cnt = 5;//假如是s开头,默认为start ,stop_cnt = 5;
Send_Buf("s\r\n",3); //测试是否进入
if((Rec_Buff[1]=='t'))
{
Send_Buf("t\r\n",3); //测试是否进入
}
}else if((Rec_Buff[0]=='l'))
{
stop_cnt = 4; //假如是l开头,默认为left ,stop_cnt = 4;
Send_Buf("l**\r\n",5); //测试是否进入
}else if((Rec_Buff[0]=='r'))
{
stop_cnt = 5; //假如是r开头,默认为right ,stop_cnt = 5;
Send_Buf("r\r\n",3); //测试是否进入
}
Rec_cnt++;
if(Rec_cnt>=BUFSIZE)
{
Rec_cnt = 0;
ES =0 ;
}
if(BUFSIZE>=stop_cnt)
{
Rec_ok = 1;
Send_Buf("test_rec_ok\r\n",13); //测试是否进入
}
}else{
Rec_ok = 0;
ES =0 ; //关中断,回复完了再ES=1;
}
}
void zd()
{
M_F = 0;
while(L == 1 )
{
M_Z = 1;
delay_us(M_TIME);
M_Z = 0;
delay_us(M_TIME);
}
M_F=1;
while( G == 1)//当原点感应器不在初始状态下,步进电机回原点
{
M_Z = 1;
delay_us(M_TIME);
M_Z = 0;
delay_us(M_TIME);
}
}
/**************自动按钮控制函数********************/
void zd_key_press()
{
if(CHZT = 1)//只有在步进电机在初始位置,自动按钮才生效
{
if(zidong == 0 )
{
delay_us(20);
if(zidong == 0 || G == 0 )
{
zd();
}
CHZT = 1;//标志步进电机在初始位置
}
}
}
/**************手动反转按钮控制函数********************/
void fz_key_press()
{
if(fanzhuan == 0)
{
delay_us(20);
if(fanzhuan == 0 )
{
M_F = 1;
/*while(fanzhuan == 0 ) //反转按钮按下,而且初始状态感应器断开,才可以转。
{
M_Z = 1;
delay_us(M_TIME);
M_Z = 0;
delay_us(M_TIME);
} */
if(G == 1)
{
M_Z = 1;
delay_us(M_TIME);
M_Z = 0;
delay_us(M_TIME);
}
CHZT = 1;//标志步进电机在初始位置
}
}
}
/**************手动正转按钮控制函数********************/
void zz_key_press()
{
if(zhengzhuan == 0)
{
delay_us(20);
if(zhengzhuan == 0)
{
M_F = 0;
/*while(zhengzhuan == 0 || L == 1) //正转按钮按下,而且初始状态感应器断开,才可以转。
{
M_Z = 1;
delay_us(M_TIME);
M_Z = 0;
delay_us(M_TIME);
}*/
if(L == 1)
{
M_Z = 1;
delay_us(M_TIME);
M_Z = 0;
delay_us(M_TIME);
}
CHZT = 1;//标志步进电机在初始位置
}
}
}
/**************初始化不进电机位置控制函数********************/
void init_m()
{
M_F = 1;
while(G == 1) //当原点感应器不在初始状态下,步进电机回原点
{
M_Z=1;
delay_us(M_TIME);
M_Z=0;
delay_us(M_TIME);
}
CHZT = 1;//标志 步进电机在初始位置
}
代码真心好长,大概看了下。首先你得把串口接收中断中的代码缩短,太长了,可能会在上位机发数据的时候你上一次的中断还没退出来,导致接收数据有误。中断执行时间要短!给你个参考
- void UART4_IRQHandler(void)
- {
- u8 ch = 0,temp=0;
- temp = UART4->SR;
- if(temp&0X20)
- {
- if( cntRxd_RS485 < 128 )
- {
- Rs485_Buf[cntRxd_RS485++] = USART_ReceiveData(UART4);
- }
- else
- {
- ch = USART_ReceiveData(UART4);
- }
- }
- …………………………
数据接收到缓冲区后拿到中断外面去处理。还要做好错误帧的识别,假如数据接收数大于你设置的stop_cnt了,但是不是你要的指令怎么办?后续的数组要接收满了才能清零从0开始? 还有一帧数据和一帧数据要有个间隔时间,后续还有很多可以完善的地方。代码嵌套的也好多,你不头晕吗?
就是头晕,现在不知道哪里出了错误。
大哥,可以把你给的代码注释一下吗?我不怎么懂
自己先看看测试结果和程序之间 的对于关系
恩,我觉得自己的逻辑没有错,就是代码不知道哪里错了。弄成这样的结果
跟你说了不要在串口中断中处理那么多数据,尤其是还要发数据出去,假如都是波特率都是9600,接收一个数据后第二个数据来了你还在中断里发送你的那些啥“测试是否进入”之类的东西,都删掉
我给你的代码本来有注释的,复制过来是乱码我就删除了。
cntRxd_RS485跟你设置的Rec_cnt一个意思,缓冲数据最大128字节。
USART_ReceiveData(UART4);就是等同于51里的SBUF,表示进来一个字节的数据。
Rs485_Buf[cntRxd_RS485++]表示每接收一个数据就放入buf里,cntRxd_RS485加1,以便接收下一个数据。
cntRxd_RS485的清零都在中断外部处理的,buf里的数据识别也都是在中断外面。