本帖最后由 strang 于 2018-12-12 16:08 编辑 7 Y( c4 B' B) Y" Z
9 z6 M; b0 d3 q0 a0 D: q* M" t4 |编辑原因:上传代码不全,补齐代码。 1 C( Y' N' h( [. L4 E* T
在“野火助力,书香醉人—第四轮书籍申请 ”活动中申请到了《STM32库开发实战指南---基于STM32F103》 一书,此书共分基础篇和提高篇,46章,693页,内容非常丰富,全面讲解了各个外设和代码分析,火哥的例程写的很详细,移植起来非常方便,而且例程也很接近项目实际应用,在此感谢意法半导体STM32/STM8技术社区,感谢野火提供的书籍,感谢工作人员! 一、NVIC中断优先级 NVIC优先级分5组,主优先级数字越小优先级越高,子优先级在主优先级同等下,数字越小优先级越高。用到哪个中断,就用对应的中断源和使能中断。 下面是使能串口1的中断,同时设置抢占优先级为1,响应优先级为2的初始化方法: - static void NVIC_Configuration(void), m& ^; ]( S7 V
- {
! E/ I$ l( k l2 u; J' J+ } - NVIC_InitTypeDef NVIC_InitStructure; T* \5 |, H e
- /* 嵌套向量中断控制器组选择 */
6 I- B% P! P' [/ m* J( P/ M - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);! F2 m$ i, G" }" d! [6 B
- /* 配置USART为中断源 */, g8 o o, u1 m; w( }
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQ;/ \4 \# m/ O, m1 ^9 y' Q( H, M
- /* 抢断优先级*/
) O( O {5 c. E - NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
+ P* g' ]. G9 F" i- S1 S - /* 子优先级 */
6 c1 l" [- Y4 q! \. }2 I' U: w - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;( z% Q7 f4 Z9 X4 q7 R5 @
- /* 使能中断 */
/ Q6 p! [* @0 W3 M+ e. e - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
4 @8 O Y5 y2 R) | - /* 初始化配置NVIC */
' R i1 K/ J/ `1 e4 M! H1 L - NVIC_Init(&NVIC_InitStructure);
! Z( j; J, t4 T) ?# ]* X' X( i3 X" ~ - }
复制代码二、DMA---直接存储器访问
# L& T U3 m3 L( h4 sDAM有DAM1和DMA2两个控制器,DMA1有7个通道,DMA2有5个通道。 DMA传输数据的方向有3个,外设到存储器,存储器到外设和存储器到存储器。 1. 串口DMA配置:(从存储器到外设) - void USARTx_DMA_Config(void)( ]" E, `3 B0 k# H* V3 t
- {5 G3 G; e2 n. P! \- A$ j
- DMA_InitTypeDef DMA_InitStructure;9 n. `6 {6 Z4 t: e; T1 B
- // 开启DMA时钟; S, c h |/ p |: ^8 Y
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);) G6 Z2 i" g/ E0 j
- // 设置DMA源地址:串口数据寄存器地址*/
]! y6 Z m' P( n. R9 ? - DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;0 u3 [, l2 M% G Q' [) n
- // 内存地址(要传输的变量的指针)
6 o; n( ]% p7 G9 r% q0 s4 [ - DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
1 y. P9 y( [" [ - // 方向:从内存到外设
2 E' n: D* M' B3 L/ [ - DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
8 A: x7 D% F; s - // 传输大小 8 A+ ]. }; N! J) D% {8 H
- DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
5 b1 F9 Q% o. N) n( [# u" h - // 外设地址不增
% s" H; c- t8 T2 o/ S a - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;; P* s K2 p" k/ x: r4 K z
- // 内存地址自增5 b; R$ P5 ?' @2 ^4 s* h3 Y, ?
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
& I, c# K8 h0 R! F5 m - // 外设数据单位
1 s2 D7 w& \. r - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;6 v% v! U1 ^" z* E( c
- // 内存数据单位
" c/ Z2 ?7 G) k7 D6 c/ _0 q' }/ I: I - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; k$ ^& M N: u, s
- // DMA模式,一次或者循环模式2 d2 T' \! p' ^# q, O9 Z6 }
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;- v7 y8 g& h9 ?- Z7 C+ G, b2 `1 h" F' }
- //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; * q) c4 e' n- u$ p% A3 E7 E
- // 优先级:中 9 T2 d8 r X# m, }6 d0 u) @
- DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
. @" E. [/ b; P' V - // 禁止内存到内存的传输& ~# ]) `1 _1 d. p+ |' c% o! D. ~
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;& y) |4 s1 ?5 ^( S! k# K0 q! y2 P
- // 配置DMA通道
6 {2 B$ t8 O; D1 j - DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure); 3 D: e/ A d6 J- M2 D
- // 使能DMA
/ m0 I! |: I/ w2 ]. @4 r - DMA_Cmd (USART_TX_DMA_CHANNEL,ENABLE);
- f8 j' X0 b- X/ _ - }
复制代码 2. 配置ADC1的工作模式为DMA模式(从外设到存储器)4路ADC- u16 AD_Value[N][M]; //用来存放ADC转换结果,也是DMA的目标地址$ U+ ~/ p8 c/ K6 L
- u16 After_filter[M]; //用来存放平均值之后的结果 C1 [/ B5 L% @- O
- ( F7 s) `2 g! s$ ?; ?& N
- //使能ADC1和DMA1的时钟,初始化PC1-PC3端口9 E# |* x! k3 F4 f# u
- static void ADC1_GPIO_Config(void)/ f8 a: _- U7 ]* B9 M
- {5 p2 r6 p6 v6 j9 e5 o
- GPIO_InitTypeDef GPIO_InitStructure;# o+ T2 `4 K' }+ Q+ y
-
$ q/ s' Y3 e7 [ - /* Enable DMA clock */, `6 O6 _" p) K9 r3 u3 b* b
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
. i5 E$ _# o4 B! N; L3 ? -
% h8 o+ O0 j# ?; j ` - /* Enable ADC1 and GPIOC clock */# P8 i1 Q9 q2 ^5 I. c3 p
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
! i7 y7 W5 u) B2 ?8 \9 B% O -
) @9 B* I; _0 x% y7 | - //PC 作为模拟通道输入引脚
. n( u, G7 ] ?- y! n0 W' z - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
8 ~$ d8 C L/ J/ s/ W" o7 s - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
L% s* K" _1 U - GPIO_Init(GPIOC, &GPIO_InitStructure);
& h4 A. \6 m( k6 M* i" l2 e. G - }1 J4 a3 A g( c. Z
. r% x9 {3 M. c: k6 s0 Q# I- //配置ADC1的工作模式为DMA模式2 G1 v3 |( v) c& Y- {0 z/ Y
- static void ADC1_Mode_Config(void)5 R7 s# Z( f! L0 R: L, F6 Z
- {
^$ ?9 N+ K/ H J - DMA_InitTypeDef DMA_InitStructure;) u) N& i& `' F
- ADC_InitTypeDef ADC_InitStructure;0 n: [( J; I, c
-
6 l; [9 ^! }3 S' f( Y: _ - /* DMA channel1 configuration */
$ e. }# m/ v. Q5 t, T1 _ - DMA_DeInit(DMA1_Channel1);1 u" l: V# ~! Q5 ^$ [# m. h8 ]* x2 W
- DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;* A& @$ X5 g$ \. P% T1 J5 E
6 h# d! ^2 v; e6 X! S/ g# J- //内存地址 7 ?/ C+ V0 E( p
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value[0][0];6 o% z/ i7 j3 b/ U9 Q
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
2 ]" s1 ?6 y3 C4 N - DMA_InitStructure.DMA_BufferSize =M*N;
* `! k& f) X4 ]/ C - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
' ~6 i( W3 T9 }$ `0 w& {& ^ - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;6 D$ `4 g: h4 d T
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;/ i& B5 S% Z0 B8 j, m
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;! N4 P1 {" \3 r, w8 v
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
8 D4 @; | I( J A0 n( O - DMA_InitStructure.DMA_Priority = DMA_Priority_High;( y. i) y# ~( v I! F
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- \0 m C; m" Q; { - DMA_Init(DMA1_Channel1, &DMA_InitStructure);
2 h3 S7 K4 k1 l! c - 6 m2 H% R( [9 Y# z3 E; B$ l/ S
- /* Enable DMA channel1 */) z9 C Q* m5 K! O2 Y# t: D: ^
- DMA_Cmd(DMA1_Channel1, ENABLE);( u. g6 Q6 i( k8 e5 w: F3 s+ x
- " ?9 j; |5 w7 r, U
- /* ADC1 configuration */
9 ^3 X0 o; I( l4 @7 V - ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;' B& K7 p1 K. I1 Y. n9 b
- ADC_InitStructure.ADC_ScanConvMode = ENABLE;( C- Z+ A( S1 _
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
# x9 i1 N& u- L7 N; ` - ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;6 Y7 h! U6 s. a+ M/ s. i/ L4 B
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
! i' z: I3 m- I$ E) H9 X- m - ADC_InitStructure.ADC_NbrOfChannel = M;% m* W' q% L" p$ j$ d0 P! c' |
- ADC_Init(ADC1, &ADC_InitStructure);# a' V" `9 \% }6 i; F8 X" V% m6 |
- . L: |9 |5 @- U. k( J# T6 @
- /*配置ADC时钟,为PCLK2的8分频,即9Hz*/
: K+ j- P% P, Q - RCC_ADCCLKConfig(RCC_PCLK2_Div8); & I6 e* O; h+ o' j0 X. m
- /*配置ADC1的通道11为55. 5个采样周期,序列为1 */ : ] ]; i- j3 F* [ j9 o W+ h
- ///ADC_SampleTime_239Cycles5 ADC_SampleTime_55Cycles5" j) M' d( d! D- K9 Q. {
- ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5);
2 _- L: M9 Q! e5 t, G - ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5);
- R c+ n6 ^2 b9 |# f4 C - ADC_RegularChannelConfig(ADC1, ADC_Channel_12 ,3, ADC_SampleTime_239Cycles5);
) v# d2 V1 @' y- a: B! G0 m - ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5);, Y/ w" q0 o/ Y3 O
-
* h# J, n. O% S# h" A ? - /* Enable ADC1 DMA */
6 Y8 N2 t2 ^! N, T - ADC_DMACmd(ADC1, ENABLE);
" t& z. v1 c7 I - 4 H- p7 h) C4 b" W o( @- H; e
- /* Enable ADC1 */
, y/ O" t$ u5 s* i/ Z - ADC_Cmd(ADC1, ENABLE);/ z) p0 O5 W: d9 }- O! P6 n
- " V: O$ l9 u. i3 q6 N
- /*复位校准寄存器 */ 2 E" i9 E$ q9 ^5 F% j+ V5 Z8 v
- ADC_ResetCalibration(ADC1);
; w# h# _0 z0 q$ f - /*等待校准寄存器复位完成*/$ P0 R/ E' x2 N+ {; s! ^9 K. g
- while(ADC_GetResetCalibrationStatus(ADC1));7 C) K# K: v; Z7 h6 T# @
- g! V+ e# P3 r4 c$ t7 a
- /* ADC校准 */
3 i' f3 L2 L9 V+ V5 O p& H2 c T - ADC_StartCalibration(ADC1);
) S$ e7 ]& x, O! z" K - /* 等待校准完成*/
5 e# ?9 ^) h+ m) j% v; P8 S% Q' K4 s - while(ADC_GetCalibrationStatus(ADC1));
( [2 Y0 _) l% e- Z, b) u - + l: r& z" N R. F
- /* 软件触发ADC转换 */ 5 P" g O! r9 v# d, ?1 E
- ADC_SoftwareStartConvCmd(ADC1, ENABLE);
U3 @! e6 \6 E5 u5 t - }
' C2 l2 ]$ A, d3 G0 q: n - /* ADC1初始化*/
% w' q4 l4 G. E2 q1 |! `, w1 G - void ADC1_Init(void)
1 u/ h, N- `- r, V w. l6 R( w - {2 G+ |) `$ T" c- w; `7 O# T
- ADC1_GPIO_Config();
5 G' m6 o/ b( ?& ?+ I - ADC1_Mode_Config();1 _: X3 e# N/ o: G
- }
复制代码- /*ADC滤波*/3 K3 U. t, b# j
- u16 MultiDMAGetAdcTest(u8 ch)
0 ]+ J1 A8 e: ]: ]- ~' e. x x - {
& R" H1 j; Q% P- l: V1 E! s - u8 i;
w; E9 w( Q/ c A3 j - u32 AdcMax,AdcMin,AdcSum,AdcResult,Adc_temp;# I7 S3 T* _: @* a! N7 C) S7 \6 ~& D
- volatile u32 ADC_Data;8 }6 O$ z4 t4 G5 O- I7 L/ B
- i9 C/ N/ J+ ~: l7 Z! b, S1 y( K
- ADC_Data=0;
' a) W# }$ V8 C4 y2 B2 } - , F+ q. n' B7 F, |5 {, B0 F3 v a: V' H
- AdcMax=0;) [$ v+ h. G n# X1 m. z- f# X) ~
- AdcMin=~0;
7 x" O$ v9 e5 {" y, ]7 w# Z - AdcSum = 0;
7 H$ y& M1 ~* d: Z" P6 z - Adc_temp = 0;; n1 E" ~7 C) N& j/ s6 a! f
- - t0 M9 E6 X& d( j
- for(i=0;i<34;i++)! k9 s* h% v2 [8 B! [; @( r
- {
& H' Y3 F' w ^ - Adc_temp =AD_Value[i][ch];
& a% w9 ~' G K! w& N* d2 W - if(Adc_temp>AdcMax)
% A' I7 z+ h. _, F9 |6 F - {7 x {: y9 \0 L
- AdcMax=Adc_temp;; t2 ` o; W+ T3 L
- }
7 c/ c" ~) z0 P8 j2 n - if(Adc_temp<AdcMin)
8 @3 Z* \8 i1 m- j" e# w - {
. U& y% r- Z _( Y7 o5 O. o s j - AdcMin=Adc_temp;# z) g# ~7 R: O! O% g
- }4 p( L/ C4 a3 I
- AdcSum+=Adc_temp;
) h7 n9 I" Z! r, c" B1 I& U: Z% R. ] - }2 t# k- b( W* p. B8 h2 j
- AdcResult=(AdcSum-AdcMax-AdcMin)>>5;
2 `( p( f# n4 M8 L5 j+ R3 b6 [ - After_filter[ch]=(u16)AdcResult;( g% R" B. x: G/ T' F
- return(After_filter[ch]);
& X9 e/ \7 [# j - } ! x$ X+ u: H0 s" L9 q# R) T
- /*获取ADC1通道0的值*/; k5 O/ |6 `/ E% Y3 x3 ` q
- uint16_t AD_Leach(void)1 i8 f$ d) A8 @, F, @: b% _
- {; R) N9 y I- C# x5 Q
- uint16_t adcx1; ?$ h& Q* a+ ]! H0 e
- adcx1=MultiDMAGetAdcTest(ADC_Channel_0);1 n. J7 S8 {9 s( b: v7 c
- return(adcx1);
2 \- M$ u! ?5 ~, o& o) s) y9 h9 `* J Q - }3 W$ k7 S6 Q0 u4 Y0 X) x; X
- /*获取ADC1通道1的值*/
- Z: ^% O- N# w- J) l' U' @ - uint16_t AD_Leach_1(void)' `' |1 ~; R4 u2 J- u
- {4 {+ W' L, d+ I; x$ y0 K, l
- uint16_t adcx2;
4 }5 o6 H) m/ c9 V - adcx2=MultiDMAGetAdcTest(ADC_Channel_1);
% ?6 E& r3 z* g8 K; N2 R! A! K - return(adcx2);
0 N) `. R3 }- [6 N; s% t- j - }
* r! L! Z" ], O- ^, G* J - /*获取ADC1通道2的值*/ j; `% F f- v) D
- uint16_t AD_Leach_2(void)
# s/ g4 {' e( R - {; F* C$ T: |: {% {5 { d
- uint16_t adcx3; a0 ]( ?5 j6 ^8 ~" [4 ]- J, R6 A
- adcx3=MultiDMAGetAdcTest(ADC_Channel_2);
6 X. I# @0 C$ v, G- \3 W9 W5 k/ Q - return(adcx3);
3 f2 s; B' Y: ]( ~2 B4 u - }
$ a- x; g* ]5 b0 M. x7 O0 V - /*获取ADC1通道3的值*/
b1 n" y$ G& I, |4 o - uint16_t AD_Leach_3(void)6 D, M# P% ?! y+ m0 q; e& v) ~
- {
) c% X% C4 j: R, Y. X" D5 z - uint16_t adcx4;
8 X2 b1 c6 Q j0 H/ o" A - adcx4=MultiDMAGetAdcTest(ADC_Channel_3);
9 L) v/ I A# a% Z1 P - return(adcx4);: Z4 R, v: ^# k; \! Y) q: M
- }
复制代码 5 p" n. P6 t, r
& u3 R. Z6 j$ |5 U H3 ~4 z/ Q
目前就学习到这里,后续再写!" b+ L; S/ V- @5 V& B# t
* |5 g; b" N; o p; s0 S( _
5 @- ]! S+ `. e4 O) z/ n: U& F( b( _( [7 T
|