本帖最后由 电子星辰 于 2019-1-14 17:27 编辑 u4 M& u/ [! n0 f L, R
2 b7 i+ A7 E1 ?! s" U6 U' ^
本文在NUCLEO-G071RB核心板平台上,使用CubeMX和HAL库,通过12位ADC,连续DMA采样和不连续转换,单通道(或双通道)采集,DAC连接外部引脚通过DMA输出的一个简易正弦波。最后通过NUCLEO自带的低功耗串口1打印采集到的一个电压。. X/ F6 T1 |! S1 ~4 t$ ]
c9 A! E0 V: r& ]$ C: @
一、Cube设置
: r9 `9 m0 v5 q1 ^( z0 C) N首先我是通过选择Board新建的工程,所以会有一个NUCLEO外设初始化的选择,可以省点力气。通过MCU新建也是一样的。: M; c# U' A6 b5 R7 P( N2 v7 F" M! k
3 I1 J% j: N$ H# F% I8 A( m/ l x# G) @, I" a/ i' _6 Z
其次,RCC、SYS、LPUART都是默认的。# j d/ B6 l* x5 @/ f' y0 w
9 r' ]3 t7 P/ Y+ w3 ?
用SWD下载的话记得勾选“Serial Wire”,要不下载之后就不能再下载了。不过这个板子有个复位跳线帽应该好整,出了问题可以复位下载试试。 _) x, C) C" b* q6 I$ p
% _$ B. w2 x6 g$ I8 j0 KLPUART1,异步模式自己改下常用参数就行了,“Data Direction”模式选择是我个人只需要发送。6 |7 w0 }4 l; o4 ?5 s, E$ o" Z U
' `1 W+ _# ]" p* F) G8 a% s w: S. ^( j
& w" _4 \* L' N然后是DAC和定时器。3 {' q* S2 u& O$ X" E
DAC输出简单点,选择仅连接外部引脚就行了,另一个连接外设的选项就是连比较器之类的。需要通过定时器做触发事件(基本定时器就够了)。
" a- d! c9 O" E- v9 c- q
5 \* Q8 l" c5 ~% |2 }( A
DMA通道不用管,方向是内存到外设。选循环模式,到时候打开了就不用管。“Data Width”选1个Byte就够了,方便点,不用取高低位。# z7 y5 v H2 e w. R# {6 K
' }" q/ K% S, R' j7 k: M% x
定时器6是基本定时器,我只需要它一个计数触发的功能。
/ d/ P# J1 A, C& W( }' yPrescaler是定时器预分频,定时器实际时钟频率为:主频/(Prescaler+1),# A& r) B+ ^/ K
Counter Period是定时器周期,当定时器开始计数到Counter Period值并且重复计数寄存器(Repetition Counter)为0时更新定时器并生成对应事件和中断,
/ `9 D6 \* t8 L" i$ w n最终定时器频率计算为: 主频/(Prescaler+1)/(Repetition Counter+1)/(Counter Period+1(也可能不需+1)),比如需要产生20ms周期定时,可以设置为:64MHz/(63+1)/(0+1)/(19999+1)=50Hz,即20ms周期。我现在设置16位定时器的最大数,64分频的话就是65.535ms。
. `$ f$ G, O, I. y' F. A0 P6 p! F
* Z" ~0 i% ]& F- K) R
+ V; ?4 S, g5 Z+ O* g接着是ADC,我写了2个通道(但是只用了其中1个)。我没有选连续转换和DMA连续请求,所以在程序里还需要循环开启ADC转换。ScanConvMode扫描转换,是根据你的转换通道数自动设置的,转换序列中如果有超过一个通道需要转换的话,那么必须开启扫描模式,否则的话,时钟只转换第一个通道。: N6 P9 ]" m ?* C6 P& S n; ^- G9 a
8 c' N. `( w5 F( Z* G2 ?, w8 ~DMA通道不用管,方向从外设到内存。选的半字“Half Word”,代码里还需对取的值取低12有效位(因为上面ADC参数我是右对齐)。
3 h8 M) n1 Z1 I( P. b3 o
, e) V D3 m, D$ C
1 m: m, f3 P2 A3 J; h `0 q/ m3 {
HCLK改为64后直接回车,它会自动配置。- D" \! u* W B" H6 ^
( G& W3 ]" D. }# c p: M. z2 e, i& N* T5 h, O. [
最后是结果,一共6个值,0.04、0.66、1.33、1.98、2.63、3.27。符合我的预期。我的输出值是0x0,0x33,0x66,0x99,0xCC,0xFF。
1 R$ A; ^, g r9 F& E; W6 N
( X2 ]6 ~) D' g- [! Y3 \
- x7 W/ O6 K; C
4 ^! s; E7 {- y( i
" `8 ?* j* W; m# }- /* USER CODE BEGIN PD */ f# v$ L* Q% l
- #define ADC_SAMPLE 2//采样数2 b- }! R" u5 [9 C# e ~$ T
- /* USER CODE END PD */
1 S& @2 h! @& z! Q
; c) O, k" k1 @. [- f2 c- /* USER CODE BEGIN PV */5 Y" C. S5 ]& j$ ]' B. Y; W
- __IO uint16_t ADC_ConvertedData[ADC_SAMPLE]={0};//DMA取得的ADC值4 d. m4 ~/ I5 [+ c. i* c/ ]
- const uint8_t aEscalator8bit[6] = {0x0,0x33,0x66,0x99,0xCC,0xFF};//DAC输出量表1 v* p9 r+ ~2 q! v9 a& `: {
- /* USER CODE END PV *// Y% q5 g+ w1 d2 R4 ^3 U
& Q! w h, z' S4 p- /* Private function prototypes -----------------------------------------------*/( T( r b& b. F; v
- void SystemClock_Config(void);3 g( E; f4 V0 L3 [* G3 ?" i
- /* USER CODE BEGIN PFP */# @- i4 E, \+ ?- f
- int main(void)1 O( Y) ?' J/ a/ {6 B! z
- {
5 U- ~3 y( |9 N: l - /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
0 e! O8 F* j0 n4 T0 I L - HAL_Init();5 L0 [: I, ]. m
- /* Configure the system clock */
" ?- Q; h& ~' [' ~/ y! c4 I; z - SystemClock_Config();! [7 J8 w$ ?* u) v" t6 Z- h+ n( N
- /* Initialize all configured peripherals */
|; M$ Z2 H& P4 _ - MX_GPIO_Init();& @0 e0 ^) P7 C9 l% L. d
- MX_DMA_Init();- ~5 p# S, L* E! F+ ~. Q. Z) A M
- MX_DAC1_Init();3 z/ L7 {: ^, H! X3 e) z# t4 w
- MX_TIM6_Init();( r/ b- L" B- _$ E
- MX_ADC1_Init();
' y0 X# e$ I6 M9 L o - MX_LPUART1_UART_Init();2 g; W& h3 q( d4 q
- /* USER CODE BEGIN 2 */+ Q0 D2 }, m9 h: I- W
- HAL_ADCEx_Calibration_Start(&hadc1);//ADC自校验
" L% `3 l5 S& V( x7 {5 Q/ V) I# n - HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_ConvertedData,ADC_SAMPLE);//启动AD转换并使能DMA传输和中断。ADC_ConvertedData的两个元素都是通道0的值6 a0 H1 i( I3 P1 Q1 z' E4 X
- HAL_TIM_Base_Start(&htim6);//开启定时器6进行触发8 J/ W6 o' q9 R2 v
- HAL_DAC_Start_DMA(&hdac1,DAC_CHANNEL_1,(uint32_t *)aEscalator8bit,6,DAC_ALIGN_8B_R);//启动DAC-DMA输出,循环输出6个8bit数
7 {; P! [" g7 k. y; ]8 }1 Z - /* USER CODE END 2 */9 k1 x* u% a8 a- Z: b3 Z: u, m" W
- ; ]2 A" s5 s0 _0 ~) M8 }
- /* Infinite loop */& |# y% [9 n, U
- /* USER CODE BEGIN WHILE */' z1 u3 l/ d0 E" }: N6 M
- while (1)
6 i H+ r) \5 C6 _ - {
( o0 e8 R. Z0 V - printf("%.2f ",((ADC_ConvertedData[0] & 0xFFF)*(3.3/4096)));//串口不是重点,这个用法可能有隐患。取有效位和换算一起进行
" E: Z; I7 q/ ^$ _ - HAL_ADC_Start(&hadc1);//因为是不连续转换,需重复开启; X( i* J8 S* ^6 S
- /* USER CODE END WHILE */
3 F& i3 T0 i6 h( N$ k - * F3 i5 ?6 u* E2 S2 p
- /* USER CODE BEGIN 3 */
, ~! S7 K/ F. c# p! C) D+ O - }. ]* ], {2 K1 L( ^$ R0 L" G
- /* USER CODE END 3 */
1 R& N' r8 ?$ M3 H - }
复制代码 ) }2 D+ i5 P; B
' p9 V' {3 w5 ^
好了,文末放下资料。
0 o4 ~7 f6 d) ~4 @0 g4 P0 J源代码和Cube工程:
NUCLEO-G071_DACandADC.rar
(7.98 MB, 下载次数: 1523)
|
我家里的万用表很老了,精度我这测不了。不好说不好说
DAC输出来的是近似0V的值,比如说零点零几V。缓冲的话我是开的内部缓冲。