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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验/ o6 M$ C) g+ P$ o
实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。3 ]3 F1 c/ _! E. f* a
. u, N0 k; `' X7 {7 |" o
1、软件模拟 SPI 驱动 TFT 实验
3 A# N. ?' {# b' x9 C" GCubeMX 配置如下,保存后生成对应的配置代码:9 A7 B8 R! d8 ]/ {, `( A5 H
13.png
+ w9 \& N4 T# k1 U# x
: e" R7 u; t* ~! D2 j4 I7 G  l
▲ CubeMX 配置
4 l5 U/ `' g' v  n/ H  n% W
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。
* @) f6 D' J7 A( c" h% w1 z
6 A) J4 o4 s# w3 o# p
相关操作函数说明:, }2 H2 _* J! d
void Lcd_Reset(void)+ i# d0 M- r8 @
* F5 r3 G# O& p- [
功能:液晶硬复位函数;4 w6 ~% I5 j. O' X: J& \$ _2 q* w0 M
参数:无;
/ v, X- _: ~2 r返回:无;
- ^) b! K9 ~$ J说明:液晶初始化前需执行一次复位操作$ H2 F; N; U- p. e
void LCD_Initial(void)6 E' N* x6 |* H1 |) B
功能:初始化液晶;) j9 `# q/ ^: I) `
参数:无;
( i: @8 N# i" u( {# Y返回:无;
: T8 v2 o9 e6 c9 H说明:在对液晶写入内容前需要进行初始化配置;. q5 B) K7 w) h5 ?7 }$ Q8 m  D5 b, y
void Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
: r$ p) K$ i) u& H- t: g* w

$ D+ P) S3 u2 k5 y2 g- n2 k- R功能:Lcd 矩形填充函数;
; L3 m5 J3 T( i6 V8 U2 b" p. L参数 1:x 方向的起始点;! a: y4 W$ v5 M' U3 v/ G
参数 2:y 方向的起始点;: Y& |$ b) A5 m: Z' Y
参数 3:x 方向的长度;
8 E8 k9 R5 W& i3 W% b参数 4:y 方向的长度;
( d; v1 k! f3 x% _5 B参数 5:填充的颜色;! h" M& S* i! ]- @7 L3 n
返回:无;
4 p4 v9 d7 `& Z% q  o说明:将指定区域内填充指定颜色,常用于清屏
$ W1 O& }9 k4 k& j6 e' z* Yvoid BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend). Y. |# }' n" p- k

# G+ G& P) M- l% A& E( k7 z功能:在一个指定位置开一个矩形框;
% N7 W' q1 \* t' u6 x# s2 ?( m参数 1:x 方向的起始点;) e0 v! l5 n: j, M; u
参数 2:x 方向的终点;; l4 D# }( r; S4 G
参数 3:y 方向的起始点;# e' p0 r! w/ u, I0 K$ g8 \- @
参数 4:y 方向的终点;
# b; `" p: r" q, P返回:无;
" ~' b" ^* T- k6 o2 D说明:开一个矩形框,方便接下来往这个框填充数据;, a2 @3 g- y$ G/ v
void DrawPixel(unsigned int x, unsigned int y, int Color)
4 i3 W7 q9 W$ P! D0 @" D功能:在 x,y 坐标上打一个颜色为 Color 的点;
/ A$ f  J' p# a1 P: C: q7 }参数 1:x 坐标;
; v. x' D0 T' p# o参数 2:y 坐标;
& _" v( _2 K2 R参数 3:点的颜色;
, _4 f8 k( |3 T; P9 i返回:无;' J) x) ^  s  h5 ]% g
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)
3 S# l6 e& B$ m4 G2 b9 T. C% ^" Y9 z. L) o1 S8 N# ~! r# n1 X
功能:显示一个字符串;' ?, [% D5 I) Y1 }& n
参数 1:起始点 x 坐标;
' V3 l; o7 C: @# {参数 2:起始点 y 坐标;
- j) G$ b7 J5 ~; m, I# G参数 3:字符串指针;
8 c  E7 d+ c) H3 N, Z( B2 ?参数 4:前景色;
0 z) M9 b( ^* ^" h: d% X) T1 V' F8 }参数 5:背景色;
' A4 _5 H" S& ]5 u; |, ^+ z参数 6:有无背景色;4 m3 a, l. m+ X; }& `( C, `, B
返回:无9 s- t8 d3 ?3 k2 x

4 W* W6 P: y2 ~/ s* N1 \) z
* C' d" }+ ^9 j, k8 k( I( W4 Y
核心代码:
7 d: y- x* C' y4 a$ }( bLCD_Initial();
. l4 G* Q& a) @& aLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏5 R: Z/ A6 C* }' O9 _' {0 H
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
& ]7 s, B* Z, r2 r2 G% \Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏1 D4 T$ K" r' `! `" O
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏! w% y4 A  _: H0 K/ i$ c! P# b
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
) Y$ S7 r( V& p+ G. N! ^& z0 ]
6 d7 I5 R# ^3 E( U) r在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。7 ^" L7 [. e* `2 b$ y, C
& K8 x( R* U) Z' W7 H5 _4 O

5 x+ B$ ]5 K' Q0 q实验现象:2 p. B2 W5 p" {; g2 I9 {
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。  |" M# P/ W0 g/ I/ m

$ Q5 p2 O) M4 _/ J/ K; o

5 M  R: S! U. z* a3 G2、硬件 SPI 驱动 TFT 实验( _  `6 S( w: q
CubeMX 配置如下,保存后生成对应的配置代码:
0 q1 B2 x- @) I' s
6 K* L1 ~. E8 p4 H2 J) ?
12.png . u& w) s# W& _$ a

  Z$ |. C) V  ?8 k
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png 9 |) a, Q" D3 Y, l/ x/ o

7 E0 C" |& |% H5 ^3 _. j
▲ CubeMX 进行 IO 速度配置
9 I  _, a8 t- V7 g& ]. r
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。

7 Z4 q3 ~% M4 t
7 l- S& a0 ~' L8 P$ f* J- c

. S3 o* ^) [4 I1 v% z( b

6 m. o- c) l2 \% D0 `" S: s
相关操作函数说明:
6 B3 z  }: ?+ {) K
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
' C" B9 W7 L* x
功能:通过硬件 SPI 发送一组数据;

( R9 l3 I7 Y5 M. ^" v' p6 \  y
参数 1:SPI 句柄,根据实际需要填写;

6 i  W. l+ O# O$ o0 a1 ?
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
3 M+ B; M* k  ]9 [
参数 3:发送数据长度,单位字节;

3 i' ?, U+ c6 B9 L- H# {4 o  x# G
参数 4:发送超时时间,单位 ms;
3 u7 t3 r8 `; f
返回:操作结果,HAL_OK,HAL_ERROR;

$ F1 B. b& s  ~4 `
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据

% M6 Y1 z& |0 l6 A8 O( l' _
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
' a# z: S" W! n4 k
功能:通过硬件 SPI 接收一组数据;

# p) Z' j  @! z2 h% C( w
参数 1:SPI 句柄,根据实际需要填写;
% U/ n2 \" x+ C; a( ]7 ]
参数 2:要接收数据保存指针;

' a3 j. S! U' W9 N( y  G# r7 Y6 N
参数 3:接收数据长度,单位字节;
$ {1 I0 g2 h4 I8 B
参数 4:接收超时时间,单位 ms;

; ]! X$ u6 f; v% R* f
返回:操作结果,HAL_OK,HAL_ERROR;
4 H7 m6 j* q$ z4 G# ]
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)

" _2 R4 d' j, u- o) \, d
功能:通过硬件 SPI 交换一组数据;
  T3 X; @4 j# w
参数 1:SPI 句柄,根据实际需要填写;
8 ?2 ~" n8 F/ j; K
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

% M# x9 `5 D9 a, r! g1 Q
参数 3:要接收数据的指针,接收数据数组的首地址;

5 g: f1 Y: k: g& R) a2 N8 C
参数 4:数据长度,单位字节;

0 j" x0 ?+ w( \, V% P- a
参数 5:超时时间,单位 ms;
( X; ~# G4 l8 X
返回:操作结果,HAL_OK,HAL_ERROR;
/ y# i) w9 \4 i8 n) t. y

! ~/ V+ H* ]$ q. w8 p

9 i. J7 [+ A) e
核心代码:

# r8 h5 @8 j4 U
LCD_Initial();
9 \  E- J* J) ?, J* ?  t: X4 [
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏

- V2 a( v1 s7 o5 m
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏

$ k% V, _" _2 i' P: W
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏

4 B; R" L: w* |' D  s2 R
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏

1 X8 Q  Z6 k# \+ P3 W5 z. m( Q
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符

1 O- M% t; i' d, |! S# w1 z
4 e3 \1 X. n; Q5 f. M( r9 @

! b; |& \0 g: G% e2 H
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
4 j3 ^% o+ ^. h3 c1 A/ H7 Q* d8 E
  S* Y: X% \+ n. K- @
& u0 q( F/ T3 L. s
实验现象:

, e. V# x3 A& c% W7 ?; h3 h! l
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
5 J! b; s  F% R6 s) j) D0 V
* }! P8 f8 K- }* U9 ?% ?
: K" _- Q% {/ ]6 _
3、硬件 SPI 驱动 TFT 实验(DMA)
* s. d! X. U: c) A, ?, G6 y* k" e1 w
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png
$ _, b' a  ~' w4 n. W8 v. @
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。

2 }% D2 V* w# t8 T& \- [! K
相关操作函数说明:
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)
4 ~# y5 u. P" Z! y
功能:通过硬件 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)

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

5 ?4 F8 r& ^: Q* Y7 j
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}

" L0 [( i8 {1 n7 Q8 n, V
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。
- Z( v7 m, h) x
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 `, _4 s* c) }8 b. e1 b
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。

& f) f3 L, O" J" X/ v! o
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);//显示字符

- r; `% i, Q; `& x1 o
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

; M! l6 e  M  j: k
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

1 O' ~& r6 l  e+ |  l5 J" y
+ E5 ?8 ^0 S; g( i7 H  w
七、IIC实验
) n+ l+ s# O3 {0 y$ [) k
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。

; ]8 J) a; o$ @7 C* o) s6 O& q0 X
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:
$ ^! P3 G) r, P: J
4.png
# U) x5 k& K8 W# d. U7 w% w

6 s* f' [, @1 G
▲ CubeMX 进行软件 IIC 的 IO 配置
7 V" E6 c) I, f9 ?
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。
0 y( ]1 Y& n3 b0 c- @2 U- T
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式

+ A% f" u6 L5 z  B
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式
' D( U. Q' L4 ?, H  k$ j
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;
( ?2 T, q5 w3 u% b: k/ R( _
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;
% x$ O3 D* _. W$ D
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;

9 K% d3 W& K  ?' L( K/ v
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;

/ A$ d4 J3 S& ~8 m! J4 k2 T' H
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
数:无;
返回:无;

+ m# P9 w9 w9 y8 o: }# a
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;
  n* j, ~. D- N+ Y% w! e
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;

; r2 J3 o3 q0 J& Z0 N
核心代码:
//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();//停止信号
}
. N5 Z8 j- v. b+ M6 a
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。
! L& m& E7 U- Z! l# e
I2CInit();
uint32_t i;

4 y$ p4 i. {' r" P
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);

0 ^- M) F/ c, u3 f& r$ ]. d9 R. E
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");
! l% h: _+ a2 v5 k4 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");
}

" ]7 _7 b% i7 R
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

- u: z) s  S7 R8 x: ~7 @0 \
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

: z3 I/ U" j+ F: ?; W- h
微信图片_20241122152540.png
# D! `0 @) G" _+ T( b2 \9 j
9 ?4 k6 X+ l1 O3 O
▲ 实验现象
8 R) Q# e5 D  h: B: S+ @
5 p% G1 Y* O$ _% i! `5 r
2、硬件 IIC 驱动 24C02 实验

9 G6 o  h8 M- \3 y& a- F5 ^
CubeMX 配置如下,保存后生成对应的配置代码:
0 t" B1 m$ W$ [2 r7 G
微信图片_20241122152543.png
& F  f/ s8 B$ r' v

; \( j0 d* C  s
▲ CubeMX 进行 IIC 配置
0 ~8 y4 {: X1 _. i7 `
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。
' T5 d6 R7 ~! W& Y) F
相关操作函数说明:
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;

7 j# }, b1 f6 {9 J# o; l
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;

# j1 z: x$ d% ^; r( H' T% {' ]
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 地址读取数据;
1 ~8 q' J2 c; G3 m; s# I
6 Z. R' w0 Z9 K/ i: t3 J6 Z
核心代码:
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");
}

: u9 |1 T: J* j) @! Y
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

4 ]  }8 w& p4 U, N# B: n
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

+ H6 e5 t2 ?# o) P5 }
微信图片_20241122152546.png
  F, L6 W5 m' ?3 ~+ ]0 E6 t' S
▲ 实验现象
$ ~$ i1 ?% Y: i" x, [
" A/ U+ W, F: ]
七、ADC实验

7 m* A+ v- V5 z1 E
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。

& P7 K  r. |: D
1、ADC 查询方式单路采集实验

5 ?) S5 V) f6 n
CubeMX 配置如下,保存后生成对应的配置代码:

3 G0 [+ G" }6 @6 \
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置

5 C' e7 P5 a3 Y* U+ V: s, \
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。

4 _' m* i% L4 k" @
相关操作函数说明:
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 进行单端采样模式下的校准;

: L) D/ h" D* s3 y3 V7 n1 w1 |
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换
  R9 l. j+ ?# I  a' r% h& K) N# r
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
6 ]4 D, U% r" I! P5 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); //等待转换完成
" y9 a0 T, O* f& ]
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
; D+ b( t" s/ L; ]
核心代码:
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);
}

. p% L. C! ]9 v/ e, Q
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。

& h7 h4 Q/ k, u% |$ k
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
# w* }4 _) w, J5 @5 h4 Z7 Y& X
微信图片_20241122152553.png
1 w7 G% ?, N4 X- W8 a
6 M; L, Z# W- t) c
▲ 实验现象
- R' t8 [/ [& A3 w0 a& m/ J7 r' o; A

9 J5 U& C( ?: C9 e& B% A7 `8 u
2、ADC 中断方式单路采集实验

+ W2 W, u) w$ ?% W8 b0 a! y, }
CubeMX 配置如下,保存后生成对应的配置代码:
& l  y* {2 y  O7 p
微信图片_20241122152556.png
▲ CubeMX 进行中断配置
' j; B: l) V3 @" P/ \, a9 Q
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。

  a  L+ S8 ~/ v/ f) X, {
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据
/ p% f3 o: d8 S/ u
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
; c, j( z* E$ o
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}

; v/ Y9 m: L; R, m: M* P7 l
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。

6 {$ q% P% p0 i. 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); //通过串口发送
}
}

9 g. L& d4 Z2 i' N. z6 P2 l( m) k
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
. ^! U/ y5 B; W( g' _
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

# q; e. D0 b, H4 \! _* e5 m
微信图片_20241122152600.png
" v7 X( D( y  d) @
8 B+ x$ y& g$ u; C! c
▲ 实验现象

3 Q  `- [- k  y$ c
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
3 X8 v6 W1 y; X4 a. k4 @; ]
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置

& X/ r$ Q( ~6 v; k! X- Q. S& L
微信图片_20241122152610.png ) j$ N% r& ?0 L, Q" }3 a/ D! x
▲ CubeMX 进行 DMA 配置

0 G9 N6 o/ C' J' M/ Y' k
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。
; A  r+ w+ f0 {; w) D, B
相关操作函数说明:
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 传输;
  D: @% b- {6 y8 H* }' ~' ?; v
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

( I8 C9 S; O/ q5 w1 _" K3 s
核心代码:
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();
}

: T/ Z4 l& x6 |6 s2 O/ r4 |
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。
, O5 S) d2 t  o. W1 I; E% G
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 转换。
- N; N( H6 Y$ u" _  g
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}

# x: z" g2 }. ?6 Y( P; v9 w. U! Q
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。

% {' T# ^5 y7 @7 v
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

# y9 z9 s: a9 J
微信图片_20241122152613.png
2 R0 _9 O- n# ^1 X
7 ]& l% ^! x6 o0 u( E
▲ 实验现象
( w! \8 s8 p' M8 P
4、内部温度采集实验
0 C, k  ^, ^0 t0 A+ L% @
CubeMX 配置如下,保存后生成对应的配置代码:
" ]& }) k! b8 c/ p8 W# P
微信图片_20241122152616.png
- B4 c. X6 ?5 H" t9 a7 M# R

. b. }, o5 i2 i# F7 J: J6 X. j
▲ CubeMX 进行温度传感器 ADC 配置
$ ^2 J3 p4 c) Y% L1 {$ _) K) j1 ^
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。

$ w& i8 R; ]0 d
相关操作函数说明:
__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);//转换温度
5 N. b3 P( p! s0 k+ H& P" n
核心代码:
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);
}

: A7 s  L8 F3 S4 Q& Q
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。

+ B2 j( U' O  ]
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。

5 n8 G/ B7 {% d7 s# }
微信图片_20241122152619.png / z1 _+ \: a/ D$ T2 _5 Q
▲ 实验现象
% {- m, L  `- I. i- ?
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:

# T( @1 k, }3 f# Q. y* W1 n
微信图片_20241122152621.png
! n- k3 e  `5 b9 ]

  b, u9 K8 _+ J) ^0 `
▲ CubeMX 进行 ADC 配置
2 J" R' a  P7 i+ m
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。
8 @2 y4 x5 c2 a" z2 V$ 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 = 3*ADC_Value*3.3f/4096;// 转换为电压
printf("VBAT: %2.4f V \r\n", ADC_Vol); //通过串口发送
HAL_Delay(500);
}

- R# w6 E, K! V, Z3 [$ V% D
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。

7 ^! s. r' q* b
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
/ j4 |' U* g+ @5 u& D) p4 K0 h
微信图片_20241122152624.png
▲ 实验现象
9 Y6 ]0 p7 Y' k0 s: M7 A1 i
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png / H8 g- Z9 m1 Q8 l9 h

; u* @4 v- r: e# V* [& H5 v
▲ CubeMX 进行温度传感器 ADC 配置

& Z2 T' F6 Q6 O+ Y
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。
! [: N6 }8 P( N4 M
相关操作函数说明:
__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+

9 X, E! L# l+ I% }8 W
核心代码:
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);
}
3 g* ^; @! F) h+ {, O
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。

( B3 q; U+ P% Z3 F+ Y; L
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。

: q; X/ e; g. }6 w+ w8 C  }
微信图片_20241122152630.png
& F# n# {+ O/ _  d

7 ?( f0 r0 x) e- x. h
▲ 实验现象

; Z! a0 k  @, l3 T
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png
, w* C9 t! G' A) K: e

' S6 N4 o( F6 Y/ I! {
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png & t7 s% H, I$ w
6 I  A' m( n8 |
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png
) l9 a) a( P8 O
- Y- ]! m# }$ n9 p
▲ CubeMX 进行中断配置

) u, v4 X  \5 F% c0 Q4 x
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。

4 ?: B) Y  f( [- G' I: U  S# P
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据
6 k& m: x" `3 }
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

+ n  S* G$ n: `& R: X6 p, z6 O: a
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1

3 Y8 X, d+ r- h4 H/ l+ y8 `
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。
) w, d# b7 X7 y7 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); //通过串口发送
}
}
" {+ z8 B% h0 m
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。

% q) j! T% R  P3 [8 |0 L
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png , C7 f8 J0 I- T+ h! {) D; c% |, c

7 ?8 o2 d' U7 L  }
▲ 实验现象
九、DAC实验

( @8 D' n* V5 i+ ]4 ^, e0 h& K
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。

& e3 i- y, z/ S
1、DAC 软件触发输出实验
+ j+ @: c2 i6 W% m
CubeMX 配置如下,保存后生成对应的配置代码:
% W) g  K1 Z- w* V; e5 q9 D* R
微信图片_20241122152645.png
4 ~# C+ I. @7 {; o

9 @  q4 j  k' ?! v2 [& Q2 G
▲ CubeMX 进行 DAC 输出配置
+ W! j0 g4 Q9 Z7 K" H
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。

3 }1 ?" c6 _' l' g- C2 ]+ Q8 H, a
相关操作函数说明:
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 输出,如果想要修改生效,还需要使用下面的函数
/ k, j' }8 b  q  m
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);// 改变输出值! P/ T3 N" F; h3 \

* a4 n# ~# m/ j$ E) ~6 D
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;
& n) n1 h" x! o0 M$ S8 X
核心代码:
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);// 延时一毫秒
}
}
$ O( E% f6 ~; k7 ~
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。
  w, \  K# P: w  o& F8 t1 @7 B
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。

3 {2 J5 L5 g0 m$ ]9 ^: n* Z5 i+ ?; ]
微信图片_20241122165909.png
2 }; I3 c% V' }  o

% K% q6 [: S7 Q8 M! h5 b  A6 ]" P
▲ 实验现象

$ C, l; H7 _5 J! {+ x
2、定时器触发 DMA 传输 DAC 输出实验
( X+ ?4 I" Y- q& N5 c9 w
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png
, g$ K. H9 |. Z* o8 B& w$ h

# L/ O+ Y" z; C/ Z4 k/ ^
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png
; F. I& X9 V, O+ Q& J

( U/ A9 I5 F% W& X1 o
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png 7 K6 d8 D9 s1 n+ p

. j! K0 T7 A# l- o
▲ CubeMX 进行 TIM4 配置
$ \% Q5 k7 D5 I( {% B9 |) E
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。
) {. Q, E( a( y: x2 l& Q
相关操作函数说明:
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 方式设置输出值

' `! w+ p* [" y! O) t2 N/ L
核心代码:
//正弦表
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
3 X+ y. \4 |6 P. K# {
以上为正弦表定义。

" V" y+ X8 P0 I" q$ G, d, w
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();
}

3 p5 I3 k* H! e7 p; b
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。
$ J6 j1 |0 U: Q) w( E* j2 c, t+ a
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png
  p/ W3 p& U! S; q; Y

2 K0 d0 X9 R7 t  J
▲ 实验现象
9 A( l/ o- n* \! O5 Q) V+ j
3、定时器触发 DAC 输出噪声实验
# [( U5 T7 x5 @& k2 j7 m# ^
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png * S3 w0 S8 b* n( ]( m8 Q
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png
! A9 u. e: d5 F0 S' O% U0 p

' o; T  }. X- c5 z1 d
▲ CubeMX 进行 TIM2 配置
8 z& y' s; V. u9 l) p; S8 Z
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。

  \( o7 I( f# B
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC

: D& E- f$ E% t9 Q, X8 W% e. y8 M
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。
/ v+ L0 i; S/ E1 |; }- E
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png " U- N: r6 M" H" h) W+ ]
▲ 实验现象
) E; V2 C: g* W$ s2 A
如有侵权请联系删除
1 X- {7 K2 O9 q/ R7 R
转载自:AI电堂
( K" v' @2 u. p2 T! `! m# \

0 _. |2 J/ r# E, P& I% G$ K: L
收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似分享

官网相关资源

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