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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验; c" c! S8 I! T9 O
实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。, d) V7 b5 ?& n+ @  r) m. Y  V9 W" _
/ Y" C, W2 A& _1 V
1、软件模拟 SPI 驱动 TFT 实验
# J* ?% B& F4 v! MCubeMX 配置如下,保存后生成对应的配置代码:
/ x: p( t/ J% ]
13.png ! x" h- Q) }! ~! y% g8 b

( \* h* C1 z7 N& x
▲ CubeMX 配置

8 c% M+ n1 e7 D5 p  P6 T) a& _
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。
9 R! s' E3 ?5 o# j$ O. G! S/ l8 p8 G9 L: k7 ]
相关操作函数说明:( Z4 w* R$ R. x* B! w) }- j3 R
void Lcd_Reset(void)
" o* Y" H" k8 J  p; Z
2 A8 h( m  K& x8 M4 c) x
功能:液晶硬复位函数;
, C- A5 K0 g" _5 b参数:无;$ u3 s, f& l! i9 j" t4 Y4 I5 h
返回:无;: s% R2 P8 j: {3 v$ y  n0 ^0 ?' A
说明:液晶初始化前需执行一次复位操作9 @) R1 U$ Q: o: O. A: N+ z
void LCD_Initial(void)) M" ^+ `- K6 Y  u4 G
功能:初始化液晶;; y2 h# M* D  f( n. A0 B# N
参数:无;
# O4 @& E- b  M7 c! J) B  q返回:无;9 a% Q  r3 z. P
说明:在对液晶写入内容前需要进行初始化配置;( K4 G8 z+ F, x! i
void Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)# A. H7 t0 F) y, O. E

! M, {; e8 B& f8 p4 k功能:Lcd 矩形填充函数;
0 u6 c; p4 B7 j: R3 e参数 1:x 方向的起始点;
+ M7 x; }, x' B, q& M参数 2:y 方向的起始点;0 {* n- s6 F' x+ o% S
参数 3:x 方向的长度;, p0 W2 C3 Z+ a* M  u* d, w
参数 4:y 方向的长度;
2 c6 z; O- Q+ A! A参数 5:填充的颜色;
- u/ k1 G& |, b3 H- m% i返回:无;' ~. s% c+ g1 q
说明:将指定区域内填充指定颜色,常用于清屏! B, w2 w; D! X6 a4 u7 L
void BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend)$ c9 @8 D' A! K! {
1 L) d- i$ q8 I% ?1 S& q( v: G5 c0 \
功能:在一个指定位置开一个矩形框;
/ |' f2 `- f8 ]7 |7 q5 i参数 1:x 方向的起始点;9 r% W* @1 Q2 W! U
参数 2:x 方向的终点;- K4 b  ]! T- D$ V2 y
参数 3:y 方向的起始点;5 _. t. {% [. ~+ D4 e; K6 `
参数 4:y 方向的终点;
$ A4 `0 J$ h3 |+ V, g  Y返回:无;
, [8 l5 c1 ~- X% }2 Q5 n说明:开一个矩形框,方便接下来往这个框填充数据;- H' e* y$ V0 G2 j: r
void DrawPixel(unsigned int x, unsigned int y, int Color)$ J5 i) [) T8 x
功能:在 x,y 坐标上打一个颜色为 Color 的点;/ J4 z2 F1 Z' }- u$ b  d
参数 1:x 坐标;  v( V# ?4 _- S, d& e4 s7 e' ]1 g
参数 2:y 坐标;
, p! l( o7 h& |参数 3:点的颜色;
2 \( l" \: ?- M  T& N返回:无;# \' o: Z: v0 T
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)
1 w  `" p% ]1 u+ K" Q
& ^! {8 i6 c4 l- \' ?功能:显示一个字符串;2 V3 K4 S$ i" C* D
参数 1:起始点 x 坐标;/ U5 Y# p) T/ U3 F
参数 2:起始点 y 坐标;
0 y% y! P! ?0 _参数 3:字符串指针;
9 R8 ]) X9 @( P+ F8 h4 Y- p0 X参数 4:前景色;
; g! }0 z  j/ h) s, j参数 5:背景色;, [) n1 z: J" a. z
参数 6:有无背景色;
$ [" K9 J% {; \, V# ~- w- G* |返回:无
- E8 A. E7 k  V7 ^& Q
) C8 J1 ]5 a3 Q

- N" {) H* X/ L/ a# j+ U  d( L( w核心代码:1 _  e, t, k5 c: u/ X  I- E
LCD_Initial();
" b! c# V' k5 Y( ^/ R2 m0 z) TLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
7 I* S; |+ o/ ]" M5 v$ p9 J% TLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏! h% G- d3 [+ L# Y/ z
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏
: n. l7 Y7 E, ?+ [2 B2 ZLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏
. p2 ?9 m: H8 e$ c' J& J" }LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
+ B7 O1 w, z( [+ q; ?. X( {+ `. Q7 f- _! h4 t% X8 e
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
3 v& V6 u7 x" w& M/ z% ~' E: w; n9 h2 ^

. ^+ g0 w$ k" ?4 s, [3 B实验现象:# _/ R5 D% Y/ M! Q' G1 a+ q
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
) O/ Z. `7 I1 L4 f; w1 P* L9 F1 E$ o* q8 Z! F/ s" ~

: I; Y; @  o/ e+ l6 W; u! P2、硬件 SPI 驱动 TFT 实验
, M: j3 c9 Y) E& @- ?CubeMX 配置如下,保存后生成对应的配置代码:. p" C/ A1 m* g# `0 {. k% t% l" {1 _  |
+ j& s8 l. j) q! g
12.png
9 r' ^( k& B1 T& i+ ~+ h

  ]3 W5 R1 ]. r2 m( a$ c
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png " f3 c0 O2 p3 S  w0 @

" h' Y5 a6 A; ]( E$ D, _$ ]5 n5 H
▲ CubeMX 进行 IO 速度配置1 e; h. Y! \, Y; l" k) R
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。
3 E) V7 x! S1 }" m. y
# L, c" F7 r1 ?% D8 W
! R4 A, W0 z0 D. g1 o4 J

; V+ c& w4 u: F3 V! R, y
相关操作函数说明:
9 F0 Q8 H: k8 V
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
. q2 k4 z8 v: B6 \% r
功能:通过硬件 SPI 发送一组数据;
" E# C- q8 I: X) a4 E5 W
参数 1:SPI 句柄,根据实际需要填写;
; O! [1 L8 _/ E
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

; p8 s* H% m$ S7 G  X. d
参数 3:发送数据长度,单位字节;

- ?8 ~2 g7 y: y
参数 4:发送超时时间,单位 ms;

& K  w# A  r# D
返回:操作结果,HAL_OK,HAL_ERROR;

1 ?' m. E* c2 q' a
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据

. d% Z$ N( ^9 `! @+ ~
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

+ |1 `" d  X4 M7 H$ R" |9 `% L2 W
功能:通过硬件 SPI 接收一组数据;
3 T- A; b2 H1 e3 l+ B
参数 1:SPI 句柄,根据实际需要填写;

, v  j' ^2 g: u9 u
参数 2:要接收数据保存指针;
/ ~/ r$ X/ l& L+ \
参数 3:接收数据长度,单位字节;

/ H% a0 `4 w7 p
参数 4:接收超时时间,单位 ms;
# E7 }, C6 \$ ?' q, T
返回:操作结果,HAL_OK,HAL_ERROR;
3 }( a* q$ }/ e! H
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)

; W; @/ g% C/ h8 _: g$ y
功能:通过硬件 SPI 交换一组数据;

$ m- i$ D, y/ R9 Z
参数 1:SPI 句柄,根据实际需要填写;
) P0 u! {6 A  `5 V' V2 _9 t
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
# K- s0 b$ e1 S
参数 3:要接收数据的指针,接收数据数组的首地址;
# S/ `) h' c2 M* M  @% h
参数 4:数据长度,单位字节;

: n7 ^9 t. B* J" w# j( T) y
参数 5:超时时间,单位 ms;
/ _- v6 ?0 `( N) X) a
返回:操作结果,HAL_OK,HAL_ERROR;

& K) b/ f' a& s( W9 p3 B

" p4 L% r+ V) V; K0 W- d1 G) v9 B

( E6 A: q% |4 e( g
核心代码:

, Q# \7 E# R$ }& W( b3 I
LCD_Initial();
3 n( _6 ?2 D5 x# |
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏

6 [! |7 h' ?  l( u+ }: [
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
4 p" H) c- c4 Q6 e- _7 }. ?: }4 N' U
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏
  O- A/ E1 B/ Q( `% A! Q" \
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏
  `+ h7 E# U7 B% r2 w& o
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符

' o( H% U! \* L6 N' P/ S
$ u+ |& }( }3 m5 g. @' t/ M3 c

: u2 m" k8 {# L& a
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
. J4 R4 |; U& l! d
# L  V% S8 ~! ]6 ]$ Q

7 B3 y& s" g4 Y! }' f5 g. p! |
实验现象:
1 b* x7 E. K8 a; I( U& z; ?
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
( @) M+ R' T% W$ D, [

$ @9 j0 l0 R4 _" B4 ^! b' T7 Q

/ {! P+ `9 H) p) n; \
3、硬件 SPI 驱动 TFT 实验(DMA)
$ n# W% y9 M1 j
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png

; {& s7 L6 r' Q
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。
5 U, G0 {2 p) z6 F% o" k8 J- p
相关操作函数说明:
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)
) x6 }. c, l8 o
功能:通过硬件 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)

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

0 S, [: j5 q$ g" a6 k" |( F2 Y
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}
4 U$ {' I+ Z6 D3 l' F
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。
* M0 D: [. t! Q- [8 d! n
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);
}
4 F. p" g# s1 _) v$ h% P3 L4 x
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。

$ C! y6 W* F# Q5 f0 u" Q9 n' u* s  T
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);//显示字符
7 a( f7 q; _# D
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

. N6 u8 r2 Q3 b% {
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

9 L7 U; c4 w+ f6 m/ ]
& S, h1 Q  B  j! u+ V/ p
七、IIC实验

+ e/ m. _+ M! q8 o5 T8 _4 \
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。

/ k9 g9 y& f$ l
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:
3 M2 `- h, A3 [8 p8 v- s
4.png
+ X* K- X+ O0 T. `

; b8 {) X% N, ]# }! O, \  Y2 f" J9 ^5 a
▲ CubeMX 进行软件 IIC 的 IO 配置

- n- x2 u8 J5 W* o- z+ c  T
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。

! r0 o9 }  x2 G. }6 ]( G4 b4 o
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式
+ b' y" `. Y# t
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式
$ c1 K7 w" ?: G: Y# q# r% z5 z
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;

$ e9 L" B$ v( V- @
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;

7 \* G- j6 i: y7 c( S; h3 ^
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;
/ e: t- |% f) M1 t% E' ?9 N' D3 t
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;

: q* D! J+ U4 h& X- u
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
数:无;
返回:无;
3 _4 Q4 j6 Z0 P- ?# Z4 r
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;

! A0 E! n6 z" Q* ?
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;
+ ^& m0 O& r7 r6 J1 U5 a
核心代码:
//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();//停止信号
}

2 o; a# r9 w, h
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。

# B, Q# ~$ ~  `! A4 N1 V  \
I2CInit();
uint32_t i;
3 b' G+ l! R: x( R. \" @
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);

' {. a; D1 ?5 d% |7 y2 M9 ?. l1 N/ |' q
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");

: T3 h) u7 }+ m0 W
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");
}
; z0 U# |/ c3 @7 h$ X4 {2 {8 q/ E$ X6 z
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
/ ]: B" F) \! N% F* ^
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
( v6 h2 J, M4 A. r) C) `1 `: w
微信图片_20241122152540.png , h5 T" i- V/ L6 Y0 b

: H" [$ B7 F- ~" ^# M) B+ w: b
▲ 实验现象
: I  t, c0 z2 D/ {' L! h5 J
& A8 ~; P' n( i  r
2、硬件 IIC 驱动 24C02 实验

$ y) ]# B" M1 @& S
CubeMX 配置如下,保存后生成对应的配置代码:

' J0 v- F3 H* v$ |( {( _3 A6 v2 w4 w
微信图片_20241122152543.png
) j7 V' `3 z* b1 ]& I; H' t

  [5 Q! @* H+ Q' I4 ^
▲ CubeMX 进行 IIC 配置

) q, \* J, H% n( y
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。
! {3 r" I% n7 T& d  S6 o. U
相关操作函数说明:
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;

* M2 z. L; f& b$ x. I* X
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;
; s. _$ g, S" }9 e/ ]
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 地址读取数据;

7 }) X6 A" r& j. k0 Z, B9 G+ {1 |
- p9 t& x7 m3 i+ Z4 U% h) O0 d& ^8 @
核心代码:
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! b; N) o3 y6 z6 q
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

9 {/ E5 G2 }& s1 A$ ]
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
; ~  W* }' p3 f7 x
微信图片_20241122152546.png
9 d3 e3 c# u* |+ o3 p
▲ 实验现象

  B2 S# s& J' R! D2 T4 d2 o" W
/ I; \; g' O* k; q, K9 L4 [6 p
七、ADC实验

7 b, R- G9 L, I; |4 C% E
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。

0 w! Z2 x: M$ r; ?) T& C# V
1、ADC 查询方式单路采集实验
( }( |9 n% O5 i* `% Z' G1 H& X, k
CubeMX 配置如下,保存后生成对应的配置代码:
# o; e- A( b/ u. F% g
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置
! n3 O8 Z3 Q8 e5 F3 n6 c
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。

! B# x7 i: _* m* j7 p( [
相关操作函数说明:
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 进行单端采样模式下的校准;
. _! B- I' [) s" n+ @4 ?( M
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换
5 z$ i7 B" b$ J2 O) J$ B/ b1 C
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
- a% M% [7 i3 F4 R$ h6 L& y/ \+ s
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); //等待转换完成

% R# F% Y2 B! ~. h2 u. Q  o
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值

- \& m  X6 K5 X# [1 u* O
核心代码:
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);
}

; U8 P' u$ z- q/ q5 \8 @' q
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。

2 Q2 [% ^% T: @9 u3 H. N7 O' g- r- U
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

, t$ q3 B6 M* O5 Z/ i, V( E! z' ?
微信图片_20241122152553.png
* P* K: k( d: ~9 g1 ]
! m: \8 `, R/ j7 n) u2 p+ g
▲ 实验现象

  K9 f9 e! j, v# V/ H) X) H
& o' m% Y/ s2 ^  K0 |
2、ADC 中断方式单路采集实验
/ q/ v; @/ V: K4 p" D6 z# ^2 R
CubeMX 配置如下,保存后生成对应的配置代码:

% D  T3 w0 d# j/ Q* T! u- B
微信图片_20241122152556.png
▲ CubeMX 进行中断配置
5 v( v$ S+ N  C/ G& `7 H, B
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。
0 F4 E* m. W8 W3 s
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据
9 p  ~: X) ^4 H* T" V$ W' o+ G3 B
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

5 }' @" t6 D' \3 ]5 i2 Y/ t+ q
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}

; }, [! }/ r+ o6 L3 I. l# l
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。

% @0 R; x5 h: D$ X$ ^" x
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); //通过串口发送
}
}

. l8 s/ t' U% l4 R3 i: o: x
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。

, J6 @. i( ~- C4 r6 T" n
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

. B! n: S6 J( v
微信图片_20241122152600.png " _+ Z  X3 l5 f! U' c

5 A) H" G& M+ L0 }- L
▲ 实验现象
. R$ d% }' ^" E( M0 W7 k
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
" Z; ^1 d# U$ X$ s' ^; N5 \
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置
1 Y. W$ M9 _4 W9 \" ~; ~
微信图片_20241122152610.png 8 a6 q9 M/ l2 o7 f: q! W
▲ CubeMX 进行 DMA 配置

2 \" ~3 `* e) L' `' _, x- H
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。
* N6 J: Q. J& v) f
相关操作函数说明:
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 传输;
, H2 m' G. {% @- ]8 y
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

0 i% d2 `9 z/ c6 K1 c3 K0 q
核心代码:
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();
}
! Q+ L* b4 `# U  T& b$ H8 }2 H
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。
: P0 q  {5 |' [3 k, r' C
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 转换。

" F, i, f- \+ k( p: D+ `( t
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}
8 G$ Q$ I# A8 T
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。

" M/ R* r+ W' I2 ?  e
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
$ \0 [4 p8 z* K7 Q0 N9 E* S# }
微信图片_20241122152613.png + N8 N7 d" }2 d* N
  P+ L8 Z: u8 u- P0 I
▲ 实验现象
0 E- a5 K& R( [; j, \# X9 Q
4、内部温度采集实验
  u0 R- q8 b& A* s( C
CubeMX 配置如下,保存后生成对应的配置代码:

: a6 \! Y, }; S
微信图片_20241122152616.png
# i- d, r+ L' a1 C& X
7 N2 I. p1 I; o; |: D8 M9 @
▲ CubeMX 进行温度传感器 ADC 配置

4 d" d* W2 b, Q: Q
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。

' ~3 T" W: s, \
相关操作函数说明:
__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);//转换温度

4 g) z  t" Y3 [( U: L" ~
核心代码:
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);
}
# b$ O; G/ E9 J9 [2 S
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。
1 I7 _# u5 ^. C1 z& z6 {& R+ X
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。
* g  Z. {& {, I3 f7 X
微信图片_20241122152619.png
8 P" V% s9 w9 X: N
▲ 实验现象

  L1 O; C8 s- a+ c! z4 N% y0 s! A8 N
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:

( t; T+ b8 s# K' L
微信图片_20241122152621.png 9 K% K0 p& {9 P/ F4 K
. p9 \8 D  o+ \1 B$ U8 f. z
▲ CubeMX 进行 ADC 配置
( E. ~3 P  L' q) n" o5 d/ S
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。
. P/ _8 z3 Q4 @& ~) s1 U
核心代码:
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);
}
7 ?3 r; r1 W% C& {! A# j1 C
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。
; f" F' R6 y, _) @0 V/ [
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

# ^' P4 I  s  l  g" c
微信图片_20241122152624.png
▲ 实验现象
  v2 n. l+ V& b2 T( ^. j
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png ! d- u( [& F- x
; o+ Y2 m; ^7 Q: Q* @6 @/ [
▲ CubeMX 进行温度传感器 ADC 配置
- r/ i5 S# }1 G$ W( U
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。
( O0 p+ A) ]& G; e1 _; Q
相关操作函数说明:
__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+
0 k- G. m- M( n+ ?3 N: s3 `# x
核心代码:
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  ?; J! M, {8 l* Z# X
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。

; I' z, O* p: m* J5 e+ r
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。
3 I7 g0 D9 P# l/ O
微信图片_20241122152630.png 3 H" `0 i5 c. V- i; o

  X% T  H5 d( ~% M% k% J' K1 u
▲ 实验现象

. J: v$ e1 K7 ~- I9 t. J8 g
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png
' |6 {! c! ?6 K: o  C4 @2 P) p% ?9 s

  `+ {5 M- ^6 v2 p: R, M$ ~, _
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png
4 D/ q( Y, ^8 g: {  f! I
! U/ |& N( E: u# `6 X" P
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png 4 f" N1 b% p1 j: I( g
( i2 D0 H$ C& G( k+ G. E
▲ CubeMX 进行中断配置
' F. a2 @# D- A- Q5 c0 ^1 i1 ]
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。
2 D5 f' C& B1 ?3 h9 I$ a5 R4 c+ G
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据
  x2 Y# b: M8 F6 c" H. P! R
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

$ @. _5 ]1 O1 _$ ?4 E+ ^' f9 ~
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1
$ F. Z* H, O' B" S" _8 E4 r9 Z+ _
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。

6 `0 @! v% Y7 K
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); //通过串口发送
}
}

9 y' G& ^. H6 ~
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
/ h, b/ D+ L7 }3 X
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png % q6 V* {& s- {& `5 l

7 F6 K8 Z9 y( @7 |8 K
▲ 实验现象
九、DAC实验
* l9 y/ X% w( u- m- G& L
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。

/ M6 s9 p6 k) p
1、DAC 软件触发输出实验
% D- l+ {. |7 z7 u
CubeMX 配置如下,保存后生成对应的配置代码:

6 b7 q) g1 F2 g8 P+ [( M" o
微信图片_20241122152645.png ) `- l: A  P- k% f
) X9 \! v7 s0 c  z
▲ CubeMX 进行 DAC 输出配置

. O: O& l9 I3 A; s2 ?5 f/ J9 o0 H& ]
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。

2 H% L' D( e0 k1 e/ A, s, y
相关操作函数说明:
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 输出,如果想要修改生效,还需要使用下面的函数

* h  y: i4 V; 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);// 改变输出值
+ f: M& s, b% ?1 J- N
! N6 S5 s) }' ]3 D* M7 n  _3 |7 w! m6 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;

: @* O9 f6 M% d# B8 `. c, f6 H
核心代码:
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);// 延时一毫秒
}
}
; c1 h+ `5 Y& x, T& A" M- L. j$ b
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。

6 D5 o9 o/ j/ n
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。
/ b8 i6 q& i4 N* A/ B, X
微信图片_20241122165909.png
4 ?+ `2 y+ T) a. s; [0 `) o  e
3 r' w0 U: n$ v
▲ 实验现象

3 k: n" k! X: C  I1 o. Y
2、定时器触发 DMA 传输 DAC 输出实验

6 v( C% M- Y3 G! p4 s; `# w" t0 r
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png
/ e! T5 V$ R4 [; ^6 U
' }, S0 U( d- z
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png
' v4 e. i& `6 X4 c
8 r$ P  I2 {; M
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png # b+ b; f) O0 I  e+ h+ r2 M: @

* H6 u5 p* [) A3 C3 O
▲ CubeMX 进行 TIM4 配置

& P8 P: }# A9 L- P1 p" Y0 c
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。

0 o- S3 d; |% v* c
相关操作函数说明:
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 方式设置输出值

  c9 e, S9 g' P& s. a* F) o% |
核心代码:
//正弦表
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

( Z: h7 e* J  ]/ V7 a) I
以上为正弦表定义。

' h6 c- g. i. c5 G
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();
}
4 }: i2 z7 c8 p. N7 U+ D1 b
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。

4 ^  k' ^. l* B% [3 w
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png
* U! R/ o5 M, o+ {! ?; m. U

+ E0 l' o: C( b7 _' q6 m  a
▲ 实验现象
; @& `/ j% }$ D' r; @4 k5 _! g
3、定时器触发 DAC 输出噪声实验

* E0 i" v" x+ a  t' h
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png 0 s. |" v+ h$ g  T- [# Q# V1 @
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png
5 d. V! E( K# y! B3 M

5 t4 p& s9 n  ^" S
▲ CubeMX 进行 TIM2 配置

. v* T( Z, c) P
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。

; N! O% d" b0 r. e) O
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC

  h2 Z3 E4 T. j: l8 v2 _
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。
& u, G* V1 d8 Z* Q4 F
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png
& Y0 \1 U. l/ z" @' `
▲ 实验现象

8 f& S0 `$ v% m
如有侵权请联系删除

, P$ R! U/ S/ m/ b. j$ X
转载自:AI电堂* ]: G% o9 L- e0 R

. A( N, D3 w. x* w0 X  w! N- D
收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版