你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【学习指南】基于STM32G474VET6 开发板实验经验分享(二)

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验
4 k2 q  y7 L8 _1 A0 n* n* H, D实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。+ q9 X4 T7 E$ m: m7 k1 j

# B0 f& V( |! t5 n& p" s1、软件模拟 SPI 驱动 TFT 实验8 B% r: Y# Q& x; Y: i; H/ P* y' ]) L
CubeMX 配置如下,保存后生成对应的配置代码:- i5 J) h- h7 ~$ B
13.png % ?3 B/ j# D7 e, T$ t. `
% u- }& R$ P3 H  [
▲ CubeMX 配置
0 N* _6 o9 r' ^: j' q/ V$ [" V+ ]/ P
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。
0 V1 Z4 i" ?4 z( {$ g$ \8 |
# }6 t" i& x* P) k
相关操作函数说明:8 L9 n( F1 l; ?" F
void Lcd_Reset(void)
# u& x0 k6 L* y, h/ m6 K
) \! b" [* l9 y9 r& Q) F
功能:液晶硬复位函数;
: e1 y7 s  h' H参数:无;4 l, n$ s. z: x7 Y
返回:无;
1 L/ C& @6 v+ B9 |6 ]说明:液晶初始化前需执行一次复位操作
6 q2 Y4 e# R% @! N8 h7 jvoid LCD_Initial(void)
) }  g+ q9 d( {功能:初始化液晶;
7 _8 w: [; k0 W参数:无;2 D% Z, M8 ?  t5 e- G- ]
返回:无;
: Z. x9 O& O9 p+ i说明:在对液晶写入内容前需要进行初始化配置;* n* ?# N; k8 E. z
void Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
* V" l4 ?3 o- D# l* G

. P3 Z! V1 a# M! K$ N功能:Lcd 矩形填充函数;
  w" X4 c4 q6 G& d% `参数 1:x 方向的起始点;
* o7 T$ Z3 ^7 `  ^2 ?# ~/ @参数 2:y 方向的起始点;! |9 T& t  q# Z! R/ @9 C
参数 3:x 方向的长度;% `) a7 H& D0 {) x4 l
参数 4:y 方向的长度;
" g* ~( R* v+ j2 X# m8 S! f参数 5:填充的颜色;: v( P$ ]6 D/ }2 B: a6 }
返回:无;5 a4 n) h9 I4 f  X
说明:将指定区域内填充指定颜色,常用于清屏' T8 K# j$ @( h7 m* r" L
void BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend); j+ c0 w0 C1 L5 S

+ V/ ^" _) F" r2 g: _9 Z功能:在一个指定位置开一个矩形框;
# G/ W1 e* }% p参数 1:x 方向的起始点;
5 Z; r; \5 c- V$ h' f参数 2:x 方向的终点;! E% }: e' D8 g1 h" u2 E7 ^' O
参数 3:y 方向的起始点;5 p, B6 v! c8 K& x/ v6 F1 _3 Y( q% g
参数 4:y 方向的终点;" \1 X6 X, v- }3 d1 j: e! ~0 N
返回:无;
+ g& W6 {8 t% G9 H/ c  U8 H/ z说明:开一个矩形框,方便接下来往这个框填充数据;& T# r9 d7 w  O4 |$ u1 U! n; ]
void DrawPixel(unsigned int x, unsigned int y, int Color)
7 [5 E8 j: Y: W8 M! Z9 I% K功能:在 x,y 坐标上打一个颜色为 Color 的点;
$ S9 p! D& r: A( x7 M7 }参数 1:x 坐标;6 P# g' _+ L" x% \# s
参数 2:y 坐标;
+ c  z6 r" v5 f$ C. _* K4 p) h* h参数 3:点的颜色;
) }. t' w" O, q, O4 u0 F7 o/ g返回:无;6 ~" s( x. o, t* l4 ~; @8 q
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)  f2 q$ `$ N0 |8 K, i# G) s" G$ b
0 p4 [6 u  G, q* [; ?. n# ^
功能:显示一个字符串;
: ?8 U! p  J+ G6 R! s% n; _$ ^参数 1:起始点 x 坐标;
! B( F! b% M4 G9 @3 R参数 2:起始点 y 坐标;. h4 l3 Q/ U$ e* [+ l
参数 3:字符串指针;
" ^& X: w) J; J$ [参数 4:前景色;+ p8 H( O, o& E. c: N7 y
参数 5:背景色;
! Q7 ^( x1 r- I8 q参数 6:有无背景色;
2 [( W; R3 x; R& S返回:无
- E/ C+ }( H' G+ Q$ ?7 j% K3 Y5 ~& Z, k$ u1 z! }8 N( z' s5 H

5 l5 R% E* S" I% U核心代码:
4 l7 G# p. S. g- e6 KLCD_Initial();8 v9 ]6 v% x. f- L
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏- |6 n" h' M. p, o! f3 ^" }
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
( o+ X1 K5 j' p: U) u; T4 n& g4 K  cLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏
; w- U0 g, Z8 d7 @Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏
& ]7 o9 v  D9 H! ^' ELCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
5 D0 F7 c# h! [  o' a
# B. Y6 P1 b; }' V! I( H& v在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
: G# F6 f) b# L: x6 h: w4 u; u% P$ y- C+ N
4 ^0 b6 G0 c) h- T. i
实验现象:
5 }, t8 `( l6 p  a4 U下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
" m+ K/ K  q( ^8 A5 a, x  c" R8 g, J  c$ |

9 p# F6 v- p4 N3 V2、硬件 SPI 驱动 TFT 实验5 q1 m# A1 j8 V: o/ T* q7 a( V- A
CubeMX 配置如下,保存后生成对应的配置代码:
6 j7 g$ P& H8 V) G

' l4 r8 V7 w8 F% A/ f6 {
12.png . B  z! }9 @: U7 V) |: i/ `- [& o
0 t+ O+ E0 E# ]
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png
3 N' ~: T, O2 X9 k) t

; _+ [) }# ]6 m3 R/ y8 t) S
▲ CubeMX 进行 IO 速度配置
! M/ x# b% S/ @; p) h% {- t
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。
$ V+ O9 x) g. G/ u% b

6 p8 a, F$ G2 _/ F

1 `3 g: C3 o8 g8 A; ?8 Y% X

1 U. G' W! H* T. h. K
相关操作函数说明:
/ M" }- Z! ?2 D: P+ N' E- [0 k
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

$ ^! c5 ~  k% q7 E
功能:通过硬件 SPI 发送一组数据;

4 }* k/ ]* [6 t$ [3 T) ]1 G* g
参数 1:SPI 句柄,根据实际需要填写;

4 c4 `7 Z# f5 [
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

! A* p& L4 |# {8 ^; [
参数 3:发送数据长度,单位字节;
" `& z# c4 d3 }3 ^: n: [
参数 4:发送超时时间,单位 ms;
" p' B5 L) ~" w& b9 z# e- y
返回:操作结果,HAL_OK,HAL_ERROR;
6 u, W, q' G3 D. [. x# B" W
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据

2 U4 F- a& S% _+ U6 z+ n3 Q
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
/ Q& ?/ \" K# u1 F5 A5 k
功能:通过硬件 SPI 接收一组数据;
- l# l1 l2 j) q) V- I, q- B4 @
参数 1:SPI 句柄,根据实际需要填写;
! j) a. d5 @% r& {% b9 m& a
参数 2:要接收数据保存指针;
; m4 q7 ^* c! c# l
参数 3:接收数据长度,单位字节;

9 N) ~$ @& `5 R2 c3 q5 N* C/ r9 [
参数 4:接收超时时间,单位 ms;

1 r7 u4 s: O' L  U# _
返回:操作结果,HAL_OK,HAL_ERROR;

& ^4 N& p7 f; z# h
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)

) v/ J) b6 y% M) {4 e0 L
功能:通过硬件 SPI 交换一组数据;

5 L$ ]5 w0 {: u7 c6 i, F; C  ?
参数 1:SPI 句柄,根据实际需要填写;
9 T- G' I5 `8 b* A0 z
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
0 s7 u3 X6 S! V9 T3 i+ _
参数 3:要接收数据的指针,接收数据数组的首地址;

6 {5 v. j$ T+ l( O7 j7 S2 w' s; @
参数 4:数据长度,单位字节;

( ^( f$ U) C# k3 b( o- K2 B
参数 5:超时时间,单位 ms;
) e( {$ u" L! f; l, x+ \; H
返回:操作结果,HAL_OK,HAL_ERROR;

& w' w6 J( p0 K. ?0 D
  d* p% j! O: V9 W2 A/ j
- ~7 @& o0 {* [) \
核心代码:
6 L: a& A5 i! D
LCD_Initial();

: u3 ~' D, n0 e: C4 N
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
$ c% U& r6 p2 d9 x5 g
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏

5 `; w" K" y4 R( Y/ k+ I' Y
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏

& }! a/ N- N8 Z# a
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏

8 x. d$ ^& T! Q
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符

0 y: c, t7 z% k( @  C

, _8 `& O$ x3 K

. ]  Z1 B; H/ r2 P; B: z: y
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

* O4 h% ^" B& Q; U* W2 i; c

5 s4 u: }$ {; w$ |8 D$ |. W# C0 ^
  r: A; W4 M- ^* e+ h/ ?  F+ T8 n3 {
实验现象:

. T2 x# w- O6 j0 h: Q
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

  d! L" \/ d) x5 |) `8 D( W

- i# W* D  W; O6 R
3 t0 s' ^$ j- {( P3 L; j
3、硬件 SPI 驱动 TFT 实验(DMA)

% `* H/ K( }1 j' l7 S  ?6 |% @
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png
+ J6 p) U& s; E) ~# q
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。
$ Y) V( E' C. Y
相关操作函数说明:
HAL_StatusTypeDef HAL_SPI_Transmit_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData,uint16_t Size)
功能:通过硬件 SPI 使用 DMA 方式发送一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
参数 3:发送数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_SPI_Transmit_DMA ( &hspi4,data_color,2*xLong );//通过 SPI4 的 DMA 方式发送颜色数据
HAL_StatusTypeDef HAL_SPI_Receive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pData,uint16_t Size)

5 Z. @1 @  }4 f. m4 T3 L
功能:通过硬件 SPI 的 DMA 方式接收一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要接收数据保存指针;
参数 3:接收数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
HAL_StatusTypeDef HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t*pTxData, uint8_t *pRxData, uint16_t Size)

8 H6 i+ |( }) `9 |, K+ C9 [
功能:通过硬件 SPI 的 DMA 方式交换一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
参数 3:要接收数据的指针,接收数据数组的首地址;
参数 4:数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
注意:使用相应 DMA 时需要对该 DMA 请求进行配置;
( m$ ~0 J9 t5 y* M+ x
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}
! y& }; k6 i! U, T) T0 c% n
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。
( C" X5 B4 \/ L
void DMA1_Channel1_IRQHandler(void)
{
if(__HAL_DMA_GET_FLAG(&hdma_spi4_tx,DMA_FLAG_TC1))
{
dma_flag_temp=1;
__HAL_DMA_CLEAR_FLAG(&hdma_spi4_tx,DMA_FLAG_TC1);
HAL_SPI_DMAStop(&hspi4);
}
HAL_DMA_IRQHandler(&hdma_spi4_tx);
}
/ j& b% t2 \1 F6 R7 c2 }6 B% V
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。
; b  [" I, h. D, p* Z0 p) r
LCD_Initial();Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
2 }  i4 L7 n( j, U% w$ ]3 {2 @% E
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

; C$ v2 g: A0 v5 m. A4 U3 [
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

5 b; K4 A7 l5 }: r* n5 s9 s7 f
+ v# C0 h, `  p
七、IIC实验
1 {  L* m* S+ x
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。

: |8 m" A6 @. Z% c) H
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:

. l0 c- G- |) K, \2 X' o( G
4.png
) I6 ]1 ^# ]: v

. G6 S1 p) @' D5 [
▲ CubeMX 进行软件 IIC 的 IO 配置
; _2 A1 E9 M& j/ I7 \. A. e: h% B
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。

5 b. v. f) k! }/ U# Z, n" l
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式

% j6 M0 L3 G) Z
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式
4 ^/ U2 T1 h2 b" `/ |: F" M% f  [
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;

5 X0 o. W$ x7 a, }, X$ S7 z4 r
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;
, S% M, f7 G/ [2 r! ]" C$ P( P) k
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;

% `# Q, ?  k6 F& ?
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;
1 `# v; i( N5 G' e8 k$ z7 J  p& e- S
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
数:无;
返回:无;
: D2 a, F8 G! w8 p4 n
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;

/ |1 V( E' x6 C1 L+ Q3 x8 ~; m
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;

- K8 m/ A4 Z) p4 p; Q9 ]5 P
核心代码:
//24C02 读取一个字节
uint8_t x24c02_read(uint8_t address)
{
unsigned char val;
I2CStart();//起始信号
I2CSendByte(0xa0);//发送器件写地址
I2CWaitAck();//等待应答
I2CSendByte(address);//发送读取的内存地址
I2CWaitAck();//等待应答
I2CStart();//起始信号
I2CSendByte(0xa1);//发送器件读地址
I2CWaitAck();//等待应答
val = I2CReceiveByte();//接收一个字节
I2CWaitAck();//等待应答
I2CStop();//停止信号
return(val);
}
//24C02 读取写入一个字节
void x24c02_write(uint8_t address, uint8_t info)
{
I2CStart();//起始信号
I2CSendByte(0xa0);//发送器件写地址
I2CWaitAck();//等待应答
I2CSendByte(address);//发送写入的内存地址
I2CWaitAck();//等待应答
I2CSendByte(info);//发送写入内容
I2CWaitAck();//等待应答
I2CStop();//停止信号
}
3 M2 z* K, p3 M, S& I6 o; u
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。

. T- n2 ^3 l: Z) N
I2CInit();
uint32_t i;
# P- N; d5 g, F3 n5 _) i
printf(" 24C02 Test ....\r\n\r\n");
//向 0x00 内存地址写入数据
for(i = 0; i < 6; i++)
{
x24c02_write(i,Data_T);
}
printf(" 24C02 Write ok\r\n");
HAL_Delay(100);
5 Q8 \, N; [0 c8 }+ a6 D5 T
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");

: b, U4 |: ?- i: f
printf("24C02 Read Data : \r\n");
for(i = 0; i < DataSize; i++)
printf("0x%02X ", Data_R);
printf("\r\n\r\n");
if(memcmp(Data_T, Data_R, DataSize) == 0)
{
printf(" 24C02 Test OK\r\n");
}
else
{
printf(" 24C02 Test Failed\r\n");
}
+ s5 L; F& I* v$ A( J
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

- P; `% r& q1 J; S
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
3 N; f' ^. \- A* P1 [
微信图片_20241122152540.png
0 s6 D8 {9 E# E3 p8 Q2 g& J
/ f, F; M# Q9 a) E& Z$ w  B9 q0 G* @* B
▲ 实验现象
* V! Q/ T) @3 k3 Y

5 l4 v7 K2 p! b# L- J
2、硬件 IIC 驱动 24C02 实验

" I- _1 r% a" q. @. I+ x3 S0 x6 ~
CubeMX 配置如下,保存后生成对应的配置代码:
+ V* C- {& f! Z! n9 _
微信图片_20241122152543.png . p, i# f' ?2 z( P% G* j, H7 w
; s. T' H: c# m% Q! D. O
▲ CubeMX 进行 IIC 配置
! w4 ?. {' c* I; g
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。
4 M0 z9 K# s3 V/ x0 r& A
相关操作函数说明:
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,uint16_t MemAddress,uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
功能:以阻塞方式将一定量的数据写入指定的内存地址;
参数 1:I2C 句柄,根据实际需要填写;
参数 2:设备地址,注意这里填入的地址应该是左移一位之后的地址;
参数 3:目标内存的地址;
参数 4:目标内存的地址大小,可选 8 位(I2C_MEMADD_SIZE_8BIT),16 位(I2C_MEMADD_SIZE_16BIT);
参数 5:带发送数据的指针;
参数 6:待发送的数据量;
参数 7:发送超时时间;
返回:操作结果,HAL_OK,HAL_ERROR;
& }/ V- A; E* C! e: Q2 j2 T  Y) c
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;
, Z9 i' j& F, m$ m! ~% R
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,uint16_t MemAddress,uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
功能:通过硬件 IIC 从一个特定的内存地址以阻塞模式读取一定量的数据;
参数 1:I2C 句柄,根据实际需要填写;
参数 2:设备地址,注意这里填入的地址应该是左移一位之后的地址;
参数 3:目标内存的地址;
参数 4:目标内存的地址大小,可选 8 位(I2C_MEMADD_SIZE_8BIT),16 位(I2C_MEMADD_SIZE_16BIT);
参数 5:带接收数据保存地址的指针;
参数 6:待接收的数据量;
参数 7:接收超时时间;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:
HAL_I2C_Mem_Read(&hi2c3,Addr_R,0x01,I2C_MEMADD_SIZE_8BIT,Data_R,DataSize,0xFF);//通过 IIC 从目标器件的 0x01 地址读取数据;

2 ~. a1 W' |" L$ J# o5 |. y* m
0 K+ ]7 c# k& F0 V& G
核心代码:
uint32_t i;
printf(" 24C02 Test ....\r\n\r\n");
//向 0x01 内存地址写入数据
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);
printf(" 24C02 Write ok\r\n");
HAL_Delay(100);
//从 0x01 内存地址读出数据
HAL_I2C_Mem_Read(&hi2c3,Addr_R,0x01,I2C_MEMADD_SIZE_8BIT,Data_R,DataSize,0xFF);
printf(" 24C02 Read ok\r\n");
printf("24C02 Read Data : \r\n");
for(i = 0; i < DataSize; i++)
printf("0x%02X ", Data_R);
printf("\r\n\r\n");
if(memcmp(Data_T, Data_R, DataSize) == 0)
{
printf(" 24C02 Test OK\r\n");
}
else
{
printf(" 24C02 Test Failed\r\n");
}
# b! N$ G2 k3 G
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

$ O0 }7 s8 w/ E$ f; Y
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

- u( u: A9 b* P. X
微信图片_20241122152546.png
$ t$ }( n' Z3 @( P
▲ 实验现象

; D' G0 j0 v: r9 u2 O5 G
# x* S& H7 W& W  @# Q) N
七、ADC实验

' O) C( x; k. e1 p) A& @
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。
+ o0 X  I+ G+ H2 G
1、ADC 查询方式单路采集实验
2 W6 {: G* `! b' m
CubeMX 配置如下,保存后生成对应的配置代码:
2 m$ N4 E0 X7 q9 `3 L; L( e
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置
7 F# p6 C3 v2 J/ L: w
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。

: A6 U8 b6 ]4 C: l. U
相关操作函数说明:
HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef *hadc, uint32_t SingleDiff)
功能:对 ADC 进行校准;
参数 1:ADC 句柄,根据实际需要填写;
参数 2:ADC 采样模式,可选 ADC_DIFFERENTIAL_ENDED(差分采样模式)或ADC_SINGLE_ENDED(单端采样模式);
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //对 ADC1 进行单端采样模式下的校准;

6 w: c. w0 z. U! F" _3 @
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换

; L8 r- h" d3 W# P. s
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;

, W! k+ J% A/ ?) `2 U
HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef *hadc, uint32_t Timeout)
功能:等待 ADC 规则组转换完成;
参数 1:ADC 句柄,根据实际需要填写;
参数 2:超时时间,单位 ms;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_TIMEOUT;
示例:HAL_ADC_PollForConversion(&hadc1, 10); //等待转换完成
- Q" C: a0 Z( U7 H
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
5 K/ P- G6 [8 W/ L5 q' |. f
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正 ADC
while (1)
{
HAL_ADC_Start(&hadc1); //开启 ADC1 转换
HAL_ADC_PollForConversion(&hadc1, 10); //等待转换完成,第二个参数表示超时时间,单位ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
ADC_Vol = ADC_Value*3.3/4096;// 转换为电压
printf("ADC_Vol: %2.4f\r\n", ADC_Vol); //通过串口发送
HAL_Delay(50);
}

  X. f0 s& X) E
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。

6 v% k0 x/ ^: U4 ^7 q
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

  S% q: h( N  x
微信图片_20241122152553.png 4 E) C9 g3 O* C3 C8 x
/ [  V. M; c* T3 d+ x. z- x
▲ 实验现象

  e  V' O% l& e! Q: F& i( `

: P0 Z- @  r2 ^
2、ADC 中断方式单路采集实验
( Y' _) }2 z; p4 M
CubeMX 配置如下,保存后生成对应的配置代码:
+ p4 f! u4 J9 k( `0 E; K& a
微信图片_20241122152556.png
▲ CubeMX 进行中断配置
* r) y: _0 t+ ]% H
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。
0 j0 S4 H8 A7 e7 o' @. K5 Z
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据
4 h) f5 {* v$ L; a5 g
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
# K8 L4 L  |/ r! y: N; d( {$ \* z
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}

) `& E8 U) ]- `- F& O. r/ ~1 M
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。

% H, ~/ `" A7 q' q3 Z1 ^7 d3 G
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
if(hadc == &hadc1){if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1),
HAL_ADC_STATE_REG_EOC))
ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
ADC_Vol = ADC_Value*3.3/4096;// 转换为电压
printf("ADC_Vol: %2.4f\r\n", ADC_Vol); //通过串口发送
}
}
5 o2 B& O% Y5 Y6 D. S4 A% x
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
; {1 c' U; g& x5 k! g, v
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
/ _, b3 e$ z" W: U3 N. a- J
微信图片_20241122152600.png # d( L0 Y* P/ q; |: Y% c

- h5 S+ {8 G" p4 N$ B* j' j
▲ 实验现象
- p' `8 t  `; V$ F' w1 [
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
( @5 ^7 S, l/ T7 M6 ]2 \3 U
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置
; S$ M+ k: F! F" {0 {+ i+ _. f
微信图片_20241122152610.png
5 p8 F& M0 ]* \- J! }7 K
▲ CubeMX 进行 DMA 配置

/ @6 d7 v" L  _4 ^7 t
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。
1 W  j3 c6 u; l  P
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef *hadc, uint32_t *pData,uint32_t Length)
功能:使能 ADC,通过 DMA 进行规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
参数 2:ADC 数据读取数组指针,一般为数组首地址;
参数 3:DMA 传输长度;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_Value,ADC_BUFFER_SIZE);//开启 ADC,开始 DMA 传输;

4 M1 Q7 G" x; F
HAL_StatusTypeDef HAL_ADC_Stop_DMA(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 DMA 传输;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Stop_DMA(&hadc1);//停止 ADC
' G% b3 W+ W2 i6 V( _
核心代码:
if(HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED) != HAL_OK) //开始
ADC 校准
{
Error_Handler();
}
if(HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_Value,ADC_BUFFER_SIZE) !=HAL_OK) //开始 DMA 传输
{
Error_Handler();
}

; I# M* ^* B+ L( l8 i- V
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。

  n0 c) x+ w# d4 E
void ADC_DMA_Handle(void)
{
if(__HAL_DMA_GET_FLAG(&hdma_adc1,DMA_FLAG_TC1))//检查 DMA 传输完成标志
{
__HAL_DMA_CLEAR_FLAG(&hdma_adc1,DMA_FLAG_TC1);//清楚 DMA 传输完成标志
HAL_ADC_Stop_DMA(&hadc1);//停止 ADC
float ave_vol = 0;uint16_t all=0;
for(uint8_t i = 0;i<ADC_BUFFER_SIZE;i++)
{
all += ADC_Value;
}
all = all/ADC_BUFFER_SIZE;
ave_vol = 3.3f/4096*all;
printf("ave_vol is %1.2f V \r\n",ave_vol);
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_Value,ADC_BUFFER_SIZE);//重启 ADC
}
}
以上为中断处理函数,需要添加到 DMA 中断中。当进入 DMA 传输完成中断之后,该函数先停止 ADC 采集,对上一轮 DMA 采集到的数据进行求均值,然后转换为相应的浮点电压发送到上位机,最后重启 ADC 转换。

8 V# m/ ]! K* J" y
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}
$ h9 g+ a6 M  ~& Y) i1 [
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。

- |: w7 Y5 b" s! e. O
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

7 U( }/ H$ c2 G; A2 a! a
微信图片_20241122152613.png + l. S$ |1 ?! ~$ X( V! n5 ~
2 S% W  S% ^3 u
▲ 实验现象

/ [9 q, S) U6 t4 H
4、内部温度采集实验

' v5 Z/ j( \* @9 j7 A
CubeMX 配置如下,保存后生成对应的配置代码:
( R/ d& d8 f& w: _
微信图片_20241122152616.png
/ ?' E) |9 {' h3 b; \5 I
. h5 i, A; a8 d4 A" S' `  c
▲ CubeMX 进行温度传感器 ADC 配置
/ z+ v2 M+ |, N- M( O
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。
4 Q1 [" M; c: e; o
相关操作函数说明:
__HAL_ADC_CALC_TEMPERATURE(__VREFANALOG_VOLTAGE__,__TEMPSENSOR_ADC_DATA__, __ADC_RESOLUTION__)
功能:将内部温度传感器的 ADC 采样值转换为温度;
参数 1:ADC 参考电压,单位 mv;
参数 2:ADC 采样寄存器数据,注意是读取的原始数据;
参数 3:ADC 采样位数,可选 ADC_RESOLUTION_12B、ADC_RESOLUTION_10B、ADC_RESOLUTION_8B、ADC_RESOLUTION_6B;
返回:转换后的温度值;
示例:
tem=__HAL_ADC_CALC_TEMPERATURE(vdda,ADC_Value,ADC_RESOLUTION_12B);//转换温度
) G6 \7 e3 [) S& q5 z
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10); //等待转换完成,第二个参数表示超时时间,单位ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
ADC_Vol = ADC_Value*3.3/4096;// 转换为电压
float tem;
tem=__HAL_ADC_CALC_TEMPERATURE(vdda,ADC_Value,ADC_RESOLUTION_12B);//转换温度
printf("ADC_Vol: %2.4f V Tem: %2.4f ℃\r\n", ADC_Vol,tem); //通过串口发送
HAL_Delay(500);
}
, f% Z) `: y% d+ b5 H# s3 C: [  _
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。
0 t1 ~# b* y; s
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。

' q  _1 _& g" j! H' x& `  l
微信图片_20241122152619.png 9 g4 w5 B/ u9 P, X8 m
▲ 实验现象

/ j- k5 {1 ~/ h$ v8 {2 W. D
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
1 g4 m1 w8 A! F7 x6 U
微信图片_20241122152621.png 2 ~8 c# I- s0 d& Y; @3 }
0 E6 C  V( y6 w+ J0 e- C- Z# u$ r
▲ CubeMX 进行 ADC 配置
3 \4 Y3 u& `* X4 x- U. D% o# e
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。

! K5 [+ ^- E! [& I! o7 K
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10); //等待转换完成,第二个参数表示超时时间,单位 ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
ADC_Vol = 3*ADC_Value*3.3f/4096;// 转换为电压
printf("VBAT: %2.4f V \r\n", ADC_Vol); //通过串口发送
HAL_Delay(500);
}

5 Q3 Q" M" s; ]$ B9 y( L. v
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。

  K( J5 z2 f' k7 W" O0 r) F& F
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
) W$ F" X0 C5 w4 X
微信图片_20241122152624.png
▲ 实验现象

; z8 w: r0 h# u
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png ) L( i3 _; W: m  Y8 o2 Z5 V: b' {
' W) {( W5 B, C! r4 j* k/ _% E+ @
▲ CubeMX 进行温度传感器 ADC 配置
! R7 r& E/ Y0 h, Q
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。
* y, g( b6 k8 p* h
相关操作函数说明:
__HAL_ADC_CALC_VREFANALOG_VOLTAGE(__VREFINT_ADC_DATA__,__ADC_RESOLUTION__)
功能:通过读取到的内部参考电压,反算实际参考电压;
参数 1:ADC 采样寄存器数据,注意是读取的原始数据;
参数 2:ADC 采样位数,可选 ADC_RESOLUTION_12B、ADC_RESOLUTION_10B、ADC_RESOLUTION_8B、ADC_RESOLUTION_6B;
返回:转换后的时间参考电压,单位 mv;
示例:VREF_MV =__HAL_ADC_CALC_VREFANALOG_VOLTAGE(ADC_Value,ADC_RESOLUTION_12B);//转换 VREF+
8 [2 A% W  d- J; ^* i% @
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10); //等待转换完成,第二个参数表示超时时间,单位 ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
VREF_MV =
__HAL_ADC_CALC_VREFANALOG_VOLTAGE(ADC_Value,ADC_RESOLUTION_12B);//转换 VREF+
printf("VREF+: %d mV \r\n", VREF_MV); //通过串口发送
HAL_Delay(500);
}
- L( x" n" N, ]8 O, y: m0 o# Z
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。

( L) p0 C! P1 l; R5 i
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。
- W6 s& S# c  P8 o/ M
微信图片_20241122152630.png
. q0 E! w( ^2 b% E/ V, S/ S

4 m, v+ w5 V6 \3 ^+ H
▲ 实验现象
( q+ c- D5 L8 h; P
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png
9 y* H# I3 Y' [7 }
" |% U0 P7 H9 o8 j% f5 r
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png 1 s* w6 r6 W" R6 u0 b
( D$ ~) p" @7 x' l. M9 L: W$ D! p
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png - s* X& G" t( t: A6 m
1 o6 g1 m7 N; K3 {3 J' Z9 M
▲ CubeMX 进行中断配置
6 F: E. U* }* N
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。

+ p4 h- g6 [2 w9 Q) j9 w
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据

8 I9 b( ?% M5 H
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
- M8 K. e" L) r- @9 _
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1
+ m, o  G! H" J* k/ A: m
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。

. [; b4 j7 \7 u
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
if(hadc == &hadc1)
{
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1),
HAL_ADC_STATE_REG_EOC))
ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
ADC_Vol = ADC_Value*3.3/4096;// 转换为电压
printf("ADC_Vol: %2.4f\r\n", ADC_Vol); //通过串口发送
}
}
: G- f8 Q2 g4 N# G5 I0 C* n
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
$ S. Z$ \: h* x2 t$ P9 O8 g$ E
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png ( P- }" K. y( ^' l% |
& |1 r1 s1 Q, D7 Y/ F7 R
▲ 实验现象
九、DAC实验
: f& a. H8 p( T7 o% @
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。

) \6 m8 ^1 S7 u( ^4 {$ b
1、DAC 软件触发输出实验

5 ?+ _% G4 F" B0 ~
CubeMX 配置如下,保存后生成对应的配置代码:
1 c/ ^" a* G1 E( T& a6 I
微信图片_20241122152645.png
; t+ C/ N% N) J

: }+ X3 I- `# G5 d- g; ?. S
▲ CubeMX 进行 DAC 输出配置
  N/ ]& M" Y9 D! a/ g# I
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。
4 I" c  R, k# K
相关操作函数说明:
HAL_StatusTypeDef HAL_DAC_SetValue(DAC_HandleTypeDef *hdac, uint32_t Channel,uint32_t Alignment, uint32_t Data)
功能:设置 DAC 输出电压;
参数 1:DAC 句柄,根据需要填写;
参数 2:DAC 通道,可选 DAC_CHANNEL_1、DAC_CHANNEL_2;
参数 3:DAC 数据格式,可选 DAC_ALIGN_12B_R(12 位右对齐)、DAC_ALIGN_12B_L(12 位左对齐)、DAC_ALIGN_8B_R(8 位右对齐);
参数 4:要写入的电压数据;
返回:操作结果,HAL_OK 或 HAL_ERROR;
示例:HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R,sinewave[temp_i]);// 设置输出值注意:此函数不会改变实际的 DAC 输出,如果想要修改生效,还需要使用下面的函数
9 q& j; j2 b  h. R8 G
HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t Channel)
功能:开启外部 DAC 电压转换;
参数 1:DAC 句柄,根据需要填写;
参数 2:DAC 通道,可选 DAC_CHANNEL_1、DAC_CHANNEL_2;
返回:操作结果,HAL_OK 或 HAL_ERROR;
示例:HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);// 改变输出值
" u) t3 t0 {, C0 z3 O& }, w: K

, `2 {- f/ H1 X7 v3 s
HAL_StatusTypeDef HAL_DAC_Stop(DAC_HandleTypeDef *hdac, uint32_t Channel)
功能:停止外部 DAC 电压转换;
参数 1:DAC 句柄,根据需要填写;
参数 2:DAC 通道,可选 DAC_CHANNEL_1、DAC_CHANNEL_2;
返回:操作结果,HAL_OK 或 HAL_ERROR;
( t& {+ u- ^: m  h1 r
核心代码:
while (1)
{
for(temp_i=0; temp_i<60; temp_i++)
{
HAL_DAC_SetValue(&hdac1, DAC_CHANNEL_1, DAC_ALIGN_12B_R,
sinewave[temp_i]);// 设置输出值
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);// 改变输出值
HAL_Delay(1);// 延时一毫秒
}
}
6 m6 [7 U& t4 r) X
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。

4 R. r0 }4 i% T  n
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。

; d$ M  Z# J/ y3 \6 ^6 ]7 c9 n
微信图片_20241122165909.png
# w/ C0 P4 z: k

# I& D( J% b9 Y$ P% x0 U+ R! K5 r
▲ 实验现象

- i/ L$ r* {5 \2 T- G
2、定时器触发 DMA 传输 DAC 输出实验
9 ^( i) z- F8 V! t# s/ |, i
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png
. n2 I* b- Z# G4 C3 H6 ]" V
. v: I2 O! [1 O' [* U. f8 E
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png 0 w' p# Y9 c- |9 K

7 B. @0 h. G* F- [) s  y3 d' F- ?
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png
2 }  d* ^6 O  {$ {

+ N3 m  p2 K9 x* O# L
▲ CubeMX 进行 TIM4 配置

' J) f% B' J6 @1 i' x( O
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。
9 y/ d' B& x, a0 N; N+ h0 w
相关操作函数说明:
HAL_StatusTypeDef HAL_DAC_Start_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel,const uint32_t *pData, uint32_t Length,uint32_t Alignment)
功能:通过 DMA 方式开始 DAC 转换;
参数 1:DAC 句柄,根据需要填写;
参数 2:DAC 通道,可选 DAC_CHANNEL_1、DAC_CHANNEL_2;
参数 3:要通过 DMA 发送的数据指针,一般为数据首地址;
参数 4:要通过 DMA 发送的数据长度;参数 5:发送数据格式,可选 DAC_ALIGN_12B_R(12 位右对齐)、DAC_ALIGN_12B_L(12 位左对齐)、DAC_ALIGN_8B_R(8 位右对齐);
返回:操作结果,HAL_OK 或 HAL_ERROR;
示例:HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1,(uint32_t *)dac_wave1,SAWTOOTH_NB_STEPS,DAC_ALIGN_12B_R) ;// DMA 方式设置输出值

6 w5 O$ z2 l( Y4 ^
核心代码:
//正弦表
uint32_t dac_wave1[80]={
0x0826,0x08C6,0x0965,0x0A02,0x0A9C,0x0B31,0x0BC2,0x0C4C,0x0CD0,0x0D4C,0x0DC0,0x0E2B,0x0E8C,0x0EE2,0x0F2E,0x0F6E,0x0FA3,0x0FCC,0x0FE8,0x0FF8,0x0FFB,0x0FF1,0x0FDB,0x0FB9,0x0F8A,0x0F50,0x0F0A,0x0EB8,0x0E5D,0x0DF7,0x0D87,0x0D0F,0x0C8F,0x0C08,0x0B7A,0x0AE7,0x0A4F,0x09B4,0x0916,0x0876,0x07D5,0x0735,0x0696,0x05F9,0x055F,0x04CA,0x0439,0x03AF,0x032B,0x02AF,0x023B,0x01D0,0x016F,0x0119,0x00CD,0x008D,0x0058,0x002F,0x0013,0x0003,0x0000,0x000A,0x0020,0x0042,0x0071,0x00AB,0x00F1,0x0143,0x019E,0x0204,0x0274,0x02EC,0x036C,0x03F3,0x0481,0x0514,0x05AC,0x0647,0x06E5,0x0785};
//正弦表点数
#define SAWTOOTH_NB_STEPS 80
& Y0 v- q3 b6 A* o9 x
以上为正弦表定义。

# j. S# o3 Q' u7 F
if (HAL_TIM_Base_Start(&htim4) != HAL_OK)//开启定时器 4
{
Error_Handler();
}
if (HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1,(uint32_t
*)dac_wave1,SAWTOOTH_NB_STEPS,DAC_ALIGN_12B_R) != HAL_OK) //开始 DMA 传输
{
Error_Handler();
}

& D4 \0 ~/ k3 H/ k, b. c
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。

, T/ \+ z( P- x2 u+ @9 C) d/ U1 V( m0 t
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png : u. C+ m. |6 w  m8 H1 w0 K% g& w
7 [5 O3 K& S' a+ t
▲ 实验现象

0 O+ k, F, V) r# e8 i+ U9 q
3、定时器触发 DAC 输出噪声实验

& f! [* r% a8 ^* Y% F
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png
6 N2 s, D# [/ s+ S+ g8 T) `
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png
% ?- i, D* T' L) g# T0 S

8 n2 p' z9 ~  I# h9 r& x) v! j' h' f
▲ CubeMX 进行 TIM2 配置

, Z) k  s: F" U& i2 F; ^
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。

/ u& N0 }6 j& f1 Z9 Y3 ?
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC
* H5 o7 F& z# |% L5 s
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。
, J1 O- h$ K) e; j9 E  I: L# N
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png ; }0 q# Z' m  D& k( p! y
▲ 实验现象
% [& G) U' i3 i+ h8 z
如有侵权请联系删除

4 P" L$ C6 o7 H/ T- W
转载自:AI电堂- l* K9 p+ @$ {" x, k

; J. T9 `/ L, N1 l, x
收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版