1 概述5 u3 s; o4 A. @# F0 K
实验的代码已经上传,无需积分。
: O3 T$ P3 v, n/ m0 ^8 V
' D7 v! {, V; ^& x1.1 资源概述
$ \# B# M: i7 s9 y开发板:正点原子STM32F103 Nano开发板
3 e: `) l2 F, t, ~+ PCUBEMX版本:1.3.07 P4 T: ~" \4 i" [
MDK版本:5.27: t+ G* y5 a2 w* I* E# t2 k0 q9 _% e
主控芯片型号:STM32F103RBT6
# `# z" c' n8 C7 X7 b. w! M6 G3 u3 h l/ L9 r) Y4 Z, d
! O8 a+ q1 A6 I4 E. L6 ~* ^& }- S6 M. Y: k& D( a! j
1.2 实现功能9 v; \" K: U& |, X% _' g
1,移植野火ADC使用DMA传输例程,实现读取B01的电压,并通过串口打印出来。野火的程序使用的RCT6芯片,引脚与RBT6相同,改动比较简单。
6 { R; C, b K& _
+ S$ V8 r0 S+ k2 程序实现
4 n: o! Z! H2 s2.1主程序
$ i3 n% C2 Z% j. G1 \' l
5 o& P) ^- t5 {0 {. o6 w2 S- /* Includes ------------------------------------------------------------------*/
' O" ^$ j2 O- q- d: b4 H! h& t - #include "main.h"
7 W; Y* E- _& {* A: C - #include "stm32f1xx.h") m- k# K9 `) d. u7 |! Z
- #include "./usart/bsp_debug_usart.h"
9 b* l2 N9 @3 @8 P - #include "./led/bsp_led.h"5 s5 c! L$ K- J' H8 v' N ^# M: d( r
- #include <stdio.h>3 K: W5 T B% N+ S3 T
- #include "./adc/bsp_adc.h"
# j7 F6 e) v- \- U7 K: Z2 `0 A/ ?* G
3 ?! k8 i% W: e3 m- // ADC1转换的电压值通过MDA方式传到SRAM# ]! e0 E( Q ]: D( s* W
- extern __IO uint32_t ADC_ConvertedValue;
. w, @' X0 l! n - " X) w( [ X$ m+ j, b0 n
- // 局部变量,用于保存转换计算后的电压值
" B8 w+ t m. x: G9 q* E - float ADC_Vol; " X; o' l" ^& }2 r+ t. c
- ; `5 ?: Q/ `6 a9 J
- static void Delay(__IO uint32_t nCount) //简单的延时函数
4 v3 Z/ ~8 I: T% z) } - {
' o {- g8 d4 s) N/ j - for(; nCount != 0; nCount--);0 F; h+ Q2 o- o( B" a- N) s U' S
- }% ^& C* g0 D8 z
- /**
# A8 A" `/ N2 O, r; d. C7 Q - * @brief 主函数& R: K$ y; t& x! ^0 P* l
- * @param 无
) o# {: @, Q w7 m8 w" @% s - * @retval 无( r) z1 r- F' M4 p0 D. b% o
- */
* l; e/ m& }+ N3 ] P8 O. c6 | - int main(void)( }& z8 r: w o
- { ! p1 k9 b- O8 K m' Z S
- /* 配置系统时钟为72 MHz */
# }1 } D- {9 _" k4 t3 W0 E - SystemClock_Config();6 J0 w8 i3 _- I/ _
- ( H. B5 H3 G5 N! g% F1 m7 }, h( i
- /* 初始化USART1 配置模式为 115200 8-N-1 */
. j/ E& M7 X# I1 k0 {, B - DEBUG_USART_Config();
- N1 Q7 w6 [: C. T; g/ W - % M; N# Y% z9 Q: x7 ?$ g
- Rheostat_Init();6 m, o8 p) E% u
- while (1)
' X( c3 [ b/ _9 _" t - {
% c7 E+ O1 K3 T: z - ADC_Vol =(float) ADC_ConvertedValue/4096*(float)3.3; // 读取转换的AD值
% ^/ V/ V" c v! o9 O+ a - printf("\r\n The current AD value = 0x%04X \r\n", ADC_ConvertedValue); & Y' K: \9 ~) y" L: S
- printf("\r\n The current AD value = %f V \r\n",ADC_Vol); 6 @& u/ h, f* P# ]# o3 G& r( w
- Delay(0x8fffff);
- |+ h' `5 I" ~! L4 ~: I- T$ r - } 1 @5 G1 ^6 V6 u
- }
# [5 x8 D8 U& ?4 A - * S+ P# q4 g; C* a y
- /**
+ J, B- \" W4 e* `- e- a" _4 ^& o1 y - * @brief System Clock Configuration: x7 ~: `9 J! e* ]) z
- * The system Clock is configured as follow : ! A1 u: {6 r- G# k: h
- * System Clock source = PLL (HSE)
# G/ E$ b7 A1 H - * SYSCLK(Hz) = 720000003 O. J: E; t2 g6 K+ F6 K
- * HCLK(Hz) = 72000000! P' Y+ g. n- o# q, r. R. y
- * AHB Prescaler = 1
& e" H2 t; r; Z- ?7 @* H" E* T- B - * APB1 Prescaler = 2$ L* \# ?2 u7 j" K! W+ f' m
- * APB2 Prescaler = 17 x. O# ?' ?+ f& N
- * HSE Frequency(Hz) = 8000000, X+ T3 z3 i- K% E5 v$ \1 Q) ?% {
- * HSE PREDIV1 = 1
! m. _+ \8 q/ ?" ~" G - * PLLMUL = 9
( {# s- u6 \, E8 ^6 }( L% z - * Flash Latency(WS) = 2/ `9 _4 u4 C. i2 H- r' g4 w! m
- * @param None
2 S9 Q* _/ v8 ]2 o; q - * @retval None: w; g+ W1 Z; s, t8 p
- */
& I9 [& B) H: h5 o9 ]2 g+ f - void SystemClock_Config(void)/ Y4 ?- R# B8 g$ l1 ^7 ?# W) F
- {
1 N8 b+ f, e8 ^6 @3 L - RCC_ClkInitTypeDef clkinitstruct = {0};3 W1 w1 [; z/ J2 I
- RCC_OscInitTypeDef oscinitstruct = {0};( \3 T4 T) L0 N& C# n4 [
- 6 x# s5 d. B q- o$ F) t
- /* Enable HSE Oscillator and activate PLL with HSE as source */
* m! \7 i8 @% } - oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
3 K, B6 \8 g; u4 S) a - oscinitstruct.HSEState = RCC_HSE_ON;
3 z/ W d% Y3 z c/ G( d0 B, A1 W4 x - oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;) |9 V# ^, X+ Z! Z4 y, P6 D4 _; q
- oscinitstruct.PLL.PLLState = RCC_PLL_ON;
" X* _# N" S" h2 j3 P - oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;7 b- Q( D5 [: g: ]4 d: q5 p2 U
- oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9;
/ f- g+ i2 P9 I5 A- F! ? - if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK)
; h# m' V+ y% W - {6 z: D; S1 o( d& \# R: j( W/ t
- /* Initialization Error */5 _ ]! e0 L1 f
- while(1);
2 S2 v) g& B* ^0 t# r1 }0 w) T$ u - }
0 O3 f4 a# i8 w
5 e: B; f) p1 Y: k- /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
( j; w6 b5 }' t( a1 G' Y - clocks dividers */
# S0 A$ `% c/ I- U) k2 C - clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);2 y5 \8 s1 c$ P6 G
- clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;6 {% S' @' S# O& @0 t2 B
- clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
5 ?' H. H( z" @* A6 s T5 Z& d+ n9 T - clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
4 U7 T6 _5 D- i6 i, X. P - clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
8 O: d* X. m) E1 ~ - if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK): q. K) T/ `) V
- {
4 ~) X1 J" y, U2 Z' e9 \' d: m - /* Initialization Error */
2 V; c$ O8 E/ I5 m - while(1);
8 C2 O8 m2 Y6 y - }
, B' W! F/ {5 B' T" \: s - }
复制代码 9 e) T7 l5 A6 V$ Z
2.2 ADC程序" ~; D2 A0 O x6 B; m3 A
- #include "./adc/bsp_adc.h"7 f9 K+ z# b- ~- T, N
- * z' V+ i }2 ]$ l
- __IO uint32_t ADC_ConvertedValue;
) A/ h2 L2 d! y- G: U3 t5 d - DMA_HandleTypeDef hdma_adcx;0 w& S0 V$ T7 B! W c+ k n
- ADC_HandleTypeDef ADC_Handle;+ x6 d% L* _) W- @& d
- ADC_ChannelConfTypeDef ADC_Config;
& l: X- b) P0 K) \! T0 Z0 o
: @6 G: K: q( d) x6 N7 c* b# o- static void Rheostat_ADC_GPIO_Config(void)
' @4 m* E5 m4 h3 W - {
w) I s& |" u4 d, c - GPIO_InitTypeDef GPIO_InitStructure;1 v8 c. Q4 ]6 ^6 ]0 \: |) S
- - t: Q5 G# ~* Y4 d$ {: F5 S; j
- RHEOSTAT_ADC_CLK_ENABLE();
/ |% U- q# ]0 Q2 b0 a - // 使能 GPIO 时钟
8 ~' [- `+ I1 g- D2 v% M - RHEOSTAT_ADC_GPIO_CLK_ENABLE();
4 {0 ~, v; o$ l% p4 |; N& \4 i
' S1 C5 j& P+ k; ~7 a* `4 |+ ^1 Z- // 配置 IO. Z( d& L# O$ H
- GPIO_InitStructure.Pin = RHEOSTAT_ADC_GPIO_PIN;" i& M3 _2 T w
- GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
- l; A8 J9 g b& m - // GPIO_InitStructure.Pull = GPIO_NOPULL ; //不上拉不下拉
$ j* u) h! Z }! d, T# e. E1 M) H - HAL_GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);
) y' T: M; [, I' {; r4 @. T, t - }
$ K4 {' k K7 a+ P/ e/ O$ i; U/ [& t
( r) H. {1 V5 V3 s4 w2 q" P- static void Rheostat_ADC_Mode_Config(void)
( d% l/ s& h0 Q' b - {
, [" r4 X- m: ]( i% q0 b% T - // ------------------DMA Init 结构体参数 初始化--------------------------
3 v8 B3 H N5 I6 e3 ] - // 开启DMA时钟- V4 U/ s+ d% P
- RHEOSTAT_ADC_DMA_CLK_ENABLE();. D2 ^7 R" O1 M$ W! c
- // 数据传输通道
, z3 {. A/ t1 H- p - hdma_adcx.Instance = RHEOSTAT_ADC_DMA_STREAM;! W' E; G5 s: ]
- : |) d; q, E3 b1 p! D* f) S
- hdma_adcx.Init.Direction=DMA_PERIPH_TO_MEMORY;; //存储器到外设: }2 B4 L( I7 }, Z/ T
- hdma_adcx.Init.PeriphInc=DMA_PINC_DISABLE; //外设非增量模式6 P d; B# h6 }( D2 M! N4 H
- hdma_adcx.Init.MemInc=DMA_MINC_DISABLE; //存储器增量模式
$ a5 j Q2 c7 H! m% P - hdma_adcx.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD;//外设数据长度:16位/ m& A4 ]9 R9 E; H6 S
- hdma_adcx.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //存储器数据长度:16位,错误已经修改
$ i: K% Y! c7 a. P$ ^7 D# f! L# j9 f - hdma_adcx.Init.Mode= DMA_CIRCULAR; //外设普通模式1 s+ @/ c' W) v/ n
- hdma_adcx.Init.Priority=DMA_PRIORITY_MEDIUM; //中等优先级
O& e% o3 c N2 w - # M4 Z0 p' d1 i8 H0 [
- //初始化DMA流,流相当于一个大的管道,管道里面有很多通道
- R6 v' t# ?! W6 ~ - HAL_DMA_Init(&hdma_adcx); ) d: f6 m% R' f# t+ ~/ a
1 }4 B' Q. _: }4 h3 T9 G5 n- __HAL_LINKDMA( &ADC_Handle,DMA_Handle,hdma_adcx);
+ P, F3 _! E0 t - * p( L- M+ |. l8 L0 E5 L
- //---------------------------------------------------------------------------8 I0 G) {" N1 s) f
- RCC_PeriphCLKInitTypeDef ADC_CLKInit;
5 d' h- i4 h1 y. P( } - // 开启ADC时钟
, ^: C1 Y/ N) R8 ` - ADC_CLKInit.PeriphClockSelection=RCC_PERIPHCLK_ADC; //ADC外设时钟
" y+ U: D2 R% m; Y& r5 S0 W% ? - ADC_CLKInit.AdcClockSelection=RCC_ADCPCLK2_DIV8; //分频因子6时钟为72M/8=9MHz; y% D& e' j7 e# m# j
- HAL_RCCEx_PeriphCLKConfig(&ADC_CLKInit); //设置ADC时钟
, a' x( I9 q' a, _; E - ' p1 e$ C- P: N! g+ b( H
- ADC_Handle.Instance=RHEOSTAT_ADC;
" K# t: Y. h3 I - ADC_Handle.Init.DataAlign=ADC_DATAALIGN_RIGHT; //右对齐
3 c9 g# X5 `: R% I; ] - ADC_Handle.Init.ScanConvMode=DISABLE; //非扫描模式0 U8 a, q: q, G
- ADC_Handle.Init.ContinuousConvMode=ENABLE; //连续转换. v0 f% t2 h) ?& [% \! ]
- ADC_Handle.Init.NbrOfConversion=1; //1个转换在规则序列中 也就是只转换规则序列1 7 b, W0 X$ |) d
- ADC_Handle.Init.DiscontinuousConvMode=DISABLE; //禁止不连续采样模式
4 L: w( x* j- h) u/ \- E) Q( ~ - ADC_Handle.Init.NbrOfDiscConversion=0; //不连续采样通道数为0
9 b$ W8 W1 u( P6 a - ADC_Handle.Init.ExternalTrigConv=ADC_SOFTWARE_START; //软件触发
: ~: f) u* p6 t - HAL_ADC_Init(&ADC_Handle); //初始化
) K: W) g" K+ [; f, Z - 9 G* U4 q0 l% v x8 I% B
- //---------------------------------------------------------------------------) T# I8 P3 R5 N# ?& d# E3 v
- ADC_Config.Channel = RHEOSTAT_ADC_CHANNEL;+ H! @. m( t. T* H p
- ADC_Config.Rank = 1;6 ^. l- a) _. m/ e h! H
- // 采样时间间隔 U% H# C: i+ K0 U7 q$ Y; n( `
- ADC_Config.SamplingTime = ADC_SAMPLETIME_55CYCLES_5 ;
9 `/ o" {9 X1 Y2 Q5 |) p - // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期
; S" R- S9 _, @8 ~& w7 g - HAL_ADC_ConfigChannel(&ADC_Handle, &ADC_Config);
) {+ Z3 E* J9 u( O9 _
; B+ ?* b3 p$ u- Z2 N- HAL_ADC_Start_DMA(&ADC_Handle, (uint32_t*)&ADC_ConvertedValue, 1);
! Z. ?8 U% Z8 r, Z7 y - }* G2 t2 F6 h3 c0 c3 k8 P
- void Rheostat_Init(void)1 A7 Y% q; B6 o) V( e7 }1 A: w
- {
, ~/ z% o+ n) g2 ~* u. z: I6 p - Rheostat_ADC_GPIO_Config();
0 @2 [- s3 E$ L: D% ^ - Rheostat_ADC_Mode_Config();, l, d, t! d2 |! g# V8 s( U! M
- }1 Z: o8 ?4 g3 x+ B; O" G
复制代码
* U$ z1 k3 v: C2.3 ADC头文件
$ g- B6 V8 V, `0 L L调整端口定义与正点Nano保持一致,这里需要注意的是,GBIOB1对应的是ADC_IN9, 对应的DMA1_Channel1(通道1,而不是11)。1 ^3 E& F9 O/ p. W+ K4 p f+ {
9 `% r4 B& y+ B" k; C
- #ifndef __BSP_ADC_H
& B$ W; P! z/ U9 l) b) f - #define __BSP_ADC_H
) g! f* [, i" L- P# e - ; i* S6 l5 D- _: m B1 _* m' |1 x& H
- #include "stm32f1xx.h"
w9 n8 N, R; W6 Z8 ^ - ' J. x( a: g8 K2 U
- // ADC GPIO 宏定义& Q A& B6 X$ D, r( g: \- |
- #define RHEOSTAT_ADC_GPIO_PORT GPIOB
. u6 g O3 l6 J( K, F& J - #define RHEOSTAT_ADC_GPIO_PIN GPIO_PIN_1
8 l9 l5 F' _+ {) V) O0 G - #define RHEOSTAT_ADC_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
! o ?6 }- M5 F0 e# J+ q u - " P" }3 W" Z1 p& E
- // ADC 序号宏定义
4 T2 M. Y9 _7 \! K( z" b - #define RHEOSTAT_ADC ADC1" N. d5 R8 Q/ _- Z a# O# q
- #define RHEOSTAT_ADC_CLK_ENABLE() __HAL_RCC_ADC1_CLK_ENABLE(); , R) c S+ @: J3 ~. f/ o4 [/ H
- #define RHEOSTAT_ADC_CHANNEL ADC_CHANNEL_9) y; H6 z1 R! T) i
% ?. Q9 Y. n5 l' r7 A( u- // ADC DMA 通道宏定义,这里我们使用DMA传输
$ M7 ~: |2 ?& e/ G - #define RHEOSTAT_ADC_DMA_CLK_ENABLE() __HAL_RCC_DMA1_CLK_ENABLE();8 x7 P0 H0 @% i3 |0 ~* [
- #define RHEOSTAT_ADC_DMA_STREAM DMA1_Channel1% B9 y/ t- D) ~$ S/ c: E9 p0 t
: T2 h% S, g) [- Y/ q- void Rheostat_Init(void);# c9 i: Q, |( Q+ z; d& K! }: L1 \2 q4 D
! @: V: Z7 \2 ~0 q; Q- #endif /* __BSP_ADC_H */
# @, b4 Y2 b! @5 W; ^$ z. z/ I% Y
复制代码
: ]6 N! k' G1 V6 H( p V) \0 M4 @& Q3 程序调试+ B a" |# t/ H; j+ k- w# Z2 {" W. b) s
在程序调试过程中,串口打印一直无法输出正确的值,都是小于1的小数,而且调节滑动电阻时,数值会发生变化。由于是移植的例程,一直怀疑是我自己改程序导致的,但是经过换成别的开发板,而且ADC端口不改的情况下,还是不好用。如果开始了漫长的查找过程。路程如下:
9 e. i- ?9 b7 D/ o1.使用CUBEMX生成一个ADC DMA传输的程序,正常运行没有错误;+ t" ^* D# }1 J
2.将生成的程序,ADC以及DMA相关部分去掉,加入野火例程中的ADC相关文件;
5 y- M5 ~+ r4 V- J/ f( w9 j3.将CUBEMX生成的ADC相关文件加到野火程序中,运行正常没有错误。
6 d5 M9 |1 q! {4.运行调试发现不好用,只显示小数;
: @+ F4 D0 j( M! i4 D0 o5.将原CUBEMX生成的函数,一块一块加到野火程序中去,替代旧的函数。最后发现在配置半字时出现问题。! ?% C: `3 P$ D D
例程中错误的配置
- H% c7 `1 l/ P5 M1 _- hdma_adcx.Init.MemDataAlignment=DMA_PDATAALIGN_HALFWORD; //存储器数据长度:16位
复制代码 9 M& J, w+ _- g& j- Q
而正确的配置为(P改为M)
* h. L) e- |% C" s$ P3 V H4 u- F% Q5 n6 `
- hdma_adcx.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //存储器数据长度:16位
复制代码
* i1 P3 X9 n7 J# H5 r- ^修改后程序调试OK,下面为更改后和更改前的结果,在错误的程序中,第三位的B丢失了。正确的位B37,错误的为37。
; T; M$ f( A8 D6 ^- |9 h4 ?6 y( x2 S6 H3 C# x) P8 p1 Q* u
* G' U+ i3 Y! O B" J4 y6 c6 i1 f: ~ Q$ d* b5 K9 b
4 查找原因
4 n$ A' h8 U r7 N0 _查看官方手册继续查找原因,将程序里边的定义一层层翻出来,结果如下。0 v C* f1 Y1 o& ?
3 \0 d* L' \3 p1 P
错误赋值函数
: w2 ]+ W* V/ S, i9 Y! I0 c! V- ?; Y" b
- hdma_adcx.Init.MemDataAlignment=DMA_PDATAALIGN_HALFWORD; //存储器数据长度:16位" Z4 p) b2 a' w2 {
- ( z H) t* E* Z- u
- #define DMA_PDATAALIGN_HALFWORD ((uint32_t)DMA_CCR_PSIZE_0) /*!< Peripheral data alignment: HalfWord */$ r' q, Z5 E1 z
1 y W, @+ H* P- #define DMA_CCR_PSIZE_0 (0x1U << DMA_CCR_PSIZE_Pos) /*!< 0x00000100 */
8 |' [% C- Z) C, v8 J" r) \$ S - 4 s! \3 ]3 X0 X6 m
- #define DMA_CCR_PSIZE_Pos (8U) 2 y6 x$ h# E! ?" Z
- 2 l% Z, V/ ^, M: Y3 ?, \3 h& V+ o: _
- STM32F1中文参考手册V10里边关于DMA配置寄存器的说明
5 Q4 q5 B# h! w! J0 A7 R - 位9:8
# Q7 s3 l. X! I9 } - PSIZE[1:0]:外设数据宽度 (Peripheral size) 这些位由软件设置和清除
/ t0 a# L% ^" D) c6 u - 00:8位
; L- m+ E4 V- j, v - 01:16位
8 r8 d0 |2 q* s0 f% F! T - 10:32位 8 O0 ^, ^" t+ q7 H" y6 O
- 11:保留
/ D: i( A4 t* f: F( c - 这是错误的设置,导致外设的数据宽度设置了两次,而存储器保持默认00,即为8位,而ADC为12位右对齐,最高4位丢失。 / }5 `( N+ R6 P; p7 I
复制代码 " D7 s$ P6 m, Y3 r5 C
正确赋值的函数! ^) L1 S( [$ p8 z
8 d1 F+ X: f; x/ {6 A- hdma_adcx.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD; //存储器数据长度:16位
b9 j! v$ C6 x
+ D, F& l) f0 O# v8 M/ G) T$ e- #define DMA_MDATAALIGN_HALFWORD ((uint32_t)DMA_CCR_MSIZE_0) /*!< Memory data alignment: HalfWord */5 @2 m& k9 S+ W
8 h( h5 k3 [0 B) x- #define DMA_CCR_MSIZE_0 (0x1U << DMA_CCR_MSIZE_Pos) /*!< 0x00000400 */
5 s+ Q4 V5 F+ @/ O4 K
& s9 ^* n$ {/ V' |" K v7 W- #define DMA_CCR_MSIZE_Pos (10U) + s* c: a3 k9 m7 l" g7 p( a, Y0 n* O
: c" z4 @& P+ d) T- o# b1 ^: U- STM32F1中文参考手册V10里边关于DMA配置寄存器的说明
8 I; e C( ~# I5 Z7 t& t2 P% k5 [: Z - 位11:10 0 S# D$ G$ Q' X* f
- MSIZE[1:0]:存储器数据宽度 (Peripheral size) 这些位由软件设置和清除
: L( J: E( [5 R - 00:8位 7 ^6 }# N/ X: I. t
- 01:16位 ; ]9 q8 H" h4 p% ] U. n' X
- 10:32位
; D9 _" K/ m( X$ u3 @* Q+ E/ A - 11:保留+ L9 p% E" `' a8 c/ ~) y7 g6 M; j9 s
- 这是正确的设置,存储器设置位01,即为16位,最高4位不会丢失6 Z0 |. }# l- m' C0 ]0 T
复制代码 9 I8 u& B9 p# d* @
原因分析和实际情况一致。
& M- r5 |5 ?0 ` X1 d查看野火给的资料,发现里边的这个地方是错的,和程序保持了一致。这个程序应该是被误写(使用自动补全),然后编译后实际验证没有认真检查导致。
( J4 s! F* K9 a$ L4 ?5 |6 e+ E, l/ O
8 K4 C+ U4 n" }9 h$ F( z2 ^7 {3 g1 x' @* l; ?( y& P7 y. D- F9 T
|