你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

[复制链接]
北京小王儿 发布时间:2009-3-25 18:05
今天是3月9号,再过3个月就要大学毕业了,最近工作找得郁闷。干脆躲回实验室,总结下我的毕业设计,算是把自己的大学画个句号吧。
6 N. V% j' V! E5 e9 D. A% i' F3 ~1 o) x( @8 E1 d! ]
1 概述 4 W) L0 s+ C: Q3 e$ J& a
毕业设计的题目是“基于STM32的简易示波器设备驱动的研究”,就是利用STM32的AD采集波形数据,然后通过它内置的USB2.0把数据传到PC上面显示出来。框图如下。

* ~/ {$ e7 n7 d/ a% h( e
+ a& B0 Y& G  |  P# Q7 I: z# y题目一共是两个人做,我和我搭档耗子。他做信号处理,采集部分。我做USB在PC下的驱动开发,以及上位机界面的显示。USB固件那部分我们是一起完成的。 - j. [7 p: N  m' \5 k; b2 K9 Q( r
  这个课题从08年10月开始,到12月圣诞前夕基本完成。最后基本实现了波形的显示,实测最大可以测量的频率是200KHZ, / V) P( T9 a+ r
效果图如下:
" O) l. |, B$ A3 e% m" Q

: d. L, M; G0 ^
3 v& q. g; I0 p( {  }# S+ f5 B+ u2 ^5 I' D! `  N. x4 a
<font color="#000000">方波的图形好像不是很漂亮会有上升沿老是有尖刺,还需要作软件做处理。没截出来,   C" l) u" Q0 F# h6 k- M

* g4 u9 d% J; Y8 M# |  最后能出数据离不开很多前辈的经验。有些地方是借鉴了他们的东西。现在先列出来。 ; a" [4 j0 F. ?& R3 T" p
第一个是21IC上面alien2006原帖地址。他也是做了一个简易示波器,但是用的是以太网传输。采集部分我很多借鉴了他的方案。 $ ^3 ~/ J* ]3 i/ S/ m% o7 n9 N
第二个是电脑圈圈,他对USB的理解令我钦佩。我能搞出驱动,他提供的源码包非常重要,有些代码也是直接在他的基础上修改的。 , z' T3 e3 H; L
' ~! Q# S0 r" @
2 整体方案 % Y) @2 o. l8 d$ j7 |- a; g* B
  先说下一次完整的采集,比如外面进来的波形是正弦波,波形电压有正负,STM32单片机的AD只能采集0~3.6V的电压,所以要对信号进行 处理。也就是需要一个模拟前端电路,把电压抬上去。接着就是采集了,STM32的AD可以用外设进行触发,这里用定时器进行触发。每过一个单位时间AD开 启一次,采集一个点,这样采集的频率只要调整这个单位时间也就是定时器就可以控制了。采集了一桢数据,比如200个点。DMA中断被触发,开启USB,把 数据发送到上位机,然后显示出来。
& ^* Q/ O: o2 D% m0 m  整个过程大体就是这样了,还有一个很重要的环节补充下。熟悉示波器的人都知道示波器有个触发概念。像刚才这样显示的话,比如前一帧数据是波 峰开始显示,后一帧是波谷开始。这样显示出来的波形就是乱的,于是为了解决这个问题,就需要做触发,也就是保证每次采集的起始电位相同。我们的采用的是用 外中断的形式,外面波形数据先不采集,先让它通过一个比较器,比如比较器的基准电压是1V,也就是每次都和1V比较,低于1V输出低电平,高于1V输出高 电平。当数据电压大于1V的时候,比较器输出高电平,高电平接到单片机外中断口,这样外中断就被触发。然后开始采集,这样就能保证每帧数据的起始点都相 同。
1 ^' C3 Z. V  K  这个方案是大体方案,后来做了下修改。就是让AD一直在采集。外中断触发了后开启的是DMA,AD一直开着,只是控制DMA什么时候去取。从哪里开始取,取多少个点。下位机部分不再详说,贴下主要的程序,大侠们随便看看,多多指教。 " q  C7 l8 [  I  j9 \
定时器设置代码如下: 1 u/ J  Z" a* a' U! t; f
/*******************************************************************************
* G5 e8 E6 x) V; j* Function Name  : TIM_Configuration
2 T+ Y2 z0 W4 Q* Description    : Configure the TIM2.
, r% I+ u  c4 S& H2 i  t$ \0 i*******************************************************************************/ + E0 y& i: N5 a1 S
void TIM2_Configuration(void)
0 J' C, y: i# {( \1 Q& s0 }. e* n{ 6 T# X# \" P/ ^8 y
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure; ! F/ t+ i" a& V2 u
  TIM_OCInitTypeDef  TIM_OCInitStructure; $ x% l) ]4 X" |6 p9 T" J
   
. O: ~5 O" i6 A+ _0 P& ~  TIM_DeInit(TIM2); //TIM2初始化 # j7 f; Q  B' E7 m0 g
     
* b" l0 |' T' ^! i5 C. j  /* Time base configuration */
+ {) w2 m/ X% s, ~! J3 q3 H0 _  e+ b  TIM_TimeBaseStructure.TIM_Period = 18; //设置了下一个更新事件装入活动的自动重装载寄存器周期的值
. X5 N/ O4 O# r( N# x' M  TIM_TimeBaseStructure.TIM_Prescaler = 0; //设置了用来作为TIMx时钟频率除数的预分频值 4 D( {  b. D$ Y
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;  //设置了时钟分割
6 E/ U; e, F* ?3 `- ~5 F( V  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //选择了计数器模式向上计数
/ \! m/ K' f3 w$ X. r
# i( c% F: x2 u  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx 2 [+ o4 q' c0 F- Y5 I
- u2 L5 V4 z! ^! k0 b8 [. Q
  /* Prescaler configuration */
( T9 t! R- r" ~//  TIM_PrescalerConfig(TIM2, 1, TIM_PSCReloadMode_Update); //设置TIMx重载次数 预分频值在更新事件装入 , F: F# Y. c4 N7 X& h: n& {8 V" h
  ' R- y+ B& h$ Y" c& @6 J
  /* TIM_OCMode_Toggle Mode configuration: Channel2 */
9 h; D* n2 ]0 J: h9 b; i  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;           
7 J* _5 D( ^8 M2 L3 I  TIM_OCInitStructure.TIM_Channel = TIM_Channel_2;             r4 c0 q2 a9 {  ~3 N# _6 s+ I8 {
  TIM_OCInitStructure.TIM_Pulse = 9;   6 W5 k5 ?5 m, h) r" }" C/ m
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;  //TIM输出比较极性低
; e: E; ^1 f. b& [( n     ( m7 o1 I! Y1 }& Y9 W  X
  TIM_OCInit(TIM2, &TIM_OCInitStructure);
5 g( |9 Y2 ?' k! A5 f   6 ?# u/ g2 X6 r3 R- M
  TIM_ARRPreloadConfig(TIM2, ENABLE); //使能或者失能TIMx在ARR上的自动装载寄存器 7 D' w3 ]! v8 Z- Y
   6 l: d5 T  |% a$ p- q6 S9 h6 B
  /* TIM2 enable counter */
/ G9 i9 L  b& F- z; o/ U' }  TIM_Cmd(TIM2, ENABLE); //使能TIMx外设 2 G' Q! G  ^- V; i( m
}
2 H' k6 Y1 T7 j( k) l+ M$ hAD以及DMA设置代码:
. s2 X9 U! }, k' l/*******************************************************************************
' c+ H1 h: u4 D7 j* Function Name  : ADC_Configuration * o$ ^7 n1 y7 K$ S- u, b4 e
* Description    : Configure the ADC1. % v# s- N, |5 f8 a+ l% Z9 [4 M
*******************************************************************************/ $ a7 w2 X3 Z/ {/ N
void ADC_Configuration(void) . H3 p0 A: `3 l$ I: C1 d# v
{ + C, L* k" p. s* l- P* n5 W
  /* DMA channel1 configuration ----------------------------------------------*/ $ c1 H2 g$ |7 h
  DMA_DeInit(DMA_Channel1); //复位DMA_Channel1
$ f1 c3 R5 j& B( c7 X1 S0 `2 r6 }+ h  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //外围设备地址 1 f; d, j+ O; O% W
  DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_Data[0]; //memory 地址
8 w# c! Y5 v6 Q7 _/ v2 W  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外围设备做为源 1 k% S; u( w" ~$ Q' @
  DMA_InitStructure.DMA_BufferSize = 1024;  //数据单元尺寸
9 ]9 }0 U. X9 r, y' u4 Z  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外围地址是否自动增长 disable不增长
  m0 q4 N1 M7 ~9 n/ P2 j/ n* ^3 ~+ O  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //memory 是否自动增长 / N, n: L0 b1 f! ]
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外围设备寄存器尺寸16位
% x2 V2 O, ~2 Z  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  //memory尺寸16位
+ `( _" S! p& b, G  K  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //DMA 循环模式 2 U0 a% m* h4 ^0 {% X
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;  //DMA 通道优先级
( n7 A$ z8 I7 r! d5 y  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //memory- to-memory转换 7 l7 j2 `* u& b. h( T
  DMA_Init(DMA_Channel1, &DMA_InitStructure);  //初始化DMA通道1 ( L' Q9 u) \0 I" i/ o0 d' `

* k' o6 d% j5 a+ l3 J+ }  /* DMA IT enable */ 6 ?/ |8 c% C0 i2 u, t$ y0 N
  DMA_ITConfig(DMA_Channel1, DMA_IT_TC, ENABLE); //使能DMA传输完成中断 7 }. @% {% c" ^* u) a4 H2 f
  7 H& w2 a: Z/ ~. R7 x: m
  /* ADC1 configuration ------------------------------------------------------*/                                                      
% b- `: ?* k0 ^) V* K1 g: T  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  //ADC 工作模式 ADC1 ADC2 单独工作     3 @  v9 N* E, L- r/ t. }
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;  //多通道扫描模式
& m: P4 k9 V! r% U' Q  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //是否启用连续转换模式 ; u( ^6 z. d% k0 ^4 \' j
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;  //触发方式
4 `, @- ~& C& w- R/ b  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;   //数据右对齐 5 h; Z/ F, l9 H8 L) J5 s6 a
  ADC_InitStructure.ADC_NbrOfChannel = 1;  //ADC规则转换通道数量
; T7 Q! u9 y8 ?5 G4 q4 u  ADC_Init(ADC1, &ADC_InitStructure);
* N+ a0 v3 L, y4 K
, S6 r# A. }) l8 o  /* ADC1 regular channel10 configuration */ //配置转换规则 8 |. i- t% u5 a4 z$ H: U/ ~, L
  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_1Cycles5); 2 T9 u8 a! G7 t5 J- t2 F
   ( x3 ^* {! F) s5 n) f
  /* Enable ADC1 DMA */
, u3 |0 R8 n3 y3 C% \: O  ADC_DMACmd(ADC1, ENABLE);
7 Y5 V  v0 S0 y' D2 S
) [% n8 }- Z, K4 G4 M  }& |& ]3 M  /* Enable ADC1 */
! D  Y) J6 L" H+ A  ADC_Cmd(ADC1, ENABLE);
$ Q* {+ [. A5 i7 O  {2 \" k- ^1 a- b, u: Q' @/ a% F! Y- J
  /* Enable ADC1 reset calibaration register */
- G4 r- R6 ~4 a  h5 r" e1 U  ADC_ResetCalibration(ADC1);  //复位ADC1 校准
7 ]* c0 e# M: Y  R' j1 J9 d( H  /* Check the end of ADC1 reset calibration register */ ; R( J6 s6 c  W( N
  while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位完成 ( Y9 ?, H3 Z& X. Q) \3 j& y$ U) Y

% w; e9 _; \1 |( b+ |) ]) A  /* Start ADC1 calibaration */ ; T/ P  u+ x9 N
  ADC_StartCalibration(ADC1);  //开始ADC1 校准转换
, P8 R) N9 K! M0 {  /* Check the end of ADC1 calibration */ 0 z( s5 Z; ?; q# }$ L! r
  while(ADC_GetCalibrationStatus(ADC1));  //等待转换完成
8 \) B9 ~. [$ u   / v& Q* m7 W/ K4 Z" S- E* ?# D
  ADC_ExternalTrigConvCmd( ADC1, ENABLE); //使能或者失能ADCx的经外部触发启动转换功能 ; U# V  x4 O  I7 ^% P& n: n8 p
}
! [% g9 c! M( A+ b1 {1 p$ A9 F( U
+ i, t' F+ B  ^6 z1 z: M3 SDMA中断服务程序: . R0 Q. W4 \' S; o
/******************************************************************************* ' Z# L# t& P# K8 E5 i  c% r9 z
* Function Name  : DMAChannel1_IRQHandler
5 T7 r4 \5 ]+ ^( J* Description    : This function handles DMA Stream 1 interrupt request.
( U: A* v2 c0 X*******************************************************************************/ / i. u( K6 f/ D
void DMAChannel1_IRQHandler(void)
$ K$ S; p, Y5 X{ 3 Z4 G/ J( t3 O; e5 E
  DMA_Cmd(DMA_Channel1, DISABLE);  //关闭DMA通道1
$ }. r8 a- [' G( }; l  for(count=64;count
1.jpg
赞 收藏 1 评论38 发布时间:2009-3-25 18:05

举报

38个回答
xujiantj 回答时间:2019-1-23 13:39:11
不错,谢谢分享
dongxu1234 回答时间:2018-1-31 19:19:36
good the code ?
qinshi1208-3586 回答时间:2009-3-26 09:39:26

RE:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

不错,不错
sfq2008-104893 回答时间:2009-3-26 10:04:21

RE:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

不错,不错.不过STM32本身的AD慢了点,建议用外置的AD,如:ADS830
- `' H% F% Y  s" @2 m$ S0 t. h3 O呵呵,双踪的呵呵......
sfq2008-104893 回答时间:2009-3-26 10:06:11

RE:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

还有,我觉得这个做得不错,楼主可以参考一下
5 C% ~0 u" {% V' Shttp://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=2228838&amp;bbs_page_no=1&amp;bbs_id=3043
dacong 回答时间:2009-3-26 12:40:56

回复:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

学习了!
hzrobin 回答时间:2009-3-26 13:56:24

RE:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

楼主大人,你怎么转帖人家的文章,把作者的信息给删了呢
dujun168 回答时间:2009-3-26 23:14:21

回复:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

不错,在校生能有这样的水平很难得!
HansLiu888 回答时间:2009-3-31 16:27:42

RE:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

very good!
yzl624358 回答时间:2009-4-3 13:34:22

回复:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

楼主真强,学习下!!!!!!!!!!!!!!!
lucky-92214 回答时间:2009-4-13 19:06:16

RE:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

very good!
山水-95029 回答时间:2009-4-25 16:08:31

RE:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

很好
. y( i" a( }1 M% L& k) h3 e不错
Janechao 回答时间:2009-7-1 09:38:19

回复:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

不错不错,好好参考一下。我是初学STM32呢
avr386 回答时间:2009-8-29 06:25:37

RE:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

XXXXXXXXXX
ken48172 回答时间:2009-9-30 14:51:41

RE:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

supercxy 回答时间:2009-10-16 17:16:55

回复:我的毕设总结-用STM32的高速AD和USB2.0做简易示波器

' \, O* F  V  w# y& r& u( \8 f& F8 I
强烈支持阿9 t4 I, i+ M& ~2 d8 ]
最近adc正看不懂呢
123下一页

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版