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

双路ad同时触发,可以同一时刻采集两路ad信号的,很实用

[复制链接]
sun-2034138 发布时间:2016-10-14 15:02
本帖最后由 sun-2034138 于 2016-10-14 16:02 编辑
1 a$ ~& L8 i- o8 F2 c. q
# W0 m/ O2 V  ?; ?0 Q双路ad同时触发的的代码。应用adc,dma,tim。用的不是hal库而是老版本的固件库和寄存器操作来进行的。f103实测
& T( o7 R3 |2 _1 z
: q4 Q$ I- n' n3 r7 f% Y
7 H0 z' D% J: I) z
STM32 的通用定时器是一个通过可编程预分频器( PSC)驱动的 16 位自动装载计数器( CNT)" F; O- A) A; W" J8 C' P
构成。 STM32 的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波
( L; x. \* p6 s$ s/ U) K形(输出比较和 PWM)等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形
) i$ `6 T! _3 i4 x: T, B# Y周期可以在几个微秒到几个毫秒间调整。 STM32 的每个通用定时器都是完全独立的,没有互相. ~9 z' o7 @9 v5 ]: C0 J! J. p$ G
共享的任何资源。
2 Y$ G& Q2 ~3 S) k3 `STM3 的通用 TIMx (TIM2、 TIM3、 TIM4 和 TIM5)定时器功能包括:
7 |6 g5 o( H( J/ u' O/ z$ }- D1)16 位向上、向下、向上/向下自动装载计数器( TIMx_CNT)。
+ l# D, o2 g% X/ G9 h$ Z# P2)16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为 1~, T0 f+ m4 f7 Z+ f% p% u: W
65535 之间的任意数值。
: Y/ J8 ?0 R  G/ U3) 4 个独立通道( TIMx_CH1~4),这些通道可以用来作为:
0 {% H0 I3 @& [6 a7 J. ]% QA.输入捕获( H8 c' g! m' {" j$ b
B.输出比较9 s! u) X( t' l% i) N3 Y% U/ N2 X
C. PWM 生成(边缘或中间对齐模式)% N6 f" k5 Z6 V9 q; `
D.单脉冲模式输出
/ v- D, K! M( N4 H4)可使用外部信号( TIMx_ETR)控制定时器和定时器互连(可以用 1 个定时器控制另外1 R/ t6 k/ |4 X' n+ V" C' W
一个定时器)的同步电路。& P* Y+ E0 E; g, m$ P1 O
5)如下事件发生时产生中断/DMA:
' V& G5 a0 H; `5 ]9 sA.更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)) y" _& R& e  U6 H' `8 c4 q  S! S) T
B.触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)) R6 ~% ^! h& S! g( n0 l5 {
C.输入捕获% d9 m1 g) L- d% a
D.输出比较. S4 d3 p6 L8 N* P
E.支持针对定位的增量(正交)编码器和霍尔传感器电路* J3 m7 {6 {: Z
F.触发输入作为外部时钟或者按周期的电流管理8 P; Z6 j; q1 U1 ~$ ]* u; r5 w4 a

* p9 r% N$ H# f, d7 y$ ?

' J8 ~2 z' `( y$ P  Ktim主要寄存器 CR1 DIER PSC 这三个寄存器是基础;7 S, |- Y( V# x" ~; X8 `
定时器的时钟来源 内部时钟(用cube看时钟树最方便了),外部输入脚,外部触发输入,内部触发输入(用其他定时器做预分频);& L- P: C% A8 l2 b% s& e
有一点值得注意的是也是很多人忽略的问题!ARR实际上是两个寄存器,他同串口的那个USART->DR的类型都是影子寄存器(类似寄存器还有几个呢)所以更新时间根据CR1的APRE位状态看是否更新,不详说看手册;
7 S3 Q$ f2 G! i: k* WSR寄存器看更新;
3 [& w' [) c) z9 K2 h' J, Q" r2 Y& I8 _6 w4 g
5 q& B. O7 I$ \, [# _6 _3 h4 A
pwm是我最常用的一种功能,先说说这个。要想控制pwm:1 F. f/ N/ |7 k
1.看好时钟源和使能;
9 ]' N& P2 F0 G, A. d/ C
% l) c, Q1 K9 y2.看是否复用,如果复用开启afio看映射的对不对AFIO->MAPR;" S0 i; z% j) [4 h
3.设置好ARR:自动装载数值(对于初学者来说就是你打算让他一次数多少个数);
9 t& D: N, Z- F" e( s4.设置好PSC:预分频(对于初学者来说就是用内部时钟确定数一个数多久),更新的话看CR1的APRE位,不是你改了当时就更新的!!!* K' }& f& G- S3 E' A- `8 _6 k) f
5.CR1:使能还有你用的到的就打钩~;3 @" t8 z- ~/ e& p" s/ ~
6.CCMR1/2:分为两层 每8位控制一个通道!道理和配置gpio没啥区别。简单说下吧,当时我看这个也搞了好久。
9 H/ [1 D( \' e. k8 WCC1S[1:0]:捕获/比较1 (方向和引脚的选择,输出的话没啥说的就是你要输出的引脚,输入的话比如映射在TL1,2或者TRC上。对于初学者的困惑可能就是TL1是啥了,这个您看通用定时器框图,芯片手册上那个大图)pwm肯定输输出。
- N6 ?8 l. P  a" B$ hOC1FE: 输出比较1 快速使能  ~~~~~~这个是触发输入的 ,就是看灵敏性吧。一般我都默认,还能当个防骚扰~~~~
  t7 b5 @) I5 h' B
OC1PE: 输出比较1预装载使能:随时写入TIMx_CCR1寄存器是否当即生效;
; L( H; k' b% r4 ?
OC1M[2:0]:输出比较1模式:这个对于pwm来说只能是110或者111, R$ z; S, ^9 A: ?
OC1CE:输出比较1清0使能  ~~~~~~~~~~这个oc1ref在哪里呢? 捕获比较寄存器和输出控制器之间。这个东西是可以做触发另一个定时器的。什么pwm1还是2不过是电平的变化而已。
' w, j' @: a- }0 @* E7.CCER:只有两位CCXP(我都是默认高电平有效,不知道你想咋用呢) CCXE(必须为1因为输出)" m0 K( x4 k4 O3 ]" Z2 j! m* v: l  O
8.CCR1-4:傻子开始数数了 ~~~ (这个除ARR里面的数就是你的占空比了)/ e0 T& ]) n- u& i
9.高级的才看BDTR寄存器呢不管你想咋设置其他为moe必须为1才能是pwm;% F* a6 u4 d4 T9 h4 J3 y. ^
. n; a% [3 I, O- q8 t( [) u8 x! K/ E) V
$ ^2 N& m; P: i- q0 Y
之后 之后就有pwm了。。。别问我为啥因为刚刚都使能了。
5 W1 e0 {# U9 W6 r) D7 H$ r这样配置一遍寄存器就是新手也对这个一定有不少了解了,具体什么的功能看看手册吧
% m, B$ U( `+ ^
8 o/ `* f* X* w6 O$ m, o
5 \3 u4 E' }( N9 K5 D$ b# K' y4 O. o之后分享一个双定时器同事dma触发双路adc的代码吧 想玩的朋友直接添加中断服务函数就可以了。rct6的 绝对可以用~~~7 [% I  c) N% l  k* ]4 f" \
' h: }3 Q2 T; v  H, r2 L# c6 C
void  Adc_Init(void)
, I" H, G- l$ `+ D7 j* M7 a- F{
; p, V. J7 M; |9 N5 z6 v1 V# v        NVIC_InitTypeDef NVIC_InitStructure;        , ~/ ?" o7 E6 O2 M( a, E$ A, D
        DMA_InitTypeDef DMA_InitStructure; 8 ~# @5 V. W* H5 r
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;& j8 H! j) N  {9 c5 w, u3 l' C) Y
        
7 S3 l7 I9 C2 u1 ~. T8 S* J/ u0 U        
/ q* E# R1 M9 u        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
4 {0 ~/ i# n, N( X0 r4 F" ?        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //ʱÖÓʹÄÜ
* J2 o1 q. |) j9 C5 _/************************************tim2*****************************************/        
7 J* i0 y( F  L5 P        TIM_TimeBaseStructure.TIM_Period = 9999; //ÉèÖÃÔÚÏÂÒ»¸ö¸üÐÂʼþ×°Èë»î¶¯µÄ×Ô¶¯ÖØ×°ÔؼĴæÆ÷ÖÜÆÚµÄÖµ         ¼ÆÊýµ½10000Ϊ1s: ]" T/ I7 }; G* A" Q8 l& B
        TIM_TimeBaseStructure.TIM_Prescaler =7199; //ÉèÖÃÓÃÀ´×÷ΪTIMxʱÖÓÆµÂʳýÊýµÄÔ¤·ÖƵֵ  10KhzµÄ¼ÆÊýƵÂÊ  
( e* Q. H) y2 I" Z; V0 z        TIM_TimeBaseStructure.TIM_ClockDivision = 0; //ÉèÖÃʱÖÓ·Ö¸î:TDTS = Tck_tim# e" G: O8 t0 t
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIMÏòÉϼÆÊýģʽ
5 @8 ?  Z5 l3 }        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //¸ù¾ÝTIM_TimeBaseInitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯TIMxµÄʱ¼ä»ùÊýµ¥Î»
; B$ H9 n2 q" }, J6 s/ C! x# F8 h) E, R6 P6 t9 Y0 ]' U
        TIM_ITConfig(  //ʹÄÜ»òÕßʧÄÜÖ¸¶¨µÄTIMÖжÏ
+ e& M8 \1 p2 X8 E" Y5 q, r) T                TIM2, //TIM2( Y) ]# [# Q5 Q* i% B+ |
                TIM_IT_Update ,
" G3 A! @. |* N3 ~) o3 c3 T                DISABLE   //ʹÄÜ
! n9 U: w% k! e8 p5 G                );
  C/ J- P; `9 ]* @        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM3ÖжÏ
9 p2 M0 {; A, P- ]/ i7 |        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //ÏÈÕ¼ÓÅÏȼ¶0¼¶: U# b" f0 a4 C7 E2 E2 K, w
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //´ÓÓÅÏȼ¶3¼¶
! x& {- p- V, A: @/ a1 Y6 X        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQͨµÀ±»Ê¹ÄÜ- s9 ]( R" a; m
        NVIC_Init(&NVIC_InitStructure);  //¸ù¾ÝNVIC_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèNVIC¼Ä´æÆ÷
+ J/ Q! Q* l" t, d6 z
# M" P2 [2 |, M* O0 D* w- y: p        TIM_Cmd(TIM2,DISABLE);  //ʹÄÜTIMxÍâÉè
/ W$ M4 x8 e9 l: i* J; W        
7 [5 d& Y+ q0 V; I# [7 Y* C2 O! Y5 k/************************************tim3*****************************************/        
2 x) x4 d9 H( e0 L1 o  u# A+ H        TIM_TimeBaseStructure.TIM_Prescaler= 7199; //100k
; e+ K+ |  D/ F        TIM_TimeBaseStructure.TIM_CounterMode= TIM_CounterMode_Up;- B2 Y2 I' V0 J6 f% k, @
        TIM_TimeBaseStructure.TIM_Period= 30;  //; N5 ~! ]) l' c1 F% W! t( w6 O
        TIM_TimeBaseStructure.TIM_ClockDivision= 0;( ^) u! c! z' \3 k: @
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;0 W& g9 k: C4 t" f2 |% {6 ~" S: ~
        TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);! P2 ?" i; f) g9 l- U
        TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update);
  {- r/ M# X3 t
) u( `3 a/ R  T* ^4 H0 Q) ^# k% Q3 M        TIM_ARRPreloadConfig(TIM3,ENABLE);7 h. b( Z  e; ]5 H
        TIM_Cmd(TIM3,DISABLE);
' i) Y: j) T! I9 ?+ L; z7 `9 K        TIM_UpdateDisableConfig(TIM3,ENABLE);
/ N4 ?7 j( B2 a2 _% E, ]/ C  I        TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);, t; ^) u7 P6 R+ ?
        
- ?7 ?) T! T9 y- ~5 ^4 ~/ |        RCC->AHBENR  |=1<<0; // dma1
1 `4 J+ p4 R! {; [        RCC->APB2ENR |=1<<4; // GPIOC . ^0 k0 K9 U& ]1 K6 b7 ^
        GPIOA->CRL |=0XFFFFF000; // PC 0 1 2 INPUT
( G% N, R) _2 c# R" J$ j        DMA_DeInit(DMA1_Channel1);
! H6 x4 b( c' h; u        DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;
$ L) l' S& V; J( d0 L& T  DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)ADC_buff; " ~' k* K6 M. i. T' y
  DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;* E4 j( s3 u" w+ E+ L
  DMA_InitStructure.DMA_BufferSize=adccnt;
& y$ ~- a! o; p" T; ]; A" A% ^  DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
  ?. u8 j2 g" r- G- Z  DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;5 H8 G% L2 d: ~, f- Q
  DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;
: s8 C  S3 k( u% p; v3 ^  DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Word ;
2 W3 }$ a* n  g. E3 w$ h  DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;
, \8 P/ n3 j& d8 n! y. G7 O3 {  DMA_InitStructure.DMA_Priority=DMA_Priority_Medium;' ^# e8 `% {# T) S; ]# @
  DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;/ B, t- d. N0 Z/ m- K8 M) y
        DMA_Init(DMA1_Channel1,&DMA_InitStructure);$ n: N5 {6 n& O% @3 E+ L! S7 T
        DMA_Cmd(DMA1_Channel1,ENABLE);
! X2 v4 Q" r4 t' F/ C" S1 S3 d6 S        DMA_ITConfig(DMA1_Channel1,DMA_CCR1_TCIE,ENABLE); //chuanshu wancheng
; v8 n0 Z) }3 |4 U) q3 l* A9 r" ]        
& L4 K# L3 D$ p+ H/ a# C        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC1|RCC_APB2Periph_ADC2|RCC_APB2Periph_ADC3,ENABLE);          //ʹÄÜADC1ͨµÀʱÖÓ
: {0 C+ G; a, n7 D0 I6 ^- }
# h# x. @9 Q4 ?1 ^3 H- ?3 X! ^$ ~        RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //ÉèÖÃADC·ÖƵÒò×Ó6 72M/6=12,ADC×î´óʱ¼ä²»Äܳ¬¹ý14M
4 `7 \3 S* C5 }        //mode3 u6 r- [2 {# r  [9 R' @5 H
        1 S+ _3 b1 C; q; D# M4 ?
        ADC1->CR1 = 0x00060020;/ E$ x" i3 \" u) W) q* q
        ADC1->CR2 = 0x00180100;  // 0x00180100; ->0x00080100 ÓÉÍⲿʼþÆô¶¯¸ÃΪ²»ÐèÒªÍⲿʼþÆô¶¯! _5 Z' @% P. j, C: p& a( Z
        ADC_Cmd(ADC1, ENABLE);        //ʹÄÜÖ¸¶¨µÄADC19 H, ]: G& B* n9 ~3 ?" ~
        ADC_ResetCalibration(ADC1);        //ʹÄܸ´Î»Ð£×¼5 H4 b0 l' ]2 H. l* P+ V6 m
        while(ADC_GetResetCalibrationStatus(ADC1));        //µÈ´ý¸´Î»Ð£×¼½áÊø1 z) X' A+ {5 Z/ f/ E+ _
        ADC_StartCalibration(ADC1);         //¿ªÆôADУ׼
1 ~, f! T4 n' M- n        while(ADC_GetCalibrationStatus(ADC1));         //µÈ´ýУ׼½áÊø0 x: O* C* |) ~! u
        
2 F+ ^6 z; S8 G) F, Y" d  ADC2->CR1 = 0x00000000;4 V; p3 p/ N0 k& ~
        ADC2->CR1|= 1<<5;
! j4 X; t  m* G+ P; R1 s        ADC2->CR2 = 0x001E0100;  
9 o/ F- U1 t6 j1 p8 e0 ^9 F0 d# p        ADC_Cmd(ADC2, ENABLE);        //ʹÄÜÖ¸¶¨µÄADC1# ?9 V9 I* o- }9 L
        ADC_ResetCalibration(ADC2);        //ʹÄܸ´Î»Ð£×¼* E3 `% A  X/ Y5 E0 ]) B# i8 B
        while(ADC_GetResetCalibrationStatus(ADC2));        //µÈ´ý¸´Î»Ð£×¼½áÊø/ Z# Q. [1 m# R5 C
        ADC_StartCalibration(ADC2);         //¿ªÆôADУ׼: [. B" B6 A) v+ T
        while(ADC_GetCalibrationStatus(ADC2));         //µÈ´ýУ׼½áÊø
- e- a) X( ~" R( k        ADC_RegularChannelConfig(ADC1, ADC_Channel_10,1,ADC_SampleTime_55Cycles5);        //ADC1,ADCͨµÀ,²ÉÑùʱ¼äΪ239.5ÖÜÆÚ                                      
8 r5 o/ ?5 M/ R4 `& u( V& I4 _6 r7 i        ADC_RegularChannelConfig(ADC2, ADC_Channel_11,1,ADC_SampleTime_55Cycles5);        //ADC1,ADCͨµÀ,²ÉÑùʱ¼äΪ239.5ÖÜÆÚ                                      
! a! {3 ~* H. s0 V" \8 t( `1 d8 R8 N5 p; h  g# J6 u
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; //ʹÄܰ´¼üËùÔÚµÄÍⲿÖжÏͨµÀ
# }+ U, H. T7 k& U& [# l8 j" w        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //ÏÈÕ¼ÓÅÏȼ¶2¼¶
7 a4 _2 f$ q9 k! d1 v        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //´ÓÓÅÏȼ¶1¼¶
! ]4 s/ K+ ?$ f6 w+ `5 A1 A        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //ʹÄÜÍⲿÖжÏͨµÀ- f- R6 V* p( G1 a3 K1 @% j0 V  d
        NVIC_Init(&NVIC_InitStructure); //¸ù¾ÝNVIC_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèNVIC¼Ä´æÆ÷        5 `6 H; M2 `. g, C) S
//long i=0x 13833572189;
% ^  Y% c  v' e7 e  H4 o. A% ?0 {5 J/ Q
}
6 S. d5 A$ P) M# Q& R  d
4 G9 r) ~! f; K8 R: v
; s6 `0 L4 k' k" g- ^
$ x! H6 k' _. q4 Q3 i3 j  D) y8 ?
以下都是摘抄的笔记,好记性不如烂笔头就收藏了下来.代码能不能用我不知道 。
" }/ Z- y* x4 l6 m  m发布的时候字数太多发布上去了....我把连接弄来...还有好几个例程呢!
; H) v  \7 M3 q8 c4 I+ _
http://blog.sina.com.cn/s/blog_81e410670100wkd8.html7 F* d7 e" `! V# h5 M
其实,PWM模块还可以有很多花样可以玩,比方在异常时(如CPU时钟有问题),可以紧急关闭输出,以免发生电路烧毁等严重事故。

; B4 S- R% ~) i! }  v( n$ T
着重补充的是有的时候你在选择管脚的时候是需要注意afio的,选择全映射还是半映射什么的,一定要看好。不然闹的根本不行不行的。
而且这个不出波形的时候是一定要查看内部寄存器的如果没有问题,那么也要多多注意你选择的周期问题!!!!!!

6 [: D- r8 y9 d! t# Z3 K- O

评分

参与人数 1 ST金币 +20 收起 理由
zero99 + 20

查看全部评分

赞 收藏 3 评论10 发布时间:2016-10-14 15:02

举报

10个回答
mark0668 回答时间:2016-10-14 15:03:54
感谢分享!
Paderboy 回答时间:2016-10-14 15:48:20
多谢
sun-2034138 回答时间:2016-10-14 16:02:27
103的  提醒一下大家
zero99 回答时间:2016-10-26 06:49:59
学习了
andypanfan 回答时间:2016-10-26 12:35:14
assssdz 回答时间:2016-10-30 13:08:07
:):):):):)
disheng4688 回答时间:2016-10-30 16:05:28
谢谢分享,学习了。
andypanfan 回答时间:2016-12-13 09:22:24
学习了,多谢分享
原田夜舞love 回答时间:2017-9-15 10:10:45
学习了
五哥1 回答时间:2017-9-17 21:27:34
注释乱码了
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版