解析MWC的串口通讯正式版0407.docx
《解析MWC的串口通讯正式版0407.docx》由会员分享,可在线阅读,更多相关《解析MWC的串口通讯正式版0407.docx(27页珍藏版)》请在冰豆网上搜索。
![解析MWC的串口通讯正式版0407.docx](https://file1.bdocx.com/fileroot1/2023-4/16/9e322f09-cc79-4288-8bc7-170410bc3028/9e322f09-cc79-4288-8bc7-170410bc30281.gif)
解析MWC的串口通讯正式版0407
解析MWC的串口通讯
一使用的软件
二使用的MWC定义串口协议文件
updated04July
Multiwiiserialprotocolwasredesigned:
•tobelight,asbefore
•tobegeneric:
itcanbeusedtransparenltybyaGUI,OSD,telemetryorhomemadeconfigtool.
ienomorespecificOSDcodeshouldbecodedinmultiwii
•tobebitwireefficient:
onlyrequesteddataaretransmittedinabinaryformat
•tobequitesecure:
dataaresentwithachecksum,preventingcorruptedconfigurationtobeinjected.
•tobeheadersensitive:
asitisdesignedwithaspecificheader,itcanbemixedwithotherframe,likeGPSframe
ie,itwillbepossibletoconnecteitheraGUIoraGPSonthesameserialportwithoutchangingtheconf
•tobelesssensitivetoevolutions:
ieincaseofparameterevolution,themainprotocolwillremaincompatibleandtheGUIwillbemuchlessversiondependent.
variabledatalengthallowstoconsideronlythebeginningofamessage,leavingtheotheroctetsattheendtoextendtransparentlythemessage(forinstancetoaddanewPID)
IthoughtfirstaboutanimplementationofMavlink,butIthinkit'snotwhatIwaslookingfor.
Evenwithapartialimplementation,thepredefinedstructuresarenotlightenoughforwhatIhaveinmind.
Somemessagesarehoweverinspiredfrommavlinkstructure.
Themainruleremains:
Multiwiineversendssomethingonitsown.
Arequestmustbedoneineachcasetoretrieveorsetdata.
Eachmessagesreceivedareacknowledgedevenifthereisnodatainside.
Thereare2mainmessagestoconsider:
•requestmessagetomultiwii
•multiwiioutputmessage
requestmessagetomultiwii
Torequestsimpledatawithoutparameters/sendaspecificcommand/injectnewparametersinmultiwii
messagesareformatedlikethis:
$M>[datalength][code][data][checksum]
1octet'$'
1octet'M'
1octet'<'
1octet[datalength]
1octet[code]
severaloctets[data]
1octet[checksum]
[datalength]canbe0incaseofnoparamcommand
multiwiioutputmessage
messagesareformatedlikethis:
$M>[datalength][code][data][checksum]
1octet'$'
1octet'M'
1octet'>'
1octet[datalength]
1octet[code]
severaloctets[data]
1octet[checksum]
ifthemessageisunknown:
$M|[0][code][checksum]
1octet'$'
1octet'M'
1octet'|'
1octet0
1octet[unknowncode]
1octet[checksum]
三、对写入MWC的原文件分析
voidserialCom(){//①MWC通过c=SerialRead(CURRENTPORT);解析缓冲区的数据
uint8_tc,n;
staticuint8_toffset[UART_NUMBER];
staticuint8_tdataSize[UART_NUMBER];
staticenum_serial_state{//串口的几种状态
IDLE,//空闲?
HEADER_START,//数据头开始$
HEADER_M,//数据头M
HEADER_ARROW,//数据箭头《
HEADER_SIZE,//数据尺寸
HEADER_CMD,//指令
}c_state[UART_NUMBER];//=IDLE;//状态数组默认空闲
for(n=0;n#if!
defined(PROMINI)//假如不是ATmega328版本执行该段代码
CURRENTPORT=n;
#endif
#defineGPS_COND//假如定义了GPS_COND执行该段代码
#ifdefined(GPS_SERIAL)
#ifdefined(GPS_PROMINI)
#defineGPS_COND
#else
#defineGPS_COND&&(GPS_SERIAL!
=CURRENTPORT)
#endif
#endif
#defineSPEK_COND//假如定义了SPEK_COND执行该段代码
#ifdefined(SPEKTRUM)&&(UART_NUMBER>1)
#defineSPEK_COND&&(SPEK_SERIAL_PORT!
=CURRENTPORT)
#endif
while(SerialAvailable(CURRENTPORT)GPS_CONDSPEK_COND){//③while循环
uint8_tbytesTXBuff=((uint8_t)(serialHeadTX[CURRENTPORT]-serialTailTX[CURRENTPORT]))%TX_BUFFER_SIZE;
//indicatesthenumberofoccupiedbytesinTXbuffer发送缓冲区占用字节标定。
if(bytesTXBuff>TX_BUFFER_SIZE-50)return;
//ensurethereisenoughfreeTXbuffertogofurther(50bytesmargin)确保发送缓冲区之手50字节的余量。
c=SerialRead(CURRENTPORT);//读串口缓冲区serialBufferRX[数据指针][串口端口号],该缓冲区的数据是由串口接收中断函数inlinestore_uart_in_buf(uint8_tdata,uint8_tportnum)获取的来自电脑的数据。
if(c_state[CURRENTPORT]==IDLE)//这是一组完整指令代码244D3C006464$M<\#0dd
{//串口状态空闲等待HEADER_START状态的到来。
c_state[CURRENTPORT]=(c=='$')?
HEADER_START:
IDLE;//判定是$字符吗?
是进入HEADER_START状态。
if(c_state[CURRENTPORT]==IDLE)evaluateOtherData(c);//evaluateallotherincomingserialdata
}
elseif(c_state[CURRENTPORT]==HEADER_START)
{
c_state[CURRENTPORT]=(c=='M')?
HEADER_M:
IDLE;
}
elseif(c_state[CURRENTPORT]==HEADER_M)
{
c_state[CURRENTPORT]=(c=='<')?
HEADER_ARROW:
IDLE;//是字符<吗?
是表示有数据要进入MWC,此前发送都是数据头。
}
elseif(c_state[CURRENTPORT]==HEADER_ARROW)
{//是ARROW字符,判定缓冲区的大小。
if(c>INBUF_SIZE)
{//nowweareexpectingthepayloadsize我们期望足够的数据占用缓冲区。
c_state[CURRENTPORT]=IDLE;//数据位置不够退出循环。
continue;//不执行该while循环包含的后面的语句,跳出开始下一轮循环。
}
dataSize[CURRENTPORT]=c;//缓冲区够,将收到的数据赋值给当前端口的数据尺寸数组dataSize[串口端口号]。
offset[CURRENTPORT]=0;//设置数据指针的偏移位0。
checksum[CURRENTPORT]=0;//初始化数据的校验和为0。
存入数组中。
indRX[CURRENTPORT]=0;//
checksum[CURRENTPORT]^=c;//说明数据长度是校验的第一个字母。
c_state[CURRENTPORT]=HEADER_SIZE;//thecommandistofollow
//MWC收到数据长度,后面就是电脑发送的数据了。
MWC串口状态进入HWADER_SIZE。
}
elseif(c_state[CURRENTPORT]==HEADER_SIZE)
{//MWC串口是在HEADER_SIZE状态吗?
cmdMSP[CURRENTPORT]=c;//在HEADER_SIZE状态收到的第一个数据是指令。
checksum[CURRENTPORT]^=c;//将该数据异或进入校验和的数组中去。
c_state[CURRENTPORT]=HEADER_CMD;//MWC收到数据后,说明在指令状态,MWC进入HEAFER_CMD状态。
}
elseif(c_state[CURRENTPORT]==HEADER_CMD&&offset[CURRENTPORT]{
checksum[CURRENTPORT]^=c;//进入校验和异或。
inBuf[offset[CURRENTPORT]++][CURRENTPORT]=c;//MWC将收到的电脑数据存入缓冲区内。
offset[CURRENTPORT]加1。
}
elseif(c_state[CURRENTPORT]==HEADER_CMD&&offset[CURRENTPORT]>=dataSize[CURRENTPORT])
{
//判定偏移指针大于等于数据预留位置大小吗?
if(checksum[CURRENTPORT]==c)
{//comparecalculatedandtransferredchecksum
//偏移指针大于等于数据预留位置大小,就将从电脑这次收到的数据作为校验和,与已经累计异或的checksum[]中的校验和数据对比,为真,表示,该数据包是有效的,可以调用下面的函数evaluateCommand()进行,数据包的解析。
evaluateCommand();//wegotavalidpacket,evaluateit我们获得了一个有效的数据包,解析评估这些数据。
}
c_state[CURRENTPORT]=IDLE;//MWC串口开始进入空闲状态。
}
}//③while循环
}//②for循环
}①
四、对MWC的配置文件的原文件分析
…………
if((time-time2)>40&&!
toggleRead&&!
toggleWrite){//不按读写按钮发送的78个数据
time2=time;
int[]requests={MSP_IDENT,MSP_MOTOR_PINS,MSP_STATUS,MSP_RAW_IMU,MSP_SERVO,MSP_MOTOR,MSP_RC,MSP_RAW_GPS,MSP_COMP_GPS,MSP_ALTITUDE,MSP_BAT,MSP_DEBUGMSG,MSP_DEBUG};
//100=d115=s102=f103=g104=h105=I106=j107=k109=m110=n253254
sendRequestMSP(requestMSP(requests));
}
if((time-time3)>20&&!
toggleRead&&!
toggleWrite){
sendRequestMSP(requestMSP(MSP_ATTITUDE));//108=l
time3=time;
}
if(toggleReset){
toggleReset=false;
toggleRead=true;
sendRequestMSP(requestMSP(MSP_RESET_CONF));//MSP_RESET_COF=208
}
if(toggleRead){//只要按读按钮就发送下面的代码36个
toggleRead=false;
int[]requests={MSP_BOXNAMES,MSP_PIDNAMES,MSP_RC_TUNING,MSP_PID,MSP_BOX,MSP_MISC};//116=t117=u111=o112=p113=q114=r
sendRequestMSP(requestMSP(requests));
buttonWRITE.setColorBackground(green_);
}
if(toggleCalibAcc){
toggleCalibAcc=false;
sendRequestMSP(requestMSP(MSP_ACC_CALIBRATION));
}
if(toggleCalibMag){
toggleCalibMag=false;
sendRequestMSP(requestMSP(MSP_MAG_CALIBRATION));
}
if(toggleWrite){
toggleWrite=false;
//MSP_SET_RC_TUNING
payload=newArrayList();
payload.add(char(round(confRC_RATE.value()*100)));
payload.add(char(round(confRC_EXPO.value()*100)));
payload.add(char(round(rollPitchRate.value()*100)));
payload.add(char(round(yawRate.value()*100)));
payload.add(char(round(dynamic_THR_PID.value()*100)));
payload.add(char(round(throttle_MID.value()*100)));
payload.add(char(round(throttle_EXPO.value()*100)));
sendRequestMSP(requestMSP(MSP_SET_RC_TUNING,payload.toArray(newCharacter[payload.size()])));
//MSP_SET_PID
payload=newArrayList();
for(i=0;ibyteP[i]=(round(confP[i].value()*10));
byteI[i]=(round(confI[i].value()*1000));
byteD[i]=(round(confD[i].value()));
}
…………………..
五、MWC处理指令的代码分析
voidevaluateCommand(){
switch(cmdMSP[CURRENTPORT]){
caseMSP_SET_RAW_RC:
for(uint8_ti=0;i<8;i++){
rcData[i]=read16();
}
headSerialReply(0);
break;
#ifGPS
caseMSP_SET_RAW_GPS:
f.GPS_FIX=read8();
GPS_numSat=read8();
GPS_coord[LAT]=read32();
GPS_coord[LON]=read32();
GPS_altitude=read16();
GPS_speed=read16();
GPS_update|=2;//NewdatasignalisationtoGPSfunctions
headSerialReply(0);
break;
#endif
caseMSP_SET_PID:
for(uint8_ti=0;iconf.P8[i]=read8();//处理来自电脑的数据从inBuf[]数组中
conf.I8[i]=read8();
conf.D8[i]=read8();
}
headSerialReply(0);//处理完成后向电脑发送“$M>\#0\#0MSP_SET_PID”
break;
caseMSP_SET_BOX:
for(uint8_ti=0;iconf.activate[i]=read16();
}
headSerialReply(0);
break;
caseMSP_SET_RC_TUNING:
conf.rcRate8=read8();
conf.rcExpo8=read8();
conf.rollPitchRate=read8();
conf.yawRate=read8();
conf.dynThrPID=read8();
conf.thrMid8=read8();
conf.thrExpo8=read8();
headSerialReply(0);
break;
caseMSP_SET_MISC:
#ifdefined(POWERMETER)
conf.powerTrigger1=read16()/PLEVELSCALE;
#endif
headSerialReply(0);
break;
caseMSP_IDENT:
headSerialReply(7);
serialize8(VERSION);//multiwiiversion
serialize8(MULTITYPE);//typeofmulticopter
serialize8(MSP_VERSION);//MultiWiiSerialProtocolVersion
serialize32(0);//"capability"
break;
caseMSP_STATUS:
headSerialReply(10);
serialize16(cycleTime);
serialize16(i2c_errors_count);
serialize16(ACC|BARO<<1|MAG<<2|GPS<<3|SONAR<<4);
serialize32(
#ifACC
f.ANGLE_MODE<f.HORIZON_MODE<#endif
#ifBARO&&(!
defined(SUPPRESS_BARO_ALTHOLD))
f.BARO_MODE<#endif
#ifMAG
f.MAG_MODE<#endif
#ifdefined(SERVO_TILT)||defined(GIMBAL)
rcOptions[BOXCAMSTAB]<#endif
#ifdefined(CAMTRIG)
rcOptions[BOXCAMTRIG]<#endif
#ifGPS
f.GPS_HOME