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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验$ T* g6 P% f: P
实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。' I5 ^1 D1 n2 a4 Z# y
& l1 Z8 J9 B& k+ x, X% s+ j3 z; W+ |
1、软件模拟 SPI 驱动 TFT 实验
4 L  X6 O( j$ W/ u. ~CubeMX 配置如下,保存后生成对应的配置代码:
" M2 w/ z( S, k! z
13.png & v- @) K7 a; H3 W
: [. J3 o  @1 x) O: a% i
▲ CubeMX 配置
9 g2 i5 s  B6 J1 w* F+ T
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。
2 @; y* C$ R2 [# M' x* }/ u& o0 v; {9 h$ M
相关操作函数说明:1 M* J, K! f! r; G
void Lcd_Reset(void)
( j! O5 A3 N/ {$ g3 [
! m; Q' m% N2 }4 K
功能:液晶硬复位函数;7 e/ T1 o% G7 E3 C' X
参数:无;
$ Z0 V" P# p2 y' Y- s! {返回:无;
3 |! v: c- W2 z5 F3 |说明:液晶初始化前需执行一次复位操作! F& ^% h0 r: y4 E) o1 s1 N* l
void LCD_Initial(void)
! s! E: u* h9 [7 i+ r功能:初始化液晶;
+ c+ ~( _7 p8 W* R# Y& q5 c参数:无;6 o1 }( ^: ]# Z& J3 b* U
返回:无;
7 T3 ^5 r1 a; }& C7 {( `$ z说明:在对液晶写入内容前需要进行初始化配置;
7 C8 `% _4 J2 l; `& @+ D! Cvoid Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
: M2 [0 a& e* V, w5 M. R, W

2 Z! B/ e+ p# q( M! S& l* O功能:Lcd 矩形填充函数;
6 D% P) C0 n. ?7 C/ V参数 1:x 方向的起始点;# w  z1 [) u9 F, Q; ]
参数 2:y 方向的起始点;
4 C, [" g7 v1 P  ?% s/ [: A参数 3:x 方向的长度;
/ o' [+ E! k8 q参数 4:y 方向的长度;/ S  Q6 E' Y3 g8 e; q7 p% U; k7 e" v
参数 5:填充的颜色;
/ o. r! w% Y* D: n) [6 @* I% g: j3 }返回:无;
. `2 X0 X1 t5 {0 N, y- ~说明:将指定区域内填充指定颜色,常用于清屏
& T/ |" \/ X6 _void BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend)0 v  s: ^. \; O0 o2 L  k
2 H$ p# Q, i" \0 P3 Z0 t7 f  q
功能:在一个指定位置开一个矩形框;$ l. z, D+ I$ Q  W
参数 1:x 方向的起始点;. ]1 a0 ~0 Q+ ]; W
参数 2:x 方向的终点;
+ U: ~3 h& b9 ^. x参数 3:y 方向的起始点;$ x0 @# X# U6 ]
参数 4:y 方向的终点;
9 X9 U# @+ s0 u/ s0 {返回:无;
+ w9 k9 g5 j" H  H说明:开一个矩形框,方便接下来往这个框填充数据;
& N) i$ Q( v( x5 tvoid DrawPixel(unsigned int x, unsigned int y, int Color)0 ]: u* r  P$ N% B1 n1 O5 A
功能:在 x,y 坐标上打一个颜色为 Color 的点;
, W7 ?! ?7 w) O& Z: n参数 1:x 坐标;
) d& z1 S( r% x- R- y7 ^3 u' `. v参数 2:y 坐标;
( }5 b# l2 `! a3 l$ v, Z; B参数 3:点的颜色;
- p" e. b, l" Q$ o返回:无;6 u) G% D- J5 e2 s" Z! N; F& |
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)
8 {1 a: r, U! x$ R) p& Y0 t: ~( v9 B) s
功能:显示一个字符串;- [* o* s" v; g# o* x
参数 1:起始点 x 坐标;
$ p  F/ S& g# l. U5 ?- k8 c参数 2:起始点 y 坐标;6 h$ ^1 s* R0 J( @4 P4 Z3 F
参数 3:字符串指针;
. b" H, j1 P) k$ X' N5 l' h; `参数 4:前景色;
0 X1 {8 y' j% k9 S6 v参数 5:背景色;6 R0 I! K3 k$ t' Q
参数 6:有无背景色;
  k# z* z( C; w9 V0 F2 U9 j返回:无
: R4 {0 T- G( |2 L
' u* @- `! `9 h) X, z( ]* c* [! Y
& O& e: v; P% a5 \
核心代码:& s) K# v/ j" }) n' u
LCD_Initial();
2 P5 o: W7 E) H' q# pLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
  K7 \1 k- \4 d- j, E6 JLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏0 Y1 U5 d6 g( @% h  _/ x) ^5 W
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏
- T# s. `' M  E1 q" t- eLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏$ G8 X: U0 ^# d4 C2 _3 j
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
- `+ A1 t( o/ U# g
& |8 \+ ^. ?. Q' @, x在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。) z7 m& J. |: @2 J' B# f, X

/ Q" W( K! V+ f
' \2 \/ T/ H& T. d7 W  A. D' V
实验现象:: `  _4 P, L, K, T+ W! {1 A
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
/ T: r8 A4 ~1 ^" Y- E, i0 g) _

, b  q1 D9 K3 q! V* t2、硬件 SPI 驱动 TFT 实验8 F2 ~0 \+ w. Z) }8 X& b4 `
CubeMX 配置如下,保存后生成对应的配置代码:: a$ x4 n! d) J2 F, v, z- f

' m0 q. R; Z4 y& _0 g! N3 X  }  H+ c, o
12.png
% Y; t7 y; `+ K& E* |5 _

8 o+ K; {5 B! }$ g0 d& c& L+ g# A  U
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png
, C) d4 U* p. A2 e, w

$ q4 ^0 v- q3 e
▲ CubeMX 进行 IO 速度配置7 X% C% y6 F5 S4 Z
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。
/ O* F, u# ~; y5 W( o' x; C
/ g, M8 y1 P  Y
) o; f! k$ _8 i7 o4 [7 G. w9 I

5 I( N! \  V; b1 A6 w
相关操作函数说明:

8 `1 z% }+ L3 N# |" p* u
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

: j" G7 R  V/ G, r. e
功能:通过硬件 SPI 发送一组数据;

1 N( r1 e! n& p% F+ b5 l, p( A
参数 1:SPI 句柄,根据实际需要填写;

$ f1 _& g" B5 Q8 w& g* s: }2 b
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

: i6 p" B  q9 O
参数 3:发送数据长度,单位字节;
- F- r' r; [# d& @/ O# [" y
参数 4:发送超时时间,单位 ms;

% b) g- I$ q) C# ?; l2 f
返回:操作结果,HAL_OK,HAL_ERROR;
' G+ y: ?8 U, P
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据
. F9 \+ F# d) ], `
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
3 E" E8 v3 G7 X$ T, b
功能:通过硬件 SPI 接收一组数据;
# e/ r" Y% W9 y+ I
参数 1:SPI 句柄,根据实际需要填写;

2 h9 Y. Y& \* I8 N8 x
参数 2:要接收数据保存指针;
/ W# F9 o; ^7 ^( ]* X4 D6 o. t5 c! T
参数 3:接收数据长度,单位字节;
& E. z! C6 Y0 ^% D3 D9 k: K8 l
参数 4:接收超时时间,单位 ms;

" J! I4 |7 s* D9 [! d% L/ Z
返回:操作结果,HAL_OK,HAL_ERROR;

7 h7 s/ ~: B% I7 l, E  A) x) r. I
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
$ k. {6 M9 c7 S7 C' |
功能:通过硬件 SPI 交换一组数据;

) O* |% x2 A! J* ?6 Y
参数 1:SPI 句柄,根据实际需要填写;

/ J; `/ L' a9 h2 W" t+ R9 m9 f$ Q
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
* f- W! |  u9 y# J1 B0 N. D! I$ t! ]
参数 3:要接收数据的指针,接收数据数组的首地址;

! G5 H: D$ a, _' Y# c/ _" c
参数 4:数据长度,单位字节;
! ?: }/ ?# t7 R& z9 V3 z/ [
参数 5:超时时间,单位 ms;
/ M  U$ b  T. z
返回:操作结果,HAL_OK,HAL_ERROR;

( b) o. B2 c8 g$ t2 I

2 f& t" E! w+ ~2 M( r

3 I) n1 S0 |/ C6 C& w
核心代码:

' ~/ N- `  k! j# q9 s
LCD_Initial();
! R  z! H% Z' U3 @( ]' y: B
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
6 C2 D$ K3 E2 k- L$ ^- s% G
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
! W& ]3 u3 R, ^, x
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏
8 h2 }2 N: f+ ?
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏
# a; ~2 J: n) |& ]; @1 w
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
8 ^% |) S+ E3 s7 Y

2 f6 b, j6 h% ?/ \  E

* B3 {4 h* G  e/ t) ?7 w
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

7 V6 t7 l3 a  N/ S; y8 |8 z1 ^

, z. J; e; \9 g# {+ ^# Z7 I: G1 L

% O# f! s3 T: g+ z& X% t
实验现象:
8 y! ]2 O  d9 ?0 W5 q
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

+ P9 j/ ^. y7 o1 f: z8 a1 Q

# s3 s4 Y: v# v5 `5 `  \
" c2 d; t5 f$ P# k8 i5 f" P* k
3、硬件 SPI 驱动 TFT 实验(DMA)

6 e# l' ]* P6 x1 U. J
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png

+ Q0 z- Y9 B! Q8 z8 o/ e
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。

2 l' X2 b0 E6 C" b
相关操作函数说明:
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)

3 M" l& A; q: T6 [. x
功能:通过硬件 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)

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

% _/ z% E5 k$ c2 i% L- h( s! H
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}

9 g3 u3 o/ H/ D, b5 ?+ N
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。

! n" g4 x6 [  [! A8 Z5 D% E
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);
}
! |) x% V$ n% `( X0 D7 [
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。

9 X8 u7 A; p0 C) L( ]3 f9 Y
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);//显示字符
1 L5 v, q9 ~' ?/ |5 H: `+ \
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

" ~- `* W3 T! _9 V8 X( x: u0 @
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
+ v. X& E4 [1 d4 M
2 f5 G8 }6 k6 P$ U. a
七、IIC实验
$ l3 P# E# K6 a
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。
9 k/ \4 b- _1 e& D
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:
8 F1 I- X0 V: S+ i1 B3 z
4.png ' [5 k6 G8 ^* f9 i! l+ i3 Y( ~

: H: G$ _- t# }6 ]2 ^
▲ CubeMX 进行软件 IIC 的 IO 配置

  N+ j6 [$ `# m; Q
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。
' Z( W  z, {, a8 B
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式

. n1 ]% t; P8 C
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式
: `7 e( F7 E% K- V$ r  _1 c
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;

# T# d6 U8 F/ h8 h# a
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;
! a. T- V! F! z7 @6 s$ w
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;

* A9 V8 w4 `0 J3 e
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;
0 v6 D4 Y! w  F% o2 Z* P; ]' J
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
数:无;
返回:无;

& [7 Y3 F, o  T1 J1 V7 }' J
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;

) G8 I8 s5 {7 n! |( T
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;

: G4 G& x  W0 e/ i6 Q
核心代码:
//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();//停止信号
}

# [( a7 S. ]3 w
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。

" }" W/ ^$ G5 X! a! M/ @3 k) P( \
I2CInit();
uint32_t i;
) G7 s3 j& z9 a7 N! w
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);

; r$ D* |; t# e( i# u" V! f! x
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");
, }7 l! t- d! \" P2 G! C
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");
}
$ `- A+ Z1 A& _
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
- H* s4 i9 `/ h/ Z& h. N7 i
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

; l' \. c6 p, L, L1 t& Y
微信图片_20241122152540.png
. m* ]" }+ i( }- G7 B

, o$ [7 W6 v+ z! r" q
▲ 实验现象
# Z' n3 ~2 M! ?% y

- e8 `0 M4 a. M" ~- W( o
2、硬件 IIC 驱动 24C02 实验

: \+ }. }0 |7 I5 }) u; G2 ]
CubeMX 配置如下,保存后生成对应的配置代码:

1 ~: s! J* v) n& v/ ]$ w4 C( y# W! J
微信图片_20241122152543.png ; x4 W$ s$ i* d& l' i1 \$ t- _

1 A7 C! t4 g- r2 ?
▲ CubeMX 进行 IIC 配置
) K; |" h. J3 z
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。

3 T( I" z5 v' }0 n& ~4 ]/ n
相关操作函数说明:
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;
6 f6 e/ H0 G+ B# L+ h  u0 X+ _
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;

  U% l8 A' b) f$ Q$ N7 G
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 地址读取数据;
- w/ ?' \/ i3 y& g% x
6 j, j# L4 D4 b% K2 t
核心代码:
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");
}

6 p; R7 b2 r. q& r. y
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
! a& [8 g: z# z) `
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

" s# r* ^5 v# ]. g) C: S, N* J
微信图片_20241122152546.png
* @6 d* y- I% _. _/ M
▲ 实验现象

6 c5 t( P+ L- m9 s1 e

4 y) O3 Q% Y, T# G! @9 W2 f3 U
七、ADC实验

2 ~3 t- n% f5 M! K3 i' l& A" X
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。
2 ~1 N+ ^1 [! j  _8 C/ f* n5 p! \
1、ADC 查询方式单路采集实验
( l% Q& q1 i% |6 `; k
CubeMX 配置如下,保存后生成对应的配置代码:

, O  M0 P+ x. x' Z9 s1 a8 u; R
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置
- ^  j- d6 G( O) y/ l2 m
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。
' Y' N( |% s1 V+ b$ i
相关操作函数说明:
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 进行单端采样模式下的校准;
1 o' _8 Z) l& ^9 h9 ~' j: F
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换
3 Z+ k" S, {& g) ~
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
7 e2 [0 O* w. B& M3 }- z5 |
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); //等待转换完成

) \7 e- n8 X$ j1 B" l
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
7 Q# f4 w7 N/ e' x1 F' z( A
核心代码:
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);
}
# [& Z; {/ p6 Q- ^
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。
8 o. T- |9 R- K( x# `5 H
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

% \7 D( F# `# m3 w0 T
微信图片_20241122152553.png
' ?, r# ]: y3 \/ ]2 _0 Q

# O- B& y* K# _; `
▲ 实验现象
. y4 c0 i- W9 m3 h

8 H! c7 Q. X: z- Q, C! G
2、ADC 中断方式单路采集实验
4 ?$ r- o1 l( D0 }8 {
CubeMX 配置如下,保存后生成对应的配置代码:

" z: N# G' I7 y# Y  k
微信图片_20241122152556.png
▲ CubeMX 进行中断配置

" M: a/ S& E% v8 t% J2 |  ?5 A" T
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。
- q/ Y7 j  W) X$ u6 X6 f
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据

% U) A  Y; ]" e
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

: r, W8 r8 }$ ~- r% e% f1 L
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}
" s% _% ^* G/ W' N, ]: A
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。

% k' V6 n' k+ Q- f9 K! I
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); //通过串口发送
}
}
; u- J! K" f  j3 h: U: Z; c/ b
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
$ G5 j  s) Z# T/ N  I+ V" Z2 ~
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

4 B3 T8 j2 M! f& k' D/ U+ Q8 k% ^' A/ c
微信图片_20241122152600.png
& ?( x# T9 i( Q, ^5 V2 ?

6 d! f0 K  a2 o) R6 ?2 {; y
▲ 实验现象

+ K( d  {0 g, J# H4 B# h5 n
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
: j& m& B. A% c: q
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置
( V! z: o- T. Z- |3 i' M" ~
微信图片_20241122152610.png 4 x* r1 ~3 c9 U5 U; C, q
▲ CubeMX 进行 DMA 配置
, U, z* j5 y% m$ a  \% Z
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。

3 y* n5 n# S! j; L& g- k8 {
相关操作函数说明:
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 传输;

/ S  v( i9 i0 L
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

2 I' p# Q$ O4 O! `9 m
核心代码:
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();
}

# }6 x! U. `0 e1 G% B! }7 v
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。

- w9 O# W  F# }- G# P# v2 R
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 转换。
$ C6 A2 @5 W- s0 k
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}
" |9 M4 G& h6 D8 A
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。

3 ^: O  W1 B0 z4 C9 l
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
- {" J, K; a, x  b  l9 W! s
微信图片_20241122152613.png 2 W, u; z7 R6 D* f9 [" C
& n3 |+ q9 i2 d3 ]
▲ 实验现象
' I. p# [" i+ W2 f! I6 X/ y& q
4、内部温度采集实验
8 f3 g1 B2 D, W2 z' Z9 H2 `
CubeMX 配置如下,保存后生成对应的配置代码:
8 L% c: A: k+ Q" d
微信图片_20241122152616.png
  k2 }/ A. O5 Z! C, V+ w9 Y, R
! K0 U6 F) H3 @7 O7 r" z
▲ CubeMX 进行温度传感器 ADC 配置

* b. W: c6 o& t, m: E3 o
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。

  x& b/ g# \' p% H4 v
相关操作函数说明:
__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);//转换温度
; e9 `1 i8 G. f
核心代码:
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* P5 C5 [* f, ^$ t/ B5 j: `! R
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。

+ m' T( b1 B( N1 g& l6 ?$ }. ?$ \- |
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。

! T3 ?+ F+ U1 F0 }
微信图片_20241122152619.png
5 Y$ G; x- O( B  p5 d
▲ 实验现象

- f. h* T# E( p; x6 t0 Y# n" d
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:

* [) O& o) z. p3 |: q
微信图片_20241122152621.png , m3 J6 r4 V, G1 z/ u' |; q
$ \$ B; g2 @: Q# h' A, l0 ~; c0 @
▲ CubeMX 进行 ADC 配置

5 F+ d8 y& ^5 g: S# V
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。

- `1 j1 S( V8 P, {$ O( R' 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 值
ADC_Vol = 3*ADC_Value*3.3f/4096;// 转换为电压
printf("VBAT: %2.4f V \r\n", ADC_Vol); //通过串口发送
HAL_Delay(500);
}

3 k% P) Z; z4 m# \
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。
/ I+ ?  F5 [5 m$ L( b2 z/ j
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

. w2 x" o7 a. [9 M
微信图片_20241122152624.png
▲ 实验现象
6 G% M/ R2 s5 V! F3 Z2 `5 c4 W; |
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png - J- F% O+ R/ z* r* X" R
- d+ z  t. Y' X$ W2 y" R
▲ CubeMX 进行温度传感器 ADC 配置

7 b& S  t# }  b: o6 }
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。

7 n0 y5 C% p( Q7 A) h4 ?+ s
相关操作函数说明:
__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+
, h4 Z, A7 c  R1 O) B
核心代码:
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);
}
( A! {7 k5 l3 L, P
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。

) K0 h+ \" f, z3 `4 Y6 |6 ]
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。
4 O/ O& b3 U* v, B  W4 H
微信图片_20241122152630.png 9 J) A5 [# p3 Y- z8 f# J: b
8 w' I# W' J8 n" U+ j3 o% D! {
▲ 实验现象

+ b% ~+ M0 ~7 J, t) b
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png
( ]1 O/ g! {5 \! o9 t* N$ C) {
- H: [- ^0 K0 c* M
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png
, E7 `3 h3 B% w& h+ ^( V$ Q1 s

2 f9 n; u  d3 G
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png   X5 G$ g  h/ B" I4 _; V1 Y6 g
2 Z; h4 G7 M+ O6 c& Y
▲ CubeMX 进行中断配置
5 f( `7 n* E" F' ^, X( {1 _: ~
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。

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

  }: C9 J& s/ B9 {: d$ U5 A- }
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

+ v+ B0 r) }( `* i/ ^- Y
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1

0 U4 f" a  l+ Y$ b, q+ Q
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。

. w3 }1 ]3 `2 V" R# d: v0 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); //通过串口发送
}
}
  w, Z4 D! x! K
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
0 Z* \% H+ w3 l2 f# j  C* w. Q7 \6 X
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png / q2 ?+ S1 |$ N* V3 l; J

8 i$ @8 P& e" C- _* }
▲ 实验现象
九、DAC实验
# r  P, Z0 ?( y; `' h4 o# H- l. X
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。
3 q  d7 ~' z; Z; s" T
1、DAC 软件触发输出实验

1 O2 M/ O( \; e4 v2 \+ b  C% ]
CubeMX 配置如下,保存后生成对应的配置代码:

2 o- T: w, H! F# K2 s; Q, h
微信图片_20241122152645.png + c+ s$ ~3 r! N- j2 ]

) y  _& m: w9 E2 Y2 @/ B: }
▲ CubeMX 进行 DAC 输出配置

% w, |# Y! T# I) O1 U
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。
' d3 e- A' z' ~  N) P
相关操作函数说明:
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 输出,如果想要修改生效,还需要使用下面的函数
* O( D- a5 o( K, _8 k
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);// 改变输出值
- [% N5 i4 |% Y! X# |
. R  b& N4 n* N# ?
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;

' ^% ~& a! w" X' x- t
核心代码:
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);// 延时一毫秒
}
}
; J  f& K- p* ^, D; ~# Y8 ]+ y9 e
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。
3 _( a7 Z% Q: u4 m  }- v
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。

, k$ K7 V$ M) U1 X# N5 e
微信图片_20241122165909.png
. B# N5 Z. R; u! t# o. x0 B

! e3 K$ j7 f; D9 e5 r' w
▲ 实验现象
5 o3 G) Y9 O) z
2、定时器触发 DMA 传输 DAC 输出实验
( P/ O/ t( Q! W! m! T$ o
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png
" e( M. j- W' p7 _
7 p: D! M. P. ?' }
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png
5 r! t' \& X1 |* i& |, J
0 z$ C1 }$ X- l& A& K) b& e
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png
' z1 j' E( R. v' Z2 g+ ~0 t+ J- r: |

# j& W3 V/ o! a
▲ CubeMX 进行 TIM4 配置

0 V$ G8 O& k8 _1 J- W" F5 i& C
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。
' f# H2 @5 k' S5 u' X2 i! 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 方式设置输出值

& A: r  N* \% n3 z7 I, e
核心代码:
//正弦表
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
: H3 E& {6 l( w( N% a  t5 U% Y
以上为正弦表定义。

, l4 t6 i" h  c
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();
}
+ B5 ^/ u0 f% |# L
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。
% ]" M% T( K- B2 ]5 S
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png
" C' r6 d( E1 X' V1 \. f0 o

* c2 i+ z. {+ g3 J6 C6 ]% V7 B
▲ 实验现象
  w! W* w% O6 U7 n
3、定时器触发 DAC 输出噪声实验

3 x- Q; F# w5 V# P' Y7 F2 K# c3 {
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png
( J5 t* \1 {; U
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png
- o4 r* T% e4 d, ?5 U1 F0 v
' E+ }. @8 o, N6 S2 j8 h/ s- d" j6 H' G. s
▲ CubeMX 进行 TIM2 配置

/ M9 _9 U# R3 c9 }% G
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。
! X. M4 P; E" @
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC
0 N8 S! j! g; m2 u: j# x4 d! Y
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。
9 F3 c, o5 x( Y4 _. h* f8 T. W
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png
. |' g# q1 S. p
▲ 实验现象
' C2 ]9 k) d+ X: P) U% P
如有侵权请联系删除

% u1 H0 Q( s, y2 e! g4 b  t
转载自:AI电堂+ j! J8 j" D% x2 D2 O8 F, x- W
5 E0 v) f7 X* k$ v* T
收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似分享

官网相关资源

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