本帖最后由 strang 于 2018-12-12 16:08 编辑
9 |& [/ [* P! Y9 ~* I2 x8 f- Q% X# F" ?1 q( Y
编辑原因:上传代码不全,补齐代码。 + `, q$ W8 `; W
在“野火助力,书香醉人—第四轮书籍申请 ”活动中申请到了《STM32库开发实战指南---基于STM32F103》 一书,此书共分基础篇和提高篇,46章,693页,内容非常丰富,全面讲解了各个外设和代码分析,火哥的例程写的很详细,移植起来非常方便,而且例程也很接近项目实际应用,在此感谢意法半导体STM32/STM8技术社区,感谢野火提供的书籍,感谢工作人员! 一、NVIC中断优先级 NVIC优先级分5组,主优先级数字越小优先级越高,子优先级在主优先级同等下,数字越小优先级越高。用到哪个中断,就用对应的中断源和使能中断。 下面是使能串口1的中断,同时设置抢占优先级为1,响应优先级为2的初始化方法: - static void NVIC_Configuration(void)0 d7 N) ~* O( R! s. D' L% ]
- {
/ X/ F* k1 d' ~4 g( M - NVIC_InitTypeDef NVIC_InitStructure; j) Q# k8 r( ^) i* s7 H% L
- /* 嵌套向量中断控制器组选择 */
( }% c B; h" |0 u. o - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);9 ]! S$ K) g2 F% l5 c
- /* 配置USART为中断源 */
8 J5 ]6 u3 q* I8 i* a6 D7 o - NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQ;
0 a5 i. f0 R/ ^* F9 N - /* 抢断优先级*/" M3 M+ k/ f8 t. w/ R1 B
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;/ X! f# e1 B- g8 ^! F/ F) f5 C
- /* 子优先级 */
2 {# C7 o) s4 Q* K" z - NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;2 w- m8 l. k& C1 d9 A
- /* 使能中断 */
1 w, o$ y8 \' }- k4 H - NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;8 x1 W8 k6 N4 o. T' C8 z; w$ p
- /* 初始化配置NVIC */) H9 f" B$ [3 T+ h, k
- NVIC_Init(&NVIC_InitStructure);! N6 E, l* x" e) }
- }
复制代码二、DMA---直接存储器访问
! ~9 V: {- K. m3 F0 }5 m7 z. a" K+ hDAM有DAM1和DMA2两个控制器,DMA1有7个通道,DMA2有5个通道。 DMA传输数据的方向有3个,外设到存储器,存储器到外设和存储器到存储器。 1. 串口DMA配置:(从存储器到外设) - void USARTx_DMA_Config(void), e* g5 ?7 t3 s* ]
- {
1 I( C( x% D8 J6 |2 Z( ^6 i t - DMA_InitTypeDef DMA_InitStructure;5 J& S& E, D4 S
- // 开启DMA时钟& g" H/ ~( O4 ~; k1 {. Q6 ^5 \- t
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);6 O$ i+ A( t" Y5 Z
- // 设置DMA源地址:串口数据寄存器地址*/
# c6 a4 {" m) I; h. M - DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
% ]! E0 \1 W) `" `% e1 e8 x4 b - // 内存地址(要传输的变量的指针)
8 [* y3 R$ \0 ^5 D - DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
6 C3 w) W" N' E! |7 v% l1 a" m - // 方向:从内存到外设 # A+ ]" \( s1 X1 w7 O/ Q" U/ Z
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;0 S, V( K# d( W( k5 [
- // 传输大小 - `6 I/ n5 w( n
- DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;6 N$ t ? g4 h( X1 G K8 P
- // 外设地址不增
3 ~- E6 B- l6 m, L" W6 a - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
, e/ A/ e1 ~8 D2 |$ t3 Y7 ^/ O3 e - // 内存地址自增9 d4 u; b5 D# v; M+ P) X7 U# n
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;2 Z, `' U. x8 d0 B0 |4 _# s9 j
- // 外设数据单位 ) _' i$ U: u1 T
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;" a7 e6 `; _- r+ z Q$ v
- // 内存数据单位
3 G1 g5 O# B0 N& p" Q- { - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; , ]# H" S+ a, W
- // DMA模式,一次或者循环模式6 d: R8 w- E5 ]! I; l
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;! H; `3 j7 r }8 }. H6 j3 x
- //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; % J3 h# b1 ?+ [% W4 m
- // 优先级:中 4 U- j" J+ D7 G0 m) r# x
- DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; $ Z: K& c* y- j
- // 禁止内存到内存的传输8 [9 d8 Q6 b" f
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; F: p9 ?7 \( K5 Y0 B% R
- // 配置DMA通道
3 g. @% {/ s' M8 g l - DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure); - h+ c- E* }+ j* _9 k/ r U5 s
- // 使能DMA1 z( P( f U. j: x- N3 ~% Y
- DMA_Cmd (USART_TX_DMA_CHANNEL,ENABLE);
$ [& s \% m2 o - }
复制代码 2. 配置ADC1的工作模式为DMA模式(从外设到存储器)4路ADC- u16 AD_Value[N][M]; //用来存放ADC转换结果,也是DMA的目标地址+ V. w( _/ ]: r; D$ @
- u16 After_filter[M]; //用来存放平均值之后的结果, S* L" I: `5 @ C
- 2 k d, l/ M( g6 A7 n+ _* Z
- //使能ADC1和DMA1的时钟,初始化PC1-PC3端口2 y1 A# g6 e- m' Q& @
- static void ADC1_GPIO_Config(void): q" F2 u* T' ^4 |& [3 R- p9 I
- {1 ]% A: r0 |- W( d) G) y0 m6 F- D8 i$ n
- GPIO_InitTypeDef GPIO_InitStructure;, T) Z* L1 O& _: p0 F/ P! Y' [
- 8 e5 k4 W. Y$ ?4 u+ ~6 M
- /* Enable DMA clock */
2 \' M3 p w6 E4 D, j - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
2 ~* I7 ~1 n, _% u" [ W8 n1 y - , i) |* {4 o% o: c* w
- /* Enable ADC1 and GPIOC clock */# V7 K, n& k2 X% Q
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
, G3 {5 Q' ~4 ~2 `) H9 K - / d' o- F" g! X
- //PC 作为模拟通道输入引脚 7 Q$ b7 W: j2 z: K
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;/ p- E5 |/ F8 G. m" g& b: F
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
" b8 e' N0 @3 G/ C) o2 c - GPIO_Init(GPIOC, &GPIO_InitStructure); 1 y1 a" e1 {" W* ^
- }% k, Z, E5 M5 H; c3 Y7 U0 b
- & X1 @6 N7 S- S4 i5 x7 |& ~* k) \
- //配置ADC1的工作模式为DMA模式! l4 U4 K+ m2 U# C5 x8 m
- static void ADC1_Mode_Config(void) q* r- c' v3 [' H4 M6 d* |/ w
- {
5 z; Z3 z- \- ~# R! Y/ }, u( I - DMA_InitTypeDef DMA_InitStructure; `" S* ]' B" Q0 G4 D0 o' D% G
- ADC_InitTypeDef ADC_InitStructure;
0 G! Y9 ?4 k7 @$ r! }" @ - 9 T- J; U7 S- Z
- /* DMA channel1 configuration */
0 D/ b" u' z) @2 i6 T - DMA_DeInit(DMA1_Channel1);
! _/ f! U4 r2 N* y' k$ h - DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;2 | O* _2 I/ J- R% _% n
- . T7 c; \( R) z6 a$ G0 ]+ v$ c
- //内存地址
$ z+ r: {, `! W, L% E) K - DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value[0][0];( z: N( c u) @* A
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
4 p, o0 H7 N7 f - DMA_InitStructure.DMA_BufferSize =M*N;# j3 D* _1 x; V2 x
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
: v; X3 i1 w0 u" w4 \$ o - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;! U) y+ J R$ T
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
9 o$ n+ a7 [+ A0 y$ p$ _ - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;( {/ W9 ?' C5 }) u1 Z( a1 \
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;: _/ f* w. \" J
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;( {$ x4 F3 v3 j+ w) f
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
3 W3 ^9 T9 }: } - DMA_Init(DMA1_Channel1, &DMA_InitStructure);
! G* \$ j. g- w) R. O1 k* y& D: R -
' f: X7 D2 i- t/ U* V% f! Z* c; w: W - /* Enable DMA channel1 */6 Q( [, [% A2 D* Q2 \
- DMA_Cmd(DMA1_Channel1, ENABLE);
" P, S" t% @6 J) k: P- }% x -
5 H* u9 ]2 D: ^' E# t - /* ADC1 configuration */
/ Q( g3 u ]6 B) D - ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;5 J8 ?4 Q$ N# p
- ADC_InitStructure.ADC_ScanConvMode = ENABLE;" j. M7 E+ ?! @% p ^
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;1 [8 h4 k# R* v l' c, L
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;- s% {" }7 N& {5 C/ H9 `
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;9 f" ]! ^: `( {6 j- f! Q. |- Q
- ADC_InitStructure.ADC_NbrOfChannel = M;: I) D; B6 J5 s# P/ n6 |$ Y/ c I4 y
- ADC_Init(ADC1, &ADC_InitStructure);
3 K' _5 T% c3 I/ F - ! ^% [% A6 @8 Y5 ]% }1 c# |
- /*配置ADC时钟,为PCLK2的8分频,即9Hz*/6 k: b' b1 N/ `
- RCC_ADCCLKConfig(RCC_PCLK2_Div8); . G' m8 v6 D; f$ m# I: H. I
- /*配置ADC1的通道11为55. 5个采样周期,序列为1 */
& d9 W* `; d# r0 n4 ~; j0 p& V) | - ///ADC_SampleTime_239Cycles5 ADC_SampleTime_55Cycles58 s- D. \" t" |9 x
- ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5);; f: m- S1 t2 \8 j
- ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5);. [9 H8 t5 G1 M4 S$ e. x
- ADC_RegularChannelConfig(ADC1, ADC_Channel_12 ,3, ADC_SampleTime_239Cycles5); 1 ?% c( W9 V$ v% O2 u
- ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5);/ p) |( b, ^" o/ ~
-
8 w0 N' A/ Q$ ?/ P3 q8 @/ w$ i - /* Enable ADC1 DMA */+ m" H) [5 i/ T; f( v
- ADC_DMACmd(ADC1, ENABLE);
- H! C; S* R, |+ | -
3 e3 Q# Y) i! \8 s - /* Enable ADC1 */6 Q [! G9 R" }* @
- ADC_Cmd(ADC1, ENABLE);2 M1 Y# g6 s: f4 H# a/ ]
-
8 m0 e, g3 P& n! e3 @6 w4 c1 g - /*复位校准寄存器 */
# {5 e* x' p1 r' q - ADC_ResetCalibration(ADC1); Q! k( i6 e7 C8 P0 t0 S
- /*等待校准寄存器复位完成*/
; M, Y+ ]0 a5 b9 i8 G& o4 N) S - while(ADC_GetResetCalibrationStatus(ADC1));! p8 H7 }9 K( r" E$ u3 _! W
-
% c$ o# Q' w- |2 U# Y( K$ p - /* ADC校准 */' b/ c$ L2 t. \- f) S
- ADC_StartCalibration(ADC1);, P/ m( [6 T- ? ]' v7 x
- /* 等待校准完成*/) d0 ?. m6 {7 F5 ~/ L
- while(ADC_GetCalibrationStatus(ADC1));
/ Y" L* M. x. A; O9 Q( B" o -
- L; i- m" D$ u$ V - /* 软件触发ADC转换 */ / q$ m2 o* N4 Q" v% W" z, J- I4 F
- ADC_SoftwareStartConvCmd(ADC1, ENABLE);9 P! B' A. Y" C7 l7 S# v
- }3 u* C4 ?+ Y$ R$ D
- /* ADC1初始化*/
+ h% }+ C7 K1 ]5 x! Z; J( [ - void ADC1_Init(void)+ l. m0 M6 b$ r0 O
- {
4 y) d8 f+ T4 u$ t7 e - ADC1_GPIO_Config();0 Y- C0 d3 X2 s' f( O& B
- ADC1_Mode_Config();
( S( s' i: O) D. d* H2 Z, z0 d6 Q - }
复制代码- /*ADC滤波*/. s& A* d9 P5 D% N$ n- Z \9 z
- u16 MultiDMAGetAdcTest(u8 ch)$ @# G0 q% b% i. y1 T3 o
- {: q$ y2 M' y/ |. z$ }' ?" v { `
- u8 i;% F4 \; s% M. q( b& P/ }% I
- u32 AdcMax,AdcMin,AdcSum,AdcResult,Adc_temp;/ t1 S$ t' i- n
- volatile u32 ADC_Data;
4 L, [. T+ x1 f7 E! J) F) }0 o7 R - ; W) V, s5 g, L6 D8 Q9 U& E
- ADC_Data=0;+ ~/ ?# z" B* U1 R" L/ K! ~
- ; t/ [. V) Q" s& i- m6 Q2 ?/ S4 M
- AdcMax=0;
" F3 ^2 E w3 a0 p3 a" |. W - AdcMin=~0;
) D9 P% X# o) Z" A7 n - AdcSum = 0;) V% \6 x6 q9 N& z: C/ {/ u
- Adc_temp = 0;
K2 Q. X0 V5 ]: G' m- d6 t7 e! A - % A& ^5 _! m p; A: a) k
- for(i=0;i<34;i++)
3 u4 ~, W' p4 k, f - {4 q* o1 Q) _8 A+ I
- Adc_temp =AD_Value[i][ch];+ R- v+ t7 [% S& w) d
- if(Adc_temp>AdcMax) + [+ `5 }1 g+ x# o3 T+ ] s
- {" o' N/ I: y5 r8 @& J) u
- AdcMax=Adc_temp;# ~7 B2 D4 c: [% z$ m# X. E6 p( U2 E
- }) Q4 c. E0 @, N* Y" w2 n, l3 K
- if(Adc_temp<AdcMin)
1 [- c/ A( L+ l* i0 e - {. [8 b8 h2 }1 |+ t" W# I z; q
- AdcMin=Adc_temp;
5 }7 S4 ^+ q: \. ^* y- \ - }
, U& o2 a& g) N9 r3 l" | - AdcSum+=Adc_temp;1 Y& `$ ^3 b' v! Z1 Z
- }
0 s0 l5 Q# @- u- Q1 b/ C - AdcResult=(AdcSum-AdcMax-AdcMin)>>5;
' K4 B/ r& I5 D) \! O - After_filter[ch]=(u16)AdcResult;
7 h5 D h5 ?6 [$ X9 W3 _) A - return(After_filter[ch]);' m. l; P& X! G$ B% [
- }
& V6 r( Z. @' T5 \ - /*获取ADC1通道0的值*/7 G2 d! d6 ]7 v H( A9 B1 N5 k8 @+ q
- uint16_t AD_Leach(void)
a0 o" j+ q7 o. u9 K0 k& f; u- C - {- {: s% M7 K1 }+ o5 J/ i j' y( {
- uint16_t adcx1;
7 v' ]7 t7 c. g2 d j& _; b/ D - adcx1=MultiDMAGetAdcTest(ADC_Channel_0);
* ^ C9 `& F4 s - return(adcx1);
% M) y8 y5 H5 A! z9 X7 u - }* `3 z2 h' A3 L) D: h
- /*获取ADC1通道1的值*/
8 p/ t3 e: P, e: S# W - uint16_t AD_Leach_1(void)
- K/ s4 G' p* x1 [8 h6 k' l$ |$ t% h - {
1 F' c' f+ j. p9 g" Q- o - uint16_t adcx2;
0 b* |' G; f& O _$ J% w2 D - adcx2=MultiDMAGetAdcTest(ADC_Channel_1);
# v# v/ R, E" C% H8 v. s: H - return(adcx2);) T% G" @6 U/ v; i" R. t4 o
- }) Q9 C$ w! Y# F9 K+ k. |$ p3 e
- /*获取ADC1通道2的值*/
& Q, |+ L4 P: T1 o; e - uint16_t AD_Leach_2(void); U1 M% p4 N1 B5 s- [
- {2 k( L% H) c+ @1 k5 Y& g# M
- uint16_t adcx3;$ ~$ o8 E8 e3 I8 l' e9 b
- adcx3=MultiDMAGetAdcTest(ADC_Channel_2);
! s8 q" G* Z9 A4 C' w* E - return(adcx3);2 K" R( G# ?1 X/ J4 r$ {
- }0 t, o" l6 V) y ^. S
- /*获取ADC1通道3的值*/! q3 E! T) G4 J5 G
- uint16_t AD_Leach_3(void)( @/ d* {; O9 ^, o% i& P0 o
- {
3 X' b( W8 L0 ?+ }3 O, w - uint16_t adcx4;% l0 J* S3 ~4 I2 d/ }5 l0 t5 j
- adcx4=MultiDMAGetAdcTest(ADC_Channel_3);! T" S9 g$ z, n$ c- W9 j
- return(adcx4);$ a O6 K7 B0 u. V9 o# C
- }
复制代码
* Y5 O, W) M9 u+ ~
+ N1 K9 ^# i( k* }) Z }: r目前就学习到这里,后续再写!
4 U8 D, G% s- K) G8 B! u
/ a6 M; {$ _# j: ?
$ x) _$ v6 P. H+ c/ T1 `- t8 [- G3 ~/ F K9 r, s5 K) Q
|