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

Sanada_Hellson 2017-09-18 04:31:30
#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;
}
}
}
}
...全文
1776 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
baoyz 2017-09-30
  • 打赏
  • 举报
回复
我用的是串口助手,目前能实现发送不乱吗,但是解析那块,桌面上的JAVA程序没有任何反应, 根据这个情况,建议你,检查上位机软件,如果是你自己做的,先别解析,让上位机显示接收到的内容,判断是否正确,再说解析的事。 如果上位机不是你做的,检查上下位机的通信模式是否一致,包括波特率、校验位、停止位
worldy 2017-09-25
  • 打赏
  • 举报
回复
for(t=0;t<8;t++) { SBUF=message[t]; //向串口1发送数据 } 不能使用循环发送数据,必须使用发送中断,或者查询中断位来发送

int i=0;
for(;;)
{
   if(TI)
   {
         SBUF=message[t];         //向串口1发送数据
         TI=0;
         i++;
         if(i>=8)break;
   }
} 
alca_bigV 2017-09-22
  • 打赏
  • 举报
回复
引用 3 楼 u013963632 的回复:
这是总程序中的一个自定义的通信协议,调试很多次都不成功,下位机向上位机发数据包,格式就是两个update函数,是传送电流和转速的,中断中是上位机解析,我觉得我的解析过程很有问题,调试了很多次也没成功,希望懂协议的大神能教我
不成功,是在哪一步不成功? 1)上位机有接收到数据包吗?是否正确?(如果没有收到,就是下位机没有发出正确的数据包,找个串口调试工具把包抓 出来,分析 下mcu部分的代码,先调通了这一步再调下面的.) 2)在1正确的前提下,再考虑 解析包,如何解析?按着你们公司规定的协议,自己编写java程序... 3)解析成功了,你的java程序 要么回包,或者 显示?或者驱动什么东西? 哪一步有问题?还是第一步有问题?
C_Rabbit 2017-09-20
  • 打赏
  • 举报
回复
你这里贴的都是MCU部分的代码啊,MCU部分的代码只影响发送出去的消息字符串和如何解析上位机发出的字符串 如果你想解决上位机发出字符串但MCU不响应的问题,那么最直观的调试方式是在MCU上调试,设置断点,查看接收缓存中存储的接收到的消息字符 然后就是我上面说的解析算法几个要素: 在接受解析过程中设置足够大的缓存来保障接收到的数据 在缓存中采用灵活的顺序查找算法定位有效数据 要及时的(不管有没有查到有效数据)清理缓存中的无效数据(已提取过或校验错误的数据) 如果是MCU发送消息而上位机没有反应,那么应该去从上位机的软件中去查找问题
C_Rabbit 2017-09-20
  • 打赏
  • 举报
回复
额,那你得到java板块去问问了,或者你还得能拿到你的上位机的相关软件源码
C_Rabbit 2017-09-20
  • 打赏
  • 举报
回复
那你需要断点调试,设置断点,分别查看MCU发出的和MCU接收到数据是不是真正想要的字符串 你的解析部分确实很不严谨,这种场景下,首先要考虑到的是数据接收漏字乱码等情况发生后,要如何补救 例子: 真实发送的数据是“*1abcd#” 在连续发送场景下,因为mcu的接收缓存大小设置、中断处理结构、线路接触不良干扰等众多因素下 真实接收到的并存在接受缓存中的数据可能是“*1abcd*1”或“#*1abcd#*”或“&*1abcd#”等等,千奇百怪的 这就需要你在接受解析过程中设置足够大的缓存来保障接收到的数据,然后在缓存中采用灵活的顺序查找算法定位有效数据,最后要及时的(不管有没有查到有效数据)清理缓存中的无效数据(已提取过或校验错误的数据),做到这三点,才算是一个能够实际使用的解析程序。最后则是在提高算法的效率和泛用度上,使之成为一个优秀的程序。
Sanada_Hellson 2017-09-20
  • 打赏
  • 举报
回复
这是总程序中的一个自定义的通信协议,调试很多次都不成功,下位机向上位机发数据包,格式就是两个update函数,是传送电流和转速的,中断中是上位机解析,我觉得我的解析过程很有问题,调试了很多次也没成功,希望懂协议的大神能教我
Sanada_Hellson 2017-09-20
  • 打赏
  • 举报
回复
#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; }
Sanada_Hellson 2017-09-20
  • 打赏
  • 举报
回复
#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
Sanada_Hellson 2017-09-20
  • 打赏
  • 举报
回复
#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();//数码管显示函数 } }
Sanada_Hellson 2017-09-20
  • 打赏
  • 举报
回复
我用的是串口助手,目前能实现发送不乱吗,但是解析那块,桌面上的JAVA程序没有任何反应,我想具体了解下,上位机如何解析下位机的数据包,并且合理地接收
C_Rabbit 2017-09-20
  • 打赏
  • 举报
回复
首先,你这代码不全,这只是一个c文件,应该是某个工程项目里的对应C程序驱动文件,看样子是仅针对于串口通讯的调用函数的。 两个update函数,是在主函数部分调用发送数据到串口的模块 remotedata函数是接收到的串口数据解析成业务数据的 根据函数数据的组合和解析方法,可以看出是字符型的通信协议 “*1xxxx#”或“*2xxxx#”,分别指代电流和速度? 没有校验位,看样子应该不是标准型的模块
alca_bigV 2017-09-20
  • 打赏
  • 举报
回复
你这,想问什么?还是想让别人通过代码看你的通讯协议是不是有问题? 通讯协议是自定义的东西,自己公司的mcu与上位机约定的... 不明白 你的意思.

27,373

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧