我使用代码对应的上位机版本为v6,具体通信协议格式在打开V6版本上位机–帮助信息–通信协议里可以看到。
这部分数据传输的核心简单的解帧。这部分的讲解以及匿名的通信协议的简介可以看另一篇文章**《串口通信协议》**
核心内容在下面一点,如果只需要研究通信协议可以直接看下面。
先来分析代码
依然注意到头文件中的一个结构体,这是一堆标志位,就不做赘述了。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24typedef struct { u8 msg_id; u8 msg_data; u8 send_check; u8 send_version; u8 send_status; u8 send_senser; u8 send_senser2; u8 send_rcdata; u8 send_offset; u8 send_motopwm; u8 send_power; u8 send_user; u8 send_speed; u8 send_sensorsta; u8 send_location; u8 send_omv_ct; u8 send_omv_lt; u8 send_vef; u16 send_parame; u16 paraToSend; } dt_flag_t;
接下来的代码类似于任务调度,在不同时刻将不同的代码发出。(可以忽略以下一大段代码)
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182/ //Data_Exchange函数处理各种数据发送请求,比如想实现每5ms发送一次传感器数据至上位机,即在此函数内实现 //此函数应由用户每1ms调用一次 extern float ultra_dis_lpf; void ANO_DT_Data_Exchange(void) { static u16 cnt = 0; static u16 senser_cnt = 10; static u16 senser2_cnt = 50; static u16 user_cnt = 10; static u16 status_cnt = 15; static u16 rcdata_cnt = 20; static u16 motopwm_cnt = 20; static u16 power_cnt = 50; static u16 speed_cnt = 50; static u16 sensorsta_cnt = 500; static u16 omv_cnt = 100; static u16 location_cnt = 500; static u8 flag_send_omv = 0; if((cnt % senser_cnt) == (senser_cnt-1)) f.send_senser = 1; if((cnt % senser2_cnt) == (senser2_cnt-1)) f.send_senser2 = 1; if((cnt % user_cnt) == (user_cnt-2)) f.send_user = 1; if((cnt % status_cnt) == (status_cnt-1)) f.send_status = 1; if((cnt % rcdata_cnt) == (rcdata_cnt-1)) f.send_rcdata = 1; if((cnt % motopwm_cnt) == (motopwm_cnt-2)) f.send_motopwm = 1; if((cnt % power_cnt) == (power_cnt-2)) f.send_power = 1; if((cnt % speed_cnt) == (speed_cnt-3)) f.send_speed = 1; if((cnt % sensorsta_cnt) == (sensorsta_cnt-2)) { f.send_sensorsta = 1; } if((cnt % omv_cnt) == (omv_cnt-2)) { flag_send_omv = 1; } if((cnt % location_cnt) == (location_cnt-3)) { f.send_location = 1; } if(++cnt>1000) cnt = 0; / if(f.send_version) { f.send_version = 0; ANO_DT_Send_Version(4,300,100,400,0); } else if(f.paraToSend < 0xffff) { ANO_DT_SendParame(f.paraToSend); f.paraToSend = 0xffff; } /// else if(f.send_status) { f.send_status = 0; ANO_DT_Send_Status(imu_data.rol,imu_data.pit,imu_data.yaw,wcz_hei_fus.out,(flag.flight_mode+1),flag.unlock_sta); } /// else if(f.send_speed) { f.send_speed = 0; ANO_DT_Send_Speed(loc_ctrl_1.fb[Y],loc_ctrl_1.fb[X],loc_ctrl_1.fb[Z]); } /// else if(f.send_user) { f.send_user = 0; ANO_DT_Send_User(); } /// else if(f.send_senser) { f.send_senser = 0; ANO_DT_Send_Senser(sensor.Acc[X],sensor.Acc[Y],sensor.Acc[Z],sensor.Gyro[X],sensor.Gyro[Y],sensor.Gyro[Z],mag.val[X],mag.val[Y],mag.val[Z]); } / else if(f.send_senser2) { f.send_senser2 = 0; ANO_DT_Send_Senser2(baro_height,ref_tof_height,sensor.Tempreature_C*10);//原始数据 } / else if(flag_send_omv) { flag_send_omv = 0; if(f.send_omv_ct) { f.send_omv_ct = 0; ANO_DT_SendOmvCt(opmv.cb.color_flag,opmv.cb.sta,opmv.cb.pos_x,opmv.cb.pos_y,opmv.cb.dT_ms); } else if(f.send_omv_lt) { f.send_omv_lt = 0; ANO_DT_SendOmvLt(opmv.lt.sta, opmv.lt.angle, opmv.lt.deviation, opmv.lt.p_flag, opmv.lt.pos_x, opmv.lt.pos_y, opmv.lt.dT_ms); } } / else if(f.send_rcdata) { f.send_rcdata = 0; s16 CH_GCS[CH_NUM]; for(u8 i=0;i<CH_NUM;i++) { if((chn_en_bit & (1<<i)))//(Rc_Pwm_In[i]!=0 || Rc_Ppm_In[i] !=0 )//该通道有值 { CH_GCS[i] = CH_N[i] + 1500; } else { CH_GCS[i] = 0; } } ANO_DT_Send_RCData(CH_GCS[2],CH_GCS[3],CH_GCS[0],CH_GCS[1],CH_GCS[4],CH_GCS[5],CH_GCS[6],CH_GCS[7],0,0); } / else if(f.send_motopwm) { f.send_motopwm = 0; #if MOTORSNUM == 8 ANO_DT_Send_MotoPWM(motor[0],motor[1],motor[2],motor[3],motor[4],motor[5],motor[6],motor[7]); #elif MOTORSNUM == 6 ANO_DT_Send_MotoPWM(motor[0],motor[1],motor[2],motor[3],motor[4],motor[5],0,0); #elif MOTORSNUM == 4 ANO_DT_Send_MotoPWM(motor[0],motor[1],motor[2],motor[3],0,0,0,0); #else #endif } / else if(f.send_power) { f.send_power = 0; ANO_DT_Send_Power(Plane_Votage*100,0); } else if(f.send_sensorsta) { f.send_sensorsta = 0; ANO_DT_SendSensorSta(switchs.of_flow_on ,switchs.gps_on,switchs.opmv_on,switchs.uwb_on,switchs.of_tof_on); } else if(f.send_location) { f.send_location = 0; ANO_DT_Send_Location(switchs.gps_on,Gps_information.satellite_num,(s32)Gps_information.longitude,(s32)Gps_information.latitude,123,456); } else if(f.send_vef) { ANO_DT_Send_VER(); f.send_vef = 0; } / / / ANO_DT_Data_Receive_Anl_Task(); / Usb_Hid_Send(); / }
接下来才是正文
以发送版本号的函数为例了解匿名飞控收发协议。
匿名飞控的通信协议
与一些较为简单的通信协议相比,这个协议增加了发送设备地址,接收设备地址,功能字,数据长度和和校验部分。其中设备地址由用户定义用来区别不同设备。功能字用来区别这一帧传输了什么内容。数据长度则是计算用户实际传输的数据长度。最后增加了一字节和校验用来校验数据。
注意这个函数是发送用的,也就是封装这个帧。
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30void ANO_DT_Send_Version(u8 hardware_type, u16 hardware_ver,u16 software_ver,u16 protocol_ver,u16 bootloader_ver) { u8 _cnt=0; data_to_send[_cnt++]=0xAA; //帧头 data_to_send[_cnt++]=MYHWADDR; //下位机地址 data_to_send[_cnt++]=SWJADDR; //上位机地址 data_to_send[_cnt++]=0x00; //功能字,表示此帧发送版本信息 data_to_send[_cnt++]=0; //len字节 //以下为数据部分 data_to_send[_cnt++]=hardware_type; data_to_send[_cnt++]=BYTE1(hardware_ver); data_to_send[_cnt++]=BYTE0(hardware_ver); data_to_send[_cnt++]=BYTE1(software_ver); data_to_send[_cnt++]=BYTE0(software_ver); data_to_send[_cnt++]=BYTE1(protocol_ver); data_to_send[_cnt++]=BYTE0(protocol_ver); data_to_send[_cnt++]=BYTE1(bootloader_ver); data_to_send[_cnt++]=BYTE0(bootloader_ver); data_to_send[4] = _cnt-5; //计算数据长度 u8 sum = 0; for(u8 i=0;i<_cnt;i++) //计算校验和 sum += data_to_send[i]; data_to_send[_cnt++]=sum; ANO_DT_Send_Data(data_to_send, _cnt); }
认识了这个那么其他函数都大同小异了,其中有一个函数ANO_DT_Send_RCData();
较为特殊是遥控器控制的发送,之后的文章中我会提到。
另外还有一个经典的函数不得不提,这个函数是校验数据用的,也就是解帧。注释如下
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49void ANO_DT_Data_Receive_Prepare(u8 data) { static u8 _data_len = 0; static u8 state = 0; if(state==0&&data==0xAA) //校验帧头0xAA,如果state为0表明刚开始解帧,如果第一个字节的数据为0xAA,说明帧头正确。 { state=1; //如果帧头正确,state为1,可以进入下一字节 DT_RxBuffer[0]=data; //串口存入 } else if(state==1&&data==0xAF) //数据源,0xAF表示数据来自上位机 { state=2; DT_RxBuffer[1]=data; } else if(state==2) //数据目的地 { state=3; DT_RxBuffer[2]=data; } else if(state==3) //功能字 { state=4; DT_RxBuffer[3]=data; } else if(state==4) //数据长度 { state = 5; DT_RxBuffer[4]=data; _data_len = data; DT_data_cnt = 0; } else if(state==5&&_data_len>0&&_data_len<80) { _data_len--; DT_RxBuffer[5+DT_data_cnt++]=data; if(_data_len==0) state = 6; } else if(state==6) { state = 0; DT_RxBuffer[5+DT_data_cnt]=data; ano_dt_data_ok = 1;//ANO_DT_Data_Receive_Anl(DT_RxBuffer,DT_data_cnt+5); } else state = 0; }
如有错误还请不吝指正,欢迎交流,我的邮箱是jia_rc@163.com。
最后
以上就是潇洒自行车最近收集整理的关于ANO匿名飞控STM32代码解读(二)数据传输——Ano_DT.c的全部内容,更多相关ANO匿名飞控STM32代码解读(二)数据传输——Ano_DT内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复