分享

关于单片机和上位机的通信协议问题

 lixinhecom 2018-06-20
#include "DCconnect.h"   //头文件里没东西,就是函数声明
#include "reg52.h"              

typedef unsigned char u8;
typedef unsigned int u16;

extern u16 cs; //current speed 当前的速度
extern u16 ss; //set     speed 设定的速度
//extern int e; //speed error 转速误差
extern u8  cmode; //0为开环,1为闭环
sbit LEDdd=P2^7; //测试LED灯位

//extern u8  r; //电阻值
//extern u16 current; //Digital Filter
char speed[5];
extern u8 iflag;
u8 t;
extern u8 flag;

void updateCurrent(u16 data1)
{
char message[8];
// LEDdd=~LEDdd;
message[0] = '*';
message[1] = '1';
message[2] = data1/1000+48;  //Transfer the number to Ascii
message[3] = data1%1000/100+48;
message[4] = data1%100/10+48;
message[5] = data1%10+48;
message[6] = '#';
message[7] = '\0';
for(t=0;t<8;t++)
{
SBUF=message[t];         //向串口1发送数据


while(!TI);
TI=0;

}

void updateSpeed(u16 data1)
{
char message[8];
// LEDdd=~LEDdd;
message[0] = '*';
        message[1] = '2';
        message[2] = data1/1000+48;
        message[3] = data1%1000/100+48;
        message[4] = data1%100/10+48;
        message[5] = data1%10+48;
        message[6] = '#';
        message[7] = '\0';
        for(t=0;t<8;t++)
   {
SBUF=message[t];         //向串口1发送数据
while(!TI);
    TI=0;
   }

}

void remoteDataIncoming() interrupt 4
{
static int i;
static flag=0;
static u16 ls;
static u8 USART_RX_BUF[7];
if(SBUF=='*') 
flag=1;
// RI = 0;
if(flag==1)
{   
USART_RX_BUF[i]=SBUF;
// RI = 0;
i++;
if(SBUF=='#')
{
flag=0;
if(USART_RX_BUF[0]=='*' && USART_RX_BUF[6]=='#')
{    
speed[0] = USART_RX_BUF[2];
speed[1] = USART_RX_BUF[3];
speed[2] = USART_RX_BUF[4];
speed[3] = USART_RX_BUF[5];
cmode=(u8)(USART_RX_BUF[1]!='1');
ls=ss;
    ss=(speed[0]-48)*1000+(speed[1]-48)*100+(speed[2]-48)*10+(speed[3]-48)*1;
if(ls != ss)
{
flag=1;
if(cmode)iflag=0;
}
//for(i=0;i<3;i++) ss+=speed[i]*10^i;
}
for(t=0;t<7;t++)
{
USART_RX_BUF[i]=0;

}
}
}
临平小两口下班没事在家赚钱,半年后存款惊人!! 广告 芒极科技 · 顶新
发表于: 2017-09-18 16:31:30 楼主 回复次数:14
CSDN官网
CSDN推荐
baidu_39576528
alca_bigV
Bbs1
本版专家分:0
结帖率:100%
你这,想问什么?还是想让别人通过代码看你的通讯协议是不是有问题?
通讯协议是自定义的东西,自己公司的mcu与上位机约定的...
不明白 你的意思.
回复于: 2017-09-20 10:05:29 #1 得分:0
C_Rabbit
C_Rabbit
Bbs4
本版专家分:1836
结帖率:100%
首先,你这代码不全,这只是一个c文件,应该是某个工程项目里的对应C程序驱动文件,看样子是仅针对于串口通讯的调用函数的。
两个update函数,是在主函数部分调用发送数据到串口的模块
remotedata函数是接收到的串口数据解析成业务数据的
根据函数数据的组合和解析方法,可以看出是字符型的通信协议 
“*1xxxx#”或“*2xxxx#”,分别指代电流和速度?
没有校验位,看样子应该不是标准型的模块
回复于: 2017-09-20 10:17:15 #2 得分:0
u013963632
Sanada_Hellson
Bbs1
本版专家分:0
结帖率:50%
这是总程序中的一个自定义的通信协议,调试很多次都不成功,下位机向上位机发数据包,格式就是两个update函数,是传送电流和转速的,中断中是上位机解析,我觉得我的解析过程很有问题,调试了很多次也没成功,希望懂协议的大神能教我
回复于: 2017-09-20 10:51:05 #3 得分:0
C_Rabbit
C_Rabbit
Bbs4
本版专家分:1836
结帖率:100%
那你需要断点调试,设置断点,分别查看MCU发出的和MCU接收到数据是不是真正想要的字符串
你的解析部分确实很不严谨,这种场景下,首先要考虑到的是数据接收漏字乱码等情况发生后,要如何补救
例子:
真实发送的数据是“*1abcd#”
在连续发送场景下,因为mcu的接收缓存大小设置、中断处理结构、线路接触不良干扰等众多因素下
真实接收到的并存在接受缓存中的数据可能是“*1abcd*1”或“#*1abcd#*”或“&*1abcd#”等等,千奇百怪的
这就需要你在接受解析过程中设置足够大的缓存来保障接收到的数据,然后在缓存中采用灵活的顺序查找算法定位有效数据,最后要及时的(不管有没有查到有效数据)清理缓存中的无效数据(已提取过或校验错误的数据),做到这三点,才算是一个能够实际使用的解析程序。最后则是在提高算法的效率和泛用度上,使之成为一个优秀的程序。
回复于: 2017-09-20 11:11:02 #4 得分:0
u013963632
Sanada_Hellson
Bbs1
本版专家分:0
结帖率:50%
我用的是串口助手,目前能实现发送不乱吗,但是解析那块,桌面上的JAVA程序没有任何反应,我想具体了解下,上位机如何解析下位机的数据包,并且合理地接收
梦寐以求爱车到手,感谢团队教我手机赚钱!! 源新创 · 顶新
回复于: 2017-09-20 10:30:52 #5 得分:0
C_Rabbit
C_Rabbit
Bbs4
本版专家分:1836
结帖率:100%
额,那你得到java板块去问问了,或者你还得能拿到你的上位机的相关软件源码
回复于: 2017-09-20 11:21:20 #6 得分:0
u013963632
Sanada_Hellson
Bbs1
本版专家分:0
结帖率:50%
#include "reg52.h"   //此文件中定义了单片机的一些特殊功能寄存器
#include"XPT2046.h"

typedef unsigned int u16;   //对数据类型进行声明定义
typedef long unsigned int u32;
typedef unsigned char u8;

sbit LSA=P2^2;   //3-8译码器充当数码管的位选
sbit LSB=P2^3;
sbit LSC=P2^4;
sbit PWM_OUT=P2^1;   //PWM输出口
sbit K1=P3^2;   //PWM占空比调节按键
sbit E6B2=P3^3;   //编码器输出脉冲口
sbit LEDdd=P2^7;              //测试LED

u16 count,count1;   //两个计数器
u8 iflag;
u8 PWM_LEVEL=0;   //占空比等级,10%-100%
u16 PwmNum=0;   //从E6B2口输出的脉冲数
u16 temp,temp1;       //temp用于存电流值,temp1暂存PwmNum用于计算转速
u8 disp[8];
u8 speed[5];
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

u32 cs; //current speed
u32 ss; //set speed
u8  cmode; //0为开环,1为闭环

/*******************************************************************************
* 函 数 名         : delay
* 函数功能    : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
while(i--);
}

/*******************************************************************************
* 函 数 名       :updataCurrent
* 函数功能  :上传电流数据
*******************************************************************************/
void updateCurrent(u16 data1)
{
static u8 t=0;
static u8 message[8];
LEDdd=~LEDdd;
message[0] = '*';
message[1] = '1';
message[2] = data1/1000+48;  //Transfer the number to Ascii
message[3] = data1%1000/100+48;
message[4] = data1%100/10+48;
message[5] = data1%10+48;
message[6] = '#';
message[7] = '\0';
for(t=0;t<8;t++)
{
SBUF=message[t];         //向串口1发送数据
while(TI==0);
TI=0;
}   
}

/*******************************************************************************
* 函 数 名       :updataSpeed
* 函数功能  :上传转速数据
*******************************************************************************/
void updateSpeed(u16 data1)
{
static u8 t;
static u8 message[8];
// LEDdd=~LEDdd;
message[0] = '*';
    message[1] = '2';
    message[2] = data1/1000+48;
    message[3] = data1%1000/100+48;
    message[4] = data1%100/10+48;
    message[5] = data1%10+48;
    message[6] = '#';
    message[7] = '\0';
    for(t=0;t<8;t++)
   {
SBUF=message[t];         //向串口1发送数据
while(TI==0);
TI=0;
   }
}

/*******************************************************************************
* 函 数 名       :datapros()
* 函数功能  :数据处理函数
*******************************************************************************/
void datapros()
{
// u16 sum; 
static u8 i;
if(i==50)
{
i=0;
temp = Read_AD_Data(0xE4); //   AIN3 外部输入
}
// updateCurrent(temp);
// updateSpeed(temp1/10);
i++;
// sum+=temp;
// averge=sum/10;
disp[0]=smgduan[temp/1000];//千位
disp[1]=smgduan[temp%1000/100];//百位
disp[2]=smgduan[temp%1000%100/10];//十位
disp[3]=smgduan[temp%1000%100%10];//个位
disp[4]=smgduan[(temp1/10)/1000];
disp[5]=smgduan[((temp1/10)%1000)/100];
disp[6]=smgduan[((temp1/10)%100)/10];
disp[7]=smgduan[(temp1/10)%10];

}

/*******************************************************************************
* 函 数 名       :DigDisplay()
* 函数功能  :数码管显示函数
*******************************************************************************/
void DigDisplay()
{
u8 i;
for(i=0;i<8;i++)
{
switch(i)  //位选,选择点亮的数码管,
{
case(0):
LSA=0;LSB=0;LSC=0; break;//显示第0位
case(1):
LSA=1;LSB=0;LSC=0; break;//显示第1位
case(2):
LSA=0;LSB=1;LSC=0; break;//显示第2位
case(3):
LSA=1;LSB=1;LSC=0; break;//显示第3位
case(4):
LSA=0;LSB=0;LSC=1; break;
case(5):
LSA=1;LSB=0;LSC=1; break;
case(6):
LSA=0;LSB=1;LSC=1; break;
case(7):
LSA=1;LSB=1;LSC=1; break;
}
P0=disp[i];//发送数据
delay(100); //间隔一段时间扫描
P0=0x00;//消隐
}
}

/*******************************************************************************
* 函 数 名       :Start
* 函数功能  :初始化INT0,定时器0
*******************************************************************************/
void Start()
{
SCON=0X50;  //设置方式
TMOD=0X22;  //定时器0,方式2,自动重装,计数器1,0010,计数模式方式2
// PCON=0X80;
TH0=0;  //定时0.1ms
TL0=0X9C;
TH1=0XE6;  //1200波特率
TL0=0XE6;
EA=1;  //开总中断
ET0=1;  //开定时器0
TR0=1;  //开定时器0
ES=1;  //打开串口中断
TR1=1;  //开计数器1
EX0=1;  //开INT0,调节占空比用
IT0=1;  //边沿触发
EX1=1;  //开INT1,用于计数
IT1=1;  //边沿触发


/*******************************************************************************
* 函 数 名       :remoteDataIncoming
* 函数功能  :串口的中断函数
*******************************************************************************/
void remoteDataIncoming() interrupt 4
{
static u8 t;
static u8 i;
static u8 flag=0;
static u16 ls;
static u8 USART_RX_BUF[7];
updateCurrent(temp);
updateSpeed(temp1/10);
if(SBUF=='*') 
flag=1;
// RI = 0;
while(flag==1)
{   
USART_RX_BUF[i]=SBUF;
// RI = 0;
i++;
if(SBUF=='#')
{
flag=0;
if(USART_RX_BUF[0]=='*' && USART_RX_BUF[6]=='#')
{    
speed[0] = USART_RX_BUF[2];
speed[1] = USART_RX_BUF[3];
speed[2] = USART_RX_BUF[4];
speed[3] = USART_RX_BUF[5];
speed[4] = '\0';
cmode=(u8)(USART_RX_BUF[1]!='1');
ls=ss;
    ss=(speed[0]-48)*1000+(speed[1]-48)*100+(speed[2]-48)*10+(speed[3]-48)*1;
if(ls != ss)
{
flag=1;
if(cmode)iflag=0;
}
//for(i=0;i<3;i++) ss+=speed[i]*10^i;
}
for(t=0;t<7;t++)
{
USART_RX_BUF[i]=0;

}
}
while(RI==0);
RI=0;
}

/*******************************************************************************
* 函 数 名       :init1
* 函数功能  :INT1的中断函数
*******************************************************************************/
void init1() interrupt 2
{
PwmNum++;
}

/*******************************************************************************
* 函 数 名       :timer0
* 函数功能  :定时器0的中断函数
*******************************************************************************/
void timer0() interrupt 1
{
count++;
count1++;
if(count==100)                     //10ms
{
count=0;
}
if(PWM_LEVEL*10<count)
{
PWM_OUT=0;
}
else

PWM_OUT=1;
}
if(count1==10000)                 //1s到读出PwmNum,并且复位
{
temp1=PwmNum;
count1=0;
PwmNum=0;
}
}

/*******************************************************************************
* 函 数 名       :init0
* 函数功能  :INT0的中断函数
*******************************************************************************/
void init0() interrupt 0
{
PWM_LEVEL++;
if(PWM_LEVEL==10)
{
PWM_LEVEL=0;
}
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能  : 主函
*******************************************************************************/
void main()
{
Start();
while(1)
{
datapros();  //数据处理函数
DigDisplay();//数码管显示函数
}
}
回复于: 2017-09-20 10:34:39 #7 得分:0
u013963632
Sanada_Hellson
Bbs1
本版专家分:0
结帖率:50%
#ifndef   __XPT2046_H_
#define   __XPT2046_H_

//---包含头文件---//
#include<reg52.h>
#include<intrins.h>

//---重定义关键词---//
#ifndef uchar
#define uchar unsigned char
#endif

#ifndef uint
#define uint  unsigned int
#endif

#ifndef ulong
#define ulong  unsigned long
#endif

//---定义使用的IO口---//
sbit DOUT = P3^7;   //输出
sbit CLK  = P3^6;   //时钟
sbit DIN  = P3^4;   //输入
sbit CS   = P3^5;   //片选

uint Read_AD_Data(uchar cmd);
uint SPI_Read(void);
void SPI_Write(uchar dat);

#endif
回复于: 2017-09-20 10:36:12 #8 得分:0
u013963632
Sanada_Hellson
Bbs1
本版专家分:0
结帖率:50%
#include"XPT2046.h"

///****************************************************************************
//*函 数 名                  :TSPI_Start
//*函数功能                  :初始化触摸SPI
//****************************************************************************/
//void SPI_Start(void)
//{
// CLK = 0;
// CS  = 1;
// DIN = 1;
// CLK = 1;
// CS  = 0;
//}

/****************************************************************************
*函数名:SPI_Write
*输  入:dat:写入数据
*输  出:无
*功  能:使用SPI写入数据
****************************************************************************/
void SPI_Write(uchar dat)
{
uchar i;
CLK = 0;
for(i=0; i<8; i++)
{
DIN = dat >> 7;   //放置最高位
dat <<= 1;
CLK = 0; //上升沿放置数据
CLK = 1;
}
}

/****************************************************************************
*函数名:SPI_Read
*输  入:无
*输  出:dat:读取 到的数据
*功  能:使用SPI读取数据
****************************************************************************/
uint SPI_Read(void)
{
uint i, dat=0;
CLK = 0;
for(i=0; i<12; i++) //接收12位数据
{
dat <<= 1;

CLK = 1;
CLK = 0;

dat |= DOUT;

}
return dat;
}

/****************************************************************************
*函数名:Read_AD_Data
*输  入:cmd:读取的X或者Y
*输  出:endValue:最终信号处理后返回的值
*功  能:读取触摸数据
****************************************************************************/
uint Read_AD_Data(uchar cmd)
{
uchar i;
uint AD_Value;
CLK = 0;
CS  = 0;
SPI_Write(cmd);
for(i=6; i>0; i--);  //延时等待转换结果
CLK = 1;   //发送一个时钟周期,清除BUSY
_nop_();
_nop_();
CLK = 0;
_nop_();
_nop_();
AD_Value=SPI_Read();
CS = 1;
return AD_Value;
}
回复于: 2017-09-20 10:36:43 #9 得分:0
C_Rabbit
C_Rabbit
Bbs4
本版专家分:1836
结帖率:100%
你这里贴的都是MCU部分的代码啊,MCU部分的代码只影响发送出去的消息字符串和如何解析上位机发出的字符串
如果你想解决上位机发出字符串但MCU不响应的问题,那么最直观的调试方式是在MCU上调试,设置断点,查看接收缓存中存储的接收到的消息字符
然后就是我上面说的解析算法几个要素:
在接受解析过程中设置足够大的缓存来保障接收到的数据
在缓存中采用灵活的顺序查找算法定位有效数据
要及时的(不管有没有查到有效数据)清理缓存中的无效数据(已提取过或校验错误的数据)

如果是MCU发送消息而上位机没有反应,那么应该去从上位机的软件中去查找问题
回复于: 2017-09-20 11:29:53 #10 得分:0
baidu_39576528
alca_bigV
Bbs1
本版专家分:0
结帖率:100%


引用 3 楼 u013963632 的回复:
这是总程序中的一个自定义的通信协议,调试很多次都不成功,下位机向上位机发数据包,格式就是两个update函数,是传送电流和转速的,中断中是上位机解析,我觉得我的解析过程很有问题,调试了很多次也没成功,希望懂协议的大神能教我

不成功,是在哪一步不成功?

1)上位机有接收到数据包吗?是否正确?(如果没有收到,就是下位机没有发出正确的数据包,找个串口调试工具把包抓 出来,分析 下mcu部分的代码,先调通了这一步再调下面的.)
2)在1正确的前提下,再考虑 解析包,如何解析?按着你们公司规定的协议,自己编写java程序...
3)解析成功了,你的java程序 要么回包,或者 显示?或者驱动什么东西?
哪一步有问题?还是第一步有问题?

回复于: 2017-09-22 12:34:54 #11 得分:0
worldy
worldy
Bbs6
本版专家分:9190
结帖率:95.83%
Blank
红花 2015年8月 硬件/嵌入开发大版内专家分月排行榜第一
2015年7月 VC/MFC大版内专家分月排行榜第一
2015年5月 VC/MFC大版内专家分月排行榜第一
2015年4月 VC/MFC大版内专家分月排行榜第一
2015年3月 VC/MFC大版内专家分月排行榜第一
2015年1月 硬件/嵌入开发大版内专家分月排行榜第一
2013年12月 VC/MFC大版内专家分月排行榜第一
2013年11月 VC/MFC大版内专家分月排行榜第一
2013年6月 VB大版内专家分月排行榜第一
2013年5月 VB大版内专家分月排行榜第一
2013年1月 VB大版内专家分月排行榜第一
2012年12月 VB大版内专家分月排行榜第一
Blank
黄花 2015年9月 VC/MFC大版内专家分月排行榜第二
2015年7月 硬件/嵌入开发大版内专家分月排行榜第二
2014年5月 VC/MFC大版内专家分月排行榜第二
2014年3月 VC/MFC大版内专家分月排行榜第二
2013年10月 VB大版内专家分月排行榜第二
2013年7月 VB大版内专家分月排行榜第二
2012年5月 VB大版内专家分月排行榜第二
2012年4月 VB大版内专家分月排行榜第二
2012年2月 VB大版内专家分月排行榜第二
2011年11月 VB大版内专家分月排行榜第二
Blank
蓝花 2015年11月 VC/MFC大版内专家分月排行榜第三
2015年6月 VC/MFC大版内专家分月排行榜第三
2015年2月 VC/MFC大版内专家分月排行榜第三
2014年1月 VC/MFC大版内专家分月排行榜第三
2012年3月 VB大版内专家分月排行榜第三
2011年12月 VB大版内专家分月排行榜第三
2011年10月 VB大版内专家分月排行榜第三
for(t=0;t<8;t++)
{
SBUF=message[t];         //向串口1发送数据



不能使用循环发送数据,必须使用发送中断,或者查询中断位来发送

C/C++ code?
1
2
3
4
5
6
7
8
9
10
11
int i=0;
for(;;)
{
   if(TI)
   {
         SBUF=message[t];         //向串口1发送数据
         TI=0;
         i++;
         if(i>=8)break;
   }
回复于: 2017-09-25 11:01:30 #12 得分:0
baoyz
baoyz
Bbs1
本版专家分:57
结帖率:100%
我用的是串口助手,目前能实现发送不乱吗,但是解析那块,桌面上的JAVA程序没有任何反应,
根据这个情况,建议你,检查上位机软件,如果是你自己做的,先别解析,让上位机显示接收到的内容,判断是否正确,再说解析的事。
如果上位机不是你做的,检查上下位机的通信模式是否一致,包括波特率、校验位、停止位

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多