amoBBS 阿莫电子论坛

 找回密码
 注册
搜索
bottom↓
查看: 7388|回复: 164

BLHeli 杂谈和研究讨论

  [复制链接]
发表于 2016-5-28 09:32:34 来自手机 | 显示全部楼层 |阅读模式
我就随便讲讲我所知道的BLHeli历史吧。

然后有源码上的问题可以问,我尽量回答。
我在论坛的权限不高,一小时只能回三篇,
所以只能慢慢说。

BLheli 是欧洲一位神人S君写的最早是在
华科耳的10a ESC上实现的。是基于atmel
8位的芯片。代码实现参考了德国另外一位
高手的无刷C代码。但是因为用atmel汇编写的,程序是完全独立的。

那个时候 atmega8 芯片是锁住的,刷程序
很麻烦,要先焊下来然后换个新的芯片上去。
去除保护位需要用到一个高电压编程,是个并
口,要接10多条线才能把那个保护位去掉,
而且需要比较高级的编程板子。S君都是直接
换个新的上去。我还做过一个接这么多脚的转
接板,但是也很麻烦就是了。

那时候基于atmel的blheli基本上没有什么人玩,
要焊芯片下来需要热风枪。事情发生转变是在
S君把blheli移植到 silabs的芯片上去。当时的
电调是xp7a和xp3a这些。推动这个的另外一个
爆发点事地平线的mcpx小直升机,当时无福翼
的小飞机第一次做这么小,非常火。但是马力
欠缺,很多人DIY改无刷。silabs的电调不要
焊下来可以直接刷blheli,一下子被大家追捧起来。

先写这么多吧。TBD。
发表于 2016-5-28 15:40:15 来自手机 | 显示全部楼层
顶起来,Bl确实好用,响应很快
发表于 2016-5-28 17:30:46 | 显示全部楼层
哈哈,我先来个问题吧,blheli的启动过程能详细讲讲么。
发表于 2016-5-28 18:10:16 来自手机 | 显示全部楼层
能改个c语言版本吗?
发表于 2016-5-28 18:14:53 | 显示全部楼层
必须顶啊
发表于 2016-5-28 18:43:46 来自手机 | 显示全部楼层
giantwjt88 发表于 2016-5-28 18:10
能改个c语言版本吗?

哈哈,顶你!
发表于 2016-5-28 19:26:08 | 显示全部楼层
喜欢楼主,顶你!
发表于 2016-5-28 20:45:27 | 显示全部楼层
lz。   这个星球上还有一个。bldc的开源sw。  名字叫。 simok。 有谁知道能不能讲下历史
 楼主| 发表于 2016-5-28 22:08:23 来自手机 | 显示全部楼层
先说一下C语言的版本,我自己写过一些。在这个silabs的8051上并不合适,f330只有4k的代码量。8051实在太过古老,用C来生成的代码不是很优化,因为8051有很多很奇葩的设计。例如只有一个数字运算寄存器A,什么东西都和这个A搞。只有一个16位指针dptr寄存器。很多设计对C很不友好。使用C生成的代码在8051上比手写汇编大概多50%左右。BLHeli支持的很多电调是只有4K代码,汇编用起来都很勉强所以C没办法完全替代blheli的功能。atmel的架构就好很多,arm的就更好了。用C可以生成比较好的机器代码。另外无刷的C代码,在atmel和arm平台上是有的,没有blheli那么流行就是了。
发表于 2016-5-28 22:28:04 | 显示全部楼层
楼主,silabs的blheli源码哪里能有
发表于 2016-5-28 23:02:13 | 显示全部楼层
rei1984 发表于 2016-5-28 20:45
lz。   这个星球上还有一个。bldc的开源sw。  名字叫。 simok。 有谁知道能不能讲下历史 ...

这个分享一个网址,我去看一下
 楼主| 发表于 2016-5-28 23:33:10 | 显示全部楼层
powerlabor001 发表于 2016-5-28 17:30
哈哈,我先来个问题吧,blheli的启动过程能详细讲讲么。

另外有人问BLHeli那里可以下到源码,这个一直就没有变过。
最新的 BLHeli永远在 github 里面 bitdump 下面的 BLHeli
我没有权限发链接,大家在 github 里面 找一下 BLHeli 就是了。

不会用 Git 的同学好好学习一下,绝对神器,值得花时间学一下。
在 Git 里面包含了历史旧的版本,如果有人对旧版本感兴趣或者
由于某种兼容问题需要找一下旧版本,git clone 一下然后找一下
历史里面就有旧版本。

先说一下,BLHeli 比较新的版本有个 BLHeli S 分支,那个还
比较新,我讲的是 Silabs 目录里面旧点的那个。新的那个应该
大体上也差不多。

程序入口在 reset: 和 pgm_start:

启动要初始化硬件 gpio crossbar 这些琐碎事情就不值得多讲
了,自己看看源码没有什么很含糊的。初始化都比较顺序执行。

初始化以后就是检测输入信号类型,是 PPM 还是 pwm 这些。
检测完以后发出 BB 叫。如果是高油门进入遥控器编程模式。

然后就是等油门信号启动马达,这个在 run1:
大家会注意到blheli 里面反复有 com3com4 这类的代码入口,
长的都差不多。这个是需要讲解一下,我当时也费了点时间理解。

无刷电机有 3 根线头 ABC。这样任意两个线通电有 3 种组合,
AB, BC, CA。然后电流还有反向 BA, CB, AC 一共是
6种排列方式。这个就对应代码里面的 com1 ... com6,就是
6种状态。做完6个就回到开始完成一个电信号的周期,但是
这个时候通常马达还没有转一圈,因为马达有超过3组线圈,
有重复系数是 N。所以电信号走完一圈马达走了 1/N 圈。

BLHeli 的启动就是个盲目启动,按照一定时间周期把这个 6
个相位顺序走一遍。如果运气好的话马达就开始转起来了。
如果运气不好的话电调就冒一阵青烟某些 fet 烧调了,这个
在开始调新电调程序的时候还挺常见的。特别是新手不会用
限流电源的时候。顶级高手据说可以从 fet 烧糊的味道辨别出
是N fet 还是 P fet 烧了。

BLHeli 的启动其实做得比较简单,有很多可以改进的方式。
做完这个 6 个相位的盲目起转之后, BLHeli 试图检测过零点
电压,如果检测到,说明马达已经获得一定的转速,然后切换
到下一个相位状态。马达运转的基本原理就是使这样,很简单。

ComXComY 里面就有打开和关闭那些 FET 的代码。
另外注意的是,上面的 P FET 在一个com相位周期里面是不变的,
下面的 N fet 是通过时钟来打开和关闭的。N fet 做 PWM 来控制
马力大小。

在新的 BLHeli S 分支里面,比较大大一个改动就是 PWM 用硬
件电路来做而不是使用时钟中断来切换。这样显然效率可以高
一些做更细分的 PWM。




发表于 2016-5-29 07:16:47 来自手机 | 显示全部楼层
lz  simok 源码   是否知道
 楼主| 发表于 2016-5-29 07:29:21 | 显示全部楼层
rei1984 发表于 2016-5-29 07:16
lz  simok 源码   是否知道

你说的是 0x.ca/tgy “SimonK's tgy “ 那个电调程序把。 知道是知道,但是没有那么熟。
这个程序是限制在 atmel 的芯片上。你如果对这个程序的历史感兴趣,那个是国外另外
一个比较大的遥控飞行器论坛上发起来的,早期的讨论都有。
发表于 2016-5-29 09:53:02 | 显示全部楼层
BLHeli 启动感觉还可以
发表于 2016-5-29 10:22:03 | 显示全部楼层
发表于 2016-5-31 10:37:56 | 显示全部楼层
helislayer 发表于 2016-5-28 23:33
另外有人问BLHeli那里可以下到源码,这个一直就没有变过。
最新的 BLHeli永远在 github 里面 bitdump 下 ...

我用BLheli-S的电调程序确实效果好很多,可以在很低速度下运行。
发表于 2016-5-31 14:44:06 | 显示全部楼层
感觉这些电调无论BLHELI或者非BLHELI,只要电机一堵转就很容易烧MOS管了。。硬件保护不行
发表于 2016-5-31 14:49:17 | 显示全部楼层
zzipeng 发表于 2016-5-31 14:44
感觉这些电调无论BLHELI或者非BLHELI,只要电机一堵转就很容易烧MOS管了。。硬件保护不行 ...

此话怎讲?
发表于 2016-5-31 15:24:49 | 显示全部楼层

我用好赢铂金的电调驱动无刷电机,电机的机构做的不好有时候卡住。这个时候电调如果要顺利启动电机是基本不行的(被卡住了),感觉电调本身的电流保护做的不好还是怎样,经常就是电调电机都发烫,甚至有青烟飘起。排除电机被卡主的问题之后,再启动电机,电调是没有任何反应的。同一个电机,换另一个电调就好了。将电调自身拆了,可以检查出某个臂中的MOS管烧了。
发表于 2016-5-31 15:26:07 | 显示全部楼层
当然,BLHELI还未试过。。好赢铂金40A那个应该不是BLHELI的
发表于 2016-5-31 17:48:04 | 显示全部楼层
怀念德国的那个开源电调始祖kz.
 楼主| 发表于 2016-5-31 19:06:07 | 显示全部楼层
zzipeng 发表于 2016-5-31 14:44
感觉这些电调无论BLHELI或者非BLHELI,只要电机一堵转就很容易烧MOS管了。。硬件保护不行 ...

这个是由与硬件上电调没法检测到电流的大小决定的。
当马达不转的时候,就没有反向电动势,这个电流主要
是消耗在导线的电阻上。一般马达的电阻都很小,所以
就容易烧。

BLHeli 是用开环控制的启动的,就是依次转换 6 个
相位,尤其容易有这个卡转电流大的问题。

其他商业电调如何解决这个问题我不是很清楚,知道
的可以说一下。

BLHeli 里面有个马达启动的马力配置,如果吧马力减少就
可以减少电流,不那么容易烧,启动对应的力也小些。
发表于 2016-5-31 19:43:34 来自手机 | 显示全部楼层
来个源码详细解说?主要是思路
 楼主| 发表于 2016-5-31 19:55:18 | 显示全部楼层
简单的思路前面已经讲了一些了。
更仔细的最好是看了源码再来有针对性的问,不然都是快餐那种讲解没有什么用的。
永远是雾里看花那种。
发表于 2016-5-31 20:00:59 | 显示全部楼层
helislayer 发表于 2016-5-31 19:06
这个是由与硬件上电调没法检测到电流的大小决定的。
当马达不转的时候,就没有反向电动势,这个电流主要
...

商业电调感觉除了FOC之外都没这个电流保护功能。。而且比较蛋疼的是,那种好赢铂金40A电调的MOS管感觉都不好买到。
型号如下:4934N
连接:http://www.szcwdz.com/IC_N/NTMFS4934N.htm
 楼主| 发表于 2016-6-2 07:09:25 | 显示全部楼层
BLHeli 的后续历史。
BLHeli 的发展由一个很大的帮助就是上位机的配置程序。这个是论坛里的数字兄完成
的。因为 BLHeli 是汇编写的,而且那个配置内存的数据不时会改变,所以对应的配置
程序需要经常更新。这点数字兄还是做得很好。
除了这个以外,大家开始都依赖于 silabs 的编程器,好在编程器本身不太贵。
后来就有人研究除了如何用 C2 协议自己往 Silabs 的单片机里面读写程序。这个其实
时有文档和示范程序的,只不过示范程序在 silabs 的MCU 上跑。需要移到其他更常用
的MCU 例如 arduino 用的 AVR 这些。
然后有人搞出了用 arduino 来刷 BLHeli。这个进一步方便了使用 BLHeli。

后面就是软件不断更新换代了。这里值得提议一下的是,如果国内有厂家用 BLHeli
希望得到比较好的支持,最好的一件事是应该发一些电调给S君。提供 pin 脚影射这些。
S君发布新的 BLHeli 的时候也可以有东西可以测试一下。
发表于 2016-6-2 08:42:19 | 显示全部楼层
BLHeli 和   simok ,还有一个openbldc  使用STM32写的
 楼主| 发表于 2016-6-2 10:25:02 | 显示全部楼层
openbldc 看上去不错,不过似乎已经有好几年没有开发更新了。
发表于 2016-6-2 13:25:01 来自手机 | 显示全部楼层
a409600516 发表于 2016-5-31 10:37
我用BLheli-S的电调程序确实效果好很多,可以在很低速度下运行。

支持s的电调买得到吗?好像只有一个型号,淘宝买不到
发表于 2016-6-2 16:08:39 | 显示全部楼层
1.请问大神是这个顺序吗?
过零> Wt_Comm_Start_L > Wt_Adv_Start_L > Wt_Zc_Scan_Start_L> Wt_ZC_Tout_Start_L >换向
能解释一下这几个参数吗?
2.  SKIP是什么意思呀?
3.  WRAP是什么意思呀?
非常感谢
发表于 2016-6-2 19:59:15 来自手机 | 显示全部楼层
顶一下子好
发表于 2016-6-2 22:17:45 来自手机 | 显示全部楼层
yat 发表于 2016-6-2 08:42
BLHeli 和   simok ,还有一个openbldc  使用STM32写的

搜不到simok的github   方便发一下吗??
 楼主| 发表于 2016-6-2 23:27:13 | 显示全部楼层
hanhanlili 发表于 2016-6-2 16:08
1.请问大神是这个顺序吗?
过零> Wt_Comm_Start_L > Wt_Adv_Start_L > Wt_Zc_Scan_Start_L> Wt_ZC_Tout_Sta ...

赞,终于有人肯看看程序来问问题而不是泛泛的给我个详细
解释如何工作的吧。

先说简单的吧。那个 wrap 我没有找到这个边量,一般 wrap 的意思就是
计数器数到头又从新开始了。就是计数器溢出了。 BLHeli 里面通常用的
wrap 时指这个计数器或者整数的溢出。

SKIP 我只找到 RCA 用那个 SKIP。 RCA 时用来检测输入信号类型的。
BLHeli 可以兼容 PPM, PWM, 反极性的 PPM。 哦对了, BLHeli 当时
一个很流行的原因时,用来做 MCPX 的尾巴部无刷的电机,配合那个 xp3a。
V1 MCPX 有点比较奇特的是尾巴 PWM 是 8K 的。当时就没有什么好办法
转成 ppm, 通常更新是 400Hz。BLHeli可以直接用 8K 的PWM 不需要转换
信号(转换损失些精度和增加延时)。
那个 SKIP 似乎就是有信号,但是检测不到有效信号以后(确认 PPM 或
PWM)。这个时候有可能是在一个有效信号的中间,有些噪音什么的。
跳过一些时间来继续检测。

然后就是比较难理解的过零检测的几个 timeout。你列的顺序是对的。

首先那个几个边量都是使用 timer 3. 那 timer 3 中断都在干什么的呢?

;**** **** **** **** **** **** **** **** **** **** **** **** ****
;
; Timer3 interrupt routine
;
; No assumptions
;
;**** **** **** **** **** **** **** **** **** **** **** **** ****
t3_int:        ; Used for commutation timing
        clr         EA                                ; Disable all interrupts
        anl        EIE1, #7Fh                ; Disable timer3 interrupts
        mov        TMR3RLL, #0FAh                ; Set a short delay before next interrupt
        mov        TMR3RLH, #0FFh
        clr        Flags0.T3_PENDING         ; Flag that timer has wrapped
        mov        TMR3CN, #04h                ; Timer3 enabled and interrupt flag cleared
        setb        EA                                ; Enable all interrupts
        reti

所以很简单, timer 3 就是清除掉那个 T3.PENDING 的 bit field。

setup_comm_wait:
        clr        EA
        anl        EIE1, #7Fh                ; Disable timer3 interrupts
        mov        TMR3CN, #00h                ; Timer3 disabled and interrupt flag cleared
        mov        TMR3L, Wt_Comm_Start_L
        mov        TMR3H, Wt_Comm_Start_H
        mov        TMR3CN, #04h                ; Timer3 enabled and interrupt flag cleared
        ; Setup next wait time
        mov        TMR3RLL, Wt_Adv_Start_L
        mov        TMR3RLH, Wt_Adv_Start_H
        setb        Flags0.T3_PENDING
        orl        EIE1, #80h                ; Enable timer3 interrupts
        setb        EA                                ; Enable interrupts again

wait_for_comm_wait:
        jnb Flags0.T3_PENDING, ($+5)                       
        ajmp        wait_for_comm_wait                                       

        ; Setup next wait time
        mov        TMR3RLL, Wt_Zc_Scan_Start_L
        mov        TMR3RLH, Wt_Zc_Scan_Start_H
        setb        Flags0.T3_PENDING
        orl        EIE1, #80h                        ; Enable timer3 interrupts
        ret


wait_advance_timing:       
        jnb        Flags0.T3_PENDING, ($+5)
        ajmp        wait_advance_timing

        ; Setup next wait time
        mov        TMR3RLL, Wt_ZC_Tout_Start_L
        mov        TMR3RLH, Wt_ZC_Tout_Start_H
        setb        Flags0.T3_PENDING
        orl       


BLHeli 把 ZC 到 下个 ZC 这个相位周期切成 4 份。
前面每份 1/4 时间。 ZC_wait 短点,1/8. ZC scan 长点, 3/8

那个 Wt_Comm_Start 应该是 ZC 发生后,等待切换到下个相位的时间,差不多 1/4 时间。
然后就换相位
Wt_Adv_Start_ 是等 一个 1/4 时间 (刚换相位有假的过零点,需要跳过)
Wt_ZC_scan 是等 另外一个 1/8 时间
然后才开始扫描 ZC,等待 ZC 发生。
然后3/8 时间差不多就有 ZC
ZC 应该在 Wt_ZC_Tout 发生以前。

大概就是这样,欢迎补充指正。
发表于 2016-6-3 01:43:26 | 显示全部楼层
mcps的无刷已经有官方版的,几年前,同事毕业后给地平线做的第一个项目。都过去了~~ 公司里现在都搞FOC了
 楼主| 发表于 2016-6-3 07:53:41 | 显示全部楼层
soos 发表于 2016-6-2 22:17
搜不到simok的github   方便发一下吗??

github.com/sim-/tgy
 楼主| 发表于 2016-6-3 08:34:50 | 显示全部楼层
qwe2231695 发表于 2016-6-3 01:43
mcps的无刷已经有官方版的,几年前,同事毕业后给地平线做的第一个项目。都过去了~~ 公司里现在都搞FOC了 ...

mcpx 无刷搞太晚啦。
发表于 2016-6-4 08:18:06 来自手机 | 显示全部楼层
请问BLHeli 的油门检测呢?有经过处理没有?还有里面的PID函数在哪里用到?
发表于 2016-6-4 11:10:43 | 显示全部楼层
突然想问楼主,以前看到过一个兼容睿斯凯的开源接收机,但是一直没有找到项目主页。使用AVR+CC2500制作的,不知道楼主知不知道地址在哪?
 楼主| 发表于 2016-6-4 18:42:03 | 显示全部楼层
a409600516 发表于 2016-6-4 08:18
请问BLHeli 的油门检测呢?有经过处理没有?还有里面的PID函数在哪里用到?

油门检测就是那个RCA 处理啊,当然要经过处理了。
不然如何知道是 ppm 还是 pwm。 arm 的事后需要油门
给些量然后变化一下。如果油门一下打太多就进入编程
模式了。

PID 是那个锁转速的模式,主要是用在直升机上的主旋翼
上。那些 CP 的旋翼一但 pitch 高了,阻力大了转速就下来
了,那个恒定转速可以帮助飞控锁定尾巴。
 楼主| 发表于 2016-6-4 18:44:05 | 显示全部楼层
菜鸟不撸 发表于 2016-6-4 11:10
突然想问楼主,以前看到过一个兼容睿斯凯的开源接收机,但是一直没有找到项目主页。使用AVR+CC2500制作的, ...

那个项目是在 rcgroup 吧。我记得是没有完全开源。
作者后来给容睿斯凯写固件分成去了。
我有空可以找找。
 楼主| 发表于 2016-6-4 20:30:29 | 显示全部楼层
菜鸟不撸 发表于 2016-6-4 11:10
突然想问楼主,以前看到过一个兼容睿斯凯的开源接收机,但是一直没有找到项目主页。使用AVR+CC2500制作的, ...

我想你说的是这个:自己加 http 和 三个w。

rcgroups.com/forums/showthread.php?t=2124647

里面有 RX 有 Hex 文件但是没有源码。
还是源码后来删掉了我就不知道了。
发表于 2016-6-5 09:43:21 | 显示全部楼层
谢谢楼主,楼主太厉害了。
请问楼主在哪个城市,有机会的话想当面拜访一下。我在深圳
发表于 2016-6-5 09:49:29 | 显示全部楼层
前段时间研究了一下BLHELI,
我看的是14版本的源代码,对于一个入门的人来说,感觉就是他的参数太多,跳来跳去,不容易看;
现在正在研究一下ESC32,请问楼主研究过这个吗?
发表于 2016-6-5 10:21:25 | 显示全部楼层
楼主真是个大好人。
前段时间看BLHELI代码的时候,有好多问题,苦于找不到高手问,看看停停,看来我又要好好看一遍了。
发表于 2016-6-5 10:25:05 来自手机 | 显示全部楼层
hanhanlili 发表于 2016-6-5 09:49
前段时间研究了一下BLHELI,
我看的是14版本的源代码,对于一个入门的人来说,感觉就是他的参数太多,跳来 ...

ESC32是什么的??分享下网站去看下
 楼主| 发表于 2016-6-5 10:36:33 | 显示全部楼层
hanhanlili 发表于 2016-6-5 09:49
前段时间研究了一下BLHELI,
我看的是14版本的源代码,对于一个入门的人来说,感觉就是他的参数太多,跳来 ...

看大的系统代码要学会整理主线分层次处理细节。
很多参数是为了干特定的事情的。用到再仔细看,
什么地方定义和修改,什么地方使用。

关键把主线整理清楚然后,才填充细节。一开始被细节
淹没就没法看下去了。

ESC32 看上去不错,似乎是 stm32 的,那里能买到
吗?我曾经想自己搭一个容易调试的 ESC。这个ESC32
挺接近,好东西。
 楼主| 发表于 2016-6-5 10:37:26 | 显示全部楼层
soos 发表于 2016-6-5 10:25
ESC32是什么的??分享下网站去看下

autoquad.org/wiki/wiki/aq-esc32/esc32-version-3/
发表于 2016-6-5 14:05:09 来自手机 | 显示全部楼层
helislayer 发表于 2016-5-28 22:08
先说一下C语言的版本,我自己写过一些。在这个silabs的8051上并不合适,f330只有4k的代码量。8051实在太过 ...

blheli的github中没有原理图的吗??
 楼主| 发表于 2016-6-5 15:59:08 | 显示全部楼层
soos 发表于 2016-6-5 14:05
blheli的github中没有原理图的吗??

没有,只有pin脚的分配。BLHeli 只是个固件程序。
不是完整的 ESC 硬件项目。
发表于 2016-6-5 23:49:58 | 显示全部楼层
helislayer 发表于 2016-6-4 20:30
我想你说的是这个:自己加 http 和 三个w。

rcgroups.com/forums/showthread.php?t=2124647

我居然沦落到了伸手党。。感谢您
发表于 2016-6-6 14:31:21 | 显示全部楼层
helislayer 发表于 2016-6-5 10:37
autoquad.org/wiki/wiki/aq-esc32/esc32-version-3/

像ESC32这些原理图是不开源的吗?
发表于 2016-6-6 15:00:19 | 显示全部楼层
1.        Comm_Period4x_H和Comm_Period4x_L存的是60度的换向时间吗?能具体说说这个变量吗?
2.启动功率设置:从Requested_Pwm=1逐渐增加到Pwm_Limit=0X32来启动吗?
3.        startup phase阶段每次过零的时候要检测10次比较器的输出结果;正常转动的时候Comm_Period4x_H的值越小,检测次数就越小,是不是速度越低,检测次数就越多,速度越高,检测次数就越少?
4.14.4版本里面有个编程参数是PWM dither是什么意思呢?
5.OneShot125和PWM以及PPM是什么关系?
谢谢大神
发表于 2016-6-6 15:51:31 | 显示全部楼层
hanhanlili 发表于 2016-6-6 15:00
1.        Comm_Period4x_H和Comm_Period4x_L存的是60度的换向时间吗?能具体说说这个变量吗?
2.启动功率设置:从 ...

还有demag compensation,这个怎么调节最好啊?大电机选大,小电机选小?是不是在程序里面就是消磁时间的长短啊?
 楼主| 发表于 2016-6-7 09:00:18 | 显示全部楼层
hanhanlili 发表于 2016-6-6 15:00
1.        Comm_Period4x_H和Comm_Period4x_L存的是60度的换向时间吗?能具体说说这个变量吗?
2.启动功率设置:从 ...

1. Comm_Period4x 就是 60 度时间 4 倍的值,你看使用的地方是用来检测
ZC 的时间是不是合理的。应该时越小越快。电机受到阻力会变慢,还有一些
其他因素,反正这个就是允许变慢 4 倍。

2: 有个 set_startup_pwm 你看一下,我的理解时启动用固定的功率启动的。
转起来以后才开始用 request pwm

3: 检测次数是和检测多可靠有关,应该和转动速度关系不大,检测10次时间
也超级短的。里面有个机制是如果发现检测到无效的就增加检测次数。

4.  https://en.wikipedia.org/wiki/Dither
就是加入一个随机噪音在比较小的信号里面防止对有规律的小误差对系统相应做
出有规律的误差控制。你找一下有个 Random 变量。

5. 就是输入信号的类型。 PPM 100% 信号是 2.5ms 的,这个限制了最高刷
新频率是 400Hz。如果你要传 6 个通道,那 PPM 刷就更慢了,所以有 OneShot
就是更短的脉宽方便一次传多个通道信号。例如教练和学徒一起操作那种 Buddy
box 两个发射器通常用这种更短的 ppm 来通信。PWM 就是可以直接用到马达线
圈的信号,不需要对脉宽进行解释。高低电比例就是油门比例。





 楼主| 发表于 2016-6-7 09:04:26 | 显示全部楼层
a409600516 发表于 2016-6-6 15:51
还有demag compensation,这个怎么调节最好啊?大电机选大,小电机选小?是不是在程序里面就是消磁时间的 ...

demag 对应的是对 ZC 比较的次数。如果 demag 大,就是比较器
不是那么可靠,因为ZC 信号被减弱需要多次比较。
发表于 2016-6-7 09:18:43 | 显示全部楼层
首先谢谢老师!
mov        Temp1, #Pgm_Enable_PWM_Input                ; Check if PWM input is enabled
        mov        A, @Temp1
        jnz        test_for_oneshot                                ; If it is - proceed

        setb        Flags2.RCP_PPM                                        ; Set PPM flag
        mov        A, Flags3                                                ; Clear pwm frequency flags
        anl        A, #NOT((1 SHL RCP_PWM_FREQ_1KHZ)+(1 SHL RCP_PWM_FREQ_2KHZ)+(1 SHL RCP_PWM_FREQ_4KHZ)+(1 SHL RCP_PWM_FREQ_8KHZ)+(1 SHL RCP_PWM_FREQ_12KHZ))
        mov        Flags3, A

test_for_oneshot:       
        ; Test whether signal is OneShot125
        clr        Flags2.RCP_PPM_ONESHOT125                ; Clear OneShot125 flag
        mov        Rcp_Outside_Range_Cnt, #0                ; Reset out of range counter


1.Pgm_Enable_PWM_Input这个是做什么用的?
2.不管是PWM还是PPM都要进入test_for_oneshot?


anl        A, #((1 SHL RCP_PWM_FREQ_1KHZ)+(1 SHL RCP_PWM_FREQ_2KHZ)+(1 SHL RCP_PWM_FREQ_4KHZ)+(1 SHL RCP_PWM_FREQ_8KHZ)+(1 SHL RCP_PWM_FREQ_12KHZ))

PWM信号有这么高的频率吗?
 楼主| 发表于 2016-6-7 14:26:46 | 显示全部楼层
hanhanlili 发表于 2016-6-7 09:18
首先谢谢老师!
mov        Temp1, #Pgm_Enable_PWM_Input                ; Check if PWM input is enabled
        mov        A, @Temp1

不要叫我老师,我就是和大家一起探讨一下。
很多东西也是你问了我才去看的。

那个 enable pwm 就是决定是否检测 pwm/ppm。
传统 ESC 用 servo 信号都是 ppm 的。BLHeli
有个配置选项。

PWM 有 8K 16K 这么高,例如mcpx v1 尾巴就是
8k 的。频率对声音也有影响。人耳朵觉得1K 的pwm
发出的声音比较刺耳。

发表于 2016-6-7 17:17:52 | 显示全部楼层
pca_int_ppm_max_checked:
        mov        A, Temp5                                                ; Multiply throttle value by gain
        mov        B, Ppm_Throttle_Gain
        mul        AB
        xch        A, B
        mov        C, B.7                                                ; Multiply result by 2 (unity gain is 128)
        rlc        A
        mov        Temp1, A                                                ; Transfer to Temp1/2
        mov        Temp2, #0
        jc        pca_int_ppm_limit_after_mult
       
        jmp        pca_int_limited               


PCA中断里面的:
Ppm_Throttle_Gain这个是通道数目吗/?
怎么是脉宽乘以通道数呢?
后面的注释是什么意思呢?
谢谢高手。
 楼主| 发表于 2016-6-7 19:07:00 | 显示全部楼层
hanhanlili 发表于 2016-6-7 17:17
pca_int_ppm_max_checked:
        mov        A, Temp5                                                ; Multiply throttle value by gain
        mov        B, Ppm_Throttle_G ...

不是啊,那个 Gain 就是个比例系数。
从 RCA 上面采样出来 PPM 有多少个timer 时钟的个数,
需要乘一个比例系数得到油门的多少。
我的理解就是时钟sample 个数和油门的比例关系。
这个gain 对 oneshot 那种就比较大,表示很短的ppm
就可以表示 100% 油门。
发表于 2016-6-7 23:57:26 | 显示全部楼层
请问大侠:以下的时间分别是什么时间?没有看太明白,请大致解释一下。谢谢!!
Wt_Adv_Start_L 和 Wt_Adv_Start_H
Wt_Comm_Start_L 和 Wt_Comm_Start_H
Wt_Zc_Scan_Start_L 和 Wt_Zc_Scan_Start_H
Wt_ZC_Tout_Start_L 和 Wt_ZC_Tout_Start_H

 楼主| 发表于 2016-6-8 03:02:18 | 显示全部楼层
小小苹果 发表于 2016-6-7 23:57
请问大侠:以下的时间分别是什么时间?没有看太明白,请大致解释一下。谢谢!!
Wt_Adv_Start_L 和 Wt_Adv_ ...

请看 34 楼有人问过了。
发表于 2016-6-8 07:45:51 | 显示全部楼层
helislayer 发表于 2016-6-8 03:02
请看 34 楼有人问过了。

看了,非常感谢,不过还是有点晕,我的理解是这样的,请问是吗?
   > (过零or> Wt_ZC_Tout_Start_L)> Wt_Comm_Start_L >换向> Wt_Adv_Start_L > Wt_Zc_Scan_Start_L >(过零or> Wt_ZC_Tout_Start_L)...
还有 Wt_Zc_Scan_Start_L 有什么作用?Wt_Adv_Start_L之后直接ZC_scan可以吗?
 楼主| 发表于 2016-6-8 08:53:34 | 显示全部楼层
小小苹果 发表于 2016-6-8 07:45
看了,非常感谢,不过还是有点晕,我的理解是这样的,请问是吗?
   > (过零or> Wt_ZC_Tout_Start_L)> Wt ...

过早ZC_Scan 可能读到错误的 ZC,要避开换相以后横流的那个假 ZC。
我没有做过实验如果过早的ZC_Scan 会发生什么事。
这个问题的确切答案是我还不知道。只是我能看出它是这么用的。
发表于 2016-6-8 10:33:31 | 显示全部楼层
谢谢!
PCA中断检测脉冲,定时器2配合做一些超时处理,定时器2中断又分低字节(128us)和高字节(32ms)Rcp_Timeout_Cntd怎么在低字节和高字节中断中都可能要被减1呢?
Rcp_Skip_Cntd这个变量主要是干什么的?
 楼主| 发表于 2016-6-10 22:10:00 | 显示全部楼层
hanhanlili 发表于 2016-6-8 10:33
谢谢!
PCA中断检测脉冲,定时器2配合做一些超时处理,定时器2中断又分低字节(128us)和高字节(32ms)Rcp ...

Rcp_Timeout_Cntd 主要是数有几个脉冲不能确定是什么类型的信号。
或者应该有脉冲没有来。 ppm 和 pwm 都是有固定的更新频率的。
那个脉从检测比较长因为变话范围很大。 的和高对应的就是不同时间
段而以。

Rcp_Skip_Cntd, 就是在检测到脉冲以后,有一段时间不再检测脉从。
我看了看,只有 ppm 是不用这么做的,只有 pwm 这么搞。那我猜就是,
因为 pwm 是直接接马达的,而且刷新频率比较高。这个估计是去抖动
之类的。ppm 的信号区间比较短,所以抖动不在有效信号里面。
pwm 允许很短的信号。所以一个 pwm刚结束不应该马上有另一个
信号进来。所以我猜是去抖动之类的。
发表于 2016-6-10 23:13:55 | 显示全部楼层
学习了
发表于 2016-6-13 11:50:10 | 显示全部楼层
楼主再讲讲PI闭环控制部分(governor)。谢谢
 楼主| 发表于 2016-6-13 19:45:32 | 显示全部楼层
hanhanlili 发表于 2016-6-13 11:50
楼主再讲讲PI闭环控制部分(governor)。谢谢

你先读读代码然后问些有意思的问题嘛。

发表于 2016-6-13 22:48:25 | 显示全部楼层
楼主能说下 INITIAL_RUN_PHASE 是个什么过程,不能STARTUP_PHASE 直接转正常?
 楼主| 发表于 2016-6-13 23:04:46 | 显示全部楼层
小小苹果 发表于 2016-6-13 22:48
楼主能说下 INITIAL_RUN_PHASE 是个什么过程,不能STARTUP_PHASE 直接转正常?

那个是给螺旋桨空中换方向用的,在空中换方向和从静止
启动不太一样。
发表于 2016-6-14 11:47:35 | 显示全部楼层
program_by_tx_checked,这个函数有什么作用?
发表于 2016-6-14 16:15:51 | 显示全部楼层
楼主
Timer2_X每32毫秒加1,然后给Prev_Comm_X,主要是启动阶段用的,注释说Store extended timestamp as previous commutation
请问这个是做什么用的?
谢谢
 楼主| 发表于 2016-6-15 00:58:32 | 显示全部楼层
846528111 发表于 2016-6-14 11:47
program_by_tx_checked,这个函数有什么作用?

这个不是函数,就是一个代码入口。就是说前面已经
检查过用遥控来给 ESC 换配置。有个编程模式。
到这个入口就是编程模式已经做完了(或者没有进入)。
 楼主| 发表于 2016-6-15 08:29:04 | 显示全部楼层
hanhanlili 发表于 2016-6-14 16:15
楼主
Timer2_X每32毫秒加1,然后给Prev_Comm_X,主要是启动阶段用的,注释说Store extended timestamp as p ...

因为启动的时候转很慢,那个换相时间会超过 8 位整数可以表示的。
那就需要用 16 位整数来表示。 Timer2_X 就是那个16 位整数的高
字节位而已。

如果硬件只有 8 位 timer,你如何用溢出中断来做个 16 位 timer?
就是这么回事。
发表于 2016-6-15 19:33:42 | 显示全部楼层
楼主这段代码能帮忙分析下吗?
init_start_bidir_done:
        sbr        Flags1, (1<<MOTOR_SPINNING)        ; Set motor spinning flag
        sbr        Flags1, (1<<STARTUP_PHASE)        ; Set startup phase flag
        sts        Startup_Cnt, Zero                        ; Reset counter
        xcall comm5comm6                                ; Initialize commutation
        xcall comm6comm1                               
        xcall initialize_timing                        ; Initialize timing
        xcall calc_next_comm_timing                ; Set virtual commutation point
        xcall initialize_timing                        ; Initialize timing
        xcall calc_next_comm_timing       
        xcall initialize_timing                        ; Initialize timing
        rjmp        run1
 楼主| 发表于 2016-6-18 09:41:09 来自手机 | 显示全部楼层
846528111 发表于 2016-6-15 19:33
楼主这段代码能帮忙分析下吗?
init_start_bidir_done:
        sbr        Flags1, (1

这段代码调用的函数都有名字,
我重复一次也没有意思。你看了这段
代码有什么具体理解上的问题?

会问正确的问题也是学习重要的一个
方法。
发表于 2016-6-18 11:58:04 | 显示全部楼层
学习学习
发表于 2016-6-21 23:21:14 | 显示全部楼层
BLHELI有支持F850芯片的吗?
如果有的话 是哪几个电调型号呢?
谢谢楼主!
 楼主| 发表于 2016-6-22 10:19:44 | 显示全部楼层
hanhanlili 发表于 2016-6-21 23:21
BLHELI有支持F850芯片的吗?
如果有的话 是哪几个电调型号呢?
谢谢楼主!

这个我就不清楚了。

BLheli 有文档支持的电调, 在 BLHeli 的 Silabs 目录
下面。

BLHeli supported SiLabs ESCs.pdf

里面有照片,你可以去找找有没有你想要的 F850.
发表于 2016-6-22 20:19:00 | 显示全部楼层
F850和F330有什么差别呢?
F850 2块钱左右,F330  4块钱左右,我看资源都一样呀?
发表于 2016-6-28 11:21:24 | 显示全部楼层
helislayer 发表于 2016-6-22 10:19
这个我就不清楚了。

BLheli 有文档支持的电调, 在 BLHeli 的 Silabs 目录

我又来伸手党了。。。。我一直在找SPracing F3开源的主页,但是找到几个都没找到他的原理图,我想自己做飞控,丢了几架飞机了,嫌太贵了。。
发表于 2016-6-28 11:35:24 | 显示全部楼层
还在瞎BB啊我以为结贴了
发表于 2016-6-28 23:22:53 | 显示全部楼层
楼主搞过直流减速电机的驱动吗?
是不是有专门的驱动芯片就可以了?
发表于 2016-6-29 20:11:30 | 显示全部楼层
请问IDLE在程序中怎么理解呀?
 楼主| 发表于 2016-6-30 14:14:48 | 显示全部楼层
菜鸟不撸 发表于 2016-6-28 11:21
我又来伸手党了。。。。我一直在找SPracing F3开源的主页,但是找到几个都没找到他的原理图,我想自己做 ...

他那个不是真的开源,是开别人的源。
其实你只要找 Naze32 的硬件,比较早的版本有原理图,
v5 以后就没有了。然后把stm32F103换成 F3 的pin 兼容
就基本上差不多了。mpu6050 换成有 spi 的。

 楼主| 发表于 2016-6-30 14:17:36 | 显示全部楼层
直流电机用两个 H 桥就可以了啊。
顶多反向驱动。

IDLE 就是没有油门输入吧。
发表于 2016-6-30 15:30:51 | 显示全部楼层
wait_for_comm:
        ; Update demag metric
        mov        Temp1, #0
        jnb        Flags0.DEMAG_ENABLED, ($+8); If demag disabled - branch
        jnb        Flags0.DEMAG_DETECTED, ($+5)

        mov        Temp1, #1

        mov        A, Demag_Detected_Metric        ; Sliding average of 8, 256 when demag and 0 when not. Limited to minimum 120
        mov        B, #7
        mul        AB                                        ; Multiply by 7
        mov        Temp2, A
        mov        A, B                                        ; Add new value for current demag status
        add        A, Temp1                               
        mov        B, A
        mov        A, Temp2
        mov        C, B.0                                ; Divide by 8
        rrc        A                                       
        mov        C, B.1
        rrc        A
        mov        C, B.2
        rrc        A
        mov        Demag_Detected_Metric, A
        clr        C
        subb        A, #120                                ; Limit to minimum 120
        jnc        ($+5)

        mov        Demag_Detected_Metric, #120

        clr        C
        mov        A, Demag_Detected_Metric        ; Check demag metric
        subb        A, Demag_Pwr_Off_Thresh
        jc        wait_for_comm_wait                ; Cut power if many consecutive demags. This will help retain sync during hard accelerations

        setb        Flags0.DEMAG_CUT_POWER        ; Set demag power cut flag
        All_pwmFETs_off
        Set_Pwms_Off

wait_for_comm_wait:                                ;等待换向
        jnb Flags0.T3_PENDING, ($+5)                       
        jmp        wait_for_comm_wait                                       

        ; Setup next wait time
        mov        TMR3RLL, Wt_Zc_Scan_Start_L                ;换向后等待下次过零
        mov        TMR3RLH, Wt_Zc_Scan_Start_H
        setb        Flags0.T3_PENDING
        orl        EIE1, #80h                        ; Enable timer3 interrupts
        ret

楼主你好,这段代码中的 demag metric 是个什么变量?
这个120最小值代表什么意思?
谢谢你!
 楼主| 发表于 2016-7-2 10:16:17 | 显示全部楼层
小小苹果 发表于 2016-6-30 15:30
wait_for_comm:
        ; Update demag metric
        mov        Temp1, #0

先说一下我的理解这个 Demag 是怎么回事。
说得不对的欢迎大家补充。

这个 Demag 是指,当马达的电感比较大的时候,如果你换了
相,但是由于有电感的原因,线拳里面的磁场需要时间才能泻
去。电感类似电容,只不过电感趋向与保持电流的恒定。所以
如果马达电感比较大的话,换相以后原来的磁场还要持续一段
时间。这段时间就添加在换相需要的时间里,先等原来的磁场
消退,然后新的换相的磁场充满。

这个引发的效果就是,电感比较大的马达突然加速的话,那个
预测的换相时间会不准,因为马达运转速度慢,产生的反向电
动势小,突然给大电流抵消不掉都变成磁场了。这个时候就容
易发生卡盾的情况。

那这个 demag 的策略就是,在换相前的一段时间里,提前关
闭FET。这样就给一段时间让磁场消退。到换相点的时候,希
望刚好磁场消退差不多了,给新的电流就可以作用上去。当然
提前多少时间可以关闭是比较关键的,需要动态调整。这个就
那个 demag metric。

你看到的这个变量在程序里影响的就是什么时候断电。

最小 120 就是如果 demag 提前关闭量太小,就不用提前关闭了。

发表于 2016-7-3 17:50:30 | 显示全部楼层
helislayer 发表于 2016-7-2 10:16
先说一下我的理解这个 Demag 是怎么回事。
说得不对的欢迎大家补充。

多谢楼主的回复,在楼主的解释下我已经有个一知半解了。
另外我觉得Demag这个消磁时间内也会有很强的感生电动势,会让比较器翻转,让我们误判为过零事件,我们也要越过这个时间后再去读比较器的结果。
楼主,我这样理解对吧?
 楼主| 发表于 2016-7-3 18:39:12 来自手机 | 显示全部楼层
小小苹果 发表于 2016-7-3 17:50
多谢楼主的回复,在楼主的解释下我已经有个一知半解了。
另外我觉得Demag这个消磁时间内也会有很强的感生 ...

当然,开始过零监测是要在这个后面,避免检查到上个相位产生的电流。有个预测的换相时间,到差不多时间才开始监测过零的。这个程序代码里面有体现,主要在T2计时器上体现。一开始就监测过零容易误判。
发表于 2016-7-4 11:39:57 | 显示全部楼层
楼主,他每次检测比较器是否过零点的时刻是在定时器1计数值大于120的时刻后,但是pwm的频率只有16k(周期62.5us)的话,我测过薪西达2200kv反电动势的时间在100us~920us,这样的话,假设现在反电动势的时间是120us,相当于对比较器的过零点检测只有两次,假如过零点发生在第一次检测后的话,下一次虽然检测到了,但是会有一个pwm的误差,那换相还能正确吗?
这是我看了blheli程序的看法,不知是否正确?如有不对之处望指点
 楼主| 发表于 2016-7-4 14:03:15 来自手机 | 显示全部楼层
浪子怀海 发表于 2016-7-4 11:39
楼主,他每次检测比较器是否过零点的时刻是在定时器1计数值大于120的时刻后,但是pwm的频率只有16k(周期62 ...

我觉得你理解对,但是什么地方说了120的单位是1us呢?没准那个120的单位是循环或者其他什么时间单位的。
发表于 2016-7-4 14:42:02 | 显示全部楼层
helislayer 发表于 2016-7-4 14:03
我觉得你理解对,但是什么地方说了120的单位是1us呢?没准那个120的单位是循环或者其他什么时间单位的。 ...

120就是pwm计数的个数 = 62.5/256 * 120,

        mov        Temp2, #120
pwm_wait:                                               
        clr        C
        mov        A, TL1
        subb        A, Temp2
IF DAMPED_MODE_ENABLE==0                               
        jc        comp_wait_on_comp_able                ; Re-evaluate pwm cycle for slower escs
ENDIF
IF DAMPED_MODE_ENABLE==1                                ; Assume same pwm cycle for fast escs
        jb        Flags1.DIRECT_STARTUP_PHASE, ($+5)
        jc        pwm_wait
        jc        comp_wait_on_comp_able                ; Re-evaluate pwm cycle during direct start          重新评估pwm周期期间直接开始
ENDIF
就是这个地方读取比较器的输出
发表于 2016-7-4 14:43:31 | 显示全部楼层
TL1,在定时器0中断中清零
 楼主| 发表于 2016-7-5 21:34:23 | 显示全部楼层
浪子怀海 发表于 2016-7-4 14:42
120就是pwm计数的个数 = 62.5/256 * 120,

        mov        Temp2, #120

不好意思最近比较忙每有机会看代码。

我刚才去看了一下代码,你看到是什么版本啊?
我在最新的 git 里面没有找到你贴的代码。有可能
你看到代码已经很老被改写了。

SiLabs]$ grep pwm_wait *
grep: Hex files: Is a directory
[ SiLabs]$

你看我搜索了一下 Silabs 目录就没有 pwm_wait 这个结果。
我刚才更新了一下 git,也没有。
发表于 2016-7-5 23:46:13 | 显示全部楼层
我也没有搜到,另外请教楼主个问题:
t3_int:        ; Used for commutation timing
        clr         IE_EA                        ; Disable all interrupts
        anl        EIE1, #7Fh                ; Disable timer3 interrupts
        mov        TMR3RLL, #0FAh                ; Set a short delay before next interrupt
        mov        TMR3RLH, #0FFh
        clr        Flags0.T3_PENDING         ; Flag that timer has wrapped
        anl        TMR3CN0, #07Fh                ; Timer3 interrupt flag cleared
        setb        IE_EA                        ; Enable all interrupts
        reti


wait_advance_timing:       
        jnb        Flags0.T3_PENDING, ($+5)
        jmp        wait_advance_timing

        ; Setup next wait time
        mov        TMR3RLL, Wt_ZC_Tout_Start_L
        mov        TMR3RLH, Wt_ZC_Tout_Start_H
        setb        Flags0.T3_PENDING
        orl        EIE1, #80h        ; Enable timer3 interrupts

第一段程序内,每次 T3 溢出中断后,TMR3RLL和TMR3RLH重装寄存器里都要写入这个延时很短的值。为什么?
第二段程序内,等待T3 溢出中断后, 把这个Wt_ZC_Tout_Start_L时间写入TMR3RLL寄存器,也改变不了当前的溢出等待时间吧。为什么不直接写TMR3L和TMR3H呢?
 楼主| 发表于 2016-7-6 12:56:09 | 显示全部楼层
小小苹果 发表于 2016-7-5 23:46
我也没有搜到,另外请教楼主个问题:
t3_int:        ; Used for commutation timing
        clr         IE_EA                        ; Disable all ...

t3 中断这个我可以看出来的就是会反复清除
T3_PENDING 这个 bit。我想这个很短时间和
你后面问的问题相关。


直接写TMR3L和TMR3H 是有race condition
冲突风险。因为你写寄存器计数器的时候不是
原子操作的。写低的时候低的就开始跑了,没
准写高的时候低的已经触发了。

所以他的策略是用这个很短的时间来装入
TMR3LH TMR3LL, 我想 MCU 应该是有
某种保护机制确保同时把 TMR3LH TMR3LL
装入到计数器不会只装了一半。

当然你也可以停止计数器然后装入然后再开始。
用的策略不一样。
发表于 2016-7-7 17:24:42 | 显示全部楼层
楼主,请教下 pgm _comm_Timing   和  DEMAG_DETECTED  起什么作用?
 楼主| 发表于 2016-7-7 21:51:53 | 显示全部楼层
846528111 发表于 2016-7-7 17:24
楼主,请教下 pgm _comm_Timing   和  DEMAG_DETECTED  起什么作用?

DEMAG 这个作用就是检测到换相时间和预计不符合的时候,
提前关闭FET 的通电好让线圈有一个提前的时间泻掉电流。

Pgm_comm_timing 就是从编程器或者那个 BLHeli 配置
工具预先设定的换相需要的初始时间。给启动这些时候用。
跑起来了这个换相时间就是动态决定的了。
友情提示:标题不合格、重复发帖,将会被封锁ID。详情请参考:论坛通告:封锁ID、获得注册邀请码、恢复被封ID、投诉必读
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|阿莫电子论坛(原ourAVR/ourDEV) ( 粤ICP备09047143号 )

GMT+8, 2017-9-19 19:43

阿莫电子论坛, 原"中国电子开发网"

© 2004-2016 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表