DSHOT600电调协议
Dshot,一种全新的电调协议。穿越机,真的是航模发展的奇迹之一。 Cleanflight,Raceflight,Betaflight,Kiss,四大开发团队,发展目标不太一样。大家知道,在遥控接收机上面,有PWM,PPM,这些都是模拟信号;而SBUS和IBUS等这些xxxBus协议就是数字协议,走的是单片机的串行接收端口。那么由Futaba和Frsky等遥控器厂家大力推行串行数字接收协议,大家也看到他们的牛逼之处。但是我们现在用的电调都是模拟PWM方波信号,于是,由Flyduino(Kiss飞控的公司)联合Betaflight开发团队共同研发了Dshot数字电调协议。
数字电调协议的组成
16位 = 11位油门信号 + 1位电调信息回传 + 4位循环冗余校验
11位 - 2048步骤的分辨率油门值
1位 -遥测要求
4位 - CRC校验(检查信号的正确性)
如何代表0和1呢?
拿Dshot600来说,一位信号就大概是1.67微秒,那么通过对时间的占空比代表0或者1.
如果表示0:高电平占据625纳秒,
如果表示1:高电平占据1250纳秒
Dshot数字电调协议的优点
1.不再需要校准电调油门行程
2.精准的电调信号,数字信号的最大优点,由于PWM是模拟信号,容易出现传输过程中出现的波形变形问题
3.相比目前“1000-2000”的值,Dshot的行程由“0-2048”扩展(从00000000000到11111111111),毕竟有11位二进制数,2的11次方就是2048
4.速度上面,比Oneshot电调协议快太多
5.安全性,Dshot自带四位循环冗余校验(CRC)
与Oneshot和Mutishot的对比
Dshot完全是数字信号,Oneshot和Mutishot是模拟信号,如果在使用上,电调硬件或者软件多多少少需要进行滤波设置,去除由于传输过程中带来的噪声,大家如果想用bls电调升级到dshot,估计就得手动把电调是的电容去除掉,而这颗电容或电阻就是用于硬件滤波的,而Dshot除了省去校准电调行程外,在传输过程中根本不需要进行滤波!毕竟0就是0,1就是1,且带有循环冗余校验位,很爽。
速度对比(全油门情况下的对比)
Oneshot125 – 250 uS
DShot150 – 106.7 uS
Oneshot42 – 84 uS
DShot300 – 53.3 uS
DShot600 – 26.7 uS
Multishot – 25 uS
以上转载至:https://www.pianshen.com/article/7004689118/
// Module Name: dshot600
// Author Name: Yang Cheng Yu 杨成煜
// Project Name: DSHOT600
// University NanJing University or Information Science & Technology
// 南京信息工程大学 电子与信息工程学院
// Xi An University of Technology
// 西安理工大学 自动化与信息工程学院
// DATE: 2021/5/4
// Describe:
// DSHOT600协议,0-10位为油门数据,11位为遥
// 测信号规定,此处默认为1,12-15位为循环冗余
// 校验码。
//
module dshot600(input i_sys_clk,input i_sys_rst_n,output reg o_out,input [10:0] i_value
);localparam CNT_1_67US = 83;//1.67uslocalparam CNT_LOW = 31;//表示0时,高电平时间625nslocalparam CNT_HIGH = 62;//表示1时,高电平时间1250nsreg[7:0] cnt_cycle;reg[4:0] cnt_bit;reg[10:0] r_value;reg[7:0] cnt_high_temp;reg[3:0] crc;reg r_i_crc_valid;wire[3:0] w_crc_in;wire[3:0] w_crc_out;wire[10:0] w_value;assign w_value = r_value;assign w_crc_in = crc;wire w_i_crc_valid;wire w_o_crc_valid;assign w_i_crc_valid = r_i_crc_valid;CRC4_D11 CRC4_D11_inst(.i_sys_clk (i_sys_clk),.i_sys_rst_n (i_sys_rst_n),.i_data (w_value),.i_crc (w_crc_in),.o_crc_new (w_crc_out),.i_valid (w_i_crc_valid),.o_valid (w_o_crc_valid)
); always @(posedge i_sys_clk or negedge i_sys_rst_n)beginif(~i_sys_rst_n)begincnt_bit <= 5'd0;r_value <= 11'd0;endelse case(cnt_bit)5'd0:begin//采集一次输入的油门值cnt_bit <= cnt_bit + 1'b1;r_value <= i_value;enddefault:begin//第1位if(cnt_cycle==CNT_1_67US&&cnt_bit==5'd16)cnt_bit <= 5'd0;else if(cnt_cycle==CNT_1_67US)cnt_bit <= cnt_bit + 1'b1;endendcaseendalways @(posedge i_sys_clk or negedge i_sys_rst_n)beginif(~i_sys_rst_n)begincnt_cycle <= 8'd0;endelse case(cnt_bit)5'd0:begincnt_cycle <= 8'd0;enddefault:begin//第1位if(cnt_cycle==CNT_1_67US)cnt_cycle <= 8'd0;elsecnt_cycle <= cnt_cycle + 1'b1;endendcaseendalways @(posedge i_sys_clk or negedge i_sys_rst_n)beginif(~i_sys_rst_n)cnt_high_temp <= 8'd0; else case(cnt_bit)0:cnt_high_temp <= CNT_LOW;1,2,3,4,5,6,7,8,9,10,11:beginif(r_value[cnt_bit-1]==1'b1)cnt_high_temp <= CNT_HIGH;else if(r_value[cnt_bit-1]==1'b0)cnt_high_temp <= CNT_LOW;end12:cnt_high_temp <= CNT_HIGH;13,14,15,16:beginif(crc[cnt_bit-13]==1'b1)cnt_high_temp <= CNT_HIGH;else if(crc[cnt_bit-13]==1'b0)cnt_high_temp <= CNT_LOW;endendcaseendalways @(*)beginif(cnt_bit==5'd0)o_out = 1'b0;else if(cnt_bit<=5'd16&&cnt_cycle<=cnt_high_temp)o_out = 1'b1;else if(cnt_bit<=5'd16&&cnt_cycle>cnt_high_temp)o_out = 1'b0; end/*crc获取行为*/always @(posedge i_sys_clk or negedge i_sys_rst_n)beginif(~i_sys_rst_n)beginr_i_crc_valid <= 1'b0;crc <= 4'd0;endelse begincase(cnt_bit)5'd1:r_i_crc_valid <= 1'b1;5'd2:r_i_crc_valid <= 1'b0;endcaseif(w_o_crc_valid==1'b1)//获取一帧CRCcrc <= w_crc_out;endend
endmodule
简易测试文件
`timescale 1ns/1ns //时间精度
`define clock_period 20 //时钟周期
module tb_dshot600; //实体名称//=====================<系统端口>=============================reg i_sys_clk ;reg i_sys_rst_n ;wire o_out ;reg [10:0] i_value ;dshot600 dshot600_inst(.i_sys_clk (i_sys_clk),.i_sys_rst_n (i_sys_rst_n),.o_out (o_out),.i_value (i_value)
);//=====================<时钟信号>=============================
initial begini_sys_clk = 1;forever#(`clock_period/2) i_sys_clk = ~i_sys_clk;
end//=====================<复位信号>=============================
initial begini_sys_rst_n = 0;#(`clock_period*20+1);i_sys_rst_n = 1;
end//=====================<激励信号>=============================
initial begini_value = 11'd0;#(`clock_period*20+1);//初始化i_value = 11'd386;
end endmodule