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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验
/ o$ M, A3 o. C! I6 v& ~/ p, j实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。
) C4 b. B- a  i. j/ R7 i

# j; ?. o% B, t* K) d1、软件模拟 SPI 驱动 TFT 实验+ e9 n% Y0 k! L; y
CubeMX 配置如下,保存后生成对应的配置代码:
5 u5 t0 X' F) z# P) C
13.png ! s4 ~) t6 ?2 e, K* b% c6 `! E

4 t5 J/ L7 h/ ]- }+ Z1 p1 Y1 J
▲ CubeMX 配置

6 O' Q: u( s" s& J
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。5 W( u2 Q, _- U) \" w( J

& o( |  E$ F5 ^" M2 o6 K: Y. x
相关操作函数说明:. r6 |: \8 l5 C2 f: t
void Lcd_Reset(void), M& m9 W0 p" P

, R0 Q. k3 I, v: ~3 J& c6 e6 O$ y/ \功能:液晶硬复位函数;. _  X" x& C5 x* ~
参数:无;
5 c8 ^! P+ Z4 s( V返回:无;! ]! q: Q( ]* [# C) b+ |: q) n
说明:液晶初始化前需执行一次复位操作
' K/ e9 e/ ]  \$ Cvoid LCD_Initial(void)
+ R# x. s, j; c/ {$ r+ R2 r功能:初始化液晶;" `6 y. T- l; z
参数:无;
0 ?) |! c6 m2 N7 M) C* g返回:无;2 E% N9 K2 I1 Z7 W8 C0 L# z
说明:在对液晶写入内容前需要进行初始化配置;
3 c  d/ K7 ]' i" n& \( dvoid Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
: m) Q$ n: D; R4 C
7 h- ?, A- a& G9 I8 x
功能:Lcd 矩形填充函数;' P- O4 a" h/ l0 B6 m
参数 1:x 方向的起始点;
9 V; r) M' R7 p5 D( m参数 2:y 方向的起始点;2 W" l5 v# K" g/ s7 Z' e% a
参数 3:x 方向的长度;
2 S8 L# s, l7 X9 c. j参数 4:y 方向的长度;
6 v/ q* e- ]" |* O参数 5:填充的颜色;
; }4 j) l( [3 _; \% a& X2 v返回:无;- L3 v) ]' \' ^# c1 z2 i
说明:将指定区域内填充指定颜色,常用于清屏2 e( s$ G" `( w! u+ ?
void BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend)4 f; A* U0 Y- I7 v( K/ V; k

" X2 k  c& J9 J$ ~  }7 @  |功能:在一个指定位置开一个矩形框;
- F1 I1 m5 ^& w参数 1:x 方向的起始点;4 M+ I6 Q5 H! z/ `0 ]% ~
参数 2:x 方向的终点;) Y' s) ~! }: H  `# W
参数 3:y 方向的起始点;1 d" w4 J& Q+ X1 Z3 w
参数 4:y 方向的终点;; J0 a8 P: @% M% J) H5 g
返回:无;
! `9 L0 L  G8 }6 J' T& C! y2 J& {+ X说明:开一个矩形框,方便接下来往这个框填充数据;) f* [7 K+ ?; f3 ?8 e
void DrawPixel(unsigned int x, unsigned int y, int Color)! g; z4 u6 n# j. J0 B- o9 j% Z
功能:在 x,y 坐标上打一个颜色为 Color 的点;
3 j0 G  ?$ y! {9 M0 v参数 1:x 坐标;5 f- |0 r* y3 I- v; M
参数 2:y 坐标;
! L8 o( D$ i  l3 i2 U+ \0 W参数 3:点的颜色;
, A! {3 L6 V7 ^# u- P返回:无;
  L! |) |9 A# u: X3 R9 P! o+ wvoid LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)5 E6 d' ~. [0 l

' D( U; b' y8 [4 ^+ r功能:显示一个字符串;8 ]1 R' t1 M9 a) T
参数 1:起始点 x 坐标;2 F0 d+ C. v! [1 J, S$ ~: U3 P
参数 2:起始点 y 坐标;
  J8 ]$ r2 d! D. Z4 v参数 3:字符串指针;
* c4 G. y5 M: U  p& a0 m  r7 j参数 4:前景色;0 ]2 i  V/ N$ q6 Y
参数 5:背景色;
/ M  S! A# D) S8 K1 A  O/ @2 ]" G9 S参数 6:有无背景色;8 L% @" c# L* B: \. O5 P
返回:无
1 e1 U# O4 u( S" t  w% I3 r5 ]5 ~! c4 J6 d/ {; h
# @% l- F/ m3 ?) b2 @
核心代码:
/ u" H8 }& F, l8 [. S1 XLCD_Initial();
# B9 W) E( c: t# J% k6 k$ fLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏6 S% w% ~+ D) h3 \& s
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏0 E8 w6 r$ [1 D1 Z: f
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏
( _6 B* k6 q# v- w9 o# zLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏0 F1 j- \  i% Q( y
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
# t; C+ `7 m( M5 p; x# I3 _
8 y$ r3 P) u& m* C3 h) `( H在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
1 ~% ^7 v& \5 s. y
% p! k- D, J$ I8 u$ ?  Z3 X. u; i
( T8 M, I3 Q7 t8 L
实验现象:2 `! z; I' m7 d3 ^, I5 ?: Y
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。; b0 E1 b1 }4 D+ r, i( o. O$ L+ ~

5 g+ J; {# n% g: c( o
  t; [3 g3 \0 Z4 H; o- r. m- X- O
2、硬件 SPI 驱动 TFT 实验
1 O- N7 m5 z5 C6 TCubeMX 配置如下,保存后生成对应的配置代码:
- J. V9 `1 e- ?+ r0 {- d  j2 Z
) Y$ ~+ L; f# }9 o
12.png * O0 }" K: k% s" |! n6 K/ B+ c! ~
' S- i( U+ M' X9 }8 E7 a% U2 \
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png 5 A1 s; \+ G( D' ~  @/ T

% v( ^& o. x. H& F. y
▲ CubeMX 进行 IO 速度配置
2 y9 d; A9 ^. p2 D) {
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。

' ^' S$ q& Q6 |6 F; e
" d$ ]$ s$ y1 G" h, i6 c+ C

0 I2 w% v8 H3 v9 y  N4 T5 i
4 ?  F7 h7 S" u
相关操作函数说明:
7 o- [; q  }, J- h; f) y
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
; R9 N' F; R; g8 y
功能:通过硬件 SPI 发送一组数据;
- A% H/ N% V& E7 q1 @
参数 1:SPI 句柄,根据实际需要填写;
: X$ x. e) V* C/ y7 O  A4 ^) e
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
3 k3 f- `4 d  W) r
参数 3:发送数据长度,单位字节;
, \$ o! w; ]- P+ Q' S0 D. b  E
参数 4:发送超时时间,单位 ms;

, a; r* [5 J8 A$ N- r& H
返回:操作结果,HAL_OK,HAL_ERROR;
$ R1 i7 k7 q6 y: z5 r$ K
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据
5 a, Q* G. w; {
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
0 M. v( p; V6 Q
功能:通过硬件 SPI 接收一组数据;

. M. M' K, [0 V
参数 1:SPI 句柄,根据实际需要填写;

: t% J4 S4 s9 U$ }. X
参数 2:要接收数据保存指针;
9 h1 h! ?! A. J. I; z
参数 3:接收数据长度,单位字节;

, u2 j; W- ^. U' O
参数 4:接收超时时间,单位 ms;
. B' W) y; n& D; m1 A* J1 k' I5 m
返回:操作结果,HAL_OK,HAL_ERROR;

% b+ ]3 N2 s4 w  o9 w, R1 P1 R4 j
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
1 z9 s2 g- b5 ]9 o9 `6 {7 W8 n7 e) f
功能:通过硬件 SPI 交换一组数据;
: T6 X0 Y! R1 w. E% x1 \: B
参数 1:SPI 句柄,根据实际需要填写;
1 h7 D" F6 j; {$ a
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
. z) T/ H, A: H" C) }' U  w
参数 3:要接收数据的指针,接收数据数组的首地址;
% Y4 c2 v2 G5 W$ M" W( p! E
参数 4:数据长度,单位字节;

& f7 A  h- Z) g
参数 5:超时时间,单位 ms;
7 u4 |) u5 y( C8 _. W
返回:操作结果,HAL_OK,HAL_ERROR;
8 c# ~: ^, ?& K

# L+ |  W5 O6 d8 L9 P( N

- c& p5 E3 V7 }" n
核心代码:

# L) ~4 w  y* \' i7 I# r, J
LCD_Initial();
+ _8 o% V) P& o) m
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏

- R6 ^: Z; A% r% }5 f6 M3 ^
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
6 h  f- o( v8 O. A; i  A, \1 h
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏

) r$ v- X) p& `& m7 p
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏

9 u) K9 t7 w% P% o
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
6 J  M: O  z3 d
  q6 S$ R$ |! d2 o; M
6 S! f/ [+ x6 y
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
. ]+ T2 @' q( r4 l1 ^6 @

+ H  E; Y# H, p

" I3 C  \1 A/ W4 p$ o- T
实验现象:
. o; ?/ ^- s7 n! @1 Z# d; a  E
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

: y2 X% Q/ U  ^

1 B/ T+ x, ^$ s7 G' w6 E3 H. _, V

, _: f* o: g6 V. `8 Y
3、硬件 SPI 驱动 TFT 实验(DMA)
4 a% h. v( s/ }, f9 ]
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png

1 l* `5 A  F+ k0 v& T
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。

# ]6 M/ {* k4 c! O1 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)

9 i. ^+ u" T6 o& g, 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)
/ @0 l0 T! m4 D! C2 n" n5 W
功能:通过硬件 SPI 的 DMA 方式交换一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
参数 3:要接收数据的指针,接收数据数组的首地址;
参数 4:数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
注意:使用相应 DMA 时需要对该 DMA 请求进行配置;
8 d/ f# n2 m3 h+ u. C8 u1 l% _
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}

/ C( H9 ]0 B) t3 B; B6 P
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。

# T* F8 i/ F* t2 x# u3 w; ]  d5 G5 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);
}
% i2 ^3 z  T  `) l
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。

2 B' g$ {1 s& P% v
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);//显示字符
- M- m5 }. Y# y5 a) G9 n
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
% j7 d* z5 x8 O' ^% z
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

0 E, u+ c% N1 d3 F1 U' |" }3 T7 G. S! j" h
七、IIC实验
, q5 ]2 z/ p3 x+ f# J
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。
6 g/ u: D; d  j
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:

2 W: O  `- S& f1 |0 i
4.png
- v+ V- h( e) }3 B
, b/ O1 _: P% A) U5 l7 W7 J" h
▲ CubeMX 进行软件 IIC 的 IO 配置

4 x( C$ l4 T/ l/ E/ H) ]% M  A* ^
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。

* P! O7 y4 w0 D6 w
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式
; I: G" r/ Q2 u9 p
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式

* G* I6 Y" [" G; u& A) q! V, K
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;
7 Z- p$ f1 _+ a1 Y- Z; V
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;
! F. X0 A' {1 y* o- @4 F8 \, h
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;

+ I6 V, }3 A: B  W" r9 Z
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;
5 U8 a& P& Y. h- i
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
数:无;
返回:无;
+ |$ n! ~. s" J  ~
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;
! O7 v. F" `- r& ^  r
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;

8 J  P# h6 t8 {5 ^
核心代码:
//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();//停止信号
}
* K) ^7 m) s( |
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。

! W* e; [" ~9 l7 T- N; i
I2CInit();
uint32_t i;

: s+ I$ m# Y8 S: [1 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);

9 r9 h* D$ S: ?5 z- l- p7 [
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");

# g1 K' m# G3 Q$ E6 i8 k  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");
}
0 I* ]" Z/ g& q' ?6 N7 R3 z
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
8 D6 }' _+ Y. z$ a/ l" N
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

% o/ r0 w0 u, N; r* X% }) ~
微信图片_20241122152540.png ' F3 r: O( S1 q$ |' e
# s+ l, H$ K6 P& X7 U3 b
▲ 实验现象
; t5 R1 y5 ]- T$ @
$ v8 k, u. z' y$ o: N7 G; V
2、硬件 IIC 驱动 24C02 实验
. b; r0 a# Z: |9 l0 [; f; j, l4 G
CubeMX 配置如下,保存后生成对应的配置代码:
' ~3 y. v& h$ M! @% Q
微信图片_20241122152543.png . o. p% v) m* ^% }0 s+ |% @3 i

4 z9 K( W, a2 X' c: T0 P! ?2 }1 w
▲ CubeMX 进行 IIC 配置
. O. V$ ], f( ~7 [3 T- H
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。

9 z" C. f( X6 M3 B" r4 ?; [+ h
相关操作函数说明:
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;

2 [& I  f$ d8 H- R  G$ o4 Y
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;

# U8 j2 D5 L( J5 a* m
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 地址读取数据;

: x  W, N9 d" X9 ]1 c8 a7 \- t+ J
: ?" Q% x2 L  q/ k5 Y: z. v" y; S, k
核心代码:
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");
}

& m/ l% D5 M/ D, J. l3 @
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

2 V+ N( t" ^( H0 W$ g
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

: G8 p6 @( G; O# N
微信图片_20241122152546.png
$ L2 V! ~  a' \3 u& [! |1 f
▲ 实验现象
: A& y+ M# v0 u6 V4 ?
+ W( t4 u5 [9 J' @
七、ADC实验
. n% W+ ?2 y9 f5 d
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。
9 ^5 b+ r7 x( X  G
1、ADC 查询方式单路采集实验

: g4 ~1 b0 e7 a3 L5 F* k1 ?
CubeMX 配置如下,保存后生成对应的配置代码:

* V+ h  ^+ }2 B$ `  E
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置
8 a, U$ n4 A! B- B( M. J5 J
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。
  H) D( v0 G( C
相关操作函数说明:
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 进行单端采样模式下的校准;

& F. _. i* |& |1 H' E; t6 ~
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换
3 |' g# O& M5 D9 F2 _5 @
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
& t0 X# w6 m, v
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/ ~8 F3 }7 w% k: M
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
' T3 p+ F3 z, C3 `! E  j. K
核心代码:
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);
}
( m2 I' P* u4 `0 L+ E2 X$ a
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。
& t7 j  `# M1 M  t' q/ o
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
0 c' A% e4 Z$ j5 Z  }
微信图片_20241122152553.png
7 T+ U& P% K: L7 l# G6 ]6 m' M" F

7 A( j. [* m. v; ?
▲ 实验现象
) v5 c  C6 s; \  f

. y7 ]& f3 e2 X5 [; Y* C
2、ADC 中断方式单路采集实验
: z& k. A, w) ^" w/ J
CubeMX 配置如下,保存后生成对应的配置代码:

; T% e- R9 W0 ~* f: M
微信图片_20241122152556.png
▲ CubeMX 进行中断配置

- }0 Q3 d0 W  Y+ M
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。

9 G. h( L* `% \/ J) t" R* `9 M
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据

- l0 a, d8 A5 o$ C
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
9 s, I9 {5 U2 L+ H0 v# o4 s
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}

, f) h: ~1 y' v7 S" `
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。

) x9 C. f+ L# V3 `6 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); //通过串口发送
}
}

/ E, n2 |5 k( Y6 f  P2 A$ C
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。

9 A* ~! N6 A1 A0 `( N
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
3 k/ ?3 J$ h8 x* a! b4 U1 D' J" H
微信图片_20241122152600.png ! F3 x9 ?/ Y- B9 b3 b

3 J& m- ?! T# Y" {
▲ 实验现象

3 U/ B$ g) h3 l. T/ f
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:

* J9 n3 J5 }' h& ~) J
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置

$ h$ w' q! a3 Q! R4 p4 }
微信图片_20241122152610.png
5 G% ?# a+ S1 S) S; u
▲ CubeMX 进行 DMA 配置

' _! c. j2 H/ v' ?% u) @/ a
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。
6 C( ~1 t; w. [. d! Y- D
相关操作函数说明:
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 传输;

' U  @/ T/ c, z0 s
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

9 ]& c& l9 {/ d) v9 H. {& 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();
}

! F) y9 y' K1 W. ]" |  @
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。

" ^; w8 E- u, D2 p* V  K! O+ k6 z6 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 转换。
/ J* w0 u( Y+ V
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}

% ], M) f& ~/ v! u  U$ K4 ]
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。

1 W( Z4 H8 @4 M9 g7 C
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
% o9 q( t8 C# t# I9 c
微信图片_20241122152613.png   c2 I8 J: k8 r% A/ z9 {- \
! I9 n' o; V/ `+ C" L) n3 b3 \" _
▲ 实验现象
% p+ F3 ^0 I9 U( v
4、内部温度采集实验

) g8 S' ^* A! c6 i# q
CubeMX 配置如下,保存后生成对应的配置代码:

5 H- M7 z2 J* [) h/ O4 v) Y2 e
微信图片_20241122152616.png 6 @; f2 b9 G9 F$ x
: r. ~. P$ z  S) X  k0 V' N  L( Z9 V
▲ CubeMX 进行温度传感器 ADC 配置
+ Y2 a* ?/ r2 c: E
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。
( E/ a3 H, l9 c" k& Q/ f
相关操作函数说明:
__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);//转换温度
' P, {) M0 ]4 d& l4 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 = 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 |1 l6 B* n! W: z# d9 Z- d, Q9 e
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。
: H- f+ ]; f- p* E  b
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。
  a/ @, I  F' }; `2 `2 @: ^
微信图片_20241122152619.png 3 h# Z" W5 ]+ F* s9 V5 \( _
▲ 实验现象
5 Y0 F# a* q7 H+ K6 J; g7 F$ t2 E' g
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
6 B# c7 y- a( T6 y+ ^; o1 n
微信图片_20241122152621.png ) F# w$ i2 h# ]% X2 u
6 ?. Y& W1 a0 S
▲ CubeMX 进行 ADC 配置

: P! }, [- M* a; b7 @. j
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。

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

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

' _. d( _1 }  J. N, I, d/ U6 {$ v. a
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

& U8 R% l% |% z9 S
微信图片_20241122152624.png
▲ 实验现象

- N$ _; n8 u' x# j3 P" B" d
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png
+ c' K/ F/ i* f+ L
+ U% T' I: w2 }$ S: a. |
▲ CubeMX 进行温度传感器 ADC 配置
  v% ^3 ]: J1 e. E
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。
8 }! K+ L- X  W* X. T
相关操作函数说明:
__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 x' h+ v) e6 E8 `
核心代码:
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);
}
; W$ U9 T7 j4 I" q6 _
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。
: A2 f. B' m4 O1 X. D
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。

- z4 t) g- s) e+ w
微信图片_20241122152630.png
8 B6 W& s& ?2 o$ I
; C- `% U! ^0 u1 [2 n6 X8 v+ P
▲ 实验现象

2 b# _! z$ N# f/ e' Z0 ^' b
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png
7 j; k# q; D' y

5 [$ f4 \6 n6 h6 E& w: Y
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png # C; b+ ?; G4 t( l: }' q/ A( U

0 v7 S$ r# V$ S3 Z+ p5 S
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png
# R3 R! L3 |* t7 {; r
( j. B2 a* t; y2 }2 [( q5 O
▲ CubeMX 进行中断配置
- q6 k( y  @; v0 j3 K
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。

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

* d+ c* {: z% {
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
: k$ x( o8 D8 W. w
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1

) A% \# k1 I5 ]! a, _/ }
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。

' {# I+ m0 _: L0 t& m: e( }
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); //通过串口发送
}
}
; }2 E6 z; R  L
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。

; B( L4 `% [7 @% m0 J$ h* T) @; ~
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png # w, `" }2 I8 i3 U

9 ?5 }6 }# u  V3 [% k7 U* W
▲ 实验现象
九、DAC实验

8 b1 N* }+ N8 ^
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。

! I+ ?2 M( s: E7 b
1、DAC 软件触发输出实验

# Y+ H3 J  X- O
CubeMX 配置如下,保存后生成对应的配置代码:
2 x, z; Q2 ~, z- L$ c; f8 C0 @; E
微信图片_20241122152645.png ! O' }' f3 |( H" o$ T# i# h4 p
. \& l" u% M& i) o' m. s
▲ CubeMX 进行 DAC 输出配置
, Q2 |/ p. U  u: u
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。

: E: d  U& F2 ]8 F: E
相关操作函数说明:
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 n4 F/ z/ W; B' Y3 }
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);// 改变输出值
4 N: b; D7 n/ ]7 F; C
0 h8 w& W! \" [
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;

# S- H7 |; t( G
核心代码:
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);// 延时一毫秒
}
}

" v6 @- A; A$ ^' v8 ~9 d$ I
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。

8 V# m3 S) B- w5 \: t: E: c
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。
' F7 `: R& W" i  K9 E4 J/ o+ a
微信图片_20241122165909.png
- ^' B! p) q, g' S
& |$ k2 m( e" l2 b4 i+ z# G% E
▲ 实验现象

2 `+ l- Q& I5 g+ G, u' i+ N
2、定时器触发 DMA 传输 DAC 输出实验
) C1 m* r1 g( R5 d" G
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png . H; n$ H' i, k5 I- o

- L! P* l9 Z0 H
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png
( z. H2 h/ T& `* ~

, J. P+ P! y9 h& D. E! D
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png 4 {  j8 @1 l* j5 X+ x% ~1 f9 J  Q

6 [2 b2 [- k0 g" U
▲ CubeMX 进行 TIM4 配置

( j2 @, E$ e1 Y# K/ ?* E$ F* W
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。
2 X  ~9 u* I  l6 n2 d: I
相关操作函数说明:
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 方式设置输出值
; r. @1 y7 k3 t9 }9 z
核心代码:
//正弦表
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

. T6 a  l  t, M. _8 `
以上为正弦表定义。

) y" h3 Q, p! M$ z/ a
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();
}
( z2 s) t: z* N4 q: g
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。

, s  z- p0 m$ o% [, H
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png ' C3 O- ]( a' ~' n5 K& S

1 I: G+ ]4 n$ D! B6 ^6 ?+ h
▲ 实验现象
& x3 N: C$ F) d3 D! A+ A! U. f
3、定时器触发 DAC 输出噪声实验
+ W2 H0 {0 `0 [% N; t' v* C1 `
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png
' h, g! c, S7 t8 Z4 R
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png
  Q6 R  u( C- Q# ]  a2 x! ]
) b* U8 b. B  m( X( [( L6 A
▲ CubeMX 进行 TIM2 配置

/ K# v1 C- m9 |7 c
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。

/ R' o/ R" S/ O( b" C2 L
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC
) F  O$ `9 C; \
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。
" k& L7 r) [) x
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png 0 F1 S, o% I$ o
▲ 实验现象
  ?( f. }' W% P# @
如有侵权请联系删除

, g$ j, z/ V+ t( Q( y, N
转载自:AI电堂
5 }0 ]% ?: A  ?) s- u
" Q$ r# G. n- L( N, e* _
收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似分享

官网相关资源

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