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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验
; r/ @) I- J: ~8 j2 Z实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。
% C' N! s7 o+ u  [7 M

& p6 r' _; V, g9 r0 w- H1、软件模拟 SPI 驱动 TFT 实验. W1 ]8 `' ?" G
CubeMX 配置如下,保存后生成对应的配置代码:
  `! n0 e( l7 d
13.png
" F8 D0 F% h( J# w5 T
' Y2 {, U( q. f
▲ CubeMX 配置
. b9 L5 [! Y$ q' j
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。) G$ g- F  M  g) e8 o& c
0 Y) X: P5 A& D4 i
相关操作函数说明:
  W0 G$ r' z/ R6 h6 y9 u( zvoid Lcd_Reset(void)
, D! Y" ~, e- F* a" g5 ^1 ]

' ^* l% ?" D: Z2 q2 M功能:液晶硬复位函数;
" l" T2 c+ M4 M- g9 t参数:无;' V4 g: P% D: L* {$ R% Y# e" p
返回:无;' N$ m  y2 |. H, |, _/ I8 E1 f
说明:液晶初始化前需执行一次复位操作% m6 Z; f  O6 b9 V/ V* q
void LCD_Initial(void)
# F8 f- r$ b, I! v: E' A功能:初始化液晶;
# I6 h% |  j% R- m4 J0 A1 Z参数:无;
3 C7 v' T# ~# x9 Z$ A返回:无;
/ h. x4 L. v& C, h4 x. q说明:在对液晶写入内容前需要进行初始化配置;
; x2 C7 d& B8 B7 ~. \void Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
1 n1 ^- }2 w4 g7 e6 o7 s$ h

" K' x1 ~* Y6 }7 e& p- B1 w1 O功能:Lcd 矩形填充函数;0 k: I! i4 w$ m1 C  P+ E
参数 1:x 方向的起始点;
  \* b; [+ [1 l& C; J3 [参数 2:y 方向的起始点;+ A+ s% c; k- ~! @: ~5 y! t
参数 3:x 方向的长度;/ H+ g. ~* ^4 [& i  f% A) c8 U. N
参数 4:y 方向的长度;9 @, Y5 O3 u+ Q( z4 |
参数 5:填充的颜色;. Y/ d: A% q: T$ v
返回:无;
2 \; ~* {) m9 y% c' O说明:将指定区域内填充指定颜色,常用于清屏9 e6 _* e% @' I6 F3 E
void BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend)7 ?- W7 i# N- W; c( P6 G3 H; ?) Q
; O. X. t0 ]$ z2 O3 o; t
功能:在一个指定位置开一个矩形框;
2 g& z8 W$ R" v" [4 s* T( f8 f参数 1:x 方向的起始点;" g% n+ h. k& w  P
参数 2:x 方向的终点;) i% C7 ?1 k  g5 K, P8 S5 F) b
参数 3:y 方向的起始点;  G+ Q0 |" _/ j3 J1 K5 g6 v5 B" d
参数 4:y 方向的终点;. `5 g( Q5 A' b" K  I7 _) T
返回:无;. \6 Q, ^- I7 |9 L  k# a- T
说明:开一个矩形框,方便接下来往这个框填充数据;% n' K; J: v0 k
void DrawPixel(unsigned int x, unsigned int y, int Color)
) o6 g. P- J! A4 e# f功能:在 x,y 坐标上打一个颜色为 Color 的点;
/ w' W; |5 v$ h# z7 A3 i4 z参数 1:x 坐标;
" L2 F+ }+ H3 r! M$ v, k参数 2:y 坐标;
9 Q6 o) C# q6 V# a2 X& l- b6 b参数 3:点的颜色;
- D) \( q. I9 D9 F& k& u+ B返回:无;' Z: o, A8 N" y5 L6 N/ R: N+ n
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)3 w8 e! {% Z* A; P4 {  V) V$ a! [
1 Q1 l9 n4 M' a2 L
功能:显示一个字符串;
/ G3 @( Q& `" G& D参数 1:起始点 x 坐标;$ s. ]/ p! M7 K6 y
参数 2:起始点 y 坐标;. f& B' r  A' U: _* r+ J7 u
参数 3:字符串指针;
! T! t; Q0 O3 A8 H参数 4:前景色;, Y: I$ v  z* G7 J, f1 O3 }/ W
参数 5:背景色;2 }$ v  m* G" J
参数 6:有无背景色;8 x) H) v& x: h+ b- A& x* r
返回:无
) h4 |/ a0 y( p. b: b/ g
& _" {' |# O4 C$ w: P( f

5 B8 Q$ P! W' j/ M" K. k) q核心代码:8 b. x1 n  m7 ]
LCD_Initial();
' ?; T7 J6 `$ ^5 I- i/ \% TLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏) X6 a2 X2 C- Q" O- b0 ^
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏0 c" T, N5 x3 ]6 a7 Y4 ]1 e
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏, j: ~- N7 N  P
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏; T4 D- ~9 A& V1 ?
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符7 x0 [' n/ o6 ^9 _, U" s. Z( c0 w, K- A

# w+ u5 s3 U  _, M" O在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。% V3 [, ~& T; i5 Y5 }

& h+ h  _. Y6 ?" I7 i2 d
+ v. U- S/ u6 H: m2 f: a# `, |5 J
实验现象:
1 n2 l  i! I" p- ]下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。, @; q1 J" J* {8 ^

6 k7 c$ q1 J* }. r

( e& ^9 ^6 E- Z; C+ ^& ^2、硬件 SPI 驱动 TFT 实验
7 C7 s# V7 U7 w7 Z  |, rCubeMX 配置如下,保存后生成对应的配置代码:! z5 m: `. _, \5 w9 {" Q; q/ A

/ J! I+ S2 Y3 r4 k
12.png ' _: r0 ~) Y( e' `  e7 k# |
3 o# r& Y% y, R1 j
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png
* D% b6 k  R1 t1 V0 w+ y/ _, Y

7 Z0 E& Q. y4 @. n" ]
▲ CubeMX 进行 IO 速度配置$ x. N+ ]: z1 x" C& U9 b
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。

3 G3 J% O) P# J/ L6 A2 {1 u7 a

" V9 D( H% \4 \7 ^, W
+ V5 r  t$ i0 n% U

) ?  x. |8 t, @" B( G
相关操作函数说明:

; U, o) y4 |* o8 o/ E4 y
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
9 s- c( W9 K+ X8 {; b. m; Y% q% h
功能:通过硬件 SPI 发送一组数据;

: l6 e' n5 ~3 M; o" ^) S7 I
参数 1:SPI 句柄,根据实际需要填写;

0 h( a2 p( o, g
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

) i) x2 m2 k1 t6 _& k# s+ F% P/ ]. ]0 e
参数 3:发送数据长度,单位字节;
- n( |! Z1 M7 V- c3 K3 ?4 P
参数 4:发送超时时间,单位 ms;
& c7 N  H# d# }; x1 \
返回:操作结果,HAL_OK,HAL_ERROR;

5 l/ Z$ s3 c# c7 y& N
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据
4 h! T# }  x7 L  q
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

# X3 }. m5 [, ~( L+ H0 p
功能:通过硬件 SPI 接收一组数据;
1 h5 L' N7 p- p9 B) p2 {
参数 1:SPI 句柄,根据实际需要填写;
" B2 U% I  ?5 O' C0 W; Z6 Z9 A
参数 2:要接收数据保存指针;

6 Z$ H7 W* i; b% K2 A! q/ Z
参数 3:接收数据长度,单位字节;
' y1 M) j; R5 }! A2 j0 o. ~9 b# a. p4 X
参数 4:接收超时时间,单位 ms;
) [; W  G) {4 f' Y, ?9 p- i; W
返回:操作结果,HAL_OK,HAL_ERROR;

2 ]  Q3 B" n. L
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
, @; C8 n& {" O. F2 e
功能:通过硬件 SPI 交换一组数据;

' g' D, b; |  s: N% g
参数 1:SPI 句柄,根据实际需要填写;

% q$ `* k. F* D3 y0 z- d
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
$ v( n/ d/ H2 D  P( I( l/ q# b" ?
参数 3:要接收数据的指针,接收数据数组的首地址;
$ N+ a( `1 X. ^9 {# p2 p" s
参数 4:数据长度,单位字节;
& u1 K! i3 D. h# P9 Q; Y
参数 5:超时时间,单位 ms;

- z2 c8 a( g, b- W3 p9 w4 v% J6 F
返回:操作结果,HAL_OK,HAL_ERROR;

  x! }. \' D, s$ k% `

1 C7 r) }0 ]' b7 Q6 d/ w! ^4 M

' @- n7 }. s+ Q0 x
核心代码:
1 d1 F8 U! W! b- o+ p& F. h. y8 y
LCD_Initial();

9 @* w$ k. J5 |& S
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏

, ^0 P4 J( I' A
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏

7 j( i" d4 ]/ V* Y6 K5 g
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏

1 E$ H0 z4 X: T7 D7 |
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏
8 g1 s) o( r  v) K1 L+ V$ k
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
' t5 A' `. x  n2 ?2 l

6 C8 J& i3 g4 N8 q

* d9 h. x% [( D! t* e: m: V
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
% ]6 V7 v7 P" K5 C" t' l
3 r( M0 [5 z5 g4 _3 T+ G

' J! j& p0 V" {( ]: q6 q  r
实验现象:
* k* L* C* l9 x+ U) t) h9 k
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

9 |! i3 R/ ^# c

+ f- q7 ?  l& |+ ^$ I, ]$ F, B( _# F0 W

/ @+ q8 w4 H6 U  I, h# V, \/ b7 y
3、硬件 SPI 驱动 TFT 实验(DMA)

7 d  A, X3 T& C" w
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png
5 a; W1 }: J# p# d
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。

1 j/ A4 ^6 M5 ]9 F# ]; 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)

6 ]8 V; }) Y0 P4 Z
功能:通过硬件 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)
8 L& k0 C9 i0 i" O9 w
功能:通过硬件 SPI 的 DMA 方式交换一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
参数 3:要接收数据的指针,接收数据数组的首地址;
参数 4:数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
注意:使用相应 DMA 时需要对该 DMA 请求进行配置;

9 r; p3 ?: C$ }( v
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}
' F# K) E9 J( |" h% ^) v
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。
0 z# I# O, \8 V, C5 |3 h
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);
}
7 A! A  S7 R, y5 h! v+ P  D
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。

9 s9 z1 e( e( ]- I) x$ F2 j
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 O- m; r! `6 K! \: |  ~
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

/ E+ p- b7 d: t) L% k6 {
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
" ^4 F' D; v" G
! ?+ P/ x+ S7 W: O$ O
七、IIC实验
6 N5 s- U- v  s/ z
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。
: {. h* F1 k% F
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:
. a# ~  t/ t9 d. j1 V$ o
4.png
% e( ^3 }- f% n% f

$ [( u7 Z5 F7 }, O! u2 ]5 S
▲ CubeMX 进行软件 IIC 的 IO 配置
% J( |' y/ ]3 B
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。

, L- b, @: o8 O+ h9 I6 h% m
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式
" @: i$ G% N/ J
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式

% y8 f  k& A' f4 E' V! r+ a
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;
8 b4 |! q1 `% F! k5 H; ~
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;

4 c" L$ m/ n# Y5 O( [
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;

6 t7 x" l8 Q' I  H9 G
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;

, e6 Q0 S+ g- U) O$ ?2 h
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
数:无;
返回:无;

$ o& E6 m9 H' H$ D2 j" g
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;

: Z8 U8 s: e( |- X+ ?4 e
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;
! P& ~+ u1 ?. O' V) W
核心代码:
//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();//停止信号
}
- q0 \: R8 q9 V# U/ p, d! c
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。
) I  Q+ J- W6 H; u7 W3 B
I2CInit();
uint32_t i;

" C4 [+ A7 o) F) I
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/ \3 e. I. `1 `. K' S8 {
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");
8 i0 q5 k, e7 a, [$ E
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");
}
% ~3 f0 l* h- r: ~! X* S& V
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

( ~8 l# d- z* ?# f! @
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

( N( B" M4 C$ r, [5 D
微信图片_20241122152540.png 1 |( H: G( Y( T' \
8 K0 i0 q$ w0 Y
▲ 实验现象

# ^& A1 I, `* Q$ e! w4 H
+ m8 I) U% S# R% a- _4 [, k* H: a
2、硬件 IIC 驱动 24C02 实验
5 ^0 f- o# H% [; M% z' [- j' B0 p7 ^
CubeMX 配置如下,保存后生成对应的配置代码:
0 @, q% U% u5 G$ w4 D4 @. C3 ^. g# s
微信图片_20241122152543.png 0 u( {+ K$ E5 r
1 K3 g2 N8 }  g2 z' Q7 n( r$ ?* Q
▲ CubeMX 进行 IIC 配置

9 ~) M1 ]! o" h# c5 O! w4 R
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。

( h+ U+ Y8 @3 N. j7 L
相关操作函数说明:
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress,uint16_t MemAddress,uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
功能:以阻塞方式将一定量的数据写入指定的内存地址;
参数 1:I2C 句柄,根据实际需要填写;
参数 2:设备地址,注意这里填入的地址应该是左移一位之后的地址;
参数 3:目标内存的地址;
参数 4:目标内存的地址大小,可选 8 位(I2C_MEMADD_SIZE_8BIT),16 位(I2C_MEMADD_SIZE_16BIT);
参数 5:带发送数据的指针;
参数 6:待发送的数据量;
参数 7:发送超时时间;
返回:操作结果,HAL_OK,HAL_ERROR;
4 E  U" }& }% H' b
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;

* J2 d* T+ r' O4 f; h" L
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 地址读取数据;
- {& U, g/ h" W1 m  S
& v8 ?7 Q9 ^! @; R" W+ ^. b9 }# H9 s
核心代码:
uint32_t i;
printf(" 24C02 Test ....\r\n\r\n");
//向 0x01 内存地址写入数据
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);
printf(" 24C02 Write ok\r\n");
HAL_Delay(100);
//从 0x01 内存地址读出数据
HAL_I2C_Mem_Read(&hi2c3,Addr_R,0x01,I2C_MEMADD_SIZE_8BIT,Data_R,DataSize,0xFF);
printf(" 24C02 Read ok\r\n");
printf("24C02 Read Data : \r\n");
for(i = 0; i < DataSize; i++)
printf("0x%02X ", Data_R);
printf("\r\n\r\n");
if(memcmp(Data_T, Data_R, DataSize) == 0)
{
printf(" 24C02 Test OK\r\n");
}
else
{
printf(" 24C02 Test Failed\r\n");
}

1 Z3 F+ B: I2 @
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
7 B" Z6 v, ^; z2 i! |5 z0 s9 a
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
& ~( v6 p- s( q! v: Z
微信图片_20241122152546.png & y! m: D0 O7 _6 s- i" ~
▲ 实验现象
/ B4 O9 C! D: r* A; W( M
! M. R$ K7 ]) s% \" x/ c
七、ADC实验

9 Q: x0 }$ e+ ?5 g
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。
5 o8 @! c1 H4 r+ r: _" c! Q
1、ADC 查询方式单路采集实验
/ _4 K8 @3 T2 n9 w1 A
CubeMX 配置如下,保存后生成对应的配置代码:
  Q4 E/ F0 V# G- e4 w
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置
5 l. L" O1 j8 ~$ y$ v) a
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。

+ Z( d$ S& O3 p& J8 F. _+ {5 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 进行单端采样模式下的校准;

1 A. ?6 \% D: p8 T! G7 s
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换
) {  z. u  B$ x! d5 u- `3 Q& z
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
7 h) d6 e  m- n  C' c4 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); //等待转换完成

# B; q1 K# c( ~2 P2 x* [! r8 `
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值

" C9 |0 V+ P! U' T' T$ l( d; G
核心代码:
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);
}
, T$ e/ A, c" ?8 R7 Y" [: }. T6 i
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。

0 X& q. d: g9 \: s$ f3 U
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
  L* R7 R/ m7 y- f7 {
微信图片_20241122152553.png : ^+ u' }9 }' Q3 F9 v/ N8 S! G1 A1 o
9 I& j. t& s1 e$ C
▲ 实验现象

# l3 P# |/ Y1 n0 _
& \/ s7 l- u, [* G- K& C& h
2、ADC 中断方式单路采集实验

: g! L6 f+ Z' t; S
CubeMX 配置如下,保存后生成对应的配置代码:

  `$ y. z6 G7 q2 l! E) O3 U
微信图片_20241122152556.png
▲ CubeMX 进行中断配置

' \; N, G/ {( `2 J2 i
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。

" V0 z3 J8 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 转换完成之后会触发中断,中断中读取采样数据
8 B, y) U2 O6 R# V! @
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
' }% Q2 [( D* ^! o  ]1 T+ d
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}

2 {' _1 K$ M$ `$ m- h
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。
7 d3 q7 E7 T! x- n* Q9 q) 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); //通过串口发送
}
}

. P3 H% W' r/ P; Z4 m5 Y; e
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。

4 F9 `- U0 _" t
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
4 s5 w& }0 ?& \; f4 q# P+ W1 W5 w0 @& z
微信图片_20241122152600.png
  ]. k- ~' q& r0 j+ O7 G
  U6 t: E3 o: s3 x/ F9 o
▲ 实验现象
  {) w7 _* o4 _* D8 P/ F( a6 o
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
; V" `1 A& v( k+ O1 o  |1 `
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置
7 n: e7 X  V9 y  J0 q5 P1 r" F
微信图片_20241122152610.png % {% U. ]1 d3 j
▲ CubeMX 进行 DMA 配置

! _1 Z1 z; U' L5 L8 C6 K
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。

+ O2 `4 G% W% n+ Z
相关操作函数说明:
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 传输;

$ o2 J. R3 \' }: k  o
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
7 p8 J9 G$ e3 b; Z
核心代码:
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();
}
( |- r/ `- ]9 E: x! W
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。
2 r4 B. @* z6 z# P* ~& J
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 转换。

$ G) a) ~) t+ v- b7 `% J- }
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}

7 k& h1 H: R5 Z2 O0 [5 z/ S4 X: Q. A
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。
6 a5 r. l$ _5 U9 G
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

2 Y! w$ K: ?( S! r6 i2 }2 u
微信图片_20241122152613.png
, d! r. a5 p5 R0 w/ ~# |

4 D; E1 c+ p1 C$ y
▲ 实验现象

# q6 J6 k5 {* z, Z
4、内部温度采集实验

. p+ c, n0 v6 v
CubeMX 配置如下,保存后生成对应的配置代码:
8 B7 B# z- S6 g3 {% e
微信图片_20241122152616.png 4 d+ f! \/ G$ u9 I" i

* b- ?4 f, [2 z: E' I; y3 h
▲ CubeMX 进行温度传感器 ADC 配置
) k1 a  [4 z3 ~" u! l! C/ p! F$ A
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。

0 c# S/ G, v3 `- j1 y
相关操作函数说明:
__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);//转换温度

  v9 u& E1 Y& T. G
核心代码:
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);
}
7 z' t! D( ?, ?+ n6 |# t& M
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。

% K7 j9 B& P; [) z, f
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。
* H: k1 m8 l, b4 b
微信图片_20241122152619.png
; L1 J  O5 p# [3 C' n* V
▲ 实验现象
5 Q& e2 K! P) L9 c: |6 S
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:

- e/ G4 M2 K2 t! o% a- ?, R
微信图片_20241122152621.png 8 K4 @: ~* A* ~2 a0 f  [* J

& p$ s  {1 K4 y% }. o0 `
▲ CubeMX 进行 ADC 配置

$ s5 t$ e9 `% i% ]3 o
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。
) D( J4 x& e2 U' W, i. j. T
核心代码:
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);
}

' ]5 Z8 j# f/ D! T! y. n9 ?. y- |  w( o. _
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。
8 o3 d7 A, D7 h" ]4 _' b
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
0 }8 `: p! M+ q: a: L
微信图片_20241122152624.png
▲ 实验现象
' o( E! s8 O3 b  s9 p2 O% b
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png
  c$ i" o. L) i- C8 R2 d  E3 D6 D

1 O' k% J: e& ^6 j& w* S
▲ CubeMX 进行温度传感器 ADC 配置

$ T2 l; n/ w9 \' I
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。

  j4 Y1 E% `/ ~* P6 l) [6 L6 \; P
相关操作函数说明:
__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 {4 @5 A: G: A. G: 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);
}

# I- q, N& w/ e$ a
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。

# n% j# K1 M6 Q& f7 W& H& ?
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。

) t  @5 l: K5 s+ ?- R
微信图片_20241122152630.png
/ ?2 }" O8 z2 f" E3 I  q& C

6 e! {: s# r0 y
▲ 实验现象
7 u& w" M7 M5 x" m# x
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png
! [8 o, x, l9 C+ Q

6 _" c* `: [8 ]' {
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png
1 I! h  U; {6 l1 N  i" f+ ?6 ^

1 |& @0 Y# [' `; M- e# W
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png
9 f; s% q8 O3 P8 t0 ~0 G% d

* _% u, C" \- s
▲ CubeMX 进行中断配置

1 R/ E& W" N3 T# ^2 A3 _8 I
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。
( n+ ]+ [8 [9 w1 p. @4 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 转换完成之后会触发中断,中断中读取采样数据

0 B' n* {7 A/ Q5 a  n( O1 b
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

. X* j% w7 C+ ]
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1

6 j0 r. E" H" N
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。

' _* p/ b: z6 {% H$ \' }6 F2 \
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); //通过串口发送
}
}

$ Y! F: I# s* @$ s' J3 L4 n/ W# o
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。

. _* v! `0 Z0 o, l0 g
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png
, }! ^! u0 P* g
3 E/ z2 S1 x5 \/ t; h" i) x/ A9 k
▲ 实验现象
九、DAC实验

0 d) m% e5 b3 x& A& q$ {1 G6 X1 ~$ A
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。
5 b. _4 v: a+ P) W
1、DAC 软件触发输出实验
3 Y. P+ j7 U* @, }/ r+ r
CubeMX 配置如下,保存后生成对应的配置代码:
% ~* o: F5 A, }
微信图片_20241122152645.png
+ g; d+ l' h2 d( U& \* @! E. N: \
( w0 j$ k% L1 k. n
▲ CubeMX 进行 DAC 输出配置

7 }3 ]: Z* M# K
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。

: E. z* s6 ~1 o/ n2 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 输出,如果想要修改生效,还需要使用下面的函数

$ g- e2 o3 c! J% p
HAL_StatusTypeDef HAL_DAC_Start(DAC_HandleTypeDef *hdac, uint32_t Channel)
功能:开启外部 DAC 电压转换;
参数 1:DAC 句柄,根据需要填写;
参数 2:DAC 通道,可选 DAC_CHANNEL_1、DAC_CHANNEL_2;
返回:操作结果,HAL_OK 或 HAL_ERROR;
示例:HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);// 改变输出值
1 `/ Q. ~  Y' p) Y. Q

. K* ~7 j! ]% v5 u
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* d6 _9 y, L% v7 P
核心代码:
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);// 延时一毫秒
}
}

- i1 Y& T% b% a7 D* t
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。
0 ^( i( v6 b% o2 K( E, K
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。
0 W" z+ g( O! z; [& B
微信图片_20241122165909.png
( R( l2 ^" M) o0 q6 S1 H8 o: S

" l9 g, I* j  m' S% x8 N+ u
▲ 实验现象

8 y, L5 G* x- M% M% v# _" r  {
2、定时器触发 DMA 传输 DAC 输出实验

5 o8 H3 y8 X; s; Y( @$ F
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png
  I2 J/ D" ^: j

2 t6 A; X. Z7 o" g
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png
1 G# s$ u0 O6 a& B" j

0 l7 a$ u6 d# }0 \* Q4 N2 T" g
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png & i6 x" L" a2 m% U
5 m7 @  g  c/ z5 B$ H. [, |
▲ CubeMX 进行 TIM4 配置
' T& J/ o% q& l$ b8 A% y6 K
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。

, A" Z( P0 t; C; u, H3 ]
相关操作函数说明:
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 方式设置输出值

7 Q& `3 H" ?9 r+ ]7 K; X$ }7 v
核心代码:
//正弦表
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

+ L5 B- h9 w  i9 p  C
以上为正弦表定义。

( B0 ~* w) H9 Q4 P+ V' n
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();
}
. c# D! S! j! ~1 m7 b5 b  Z& _
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。
7 B. s* S& ?- Y2 n9 m
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png 1 N2 ]( y7 X6 [( `3 X
# @( i8 l/ p/ o7 s5 g
▲ 实验现象

3 b, B( s' x& H, n. Y- {8 x
3、定时器触发 DAC 输出噪声实验

4 S' t: E  _5 T/ \6 ^$ J" f
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png
  f0 p% w2 g/ b
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png 7 X5 \) H! v$ G

. G: y7 A0 b5 R/ U8 y% a
▲ CubeMX 进行 TIM2 配置

% L$ t) s9 Z6 O* {& k
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。
; L  Z' v; l5 Q( V! d5 |
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC

6 T) [5 Q! m' O
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。
5 K4 I- E% j( Y6 B$ q
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png
3 G1 b$ I$ D7 k
▲ 实验现象
0 I3 Z' W) i. V2 _* h
如有侵权请联系删除

# m7 V* @: a& m
转载自:AI电堂- e5 T- O+ R% u7 R
  |, B+ Z3 r# w( Q' K
收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似技术帖

官网相关资源

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