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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验
" s+ W$ Y+ `" U# I6 o! D! A实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。
( N8 t6 L" F4 v0 W6 n
1 O  j/ ], g5 E1 P; C# G& C
1、软件模拟 SPI 驱动 TFT 实验
1 q2 C+ A' W- w% L) {4 UCubeMX 配置如下,保存后生成对应的配置代码:
/ ^! i3 D" S' k, U( P* P1 [8 b, {
13.png 3 G% o$ S4 @* ?' Y$ B% ?
$ M; G  E( g6 o2 e# \
▲ CubeMX 配置

" D/ Z( G6 o. o; s% m
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。9 Y2 `, |( i# U5 l- m- l

# u, B; x& g; G5 y" L6 K
相关操作函数说明:
4 ~1 {% `* s/ j, x6 P6 o9 ?6 k# vvoid Lcd_Reset(void)
. K& q0 l6 r0 B, f2 g" @9 M7 N

3 E6 g6 n' h" Z' G功能:液晶硬复位函数;
& V* ]- T% d1 Q- P7 Q参数:无;8 R3 z7 ]1 E0 D% n( m
返回:无;
' C( Q/ V' K% m说明:液晶初始化前需执行一次复位操作+ ~" F( I& @5 K6 b& b
void LCD_Initial(void)
& g0 R& n4 @6 V+ Z+ L功能:初始化液晶;$ ~/ j) j% u5 P
参数:无;
4 p( f0 I" R. }% u返回:无;
- I0 q1 N- J( E" F说明:在对液晶写入内容前需要进行初始化配置;% v' D0 M5 a1 e- P
void Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
6 w7 M2 P5 V  @' W0 M- c* B6 u7 t
4 F5 I0 Y  v2 a0 k, J& n
功能:Lcd 矩形填充函数;3 A; U% [# ]5 E+ w7 h
参数 1:x 方向的起始点;' A5 b8 w6 a- i; ~" S
参数 2:y 方向的起始点;& g1 Q# F/ n& \8 p
参数 3:x 方向的长度;! O8 X: S4 m6 _5 i, Q
参数 4:y 方向的长度;
0 I. @! n" Y: S6 P. C$ b参数 5:填充的颜色;
+ u7 w2 v: Q9 m' E5 N& x" `- b返回:无;
+ X" N- o( e1 }) v, @5 R0 |说明:将指定区域内填充指定颜色,常用于清屏- }/ b* q# \& b2 |% \# O' i% ]" A
void BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend)
7 f; {0 j# H6 @  M! B
6 ?* d' b. k0 W2 {  g+ {功能:在一个指定位置开一个矩形框;
0 _  k5 t  F' V0 Y8 x. a% c' v参数 1:x 方向的起始点;$ i* m% Y+ A+ J: M/ j
参数 2:x 方向的终点;0 {6 B5 W; r5 e( o4 J  p' A1 }; k
参数 3:y 方向的起始点;% t4 M( a9 e/ d" ^: E
参数 4:y 方向的终点;
( e( b2 i  [- Z# V3 _返回:无;
/ B8 ~0 F2 S" f1 i5 B* X( _" X. x" L说明:开一个矩形框,方便接下来往这个框填充数据;5 H1 x9 O1 e/ N9 S( R) g
void DrawPixel(unsigned int x, unsigned int y, int Color)
  w* `- v6 N6 }* H2 T7 G% a功能:在 x,y 坐标上打一个颜色为 Color 的点;
# h1 Y' u/ [0 E  ~6 _! y参数 1:x 坐标;
3 d3 s1 U# L4 X2 N参数 2:y 坐标;
" s' Q9 [: C  V. ~1 g- \参数 3:点的颜色;
4 f# G- F) Q, O7 h, M返回:无;5 T* \9 v7 E$ i1 w
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)
3 x) d# L; w3 H; c3 M7 G; R8 i+ k! J8 S! T5 K" Z0 r
功能:显示一个字符串;
0 f- ~4 |# r5 m* Q/ m3 d8 \. ]4 t4 z参数 1:起始点 x 坐标;6 d) ~; Q* I* _8 `* r! I
参数 2:起始点 y 坐标;
2 w- [2 f# A: ]) |7 D参数 3:字符串指针;
! t8 n+ ~! c( I) N, K- h  E  d) l参数 4:前景色;
/ t# w2 o* G1 y7 j% M, h参数 5:背景色;: I8 G( E  s+ p& T
参数 6:有无背景色;- _2 A# O* _7 L: x
返回:无' }: _# s" J2 b! I: U

+ p, w4 f( @# \( q8 e
6 T( C( k  G: u. \( m2 P
核心代码:6 d1 Z4 O  y5 {& J9 U
LCD_Initial();
+ |! \; {0 d' @# I9 e1 }Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
- W$ \$ Y& C( U) F) s8 r7 F# ]Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏) M/ g( q( X! k
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏
3 ^" C6 C0 v! \$ B/ i9 h- N  YLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏
9 L/ k& k8 a/ Q; q  }LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符0 ~, v8 K/ X# E% M
0 B# z. |8 }' X) l( c: H' K
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
! w' T6 z! _# x+ W( f$ Y6 i( z6 C7 d0 ^3 q
3 p3 F8 I8 H) r* {+ G0 s4 s6 @
实验现象:
9 ~9 ^; S4 d, Y, J& \下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。2 T" e. D; Q% d, v
* \. m. \5 C! y1 c0 I0 I

$ F3 z4 c% V1 ?; ]1 E; j2 M2、硬件 SPI 驱动 TFT 实验
: b8 Y( @# z) s* i% zCubeMX 配置如下,保存后生成对应的配置代码:
& S9 P- b" i/ I1 D1 ?; |; O
1 K4 ]0 k: t, y$ c: @9 D4 |2 ?
12.png 0 @" y3 ]; _( n$ l4 a# b

% }: i3 ]$ k6 A$ k
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png : Q; P) F2 n. W1 T" D8 E$ C
0 Z. [. w# l6 M* P
▲ CubeMX 进行 IO 速度配置7 F6 U- i/ s5 t0 Q
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。
7 C$ R, Q$ Q4 o" L: |& L
% r" l0 Z7 C$ O% x

, A, K3 g- {' P& e) f# v4 H+ e

6 v2 C$ ~* i8 o
相关操作函数说明:
6 t- n5 `/ p: [# T: O5 V% O
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

* n4 g, D& k: Z. n0 V8 E
功能:通过硬件 SPI 发送一组数据;
9 A9 M* J& M& n* d! W
参数 1:SPI 句柄,根据实际需要填写;

/ O6 L) X% P* U, Q# k" f4 t
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
1 E1 F, O8 l8 S1 t- q2 f' x
参数 3:发送数据长度,单位字节;

" m7 F2 i" j+ n& [9 N
参数 4:发送超时时间,单位 ms;

+ d$ G9 l* I5 @* t
返回:操作结果,HAL_OK,HAL_ERROR;

- l1 r/ a* @; U
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据

6 M, M1 Z$ Z! A3 b. Q
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
, s) _  Y- f" g+ ?3 f8 L/ y/ b$ ]* D
功能:通过硬件 SPI 接收一组数据;

) P: y$ S% l; h- T
参数 1:SPI 句柄,根据实际需要填写;

1 Y: Z  B3 l3 q" p$ t! _
参数 2:要接收数据保存指针;

5 L- k2 p8 N3 j1 `/ N7 e9 p
参数 3:接收数据长度,单位字节;
$ y8 ~+ Z# `% i' X) E
参数 4:接收超时时间,单位 ms;

' x# o. M7 f& \: W
返回:操作结果,HAL_OK,HAL_ERROR;

& S- j* @( `  N5 E( j3 h
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)

, s  `( x. F# T2 L! |7 K7 P" d7 u
功能:通过硬件 SPI 交换一组数据;
/ R0 n1 C. Y( b5 O# M9 K
参数 1:SPI 句柄,根据实际需要填写;

( w: V& m& l- ~2 x5 ?* k
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

2 s9 r3 o' y# |. h9 @
参数 3:要接收数据的指针,接收数据数组的首地址;
, y( V- f" C2 u9 w
参数 4:数据长度,单位字节;

3 e" \% @! C. m' }$ q& r
参数 5:超时时间,单位 ms;
  P- P6 s& Y+ b& ^
返回:操作结果,HAL_OK,HAL_ERROR;

8 p7 X5 D2 m. X2 h2 ~  X
/ l0 f. Y( o, {6 {& z- ?" Y( d3 Q

- i: ?$ l1 ~- |& {0 ^: K1 ~2 D: I
核心代码:
2 E1 I. Z5 O* l+ S
LCD_Initial();

& b. ?. A  Z; [, e$ a& \
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
4 Y! v. a0 _, s# w" d
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
8 k% ~3 H& B* k" ]. l
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏

5 G( E8 K. e8 }6 m$ }  \
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏

: _( m! p  v7 [& [- r/ Z3 {
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符

$ Z" t: M+ E0 g) O% A0 P  ]
* j& Y% T  R* F! j8 }

% Q+ v) E- r4 g9 o; F& Y
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

* A- d9 w. Q! U" ^3 v

$ y. y! U, ^4 I- T

! H2 |& f7 w' \8 f8 G3 Y' C: _
实验现象:
2 p1 Q; w6 G( j' ^6 k$ y
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
6 d% u8 J& Q3 X

9 G6 H  ^# _  L- L; z8 k/ x$ c

1 P. Y3 z3 A# [$ u# q: a1 ]8 T
3、硬件 SPI 驱动 TFT 实验(DMA)

2 f1 a+ c; M5 a1 _  M/ }  Y2 w
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png
9 M: }+ a- {9 c1 I" [; d/ f
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。

& I; F* x5 v, e, z" J
相关操作函数说明:
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)
- F, F% ]: `9 e
功能:通过硬件 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)

# k" K4 G. k6 r
功能:通过硬件 SPI 的 DMA 方式交换一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
参数 3:要接收数据的指针,接收数据数组的首地址;
参数 4:数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
注意:使用相应 DMA 时需要对该 DMA 请求进行配置;

& {: G9 u: _$ `8 f: U
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}
9 j2 l4 n+ w( i* f* H
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。

6 O9 S" H5 ]  R- O
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);
}
5 y3 _* D. \7 A. T& ~' L
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。
+ J  n5 U9 j; K
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);//显示字符
* w2 e; ]7 {4 y% O# l: [( m
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

! C+ ~4 V% {2 ?& ]4 u9 a; y/ }
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
8 h$ y  M4 b7 _9 j8 u
2 Y7 }. z) K* C% k) G6 `' k
七、IIC实验
# c( D" A) _; j/ k' V
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。

# i. }+ F8 [# X# P3 r
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:
8 |& k/ @7 \8 m: O& @
4.png
6 O" m  \% h3 W: n; G' M+ N
) M$ _% \' h2 R% M! U0 Y1 K) V
▲ CubeMX 进行软件 IIC 的 IO 配置

% q9 i; V* a. J5 L1 D0 O3 k
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。
: n8 ~. _) s' C6 d2 e2 p8 j, i
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式
8 S- ?" V! \( `+ O
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式

& H" \: n; |: o' G, @4 s
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;
/ t. K) r& J9 m  N; j) T3 X
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;
# ~- U5 `+ w' b+ [( F5 w, q# n
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;

; d- y6 v! E, Y8 ^1 E- {" c
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;

) |4 G. f0 e+ l" ~' I
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
参数:无;
返回:无;
& F+ P# }; g' _0 n" J! h6 I( f
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;
3 {8 D8 h/ W! g8 ~$ [( u
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;
3 r8 M" P- d1 ]: c2 s3 R
核心代码:
//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();//停止信号
}

  E6 z( L8 U3 K9 G" P
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。
4 [7 V" p5 h" @
I2CInit();
uint32_t i;
. g( t" B2 l. [( ?6 j4 K8 t% d
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);
1 |; q; f1 N. o. S. h+ j6 \
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");

" Z  g# U7 \+ {) Z( `
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");
}
: D- B5 x7 m2 F7 P( d: @
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

6 I9 K1 }# T7 m. d- A1 E+ H
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
$ p( d7 t3 N% Y
微信图片_20241122152540.png $ ~# G  v; I# b( ?9 V' Z& ]

" j5 p" ^; M/ t' v
▲ 实验现象
/ \# P$ y5 c8 y/ p5 }
" M" s$ T6 ^2 P# [
2、硬件 IIC 驱动 24C02 实验

, a* x, c" k0 n( o: E
CubeMX 配置如下,保存后生成对应的配置代码:
4 C1 {4 h) W/ K
微信图片_20241122152543.png
+ d3 E4 L# `1 }4 {
& }& w3 v8 J- m5 R% T
▲ CubeMX 进行 IIC 配置

# n) c) s1 K* R) h6 U
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。
8 {. j7 L' M( C: @
相关操作函数说明:
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;

4 L" o" V' H) F7 g# z
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;
! u! ?2 A' n+ B1 O' k0 B& B
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 地址读取数据;
3 _; Q& j( S/ x5 C: e1 {

8 A+ @# C' A1 Q0 C2 s
核心代码:
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");
}

) `/ ^9 i& P; O0 P$ n9 `9 e( g
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

7 M: M$ T" p; N( O- G) D$ [9 s
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
" g$ W* r! f2 W" Y7 R7 p+ ^' a
微信图片_20241122152546.png
# t( C+ k: r" \4 C4 i7 g
▲ 实验现象

# P0 D" d" v. n( j- m/ I  y1 T! ~
: z+ Z4 M+ g  i- e% i
七、ADC实验

$ V" D! M$ r. @! z
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。
$ f, ^: B8 B1 _6 l
1、ADC 查询方式单路采集实验

9 e+ x9 N) [! ?$ C
CubeMX 配置如下,保存后生成对应的配置代码:

5 t3 z( G& g% K! l) m% _8 p
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置

+ i7 b9 T: U. {& ~
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。
. m9 e1 E: q( ~. _
相关操作函数说明:
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 进行单端采样模式下的校准;
# X+ c; {, `8 |; v* r) L; m
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换

" o5 u0 Y/ H2 y) K9 c, j4 }
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;

/ O8 J6 e) Q  \) c$ }
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); //等待转换完成
- t: X6 s! r  H6 O
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值

- C6 U) u# v6 ]! A# {7 R5 }
核心代码:
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);
}
& Q1 O0 h, a- o% r9 ]
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。

3 N0 d* Z3 D9 [4 V- F4 y* k+ _! r
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

( W  X1 k4 z" y; Q# T
微信图片_20241122152553.png
7 j- ?8 i; l( D$ e! w; G5 D
& b8 z# d- y0 Q; ^% M+ [
▲ 实验现象
5 O# C% B  c( X5 H4 k. o( d

/ V) ^$ x+ e! d9 k. q
2、ADC 中断方式单路采集实验

- k9 S9 ^% R! T, g
CubeMX 配置如下,保存后生成对应的配置代码:
8 v! K+ a& c- `
微信图片_20241122152556.png
▲ CubeMX 进行中断配置

: p0 ^$ C; ^# b  G5 u; |( F% k5 j
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。

5 q* M& S# a4 W, E: x- 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 转换完成之后会触发中断,中断中读取采样数据

/ C8 u5 M3 z$ u- z0 P
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
$ d9 e. A' g6 F  @3 @+ T# s! a
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}

  i* `" d: E) o
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。

* l! B* v2 W6 P7 I2 X9 A
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); //通过串口发送
}
}
( q+ f* `. B$ p6 ]- l5 c: Z8 T
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
( _5 ~3 O) G& M& ^) g* k
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

6 O# o% |7 x, ?: L: W
微信图片_20241122152600.png - h0 _1 n) F' G
5 T0 T# J0 v$ D" Y! X7 S
▲ 实验现象
: j0 t6 w7 D% j3 Z7 Q% ^
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
  E2 X  K& B; g4 Q9 h% v9 p& O' T
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置

- o# V4 d5 {+ x5 n; J2 Y* w
微信图片_20241122152610.png 0 H- c7 |* Y% ]6 j# I
▲ CubeMX 进行 DMA 配置

3 g# c' g+ ^9 \& y9 ]
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。

" ~2 ~2 S9 I* q; I. ~/ I8 O
相关操作函数说明:
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 传输;
& C8 ?) ~3 \* @6 c8 k3 H
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
" Z  b; U% I) u7 U/ e
核心代码:
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();
}

: l$ L6 [7 P' v5 r) i$ e
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。
. V% Z0 y" ]3 C/ \% x: l4 h# L
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 转换。

5 y0 P2 h  h: l4 e% Z1 w/ X
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}
+ n. Y6 G) g9 C. x* \
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。
& D6 B% F" W% X- |4 {1 Z
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

* g* n. a6 i1 q* j# R& u1 V
微信图片_20241122152613.png 6 B& _, T' n1 a. p# V  }
0 F* `6 {, d, C' {: N9 t
▲ 实验现象

  D8 `; Z) [- s  r# i7 D& @
4、内部温度采集实验
& K7 N, m) P9 {; O
CubeMX 配置如下,保存后生成对应的配置代码:

6 o5 H8 B( Y: V: S, d% `( T
微信图片_20241122152616.png
% [" {% G" _9 Q4 ?- u: t' W
' S. P; ?+ r& z  n5 I/ d4 i
▲ CubeMX 进行温度传感器 ADC 配置

: N" l0 G% F2 I4 o( ^
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。
0 ~* E" f4 L9 u# B9 y4 ]
相关操作函数说明:
__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);//转换温度
8 J/ }& ]- [0 ~
核心代码:
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);
}
' P- {, ?1 S3 I% s0 E
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。
! z3 H( J- B2 y( y5 _; I
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。
. k0 M/ G( o, |$ I! R" Q! U9 U$ c
微信图片_20241122152619.png & s( `; d4 ?) ^- t2 R
▲ 实验现象
- z2 q& ^. ~  v! c+ @8 `, ~' S" k8 j; A
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
4 T% m4 j7 u  g6 [0 R$ |8 ]0 J1 n
微信图片_20241122152621.png
) V! o$ j/ \! s) L7 P& E* ?- R# Y
3 k+ d7 B* B5 L  t8 z9 }
▲ CubeMX 进行 ADC 配置
* ]/ m/ x. R* P! G
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。
7 T/ g' v& ?' o' H
核心代码:
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);
}
4 I8 E4 @: K0 H4 f6 ~8 H4 W" e) _# @
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。
0 D: ^' O  S6 X: f6 k
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
* P! B' H; x8 {
微信图片_20241122152624.png
▲ 实验现象
' G2 J% f" n; Q, f5 @4 K9 q
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png
; c; l5 H+ X; \. M' @8 O
& l* S/ Z6 m8 e6 W# @" D: g6 {+ R( F
▲ CubeMX 进行温度传感器 ADC 配置
! ~' z% V$ K: n+ \  u# s
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。

+ B6 _( Q6 w7 r* V- ?3 Y, Z
相关操作函数说明:
__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+

! o3 a" c1 Z% D- ?5 J" I2 j
核心代码:
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);
}
, y+ E& n5 b9 J! M. b
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。
6 K7 Q% ?$ f/ R7 [6 `8 F) s
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。
! z7 G- `8 ?/ G4 s
微信图片_20241122152630.png
7 O  r, p5 J% G7 A
% }: z( y% r* y) o4 E$ |5 K
▲ 实验现象

7 h& ]. h) \9 i) K& p
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png + s4 A% j4 z: r/ E! d. ]
- A' k& m1 l, J. Y. [# e" y! T3 g
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png
/ c% x9 t; }5 }1 j9 v  q

' q( g8 p' Q0 F
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png
* i4 v, Q' H' Y; m$ [9 r, S- y
0 |* P8 `# M$ L) S. J3 s+ i2 K! C
▲ CubeMX 进行中断配置

% y! Y& c% R. {! \& @
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。

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

( H8 V  ]4 V! g* V0 x
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

3 H  O3 {2 Y9 W) I$ A
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1

3 v& D: Y3 i8 ]7 N( ?
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。

- u. E3 D, x" K7 b# E# s4 c4 b
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); //通过串口发送
}
}

6 [5 o( H. q! \. {& o! O) k1 I
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
' j( T4 T! |' v/ U, w& c
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png 7 J, b' n& @8 t4 m) _; B
, i% q4 ]6 ^! N7 a; L6 b) ^- H
▲ 实验现象
九、DAC实验
: r: Y- B# Q( P) i( p% g* e
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。

! x4 c( ^8 p1 }% i
1、DAC 软件触发输出实验
& F/ ?1 g" M9 j' H# o
CubeMX 配置如下,保存后生成对应的配置代码:
* s/ i( \/ o( _9 F! y; e
微信图片_20241122152645.png
+ O% j) R! M8 B8 [

: ]) v- j6 \) Z2 T7 X$ Z  s
▲ CubeMX 进行 DAC 输出配置
' }& d8 s$ `- _! @( b
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。
5 [& P: e' B/ a$ \& |* U
相关操作函数说明:
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 输出,如果想要修改生效,还需要使用下面的函数

1 S' e3 K2 |8 G, [- U8 p' {
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);// 改变输出值
; }0 {5 g6 R" v8 C
- y. C" E9 Y0 H1 F
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;

* ?( g! A) b, e" p, N" e
核心代码:
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);// 延时一毫秒
}
}
/ M1 X- ^1 ~1 j! H5 U
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。
2 t! U$ Y: ^1 B; D$ @( K8 T! e
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。
7 k9 B* f+ N' N' E: y/ s$ E
微信图片_20241122165909.png
, ]1 e$ K8 L5 ]6 b0 [( _
3 A8 I" m8 \: ?( H$ @( E3 r- a% {
▲ 实验现象
' M( H9 L3 f: @, ?7 l+ f' B+ }' D
2、定时器触发 DMA 传输 DAC 输出实验
0 n0 G$ \, H  ?* [% a: i+ {
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png
% Z6 }3 b* I2 ?6 a7 m) {% x

$ H) [7 i8 i  e3 K: T
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png 3 T! h+ t7 I! Y! j

' p& V# z  \8 N+ x+ }1 b  ?
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png
" Q5 p) r% w4 X" f4 g. o& q
& y* a. v1 Q  z5 A, `
▲ CubeMX 进行 TIM4 配置

# |( v" t4 J7 Z2 |5 Q- E, {
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。

  t3 C% m6 D4 p' \1 `" u) H# t' \
相关操作函数说明:
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 方式设置输出值
# c( w! I& G1 E/ H5 E! R2 u. C
核心代码:
//正弦表
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

/ y* Y0 |& P% o/ ^% H6 z- o
以上为正弦表定义。

3 `8 i3 R$ Z8 T# A% P% Y7 m
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();
}
  |  ?0 `7 I# }  n
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。
0 e7 Z. O/ y# p# k# ]
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png / S' Z9 h2 q( b8 t, T+ O  s

* ^6 Q% K2 z9 R/ X
▲ 实验现象

) y6 X# B4 X% }2 n9 r
3、定时器触发 DAC 输出噪声实验

4 E6 r5 o6 r4 B
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png & `2 {7 k6 L* ?$ g8 m2 g" V& M
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png 7 D! h6 P4 N  i0 `$ |' w5 x2 ?* A

. j( z" \2 u6 Q7 f: [% J
▲ CubeMX 进行 TIM2 配置

2 o0 t+ o6 Z+ z  a
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。
$ |% C6 H4 m  U
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC

) a' `2 s8 [0 M$ s' U" D
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。

7 C" I' S/ P; ?5 \+ w1 |2 ^
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png
: X& S0 `8 D3 k# G& @
▲ 实验现象

9 @9 O7 f6 K$ l: n/ Z) l
如有侵权请联系删除
9 o. F/ H. T$ Q
转载自:AI电堂1 Z7 m6 b8 L0 _( M, a5 X' I0 m: L

/ l4 Q  n/ y. \. ^  y+ S
赞 收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版