本帖最后由 strang 于 2018-12-12 16:08 编辑
! W0 d% }+ N/ y7 s) p8 `( t4 t8 [. Y, e/ F7 a
编辑原因:上传代码不全,补齐代码。 ! g# z3 i7 C( m4 j0 E
在“野火助力,书香醉人—第四轮书籍申请 ”活动中申请到了《STM32库开发实战指南---基于STM32F103》 一书,此书共分基础篇和提高篇,46章,693页,内容非常丰富,全面讲解了各个外设和代码分析,火哥的例程写的很详细,移植起来非常方便,而且例程也很接近项目实际应用,在此感谢意法半导体STM32/STM8技术社区,感谢野火提供的书籍,感谢工作人员! 一、NVIC中断优先级 NVIC优先级分5组,主优先级数字越小优先级越高,子优先级在主优先级同等下,数字越小优先级越高。用到哪个中断,就用对应的中断源和使能中断。 下面是使能串口1的中断,同时设置抢占优先级为1,响应优先级为2的初始化方法: - static void NVIC_Configuration(void)
6 _& m: c& \: @4 L - {! a/ H1 t7 Z$ e3 w9 a" T% t- k
- NVIC_InitTypeDef NVIC_InitStructure;3 {; D1 |1 W, o" e
- /* 嵌套向量中断控制器组选择 */! P- j# O: P! k) v/ q/ Q: n3 a z0 x
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
$ f) x+ k8 M7 [2 ^ - /* 配置USART为中断源 */, {6 Y% S- r! K7 d0 r
- NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQ;
* ~+ w( m7 |) a! e - /* 抢断优先级*/2 c* P+ o) e* w! N* A* b/ ?$ |
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;. o% c; L x& ]" \! H* Z
- /* 子优先级 */: K" ?/ ]7 p( K& d, O
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
1 c4 D+ ^' }7 @$ O( h - /* 使能中断 */$ G5 d/ R% K1 C: V, t9 J: t9 e
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
2 \% T2 |; B; k% o( h! g - /* 初始化配置NVIC */
/ ^0 r8 x, [2 h$ Q - NVIC_Init(&NVIC_InitStructure);
; n, n# M8 W2 p6 N4 E! h - }
复制代码二、DMA---直接存储器访问 0 Z( K! R1 b% b6 E& C0 j/ J
DAM有DAM1和DMA2两个控制器,DMA1有7个通道,DMA2有5个通道。 DMA传输数据的方向有3个,外设到存储器,存储器到外设和存储器到存储器。 1. 串口DMA配置:(从存储器到外设) - void USARTx_DMA_Config(void)
1 y. U: a# i9 [8 I6 U) g8 N' D$ _0 w - {
/ |3 y8 ~, s0 v$ I; g4 h+ R: j - DMA_InitTypeDef DMA_InitStructure;5 F$ a; m Y3 \& _% y
- // 开启DMA时钟
! b0 g. D) H6 s - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
8 \2 e6 C# U7 Z3 Z7 _2 ? - // 设置DMA源地址:串口数据寄存器地址*/. l) `% E+ [4 Y" s# v
- DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;5 W6 C6 z( j7 B% x" f# H) r
- // 内存地址(要传输的变量的指针)# |9 l5 a3 e/ w, Y. y8 m0 D$ z
- DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;
( _4 Q( G" Y5 z& ^ - // 方向:从内存到外设 6 N; I# U" @5 o2 ^3 `$ E5 a& V
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;" w8 G! r3 P$ @
- // 传输大小 / o6 A% [: r8 ]- u7 R) [% z4 X
- DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
( J4 V! @) `+ W - // 外设地址不增 - l2 `& l* G/ U; J
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;% |7 ~5 d; P4 V) `7 I$ ]* z
- // 内存地址自增5 ^( C' g3 c/ E% u6 n9 f+ u
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;6 [# r8 F. h6 S) g; i
- // 外设数据单位 * b% v3 c1 Y4 v2 ?$ U5 _; N, S4 f
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;# B% _, }/ w+ o
- // 内存数据单位
1 o6 ~+ L6 Q5 N# @8 i) ^! H - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; . G6 z; O, M: U f6 {
- // DMA模式,一次或者循环模式
6 A: V& [' o- x2 a+ s, l - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;( E8 j& Q) t( b* l# [* o+ K) W- y
- //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
, F8 D6 i+ b6 F8 z& g4 k - // 优先级:中 , d8 D& g$ r- `
- DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; 8 v' G$ Z* \! u) A8 r
- // 禁止内存到内存的传输0 f. ?9 w* ~6 f: k
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
) _" f/ A3 a2 F - // 配置DMA通道 ( b& I9 }: R1 u0 ]+ @
- DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure); ! j9 h6 k- |" S: R5 s# u' J2 C; b
- // 使能DMA4 v/ t; d9 G Y% K2 d% X3 t+ [9 \0 e3 m
- DMA_Cmd (USART_TX_DMA_CHANNEL,ENABLE);
2 G" Q+ S* Y# ^0 L9 Z - }
复制代码 2. 配置ADC1的工作模式为DMA模式(从外设到存储器)4路ADC- u16 AD_Value[N][M]; //用来存放ADC转换结果,也是DMA的目标地址- U/ `% @8 e- d( t
- u16 After_filter[M]; //用来存放平均值之后的结果2 Z( N- d& t3 s v7 B/ r$ A" n" n2 X
- 9 M; r* L: n: ]
- //使能ADC1和DMA1的时钟,初始化PC1-PC3端口
3 _1 X8 W$ ?) O - static void ADC1_GPIO_Config(void)9 f5 W5 x6 J6 {- @3 w+ L
- {4 A4 N3 `1 _" {* r
- GPIO_InitTypeDef GPIO_InitStructure;' M$ M! W' f+ A I. w
-
. E" [" o& @( T* L - /* Enable DMA clock */6 Q( s3 p8 D/ m/ X
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
[' v6 j9 z7 M/ X' W - ! M- M( @; J! Z2 Z
- /* Enable ADC1 and GPIOC clock */+ a6 b4 }" g) o4 l' w: W
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
' E' S- a0 h! ]& A, B* I$ u -
8 _( v* X5 ^* N- R! t" D - //PC 作为模拟通道输入引脚
( ^9 I4 `5 S, f a! Y R- N8 } - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
6 k% A, i, K/ T) L; i& A5 o - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; ; C6 Y# S f% @1 V4 o# q
- GPIO_Init(GPIOC, &GPIO_InitStructure); 9 b( `+ v3 x& _+ ]
- }+ R# t3 p8 `( R" y7 y2 _, `
- ; E( l: K# m1 W- N( F/ m
- //配置ADC1的工作模式为DMA模式
' X1 j0 r5 x: f: I6 b - static void ADC1_Mode_Config(void)5 o( R: j8 I3 f4 I% Y, l8 p
- {" A3 \- t: V$ a$ P5 T
- DMA_InitTypeDef DMA_InitStructure;5 M) w6 {* s& Z) V" ~$ {
- ADC_InitTypeDef ADC_InitStructure;# R; b7 W# ?5 V) g
-
8 P) _. m) \! D, ^; f% @ - /* DMA channel1 configuration */3 ^9 x, k) |3 c( u/ E$ r. ?
- DMA_DeInit(DMA1_Channel1);9 |% E7 v. h7 P: W; x
- DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
% `4 g! b' I! D - l1 g5 ?% G& S( J; o
- //内存地址
+ {& g. c/ ]" s6 c. I( q" r - DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value[0][0];% [" i1 R1 @% J, ]# }4 e5 V
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
+ |! v! y0 v1 u8 [ - DMA_InitStructure.DMA_BufferSize =M*N;
: k( F9 Q8 F8 |9 ^' _' W& U( c - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
. ?, @+ }" n" E: W( N - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
/ X2 }5 q9 i4 H( W - DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;+ b4 U0 W: z; x$ F1 j
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;( P8 w' C ?/ H* C' M
- DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;' j8 L) V6 G# b" ~
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;
. e$ y$ C, V5 Q j - DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;4 ~3 t" f0 W- F" `5 f9 |0 T
- DMA_Init(DMA1_Channel1, &DMA_InitStructure);# D( [: y8 K2 l: {# p- r7 x2 w
- + V5 A: ~& G' F% T
- /* Enable DMA channel1 */& \9 p4 z/ ` s' `
- DMA_Cmd(DMA1_Channel1, ENABLE);2 f/ ~& _: _- b+ S" R) U. b# C
-
5 M8 P& n& Y* w: U5 @ - /* ADC1 configuration */
" J+ a; Z! x5 L1 D" H2 B- ~ - ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
9 I! `( b% D6 }( k& u0 Y& r: f% J - ADC_InitStructure.ADC_ScanConvMode = ENABLE;; w5 h! p' W7 i" O- w' k" G
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
% D5 T6 Q4 c3 h, ~3 ~ - ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
+ a4 }* h w9 }$ c# X$ S - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;: h7 t+ t: Y2 p2 U8 O
- ADC_InitStructure.ADC_NbrOfChannel = M;
! \$ k' | k3 t9 c F0 P0 S9 i - ADC_Init(ADC1, &ADC_InitStructure); R2 R+ P9 H& I) h7 h( D
- ( @- S* D/ r* m8 ~3 b6 L3 j+ k
- /*配置ADC时钟,为PCLK2的8分频,即9Hz*/
) e$ I7 I& e/ w) Y" |' b - RCC_ADCCLKConfig(RCC_PCLK2_Div8);
* m* F) x/ K$ u/ g* z - /*配置ADC1的通道11为55. 5个采样周期,序列为1 */
# U5 V+ Y# R1 |+ v' j5 o* ^ - ///ADC_SampleTime_239Cycles5 ADC_SampleTime_55Cycles5
0 ?2 Y! W$ A! c k6 u - ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5);4 Q* R* \- Q; i. N- O2 y
- ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5);
3 Y+ M; d+ F; b% K. h* h: b% T1 Y - ADC_RegularChannelConfig(ADC1, ADC_Channel_12 ,3, ADC_SampleTime_239Cycles5);
3 ^' V/ x9 X" y: x @" \ - ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5);
, W3 [+ {7 g9 h8 Z4 z9 n - 9 O9 n- C4 }) j. z4 @9 a# c
- /* Enable ADC1 DMA */4 F3 Q1 |5 y0 l" J
- ADC_DMACmd(ADC1, ENABLE);
A0 Q# x/ k2 y6 h, U1 r$ j -
; u/ ~/ @/ l+ C! J& g7 W9 c - /* Enable ADC1 */' h! O& v4 k8 r
- ADC_Cmd(ADC1, ENABLE);/ \! n% `( h+ r
- & }) T4 W& F _) J: ]8 z
- /*复位校准寄存器 */
5 g- v) S3 u+ W - ADC_ResetCalibration(ADC1);. K1 ], c }6 @" e0 C2 B6 i5 E
- /*等待校准寄存器复位完成*/4 A1 l4 Y6 q) M) t5 s4 x; ~
- while(ADC_GetResetCalibrationStatus(ADC1));
; R3 l# p* C1 N' u9 b -
9 `& s) c6 s5 L - /* ADC校准 */7 R' k6 a$ E6 R+ V& Z! U
- ADC_StartCalibration(ADC1);
+ g& W- D: d& g% S# N% Z0 Z - /* 等待校准完成*/
9 B9 j" P& g7 I8 _ - while(ADC_GetCalibrationStatus(ADC1));
0 Z' H& e+ r V -
, r* m! m% U& W; e! L; g+ D - /* 软件触发ADC转换 */
$ X' h. @4 l; ~7 @ - ADC_SoftwareStartConvCmd(ADC1, ENABLE);
. I+ m. u# ^6 u& X! z+ x - }0 L' v0 b0 r! ~' q; d
- /* ADC1初始化*/
% c5 j3 Z9 D" L8 A6 x/ U1 O; M( j2 w% J - void ADC1_Init(void)
7 {2 R: `# |9 ?5 P - {& e( Z# h- C7 Q. f& ]$ l, j j5 k
- ADC1_GPIO_Config();
% t. b) [: x m; t - ADC1_Mode_Config();
3 o0 i h# ^1 I' s+ l - }
复制代码- /*ADC滤波*/7 f' x7 \" {2 u! B( Q4 g v
- u16 MultiDMAGetAdcTest(u8 ch)6 [1 D# L$ W7 L% A+ b4 V
- {
+ h# r2 M+ l. W/ f - u8 i;+ ]3 E3 y/ v% k( C) E* J
- u32 AdcMax,AdcMin,AdcSum,AdcResult,Adc_temp;1 T: Y* G# | \
- volatile u32 ADC_Data;1 e9 L0 j+ I" v2 D6 {8 C+ k
- * B9 D$ C2 I8 B5 z( D
- ADC_Data=0;
' ?" w* Q! D7 }' J5 G5 F - - _: {$ g& k6 c; p: ?
- AdcMax=0;
/ _+ ]3 s3 h0 f* S8 ^2 \ - AdcMin=~0;* A" ~) ]* I$ U- Z/ d! n
- AdcSum = 0;. a% G+ y- L2 n; H3 N
- Adc_temp = 0; r* Y# D; b* ^; c0 q& J
2 q1 }$ O: A8 P- for(i=0;i<34;i++)9 \( e# F$ @, ]6 N8 b+ n
- {
5 |) Y# ?1 q" j z, C: _- @( Q - Adc_temp =AD_Value[i][ch];' i+ t0 |" c/ C$ M
- if(Adc_temp>AdcMax)
! l1 L. [( `3 Z5 j$ O2 { D! |8 B7 \2 e - {
8 d) w j2 A- A - AdcMax=Adc_temp;% G8 Y6 K% Q \$ W" K
- }& H; O0 p' i2 C9 H
- if(Adc_temp<AdcMin), t4 _: ]" j f; T
- {
* m' H5 m. k& ~$ u- f0 P( c* f - AdcMin=Adc_temp;
' K. r9 {+ d5 [' w/ k7 }0 N - }6 i6 g4 v; S$ p# ] _0 P' i- |$ b
- AdcSum+=Adc_temp;6 J, j8 u) R4 F% G8 _3 [
- }
% U& n) N- |, R, ~1 y o - AdcResult=(AdcSum-AdcMax-AdcMin)>>5;
7 [0 I, o2 ]5 n9 q. H" ?3 k - After_filter[ch]=(u16)AdcResult;7 g O9 F1 h- @/ e4 b8 ?
- return(After_filter[ch]);
1 R1 I* b& G# g1 R& K3 a C: O - } 6 l8 V U, M1 V% I% |* K( y1 Z( W8 }5 G
- /*获取ADC1通道0的值*/
& }. [9 R+ E) }7 q5 W% T - uint16_t AD_Leach(void) w* c: D. d/ _
- {+ w0 c% M, v- u$ y+ B
- uint16_t adcx1;- P- ?; d' F2 k+ J; @
- adcx1=MultiDMAGetAdcTest(ADC_Channel_0);$ q+ B9 J! |6 h* N
- return(adcx1); _- S" C% H" F8 c( d; b
- }
5 b4 t( L1 j( p2 S" d6 f - /*获取ADC1通道1的值*/
! Y6 q1 _7 T, s( V' V7 f8 V( h - uint16_t AD_Leach_1(void)
4 o: z. t5 C. o' L" O2 `) J) K# ] - {1 D, C7 D g. K \
- uint16_t adcx2;. j1 f, F. E) v; N- q
- adcx2=MultiDMAGetAdcTest(ADC_Channel_1);
) ]! R/ P; N' D& L( U - return(adcx2);
2 d J, k i5 @: S4 V" M - }9 x6 G( p3 T" ~% f7 @+ n
- /*获取ADC1通道2的值*/
. v6 c. S. x' y1 ~3 ?- p8 N/ n - uint16_t AD_Leach_2(void)3 O" }1 i( D' Y3 u
- {
( z, x; g7 D* i7 ^# |: n - uint16_t adcx3;! {. p0 M" B* F; z/ ^$ n I# e
- adcx3=MultiDMAGetAdcTest(ADC_Channel_2);
1 W! R$ t& b. X' ~% y( i: t1 E - return(adcx3);
2 v$ P0 W1 ~6 B+ j# n) j - }$ t1 G& U; A6 A" R& D$ j. x
- /*获取ADC1通道3的值*/9 S7 D2 I/ @! L# H `8 o9 p, L, T2 `
- uint16_t AD_Leach_3(void)& O I& P- M3 ^: q& @7 ?1 j
- {
( l' p# |+ R2 Z1 r) |( Z - uint16_t adcx4;) x6 _" l# r* C7 V, v
- adcx4=MultiDMAGetAdcTest(ADC_Channel_3);
) W7 a$ v( n3 }. {' Z" v - return(adcx4);8 p, J# o' F4 j' g
- }
复制代码 1 z3 f' p) W# o7 l
! g9 h& X& ~( e* k2 a5 {" [+ m: @目前就学习到这里,后续再写!) T$ ^& w5 j* e5 c& b: g
. V9 q4 [5 w% _* q# O; [
7 R I( G7 x; I, E
2 q9 p% D7 s3 Z/ \. [# Q |