精华内容
下载资源
问答
  • 2019-09-18 20:46:01

      下面是对场效应管的测量方法
      场效应管英文缩写为FET。可分为结型场效应管(JFET)和绝缘栅型场效应管(MOSFET),我们平常简称为MOS管。而MOS管又可分为增强型和耗尽型而我们平常主板中常见使用的也就是增强型的MOS管。
      下图为MOS管的标识


      我们主板中常用的MOS管G D S三个引脚是固定的。。。不管是N沟道还是P沟道都一样。。。把芯片放正。。。从左到右分别为G极D极S极!如下图:


      用二极管档对MOS管的测量。。。首先要短接三只引脚对管子进行放电。。。
      1、然后用红表笔接S极.黑表笔接D极.如果测得有500多的数值..说明此管为N沟道..
      2、黑笔不动..用红笔去接触G极测得数值为1
      3、红笔移回到S极.此时管子应该为导通...
      4、然后红笔测D极.而黑笔测S极.应该测得数值为1.(这一步时要注意.因为之前测量时给了G极2.5V万用表的电压..所以DS之间还是导通的..不过大概10几秒后才恢复正常...建议进行这一步时再次短接三脚给管子放电先)5、然后红笔不动.黑笔去测G极..数值应该为1
      到此我们可以判定此N沟道场管为正常
      有的人说后面两步可以省略不测...不过我习惯性把五个步骤全用上。。。当然.对然P沟道的测量步骤也一样...只不过第一步为黑表笔测S极.红表笔测D极..可以测得500多的数值..

           场效应管G16P03的参数
      品牌 :GOFORD
      种类 :绝缘栅(MOSFET)
      导电方式 :增强型
      封装外形 :SMD(SO)/表面封装
      型号 :G16P03
      沟道类型 :P沟道
      用途 :S/开关
      材料 :P-FET硅P沟道

    转载于:https://my.oschina.net/u/3911785/blog/3089611

    更多相关内容
  • mos管测量方法图解

    2020-07-13 10:01:23
    mos管测量方法图解 场效应管英文缩写为FET.可分为结型场效应管(JFET)和绝缘栅型场效应管(MOSFET),我们平常简称为MOS管。而MOS管又可分为增强型和耗尽型而我们平常主板中常见使用的也就是增强型的MOS管。 下图...
  • 针对现有多交变光场的光源一致性差、体积大、难集成的问题,提出一种单交变光场的驻波合成电行波的微控移相精密直线位移测量方法。该方法利用单路交变光源与四路正弦栅面空间调制获得四路光强信号;通过微控移相电路...
  • 基于条纹反射的相位测量术被广泛用于获取镜面物体的表面三维形貌数据, 系统标定是相位测量术中重要的一步, 它直接决定了测量结果的精度。提出一种基于相位信息获得系统模型中未知参数的方法, 建立相位和深度间的直接...
  • 实现摄影测量常用的方法 包括后方,前方交会;相对绝对定向,和一步定向法。内含数据,结果正确。
  • 采用一步前预测方法构造网络的训练样本,用带自适应学习率的动态BP算法进行网络的训练,通过训练后的网络对各测量参数进行估计,实现测量数据的在线检验。对某电厂CCS系统进行了仿真试验,结果表明该方法可避免形成...
  • 手表的尺寸是我们在购买手表的时候一个很重要的选择标准,在购买的时候一定要很准确的知道自己的尺寸,不然买大了或者买小了戴起来都会不太舒服。...转换上一步测量到的尺寸单位至毫米。例如:16厘米转换...

    手表的尺寸是我们在购买手表的时候一个很重要的选择标准,在购买的时候一定要很准确的知道自己的尺寸,不然买大了或者买小了戴起来都会不太舒服。

    手表尺寸怎么测量的

    应该使用软尺测量你的手腕(应紧紧缠绕),紧挨着手腕突出骨后的位置。如果你没有一个卷尺,可以用柔软的绳或一张软纸围绕在手腕相应位置,记住,必须是你要佩戴手表的手腕,每个人的左右手腕一般粗细不同。转换上一步中测量到的尺寸单位至毫米。例

    如:16厘米转换为160毫米。用你想买的手表直径数字去除这个数字,例如:你想购买直径 38毫米的正装手表,而你的手腕周长为160毫米,其结果将是160+38

    =4.2,这个数字称之为表壳指数。

    根据这个结果我们就能判定手表尺寸是否适合 你的手腕。最适合你用的表壳指数范围从4到5;

    小于4的话手表太大了,大于5的话手表就太小。比如你的手腕大小为160毫米。那么大小32毫米至40毫米的手表就适合你佩戴。

    手表尺寸选购技巧

    1、对于一些“吃不胖”女生来说,手腕往往十分纤细,测量出来的手腕周长可能不到12cm。这时候请尽量选择一些小尺寸的丽声手表,一般以30mm左右表径的手表会比较合适。

    2、一些手腕粗细正常的女性,手腕周长一般是在13cm~15cm之间,这时候就应该选择一些尺寸稍大的腕表,丽声小编建议表径为31mm~38mm的丽声手表最为合适,既小巧又配搭比例合宜,看时也更加清楚。

    3、对于一些手腕较细的男性和女性来说手腕周长一般维持在16cm左右,因此在表径的需求上就会更大一些,以表径为38~39mm的手表表径为主,可以适当做出微调。

    4、针对男性朋友们一般来说,手腕周长会在17~18cm左右,因此选择尺寸40到43mm的手表最为合宜,因为男性这个腕长处于最合适的比例,因此这个区间的手表种类也最多。

    5、如果你的手腕周长为19cm左右,那么丽声小编建议你一般40mm左右的腕表已经无法匹配你手腕的周长,需要选择尺寸44~45mm的丽声手表最好,既能方便看时,也可以修饰腕间,可谓一举两得。

    手表尺寸选购标准

    最理想的就是,腕表的表壳和手腕差不多大小,尽量不要超过手腕边缘。想象你的手腕是一个盘子,你往里盛食物,当然不希望食物溢出来。所以,到底腕表要多大,这是个人喜好的问题,但切记不要超出手腕。

    如果你想买一款中等尺寸的腕表,有一个不成文的规则,那就是腕表表壳至少占据四分之三的手腕。否则,会让人感觉女性化。

    有时,一款比较厚的表会看上去宽,一款薄的表则看上去小。大多数男士认为直径为40-44毫米的腕表好看,因为这个尺寸对他们来说属于大中型尺寸。如果你的手腕较小,那么36毫米的表在某些情况下比较适合,但请尽量避免选择38毫米以下的腕表。

    手表购买注意事项

    手表壳的材质常见的有K金、镀金、钛材、不锈钢、半钢镀铬、合金壳等。K金表壳只有名牌高档表采用,其售价一般在数万元以上;而半钢(只有手表后盖是不锈钢)

    镀铬一类的表都属于低档表,表壳容易被腐蚀。镀金表壳比较漂亮,但没有一定镀金厚度(包括表带)也很容易被磨掉。如果要选择镀金表,镀层厚度最好在10微米以上。镀钛金的表比较结实耐磨,但颜色不太好看。现在比较流行的是双色表壳表带

    (金或镀金和不锈钢的),它们比较美观和耐用。镀金表比全钢的表贵,皮表带的手表要比同款钢表带的手表便宜很多。

    而爱出汗的人或爱运动的人、室外工作者、长期接触化学酸碱物质的人(比如医务工作者)都应戴不锈钢壳的表。含汞的化学药品对K金和镀金有极大的损害,会使金变色。铜材电镀的表把头、表壳及表带里侧很易被汗液腐蚀,使镀层脱落。钢表带有空芯和实芯之分,空芯表带分量较轻属于低档表用的,实芯表带比较结实耐用。

    表带节之间的穿钉和表带扣是佩戴手表时最容易出问题的部位,购买手表时一定要仔细检查。有些表扣长期开闭,容易出问题的地方如“蝴蝶”扣等,而陶瓷表带容易碎,这些也应该在购买手表之前考虑清楚。

    展开全文
  • gps测量仪器使用方法及教程

    千次阅读 2021-07-26 04:58:39
    本文将介绍GPS测量仪(手持机)的使用方法。GPS测量原理卫星定位法是利用地面站接收机接收某种导航卫星的信息,直接测定地面接收站的地心大地坐标。5.2.3用户接收部分组成---用户---接收设备接收设备---gps信号接收机-...

    20120218034652651.gif

    GPS(Global PosiTIon System)是美国于1973年开始筹建的全球定位系统,1994年建成投入使用,可向全球提供实时的三维位置、速度和时间信息。本文将介绍GPS测量仪(手持机)的使用方法。

    8ea4e102de11b6c15699d347eba92dca.png

    GPS测量原理

    02a336cbd791d3e7d9379a3570839644.png

    卫星定位法是利用地面站接收机接收某种导航卫星的信息,直接测定地面接收站的地心大地坐标。5.2.3用户接收部分组成---用户---接收设备接收设备---gps信号接收机---其它仪器设备5.3gps定位的方法按参考点的不同位置划分为:(1)绝对定位(单点定位):在地球协议坐标系中,确定观测站相对地球质心的位置。 可以接收卫星(gps、glonas、北斗星)时间信号、国家授时中心bpl长波授时信号,或者接收外部irig-b码,并采用fpga完成先进的“时间驯服算法”,由高精度的卫星脉冲对本地守时脉冲进行驯服,从而实现高精度的守时功能。

    be1f34b33505c32a0447cb8fc0373dfd.png

    GPS全球定位系统分为:

    5f3c899d5c4a4fd91f594c87119795d6.png

    空间部分,控制部分和用户部分。其中空间部分通常有24颗卫星和备用卫星,6个卫星轨道面,相互夹角60度,每个轨道面上4个卫星。每个卫星每天在20200千米高度12小时的轨道上运行,全球各点都可以收到5到12颗卫星的信号。

    47b12acaa4bbf48742d8ad02a6134f62.png

    gps测量仪器使用方法具体操作过程如下:

    4785b102e3e9a6d359b38bf67dd263f7.png

    1、备份:电脑与接收机连接后,启动刷机工具,点‘参数配置’或‘ >> ’按钮进行参数设置:(1)gx3001储存器为1m的接收机,晶振频率选‘4mhz’,联接方式选择‘串口flash’剩下的按默认就行,然后选择com口,选择“操作模式”为第三项‘导出’,刷写项目选择‘all’(全部),点‘浏览’按钮即弹出保存对话框,在那个保存对话框中填写带扩展名的文件名称,例如‘gx3001.bin’,然后先点那个‘导出固件’大按钮,再开接收机电源(这一步与海尔工具不同,海尔是先开接收机电源再点‘读取’),进度条走动直至100% 。第一步:打开控制面板的"查看网络连接任务"或者直接点击右下角小电脑图标,打开网络共享中心,方法不是一种,找到一种适合自己的即可 第二步:点击"设置新的连接或网络" 第三步:"选择一个连接选项"选择"连接到工作区". 第四步:如果已经存在其他连接,则在这一步选择"否,创建新连接":如果没有,则这一步将被跳过 第五步:选择"使用我的internet连接(vpn)",点击"下一步&q。 6、配置网络连接,我们需要象宽带上网一样建立一个连接,因为gprs属于拨号方式上网,所以我们要建立一个拨号连接,步骤如下:首先打开“internet explorer 浏览器”,选择“工具”,然后选择“internet 选项”,选择“连接”,然后点击“建立连接”,按照提示进入下一步,选择“连接到 internet”,进入下一步,选择“手动设置我的连接”,进入下一步,选择“用拨号调制解调器连接”,进入下一步,输入您需要建立的连接的名称,一般输入“gprs”,进入下一步,电话号码栏里面输入需要拨叫的号码(详情请看本文最后罗列),进入下一步,用户名密码都为空,下面的“默认为internet连接”可以取消不选,点击下一步,选择“需要在桌面上添加到此连接的快捷方式”,然后点击“完成”即可完成网络连接配置。

    2、新建任务,选择需要的坐标系统,打开此任务

    3、设置好电台频率,配置基准站,启动基准站,电台开始正常发射

    5ba2916e3fb6c904c0aa66f0f6811958.png

    4、配置流动站,频率和电台上的频率保持一致,启动流动站,开始测量。

    以上是RTK的简单操作流程,如果你要是做静态,就在configaTIon toolexr软件里面设置采样间隔,开机后自动进行静态记录。

    下图是GPS全球定位系统的卫星星座。

    96c9e71720ce1e319515faa0bb10a36f.png

    9dc76466c258c6d72392861e69ec9142.png

    利用GPS测量仪(接收机)进行测距。当MARK(存点)第一个位置时,GPS生成A航点,并且A的信息被保存下来。到达第二个位置时,再MARK(存点)一下,生成B航点。gps接收机使用

    本文来自电脑杂谈,转载请注明本文网址:

    http://www.pc-fly.com/a/shumachanpin/article-95245-1.html

    展开全文
  •  一、参数测量的使用方法 打开测量比较简单,记住两个要点: 1、我要测量哪个通道? 2、我要测什么? 图1 打开测量 小结:测量项目有51项之多,支持24项测量项目同屏幕显示。 二、参数测量算法分析 示波器...
  • 软件部分根据超声波信号的特点,选用新型的构造包络的方法,在准确判断超声波到达时间的问题上有所改进。   文章共分六个部分。第一章绪论介绍了超声波风速测量仪表的发展现状、本篇论文选题的目的和意义、...
  •  一、参数测量的使用方法  打开测量比较简单,记住两个要点:  1、我要测量哪个通道?  2、我要测什么?  图1 打开测量  小结:测量项目有51项之多,支持24项测量项目同屏幕显示
  • 详细介绍了有关三维人体自动测量的现状、主要过程、应用、分类及各种测量方法的原理和特点,并讨论了各种测量方法的利弊,指出了目前制约三维人体测量技术发展的主要因素,最后提出了三维人体自动测量下一步的发展...
  • 针对这个问题,提供了一种可对大功率激光二极管线阵进行大动态范围波前测量的新方法,可在-π/2~π/2范围内进行高精度的波前斜率测量(±1′)。通过波前斜率的测量,可得到大功率激光二极管线阵的波前复振幅,实现...
  • OD流很难直接测量得到,需通过高聚集链路测量反演技术推测,然而反演误差将直接影响下一步基于特征参数的异常诊断。本文提出了一种直接由链路测量进行OD流异常检测的框架,该框架采用RMLP神经网络,并加入部分OD 流...
  • 基于opencv平台编写的单目相机标定程序,使用的张正友的方法,只要准备十二张单目相机拍摄的棋盘格的图片就可以标定出单目相机的焦距等参数,...可以用于机器视觉测量中,也可以用于双面相机标定的前一步,精度很高。
  • 究竟该相信谁,示波器还是信号发生器?...经过大家的辩论,我也请教了这方面的高手,也通过具体的实验,更深一步地了解到了问题的本质。这里首先和大家分享一下如何更合理使用示波器, 来减少幅度测量误差。
  • 在串联双容水箱水位的控制中,进水首先进人第一个水箱,然后通过第二个水箱流出,与一个水箱相比,由于增加了一个水箱,使得被控量的响应在时间上更落后一步,即存在容积延迟,从而导致该过程的难以控制。...
  • 测量频率和占空比的几种方法

    千次阅读 2019-04-04 15:37:29
    而这两个的测量方法联系比较紧密,所以也一并把测量占空比的方法写出来。因为时间有限,所以并不能把所有思路都一一测试,只是写在下面作为参考,敬请谅解。 使用平台:官方 STM32F429 DISCOVERY 开发板 , ...

    转:https://blog.csdn.net/yyx112358/article/details/78414594

    想当年天天水论坛好为人师,现在已经全面转向计算机视觉方向了,颇为感慨。不过,自己的理性选择,个中得失早就意料之中。塞翁失马,焉知非福?

    原文链接:http://www.openedv.com/forum.php?mod=viewthread&tid=82594&extra=


    【教程】使用STM32测量频率和占空比的几种方法(申请置酷!)


    这几天在论坛上面解答了好几个询问 STM32 测量频率的贴子,觉得这种需求还是存在的(示波器、电机控制等等)。而简单搜索了一下论坛,这方面的贴子有但是不全。正好今年参加比赛做过这方面的题目(最后是一等奖嘿嘿),所以把我们当时尝试过的各种方案都列出来,方便以后大家使用,也是作为一个长期在论坛的潜水党对论坛的回报。

    PS: 由于我们当时的题目除了测量频率之外,更麻烦的是测量占空比。而这两个的测量方法联系比较紧密,所以也一并把测量占空比的方法写出来。因为时间有限,所以并不能把所有思路都一一测试,只是写在下面作为参考,敬请谅解。

    使用平台:官方 STM32F429DISCOVERY 开发板, 180MHz 的主频,定时器频率 90MHz 。

    相关题目:
    ( 1 )测量脉冲信号频率 f_O ,频率范围为 10Hz ~ 2MHz ,测量误差的绝对值不大于 0.1% 。( 15 分)
    ( 2 )测量脉冲信号占空比 D ,测量范围为 10 %~ 90 %,测量误差的绝对值不大于 2% 。( 15 分)


    思路一:外部中断
    思路:这种方法是很容易想到的,而且对几乎所有 MCU 都适用(连 51 都可以)。方法也很简单,声明一个计数变量 TIM_cnt ,每次一个上升沿 / 下降沿就进入一次中断,对 TIM_cnt++ ,然后定时统计即可。如果需要占空比,那么就另外用一个定时器统计上升沿、下降沿之间的时间即可。

    缺点:缺陷显而易见,当频率提高,将会频繁进入中断,占用大量时间。而当频率超过 100kHz 时,中断程序时间甚至将超过脉冲周期,产生巨大误差。同时更重要的是,想要测量的占空比由于受到中断程序影响,误差将越来越大。

    总结 : 我们当时第一时间就把这个方案 PASS 了,没有相关代码(这个代码也很简单)。不过,该方法在频率较低( 10K 以下)时,可以拿来测量频率。在频率更低的情况下,可以拿来测占空比。


    思路二: PWM 输入模式

    思路:翻遍 ST 的参考手册,在定时器当中有这样一种模式:
    总结 : 我们当时第一时间就把这个方案 PASS 了,没有相关代码(这个代码也很简单)。不过,该方法在频率较低( 10K 以下)时,可以拿来测量频率。在频率更低的情况下,可以拿来测占空比。


    思路二: PWM 输入模式

    思路:翻遍 ST 的参考手册,在定时器当中有这样一种模式:



    简而言之,理论上,通过这种模式,可以用硬件直接测量出频率和占空比。当时我们发现这一模式时欢欣鼓舞,以为可以一步解决这一问题,代码如下:

    
      
    1. void Tim2_PWMIC_Init(void)
    2. {
    3. GPIO_InitTypeDef GPIO_InitStructure;
    4. NVIC_InitTypeDef NVIC_InitStructure;
    5. TIM_ICInitTypeDef TIM_ICInitStructure;
    6. /* TIM4 clock enable */
    7. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
    8. /* GPIOB clock enable */
    9. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
    10. /* TIM4 chennel2 configuration : PB.07 */
    11. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    12. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    13. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    14. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    15. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP ;
    16. GPIO_Init(GPIOB, &GPIO_InitStructure);
    17. /* Connect TIM pin to AF2 */
    18. GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_TIM4);
    19. /* Enable the TIM4 global Interrupt */
    20. NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
    21. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    22. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    23. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    24. NVIC_Init(&NVIC_InitStructure);
    25. TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;
    26. TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    27. TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    28. TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    29. TIM_ICInitStructure.TIM_ICFilter = 0x0;
    30. TIM_PWMIConfig(TIM4, &TIM_ICInitStructure);
    31. /* Select the TIM4 Input Trigger: TI2FP2 */
    32. TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);
    33. /* Select the slave Mode: Reset Mode */
    34. TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);
    35. TIM_SelectMasterSlaveMode(TIM4,TIM_MasterSlaveMode_Enable);
    36. /* TIM enable counter */
    37. TIM_Cmd(TIM4, ENABLE);
    38. /* Enable the CC2 Interrupt Request */
    39. TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);
    40. }
    41. //中断程序:
    42. void TIM4_IRQHandler(void)
    43. {
    44. /* Clear TIM4 Capture compare interrupt pending bit */
    45. TIM_ClearITPendingBit(TIM4, TIM_IT_CC1|TIM_IT_CC2);
    46. /* Get the Input Capture value */
    47. IC2Value = TIM_GetCapture2(TIM4); //周期
    48. if (IC2Value != 0)
    49. {
    50. highval[filter_cnt]=TIM_GetCapture1(TIM4); //高电平周期
    51. waveval[filter_cnt]=IC2Value;
    52. filter_cnt++;
    53. if(filter_cnt>=FILTER_NUM)
    54. filter_cnt= 0;
    55. }
    56. else
    57. {
    58. DutyCycle = 0;
    59. Frequency = 0;
    60. }
    61. }
    62. //主循环:
    63. while ( 1)
    64. {
    65. uint32_t highsum= 0,wavesum= 0,dutysum= 0,freqsum= 0;
    66. LCD_Clear( 0);
    67. for(i= 0;i<FILTER_NUM;i++)
    68. {
    69. highsum+=highval[i];
    70. wavesum+=waveval;
    71. }
    72. [/i] delay_ms( 1);
    73. DutyCycle=highsum* 1000/wavesum;
    74. Frequency=(SystemCoreClock/ 2* 1000/wavesum);
    75. freq=Frequency* 2.2118 -47.05; //线性补偿
    76. sprintf(str, "DUTY:%3d\nFREQ:%.3f KHZ\n",DutyCycle,freq/ 1000);
    77. LCD_ShowString( 0, 200,str);
    78. delay_ms( 100);
    79. }

    但是,经过测量之后发现这种方法测试数据不稳定也不精确,数据不停跳动,且和实际值相差很大。 ST 的这些功能经常有这种问题,比如定时器的编码器模式,在 0 点处频繁正负跳变时有可能会卡死。这些方法虽然省事,稳定性却不是很好。

    经过线性补偿可以一定程度上减少误差(参数在不同情况下不同):

    freq=Frequency*2.2118-47.05;

    这种方法无法实现要求。所以在这里我并不推荐这种方法。如果有谁能够有较好的程序,也欢迎发出来。


    思路三:输入捕获

    思路:一般来说,对STM32有一定了解的坛友们在测量频率的问题上往往都会想到利用输入捕获。首先设定为上升沿触发,当进入中断之后(rising)记录与上次中断(rising_last)之间的间隔(周期,其倒数就是频率)。再设定为下降沿,进入中断之后与上升沿时刻之差即为高电平时间(falling-rising_last),高电平时间除周期即为占空比

    程序如下,注意由于为了减少程序复杂性使用了32位定时器5(计数周期如果是1us时可以计数4294s,否则如果是16位只能计数65ms),如果需要在F1上使用则需要自行处理:

    
     
    1. //定时器5通道1输入捕获配置
    2. //arr:自动重装值(TIM2,TIM5是32位的!!)
    3. //psc:时钟预分频数
    4. void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
    5. {
    6. GPIO_InitTypeDef GPIO_InitStructure;
    7. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    8. NVIC_InitTypeDef NVIC_InitStructure;
    9. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5时钟使能
    10. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟
    11. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0
    12. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
    13. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
    14. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
    15. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
    16. GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0
    17. GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //PA0复用位定时器5
    18. TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频
    19. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
    20. TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值
    21. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    22. TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
    23. //初始化TIM5输入捕获参数
    24. TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
    25. TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
    26. TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
    27. TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
    28. TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器 不滤波
    29. TIM_ICInit(TIM5, &TIM5_ICInitStructure);
    30. TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE); //允许更新中断 ,允许CC1IE捕获中断
    31. TIM_Cmd(TIM5,ENABLE ); //使能定时器5
    32. NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
    33. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2; //抢占优先级
    34. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级
    35. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
    36. NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
    37. }
    38. //捕获状态(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
    39. //定时器5中断服务程序
    40. void TIM5_IRQHandler(void)
    41. {
    42. if(TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET) //捕获1发生捕获事件
    43. {
    44. if(edge==RESET) //上升沿
    45. {
    46. rising=TIM5->CCR1-rising_last;
    47. rising_last=TIM5->CCR1;
    48. TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=0 设置为上升沿捕获
    49. edge=SET;
    50. }
    51. else
    52. {
    53. falling=TIM5->CCR1-rising_last;
    54. TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
    55. edge=RESET;
    56. }
    57. }
    58. TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
    59. }
    60. 主程序:
    61. while ( 1)
    62. {
    63. uint32_t highsum= 0,wavesum= 0,dutysum= 0,freqsum= 0;
    64. LCD_Clear( 0);
    65. delay_ms( 1);
    66. sprintf(str, "rise:%3d\nfall:%d\nfall-rise:%d",rising,falling,falling-rising);
    67. LCD_ShowString( 0, 100,str);
    68. sprintf(str, "Freq:%.2f Hz\nDuty:%.3f\n", 90000000.0/rising,( float)falling/( float)rising); //频率、占空比
    69. LCD_ShowString( 0, 200,str);
    70. delay_ms( 100);
    71. }

    注意的是,中断程序当中的变量rising,last因为多次修改的缘故,与名称本身含义有所区别,示意如下:


    该方法尤其是在中低频( <100kHz)之下精度不错。
    缺点:稍有经验的朋友们应该都能看出来,该方法仍然会带来极高的中断频率。在高频之下,首先是 CPU时间被完全占用,此外,更重要的是,中断程序时间过长往往导致会错过一次或多次中断信号,表现就是测量值在实际值、实际值× 2、实际值× 3等之间跳动。实测中,最高频率可以测到约 400kHz。
    总结:该方法在低频率( <100kHz)下有着很好的精度,在考虑到其它程序的情况下,建议在 10kHz之下使用该方法。同时,可以参考以下的改进程序减少 CPU负载。
    改进:
    前述问题,限制频率提高的主要因素是过长的中断时间(一般应用情景之下,还有其它程序部分的限制)。所以进行以下改进:
    1.           使用 2个通道,一个只测量上升沿,另一个只测量下降沿。这样可以减少切换触发边沿的延迟,缺点是多用了一个 IO口。
    2.           使用寄存器,简化程序
    最终程序如下:

    
     
    1. /TIM2_CH1->PA5
    2. //TIM2_CH2->PB3
    3. void TIM2_CH1_Cap_Init(u32 arr,u16 psc)
    4. {
    5. GPIO_InitTypeDef GPIO_InitStructure;
    6. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    7. NVIC_InitTypeDef NVIC_InitStructure;
    8. TIM_ICInitTypeDef TIM_ICInitStructure;
    9. TIM_DeInit(TIM2);
    10. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //TIM2时钟使能
    11. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB, ENABLE); //使能PORTA时钟
    12. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //GPIOA0
    13. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
    14. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; //速度100MHz
    15. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
    16. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
    17. GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0
    18. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //GPIOA0
    19. GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化PA0
    20. GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM2); //PA0复用位定时器5
    21. GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_TIM2); //PA0复用位定时器5
    22. TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频
    23. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
    24. TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值
    25. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    26. TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
    27. //初始化TIM2输入捕获参数
    28. TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
    29. TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
    30. TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
    31. TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
    32. TIM_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 配置输入滤波器 不滤波
    33. TIM_ICInit(TIM2, &TIM_ICInitStructure);
    34. TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; //CC1S=01 选择输入端 IC1映射到TI1上
    35. TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling; //上升沿捕获
    36. TIM_ICInit(TIM2, &TIM_ICInitStructure);
    37. TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1|TIM_IT_CC2,ENABLE); //允许更新中断 ,允许CC1IE捕获中断
    38. // TIM2_CH1_Cap_DMAInit();
    39. TIM_Cmd(TIM2,ENABLE ); //使能定时器5
    40. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    41. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0; //抢占优先级3
    42. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级3
    43. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
    44. NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
    45. }
    46. //定时器2中断服务程序(对于32位定时器来说,1us计数器加1,溢出时间:4294秒)
    47. void TIM2_IRQHandler(void)
    48. {
    49. if(TIM2->SR&TIM_FLAG_CC1) //TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
    50. {
    51. rising=TIM2->CCR1-rising_last;
    52. rising_last=TIM2->CCR1;
    53. return;
    54. }
    55. if(TIM2->SR&TIM_FLAG_CC2) //TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET)
    56. {
    57. falling=TIM2->CCR2-rising_last;
    58. return;
    59. }
    60. TIM2->SR= 0;
    61. }


    之所以改用 TIM2 是因为 TIM5 的 CH1(PA0) 还是按键输入引脚。本来想来这应当也没什么,按键不按下不就是开路嘛。但是后来发现官方开发板上还有一个 RC 滤波……
    所以,当使用别人的程序之前,请一定仔细查看电路图。



    这样,最高频率能够达到约1.1MHz,是一个不小的进步。但是,其根本问题——中断太频繁——仍然存在。


    解决思路也是存在的。本质上,我们实际上只需要读取CCR1和CCR2寄存器。而在内存复制过程中,面对大数据量的转移时,我们会想到什么?显然,我们很容易想到——利用DMA。所以,我们使用输入捕获事件触发DMA来搬运寄存器而非触发中断即可,然后将这些数据存放在一个数组当中并循环刷新。这样,我们可以随时来查看数据并计算出频率。


    这一方法我曾经尝试过,没有调出来,因为,有一个更好的方法存在。但是理论上这是没有问题的,以供参考我列出如下。


    【注意:这段程序无法工作,仅供参考!!!】


    
     
    1. //TIM2_CH1->DMA1_CHANNEL3_STREAM5
    2. u32 val[FILTER_NUM]={ 0};
    3. void TIM2_CH1_Cap_DMAInit(void)
    4. {
    5. NVIC_InitTypeDef NVIC_InitStructure;
    6. DMA_InitTypeDef DMA_InitStructure;
    7. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE); //DMA1时钟使能
    8. DMA_DeInit(DMA1_Stream5);
    9. while (DMA_GetCmdStatus(DMA1_Stream5) != DISABLE){} //等待DMA可配置
    10. /* 配置 DMA Stream */
    11. DMA_InitStructure.DMA_Channel = DMA_Channel_3; //通道选择
    12. DMA_InitStructure.DMA_PeripheralBaseAddr = ( uint32_t)&(TIM5->CCR1); //DMA外设地址
    13. DMA_InitStructure.DMA_Memory0BaseAddr = ( uint32_t)val; //DMA 存储器0地址
    14. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; //存储器到外设模式
    15. DMA_InitStructure.DMA_BufferSize = FILTER_NUM; //数据传输量
    16. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设非增量模式
    17. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器增量模式
    18. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //外设数据长度:8位
    19. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //存储器数据长度:8位
    20. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 使用普通模式
    21. DMA_InitStructure.DMA_Priority = DMA_Priority_High; //中等优先级
    22. DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    23. DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
    24. DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //存储器突发单次传输
    25. DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //外设突发单次传输
    26. DMA_Init(DMA1_Stream5, &DMA_InitStructure); //初始化DMA Stream
    27. TIM_DMAConfig(TIM5,TIM_DMABase_CCR1,TIM_DMABurstLength_16Bytes);
    28. TIM_DMACmd(TIM5,TIM_DMA_CC1,ENABLE);
    29. //如果需要DMA中断则如下面所示
    30. NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream5_IRQn; //使能TIM中断
    31. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级
    32. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级
    33. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
    34. NVIC_Init(&NVIC_InitStructure);
    35. DMA_ITConfig(DMA1_Stream5,DMA_IT_TC,ENABLE);
    36. //开启DMA传输
    37. DMA_Cmd(DMA1_Stream5, ENABLE);
    38. }
    39. void DMA1_Stream5_IRQHandler(void)
    40. {
    41. DMA_ClearITPendingBit(DMA1_Stream5,DMA_IT_TCIF5);
    42. }


    @xkwy 大神在回复中提出了几个改进意见,列出如下:
    1. 可以设定仅有通道 2 进行下降沿捕获并触发中断,而通道 1 捕获上升沿不触发中断。在中断函数当中,一次读取 CCR1 和 CCR2 。这样可以节省大量时间。
    2. 可以先进行一次测量,根据测量值改变预分频值 PSC ,从而提高精度
    3. 间隔采样。例如每 100ms 采样 10ms.
    这样的改进应当能够将最高采样频率增加到 2M. 但是频率的进一步提高仍然不可能。因为这时的主要矛盾是中断函数时间过长,导致 CPU 还在处理中断的时候这一次周期就结束了,使得最终测量到的频率为真实频率的整数倍左右。示意图如下:


    因此,高频时仍然推荐以下方法。


    思路四:使用外部时钟计数器


    这种方法是我这几天回答问题时推荐的方法。思路是配置两个定时器,定时器a设置为外部时钟计数器模式,定时器b设置为定时器(比如50ms溢出一次,也可以用软件定时器),然后定时器b中断函数中统计定时器a在这段时间内的增量,简单计算即可。


    代码:

    
     
    1. //TIM7->100ms
    2. //TIM2_CH2->PB3
    3. void TIM_Cnt_Init(void)
    4. {
    5. GPIO_InitTypeDef GPIO_InitStructure;
    6. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    7. NVIC_InitTypeDef NVIC_InitStructure;
    8. TIM_DeInit(TIM2);
    9. TIM_DeInit(TIM7);
    10. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2|RCC_APB1Periph_TIM7,ENABLE); //TIM2时钟使能
    11. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); //使能PORTA时钟
    12. //IO
    13. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //GPIOA0
    14. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
    15. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; //速度100MHz
    16. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
    17. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //下拉
    18. GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化PA0
    19. GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_TIM2); //PA0复用位定时器5
    20. //TIM2配置
    21. TIM_TimeBaseStructure.TIM_Prescaler= 0; //定时器分频
    22. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
    23. TIM_TimeBaseStructure.TIM_Period= 0xFFFFFFFF; //自动重装载值
    24. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    25. TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
    26. TIM_TIxExternalClockConfig(TIM2,TIM_TIxExternalCLK1Source_TI2,TIM_ICPolarity_Rising, 0); //外部时钟源
    27. //TIM7 100ms
    28. TIM_TimeBaseStructure.TIM_Prescaler= 18000 -1; //定时器分频
    29. TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
    30. TIM_TimeBaseStructure.TIM_Period= 1000 -1; //自动重装载值
    31. TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    32. TIM_TimeBaseInit(TIM7,&TIM_TimeBaseStructure);
    33. //中断
    34. NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
    35. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0; //抢占优先级3
    36. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级3
    37. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
    38. NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
    39. TIM_ITConfig(TIM7,TIM_IT_Update,ENABLE); //允许更新中断 ,允许CC1IE捕获中断
    40. TIM_Cmd(TIM7,ENABLE ); //使能定时器5
    41. TIM_Cmd(TIM2,ENABLE ); //使能定时器5
    42. }
    43. u32 TIM7_LastCnt;
    44. //频率为TIM_ExtCntFreq
    45. void TIM7_IRQHandler(void)
    46. {
    47. char str[ 32];
    48. TIM_ExtCntFreq=(TIM2->CNT-TIM7_LastCnt)*( 1/SAMPLE_PERIOD); // SAMPLE_PERIOD为采样周期0.1s
    49. sprintf(str, "%3.3f",TIM_ExtCntFreq/ 1000.0); //必须加这一句,莫明其妙
    50. TIM7_LastCnt=TIM2->CNT;
    51. TIM_ClearITPendingBit(TIM7,TIM_IT_Update);
    52. }


    缺点:


    1. 无法测量占空比,高频的占空比测量方法见下文。


    2. 在频率较低的情况下,测量精度不如思路 3 (因为测量周期为 100ms ,此时如果脉冲周期是 200ms ……)。


    3. 输入幅值必须超过 3V 。如果不够或者超出,需要加入前置放大器。


    总结:这种方法精度很高,实测在 2MHz 之下误差为 30Hz 也就是 0.0015% (由中断服务程序引发,可以使用线性补偿修正),在 25MHz 之下也是误差 30Hz 左右(没法达到更高的原因是波形发生器的最大输出频率是 25MHz^_^ )。同时,从根本上解决了中断频率过高的问题。而由于低频的问题,建议:在低频时,或者加大采样间隔(更改 TIM7 的周期),或者采用思路 3 的输入捕获。


    此外,还有一个莫名其妙的问题就是,中断当中如果不加入 sprintf(str,"%3.3f",TIM_ExtCntFreq/1000.0) 这一句, TIM_ExtCntFreq 就始终为 0 。我猜测是优化的问题,但是加入 volatile 也没有用,时间不够就没有理睬了。



    思路五: ADC 采样测量(概率测量法)


    一般的高端示波器,测量频率即是这种方法。简而言之,高速采样一系列数据,然后通过频谱分析(例如快速傅里叶变换 FFT ),获得频率。 F4 有着 FPU 和 DSP 指令,计算速度上可以接受。但是 ADC 的采样频率远远达不到。官方手册上声明,在三通道交替采样 +DMA 之下,最高可以达到 8.4M 的采样率。然而,根据香农采样定理,采样频率至少要达到信号的 2 倍。 2M 信号和 8.4M 的采样率,即使能够计算,误差也无法接受。所以, ADC 采样是无法测量频率特别是高频频率的。


    但是,无法测量频率,却可以测量占空比,乃至超调量和上升时间(信号从 10% 幅值上升到 90% 的时间)!原理也很简单,大学概率课上都说过这个概率基本原理:

    当采样数n趋于无穷时,事件A的概率即趋近于统计的频率。所以,当采样数越大,则采样到的高电平占样本总数的频率即趋近于概率——占空比!


    因此,基本思路即是等间隔(速度无所谓,但必须是保证等概率采样)采样,并将这些数据存入一个数组,反复刷新。这样,可以在任意时间对数组中数据进行统计,获得占空比数据。

    以下是代码,使用了三通道 8 位 ADC+DMA 。理论上,采用查询法也是可以的。
    
     
    1. //ADC1-CH13-PC3
    2. //DMA2-CH0-STREAM0
    3. #define ADCx ADC1
    4. #define ADC_CHANNEL ADC_Channel_13
    5. #define ADCx_CLK RCC_APB2Periph_ADC1
    6. #define ADCx_CHANNEL_GPIO_CLK RCC_AHB1Periph_GPIOC
    7. #define GPIO_PIN GPIO_Pin_3
    8. #define GPIO_PORT GPIOC
    9. #define DMA_CHANNELx DMA_Channel_0
    10. #define DMA_STREAMx DMA2_Stream0
    11. #define ADCx_DR_ADDRESS ((uint32_t)&(ADCx->DR))//((uint32_t)0x4001224C)
    12. void ADC_DMAInit(void)
    13. {
    14. ADC_InitTypeDef ADC_InitStructure;
    15. ADC_CommonInitTypeDef ADC_CommonInitStructure;
    16. DMA_InitTypeDef DMA_InitStructure;
    17. GPIO_InitTypeDef GPIO_InitStructure;
    18. /* Enable ADCx, DMA and GPIO clocks ****************************************/
    19. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
    20. RCC_AHB1PeriphClockCmd(ADCx_CHANNEL_GPIO_CLK, ENABLE);
    21. RCC_APB2PeriphClockCmd(ADCx_CLK, ENABLE);
    22. /* DMA2 Stream0 channel2 configuration **************************************/
    23. DMA_InitStructure.DMA_Channel = DMA_CHANNELx;
    24. DMA_InitStructure.DMA_PeripheralBaseAddr = ( uint32_t)ADCx_DR_ADDRESS;
    25. DMA_InitStructure.DMA_Memory0BaseAddr = ( uint32_t)&(ADC_DATAPOOL[ 0]);
    26. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
    27. DMA_InitStructure.DMA_BufferSize = ADC_POOLSIZE;
    28. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    29. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    30. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    31. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    32. DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    33. DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    34. DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
    35. DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
    36. DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    37. DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    38. DMA_Init(DMA_STREAMx, &DMA_InitStructure);
    39. DMA_Cmd(DMA_STREAMx, ENABLE);
    40. /* Configure ADC3 Channel7 pin as analog input ******************************/
    41. GPIO_InitStructure.GPIO_Pin = GPIO_PIN;
    42. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    43. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
    44. GPIO_Init(GPIO_PORT, &GPIO_InitStructure);
    45. /* ADC Common Init **********************************************************/
    46. ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
    47. ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
    48. ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
    49. ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
    50. ADC_CommonInit(&ADC_CommonInitStructure);
    51. /* ADC3 Init ****************************************************************/
    52. ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
    53. ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    54. ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    55. ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    56. ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
    57. ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    58. ADC_InitStructure.ADC_NbrOfConversion = 1;
    59. ADC_Init(ADCx, &ADC_InitStructure);
    60. /* ADC3 regular channel7 configuration **************************************/
    61. ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, ADC_SampleTime_480Cycles);
    62. /* Enable DMA request after last transfer (Single-ADC mode) */
    63. ADC_DMARequestAfterLastTransferCmd(ADCx, ENABLE);
    64. /* Enable ADC3 DMA */
    65. ADC_DMACmd(ADCx, ENABLE);
    66. /* Enable ADC3 */
    67. ADC_Cmd(ADCx, ENABLE);
    68. }
    69. 主程序:
    70. for(j= 0;j<ADC_POOLSIZE;j++)
    71. {
    72. if(ADC_DATAPOOL[j]> 0x01)
    73. posicnt++;
    74. }
    75. duty= 100*posicnt/( float)(ADC_POOLSIZE)+ 0.1f; //线性补偿

    缺点:

    1. 精度低:实测 2MHz 下误差约 1.3% ,低频时无法统计(比如,频率 10Hz ,而 ADC 采样时间 50ms 。这时如果采样时间中刚好全是高电平,占空比为 1 ……)。

    2. 内存占用大:数据池大小为 65536 ,占用了 64KB 内存 。

    3. 有响应延迟:测量出来的是“平均占空比”而非“瞬时占空比”。由于我测试时使用的是波形发生器,输出波形相当稳定( 1W+ 的价格毕竟是有它的道理的……),实际应用当中一般不能够达到这样的水平,势必带来响应延迟(准确说应该是采样系统积分惯性越大)。

    4. 幅值过低( 0.3V )无法测量,过高则超过 ADC 允许最大值。所以必须视情况使用不同的前置放大器。

    实际上使用时如何取舍,就需要看实际情况了。毕竟,这只是低成本下的解决方案而已。



    综上,对这几种方法做一个总结:

    外部中断:编写容易,通用性强。缺点是中断进入频繁,误差大。

    PWM 输入:全硬件完成, CPU 负载小,编写容易。缺点是不稳定,误差大。

    输入捕获:可达到约 400kHz 。低频精度高, 10Hz 可达到 0.01% 以下, 400kHz 也有 3% 。缺点是中断频繁,无法测量高频,幅值必须在 3.3~5V 之间。

    外部时钟计数器(首选):可达到非常高的频率(理论上应当是 90MHz )和非常低的误差( 2MHz 下为 0.0015% 且可线性补偿)。缺点是低频精度较低,同样幅值必须在 3.3~5V 之间。

    ADC 采样频率测量法:难以测量频率,高频下对占空比、上升时间有可以接受的测量精度( 2MHz 下约 1.3% ),低频下无法测量。幅值 0.3~3.3V ,加入前置放大则幅值随意。

    ADC 采样频谱分析:高端示波器专用, STM32 弃疗。


    我采用的方法是:首先 ADC 测量幅值并据此改变前置放大器放大倍数,调整幅值为 3.3V ,同时测量得到参考占空比。而后使用外部时钟计数器测量得到频率,如果较高( >10000 )则确认为频率数据,同时 ADC 测量占空比确认为占空比数据。否则再使用输入捕获方法测量得到频率、占空比数据。

    对于各个方法存在的线性误差,使用了线性补偿来提高精度。一般情况下,使用存储在 ROM 中的数据作为参数,当需要校正时,采用如下校正思路:

    波形发生器生成一些预设参数波形(例如 10Hz , 10% ; 100K , 50% ; 2M , 90% ……),在不同区间内多次测量得到数据,随后以原始数据为 x ,真实数据为 y ,去除异常数据之后,做 y=f(x) 的线性回归,并取相关系数最高的作为新的参数,同时存储在 ROM 当中。

    我认为,我的这篇文章,应当是很全面了。当然,限于水平,存在着未完善和不正确的地方,也欢迎指正。


    展开全文
  • 我们在本文中提出一种将固定化的人工光系统I(IAPSI)组装在微流控芯片中的一步方法,该方法在一个芯片中集成了预先形成的石墨氮化碳光催化剂(g-C3N4)和电子介体(M)并模仿了特性g-C3N4和M的同时组装可以在可见光...
  • 标定是结构光三维立体视觉测量系统中的关键一步,标定的准确性对测量系统至关重要。基于镜头的畸变规律,提出了一种新型的系统标定方法,即以光轴为中心分隔同心圆环,形成多个子标定区域,通过反向投影标定法一一...
  • MT方法是一种被动的地质勘探技术,它基于对地球表面电场和磁场变化的同时测量。 Tikhonov(1950)和Cagniard(1953)发现,可以从这些测量结果中计算出复杂的比率,称为阻抗,描述了地球内部电磁场的渗透。 然后将...
  • 压缩感知测量矩阵构造方法研究

    万次阅读 多人点赞 2017-08-03 10:23:11
    测量矩阵的设计又是压缩感知的关键一步。如何设计出采样效率高,重构效果好且易于硬件实现的测量矩阵是我们必须考虑的问题。所以,探索它的设计方法具有重大意义。 本文首先通过常规压缩技术和压缩感知的对比,...
  • 视觉测量

    千次阅读 2019-08-01 16:31:55
    1.1 视觉测量技术 1.1.1 现代检测技术的发展趋势 检测技术是现代化工业的基础技术之一,是保证产品质量的关键。在现代化的大生产之中,涉及到各种各样的检测。随着工业制造技术和加工工艺的提高和改进,对检测手段...
  • 使用 STM32 测量频率和占空比的几种方法

    万次阅读 多人点赞 2017-11-01 15:26:30
    以前在本科时写的教程文章,主要是把自己当时参赛的...【教程】使用STM32测量频率和占空比的几种方法(申请置酷!) 这几天在论坛上面解答了好几个询问STM32测量频率的贴子,觉得这种需求还是存在的(示波器、电机
  • 该系统利用四套线结构光传感器来测量路面特定点的三维数据,通过激光测距仪获得距离信息,提出了一种测量系统运动颠簸误差修正方法,设计并研制了颠簸误差传感器。设计了一种新型全局平面靶标,可一步同时完成多个...
  • 光谱测量实践教程

    千次阅读 2020-01-03 11:26:41
    • 测试方法:在上午11:30~14:30进行测量,也可以提前到10:00。每种地物光谱测量前,对准标准参考板进行定标校准,得到接近100%的基线,然后对着目标地物测量;为使所测数据能与卫星传感器所获得的数据进行比较...
  • 直流调速器检修方法如下: 1、检查电枢碳刷,碳刷的长度,接触面和弹力都合适; 2、检查换向环,表面应平整,无凹痕,无损伤,沟槽没有被碳粉短路; 3、检查测速反馈部件与电机非负载测的连轴节没有问题。 4、检查...
  • 自动驾驶基础——惯性测量单元(IMU)

    千次阅读 2019-03-18 15:12:40
    例如在车道保持、车道偏离预警、车距保持,障碍物警告中,需要预测本车与其他车辆、车道、行人等在未来一段时间内的状态,并做出下一步动作决策。这项技术相当于自动汽车的“驾驶脑”,以算法为核心,并通过半导体等...
  • 视觉SLAM笔记(34) 三角测量

    万次阅读 2019-10-13 15:12:04
    对极几何约束局限性(仅通过单张图像无法获得像素的深度信息)、三角测量(通过在两处观察同一个点的夹角,确定该点的距离)、于噪声的影响,这两条直线往往无法相交,可以通过最小二乘去求解、三角测量的矛盾
  • 2.检查电流表、电压表指针是否在零刻度,如果偏差,要讲指针调至零刻度线对齐。3.根据实验电路图,将电路元件逐一连接好,电压表和电流表接入电路时,要选择合适的量程。即电压表选择0—3V(或3.8V时,选择0-15V)...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 39,684
精华内容 15,873
关键字:

一步的测量方法