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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验  d( o% x: R% m. h4 h
实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。* C* Y* }1 |3 v& \, f) O

; d! @; c9 a) O3 ]1、软件模拟 SPI 驱动 TFT 实验% d% ^# k6 M. `- d
CubeMX 配置如下,保存后生成对应的配置代码:( w9 \* I+ R% o, D
13.png
- `" N8 g' ?2 j: `

1 Y. m* @) m0 b# Y
▲ CubeMX 配置

& R; F5 C' o8 A4 ~. y5 r! |0 g& i/ P
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。1 q6 H4 f* h" T9 k- d! }5 e
4 g, O! p# R0 e. B
相关操作函数说明:2 e( O# i5 S2 M" z4 D3 o
void Lcd_Reset(void)$ a* m2 q6 _/ x. `; [- Y7 y% s
3 z5 @5 f+ b3 O2 l
功能:液晶硬复位函数;# K, b! o& e8 h/ `. G0 m7 R: X
参数:无;4 K3 u6 [0 k/ S) y0 \* |
返回:无;
' t" g1 W. r9 C4 L( ], w% }说明:液晶初始化前需执行一次复位操作$ z% Q! p6 X1 n3 O" D* L
void LCD_Initial(void)4 D7 E( \  h% s0 i5 S
功能:初始化液晶;
9 d  \8 U  d  U" D- J3 m% N; J5 R参数:无;0 V/ ~2 ]4 c4 U3 m! F) V/ r0 Z$ @
返回:无;& m$ c1 |/ g! l9 @2 n0 Q4 e' J
说明:在对液晶写入内容前需要进行初始化配置;9 ?3 K) a( s9 p2 [5 s( l. l* I& \) q
void Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
" L$ R6 _: d+ p

* s0 _6 g6 m' L# J功能:Lcd 矩形填充函数;+ @8 N) b' x7 u; I
参数 1:x 方向的起始点;
) z# n3 L7 t# R+ g% D+ M参数 2:y 方向的起始点;
. O7 r  r* }4 S参数 3:x 方向的长度;& _: s0 C  e9 ~
参数 4:y 方向的长度;
& w9 m9 D% [1 _4 Y, Y% z参数 5:填充的颜色;
/ k1 B* N" X# `! K- f7 @返回:无;4 M" r& @9 [% n" I# e& F
说明:将指定区域内填充指定颜色,常用于清屏
5 O+ h8 M+ M- ]void BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend)
* ?0 `- T# A5 |8 t0 F. ^4 B- v+ a& h0 V. d; b/ G9 Q' |9 R$ L6 R1 j7 J
功能:在一个指定位置开一个矩形框;
! j# c4 a" k( i% J9 l参数 1:x 方向的起始点;
' D. [9 z/ G: l+ b参数 2:x 方向的终点;
0 E6 v& Y) \9 N, F1 N6 a; L' Y$ O参数 3:y 方向的起始点;
/ n* L1 `9 r4 f( M参数 4:y 方向的终点;
8 R( X* y8 d) [7 u8 y$ V返回:无;
+ |/ u# m/ Y* j说明:开一个矩形框,方便接下来往这个框填充数据;
7 M3 y- A. q, j) q1 g' w% v& ]1 F' Kvoid DrawPixel(unsigned int x, unsigned int y, int Color)
; c" Z# a' g. [9 K0 e7 |功能:在 x,y 坐标上打一个颜色为 Color 的点;0 a( D) `) k( V) _/ C
参数 1:x 坐标;/ c2 Y& i5 y8 P7 s- `  a
参数 2:y 坐标;
3 U1 i' A- G; B5 N5 n4 I2 I参数 3:点的颜色;& ~1 }+ P  t. o! g, Y+ P( w. N
返回:无;1 V4 k7 }  u5 R& ]
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)
+ e' @- z" I  J& Y: G8 e1 F5 r8 I! |7 q! ?
功能:显示一个字符串;0 B2 S" w9 k  t9 M) l$ O# p
参数 1:起始点 x 坐标;
' y, m; U: h- ~3 Y7 N参数 2:起始点 y 坐标;
* Z+ W5 T1 V6 n0 k- ~参数 3:字符串指针;
( n. e5 g: {2 C& _! v3 w0 Y参数 4:前景色;
$ U* O; H3 d- {! i, w参数 5:背景色;  Z, o7 `( x( o. U
参数 6:有无背景色;
0 @" p9 X, ^6 n1 F0 I4 `7 ^+ d返回:无
  _- r& v  V, j5 ^+ ?( I# C/ e# \. `! h' |" H

$ p% S1 }6 s2 e- `4 W9 N核心代码:% K* Q7 V+ }" v0 F  l: y/ y& c
LCD_Initial();: T/ R0 [5 U" s9 N/ q* X5 f/ l
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
. ?* b0 X! A- |' S" zLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
; m5 I& Q8 A$ v: ?: V& m6 zLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏( n+ u% g5 I/ V( s5 W3 T
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏6 k- R) L' S9 y4 B
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
# c6 [5 B! j' l, e9 p4 E: T& p2 R8 ?- Q0 u6 ^5 m" V2 m' G
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
3 s* D- ^; c% D* [0 B; O; N4 s6 X0 `. L

( k2 u1 Z* A- w5 S8 h; e实验现象:
4 I6 ]0 ~; Q( u7 G( P$ @下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。" [& d0 c0 x! E, C% V
  J7 T: c- H5 U; v! S( t8 \7 r

& |  p  y: `  I2、硬件 SPI 驱动 TFT 实验$ v/ y5 ?# W3 B  o2 r. y2 m$ r
CubeMX 配置如下,保存后生成对应的配置代码:
8 b. M6 x. {6 |- j" s
. f0 y3 ^0 r& u/ j9 t+ G
12.png
- ^4 Z! }* p# f8 [" Q

' F1 D# g6 p! }9 b
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png 2 L  s5 N9 o- \, p6 ?. b1 F7 t

2 t. {& H3 {0 _' F* _8 P  @
▲ CubeMX 进行 IO 速度配置
! V. s% F# x: [$ F
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。
* |! b( `- J1 a2 _1 m' j: U( u) c" G

3 \, a/ ?% l+ b
5 z2 O( _% z- z- f- y

! g& f7 J" Y- H  c+ r% u1 x
相关操作函数说明:
& B$ H. W7 j, m: G* O6 r
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
6 i1 f7 @3 j, c' n) w4 ^5 W. h
功能:通过硬件 SPI 发送一组数据;
0 }3 Z  B8 U+ j4 m3 O) f
参数 1:SPI 句柄,根据实际需要填写;

$ d" \5 u- q& t, S! P
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
/ d( _/ }) J& u/ L
参数 3:发送数据长度,单位字节;

% j3 S. c; @% C5 y3 {) Q
参数 4:发送超时时间,单位 ms;
' `. u) Y1 A  z1 ]" Z7 J( l
返回:操作结果,HAL_OK,HAL_ERROR;

/ ~& u) Q8 q( S
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据
  @' D4 W) ]+ |0 C! H- w" u
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
& ]1 }; Q% l0 S* v6 H; t
功能:通过硬件 SPI 接收一组数据;
1 y6 l8 v" [$ n% V2 i$ C# ?1 \
参数 1:SPI 句柄,根据实际需要填写;

  B+ v' R; {6 c2 [2 H; T( g
参数 2:要接收数据保存指针;
4 L  t; u% v$ W) \0 H) }7 k- \
参数 3:接收数据长度,单位字节;
6 U6 u3 D' R& o, ]# K) g
参数 4:接收超时时间,单位 ms;

& N! b4 d, u9 {, C0 K! _
返回:操作结果,HAL_OK,HAL_ERROR;

+ E3 I0 Y1 ]" y; R! s$ i/ E
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
1 }0 _- I$ i7 j, x( j+ ?4 e" c
功能:通过硬件 SPI 交换一组数据;

- z: m; y4 i$ E2 @- R; @
参数 1:SPI 句柄,根据实际需要填写;
; z" ~/ c. A8 L) ]# `( N! }
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

' E# |7 h' ~0 ^6 o' w$ J
参数 3:要接收数据的指针,接收数据数组的首地址;
9 k/ T- B- _3 ^& k+ C8 s
参数 4:数据长度,单位字节;
& h8 X1 K7 T2 ]! F+ S7 c% m
参数 5:超时时间,单位 ms;
- [/ I6 k8 i4 b$ ?
返回:操作结果,HAL_OK,HAL_ERROR;

6 W2 B! n2 |, S

2 y- B- Z6 B: ?
+ [$ @8 c" }: C. d# s+ c; b
核心代码:

9 z9 ^" g# w  k2 |9 q  ]; K7 z
LCD_Initial();

1 \) P" X* x( ^4 b- [* ^& h
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
% \+ U, X/ z3 T2 I0 r  D9 U( S
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
. W. t5 f1 d/ x. z) A( e" T( ~
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏

8 n: j2 p9 `: n1 G' j# ]4 ]
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏

( K4 v- m6 {9 x7 E- n
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符

7 ?# u% O7 C6 |0 }
. d8 u- n9 c6 W+ T. e+ W) W

1 k9 D( Q' m& O1 h
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
& T) W4 }$ A# S( O

- K; j8 y) r6 J# I0 L1 L1 t5 _
6 o; Y$ @5 [- ^9 e, T# m7 b3 Z
实验现象:

/ e& O7 n2 ~) z: j9 N
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
7 B" L7 O/ E- i6 _
5 m- L+ r; q6 J+ g! t

+ @5 P/ [  T: S  d: b. K  k
3、硬件 SPI 驱动 TFT 实验(DMA)
+ @" m0 m# N% Q/ [" i
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png
- \+ g. `0 Z# R, {9 l+ Y
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。

1 @' g4 ^5 O8 o! |8 y
相关操作函数说明:
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)
) O, F$ c/ d# X9 \1 s6 m9 q$ ?; h
功能:通过硬件 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)

; L( A5 n, j7 `7 K3 M1 |; \
功能:通过硬件 SPI 的 DMA 方式交换一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
参数 3:要接收数据的指针,接收数据数组的首地址;
参数 4:数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
注意:使用相应 DMA 时需要对该 DMA 请求进行配置;
: E( B0 ?8 l, J. ]$ w
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}

5 s8 V6 X! f) L+ ?, W- |
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。
/ z1 _1 E. c! v1 K! Z4 Y& 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);
}

" q% z8 [% N  E
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。

$ n1 V& \% r- e$ M  B% `
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);//显示字符
" h1 i2 a) t* K) f/ h0 d
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
4 _; ^* n  p! _6 ~. p
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

8 F; W% ]5 M+ P) Y& ?
! I- [! S: g, n. y# r
七、IIC实验
, R% ~' E. ~% B; y
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。

5 o/ t9 n. H2 n; p( o0 z' t
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:
8 V  j3 ]5 E2 z7 K) }$ E  M
4.png
' V3 ]1 n: B" T
6 w3 r, R/ v" l" j. P  Z8 W
▲ CubeMX 进行软件 IIC 的 IO 配置

, t2 L$ w3 a# O1 V: }
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。

: }: M: f' V: z1 I. _% D0 ~9 y
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式

/ J  n' l3 ^. B
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式
$ h' ]7 W! a4 ~$ o
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;
. N7 V& i1 s+ }2 U  a" K  o
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;
- L- z. L; C. U7 \/ `4 h! @
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;
: n5 Q" g4 ^7 B5 [" l
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;
3 [4 f: q& X1 M+ Q
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
参数:无;
返回:无;
0 ]  t( i/ ]% x/ c3 E$ X
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;
( ~& S0 o) d' P: J, S  _
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;

1 w. E0 n; p6 q  b! a0 z9 a
核心代码:
//24C02 读取一个字节
uint8_t x24c02_read(uint8_t address)
{
unsigned char val;
I2CStart();//起始信号
I2CSendByte(0xa0);//发送器件写地址
I2CWaitAck();//等待应答
I2CSendByte(address);//发送读取的内存地址
I2CWaitAck();//等待应答
I2CStart();//起始信号
I2CSendByte(0xa1);//发送器件读地址
I2CWaitAck();//等待应答
val = I2CReceiveByte();//接收一个字节
I2CWaitAck();//等待应答
I2CStop();//停止信号
return(val);
}
//24C02 读取写入一个字节
void x24c02_write(uint8_t address, uint8_t info)
{
I2CStart();//起始信号
I2CSendByte(0xa0);//发送器件写地址
I2CWaitAck();//等待应答
I2CSendByte(address);//发送写入的内存地址
I2CWaitAck();//等待应答
I2CSendByte(info);//发送写入内容
I2CWaitAck();//等待应答
I2CStop();//停止信号
}
& h( U; V; u, ?2 N7 G$ p  n
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。
# b! I9 d" a5 v& S; T+ j1 U4 k
I2CInit();
uint32_t i;

2 s( z- i& @3 e- G# K4 ^6 m! e& ^8 j
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);
6 y; \$ d' F" h3 s0 C
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");
/ w: D, P; s- W: F. N4 B
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");
}

: h) s5 u; O# [7 G& P
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

4 N# f; g, R. f2 m% l9 K
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
; b' W3 z) n- n* W1 s- N; Q) Y( e# W: q
微信图片_20241122152540.png
5 N. V, X4 ]' J9 c9 _5 L+ `" N
+ ]0 Q! A" B/ a1 p9 Z
▲ 实验现象

- i) ?; A% o, ~! \' W( P! j& a
  X  H. L+ V) a5 M; ]' c" |$ s
2、硬件 IIC 驱动 24C02 实验
  [* y: {0 S$ B/ ^
CubeMX 配置如下,保存后生成对应的配置代码:

6 M3 z4 Z# k% e) ^; Q  f
微信图片_20241122152543.png
7 c# J+ v# I7 m& i0 P  ~7 o: E. G; H

% D5 k) z% |! @5 f3 ]  ]
▲ CubeMX 进行 IIC 配置
2 [5 Z, J& G% T, k9 p* Y
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。
9 |" N- k0 p+ E3 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;
1 A1 ]  B$ C; z' P# ~
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;

6 |0 V: w4 W8 C. g5 w. P
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 地址读取数据;

5 R  \7 }4 `7 f& M; k9 |
' S+ Q- I0 F3 W1 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");
}
) z' x# E4 T9 {6 ?! W
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
. }. `3 A/ N% @$ @0 h' d
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

7 O5 ?4 _3 c; H, C
微信图片_20241122152546.png 5 `4 @8 m  z8 Z6 w1 k
▲ 实验现象

3 ~* ]) O' _& }) B) H9 B
6 a, c4 Y/ A. u
七、ADC实验

& d) X* ^  Q# [2 \& U4 a
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。

1 l' I7 N- t5 F2 Z( E
1、ADC 查询方式单路采集实验

; w- p5 |, r7 f$ V, U% ^% U* G
CubeMX 配置如下,保存后生成对应的配置代码:

1 l. q/ j. Z( q! l. W; S7 R- Y
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置
% w/ A( @1 O' T; S9 {; L+ F
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。

& b) s6 b2 T# D6 U# n7 u( S
相关操作函数说明:
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 进行单端采样模式下的校准;

6 w  K3 ^6 A3 b( K
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换

  n" Y0 z, s$ ]
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
6 Z3 {% p% X# Z8 C, {
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); //等待转换完成

  C: o1 q: J, r' h3 B% u
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值

1 [+ j! o! i( E3 I% B" 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);
}

) |1 p# ]( u: Q' J
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。

! L! V3 F0 e7 e7 l% l
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

$ U7 g$ f- Z, \/ i- a; n
微信图片_20241122152553.png
9 {6 a7 A: B0 C
. }6 }# D9 L) k" b' k5 t1 s+ h
▲ 实验现象
) E- {( B: A  r! O' R! ?: C
3 J$ F, P- U6 b8 m/ \# {; I
2、ADC 中断方式单路采集实验
0 u, J2 ~  _5 {2 ?/ M
CubeMX 配置如下,保存后生成对应的配置代码:

" a; X' j5 ~7 O1 u
微信图片_20241122152556.png
▲ CubeMX 进行中断配置
5 S5 }5 C1 B' p
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。

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

4 S! ~4 E9 A- w+ J6 o5 s: [
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
. N" y# H' O* T' i% D
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}

) \0 s. r) S4 j' T, o9 @
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。
: I6 `- z8 a" e- d2 F- w" l+ r5 @
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); //通过串口发送
}
}

0 ^4 C% }5 \& o5 h0 a' ]
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。

: k( K9 f2 ^7 h. E
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

3 H& c0 s0 C. Y, b7 w# k1 z" t
微信图片_20241122152600.png
  D! l, o# I  w1 \1 k

. h3 h1 k0 S0 y' z1 K/ B6 ^# z0 P
▲ 实验现象
& k2 J, [: c, O( N8 u" B
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:

! X1 `; i8 f- C8 W- x
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置

5 @3 M) J$ h9 P% k; ^1 z
微信图片_20241122152610.png
2 Q/ O- R6 `; Q% R. g+ p- y
▲ CubeMX 进行 DMA 配置
+ t' \7 ~4 k6 S, h' p# z
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。

/ M- f' p" J" |
相关操作函数说明:
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 传输;
0 @5 V7 F- N: P3 j
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
/ p, t% X8 ~4 B! m; _9 I
核心代码:
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();
}

  W+ x8 j! h; H* }, Z% `7 a
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。

4 Y1 x$ D6 S8 y# c( }/ @
void ADC_DMA_Handle(void)
{
if(__HAL_DMA_GET_FLAG(&hdma_adc1,DMA_FLAG_TC1))//检查 DMA 传输完成标志
{
__HAL_DMA_CLEAR_FLAG(&hdma_adc1,DMA_FLAG_TC1);//清楚 DMA 传输完成标志
HAL_ADC_Stop_DMA(&hadc1);//停止 ADC
float ave_vol = 0;uint16_t all=0;
for(uint8_t i = 0;i<ADC_BUFFER_SIZE;i++)
{
all += ADC_Value;
}
all = all/ADC_BUFFER_SIZE;
ave_vol = 3.3f/4096*all;
printf("ave_vol is %1.2f V \r\n",ave_vol);
HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_Value,ADC_BUFFER_SIZE);//重启 ADC
}
}
以上为中断处理函数,需要添加到 DMA 中断中。当进入 DMA 传输完成中断之后,该函数先停止 ADC 采集,对上一轮 DMA 采集到的数据进行求均值,然后转换为相应的浮点电压发送到上位机,最后重启 ADC 转换。

, D+ t$ S; Y" s( O7 O* i
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}
7 E6 Q/ y' x2 S, ~; g" `- b
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。
" E! A3 r# g% L+ A
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
, l1 P2 e+ E& Y* b: p' e! x2 X: t
微信图片_20241122152613.png 3 m) D7 L4 E3 h# l, u7 [
( j  Z3 C! P$ Q
▲ 实验现象

! a& E' j1 Z% J, }( j& h
4、内部温度采集实验
' H4 p6 |# S  J
CubeMX 配置如下,保存后生成对应的配置代码:

0 e- c- g+ Z6 [# i, c% F6 Q8 x
微信图片_20241122152616.png 6 C" |, r& R6 I0 [3 f
/ c4 j7 g# V! }4 U
▲ CubeMX 进行温度传感器 ADC 配置

. ~( w$ D4 Z9 O$ e/ w
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。

$ s* Q% v7 o9 N* W5 l1 J. M
相关操作函数说明:
__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);//转换温度

+ u" U4 ]( j. H, o' J* P9 \" c
核心代码:
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);
}
. k' x9 P6 J4 V+ D8 K4 s5 E
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。
, `$ U- F- V3 m# X# ^
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。
) G7 a* \5 w% g  \7 R; _6 @. d
微信图片_20241122152619.png # ?. X& w# b2 H6 z4 A. j, q& w( s2 l. p
▲ 实验现象
; w& [0 X" v& A' k$ o
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:

6 b( S; @+ A9 x$ R+ ]% _
微信图片_20241122152621.png
9 D% f( n+ G% P

9 n# E4 A+ f6 A4 j9 k& p
▲ CubeMX 进行 ADC 配置
0 ~1 M- N: e5 |/ V+ O
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。
3 Q% c. v5 X2 D9 b9 O
核心代码:
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);
}
) }8 J% G# u6 d4 E0 `5 b
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。
( X* m8 [9 v  @
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
7 U3 ?) T5 K1 ^2 v
微信图片_20241122152624.png
▲ 实验现象
" p+ V) C3 s; Y" |% q3 b. q
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png
) `+ p3 r& w: K, f/ b5 S: f1 i

9 h. p" Z1 i, W
▲ CubeMX 进行温度传感器 ADC 配置

. T. N: k5 P& A5 I3 }; X
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。

7 r7 J: ]. Y) l  }9 C- a# i) J
相关操作函数说明:
__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+

# ^/ {6 p6 v5 D* q
核心代码:
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);
}
0 ~, \2 _7 i' C
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。
2 |1 c8 F& x  q. H0 T0 A
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。

2 e* H1 x, u/ r( \
微信图片_20241122152630.png 8 A1 p: W6 s8 v; A0 d' ^* d( e
$ X" R" e7 x  j" O0 K8 V( I
▲ 实验现象
7 q2 U( x* S+ S+ J. e- g9 ]
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png ; O8 Z! S8 s6 g1 q* v- l

; u+ K1 I% W3 C! |
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png
; b! ?: u1 \3 q9 G# D' S5 X* F
5 g; p& A5 s3 L' ^
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png * k0 F" S0 \5 W# n4 W! z
' H# N4 f4 H+ G% E. y) L
▲ CubeMX 进行中断配置
) q( z! m7 V2 s  m9 Q) U% v1 y
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。

8 {# Z7 L0 g/ _8 Z" \4 O& z
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据
  F7 z0 v' B0 A) _; {: M8 l6 s0 G$ \
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
) |& P$ X* P. a& R6 u, b9 v
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1

1 T  D  V; I) i, @% ]! p) w0 l
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。
/ Y) b1 t% s' c2 L- M9 a
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 V; V" F! a+ ~- j4 ?
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。

: o* M% Y! R8 `6 ]( {' i" `
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png
9 r8 b" D5 L- g. {

2 d/ O" G1 y" i: i$ J4 W
▲ 实验现象
九、DAC实验
& P! q% T( N& a* l5 s3 U2 o8 i& G
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。

4 M4 R7 G+ d; x) d8 l# j8 x# @
1、DAC 软件触发输出实验
& G. j. F. C+ B/ K+ [- T) |* |
CubeMX 配置如下,保存后生成对应的配置代码:

5 J2 ?3 R+ d1 x9 g  w
微信图片_20241122152645.png
- _' L0 d6 v5 H: |7 k: O

5 |. [  u2 ^; e) B8 u- u2 [
▲ CubeMX 进行 DAC 输出配置
% g) q- O) H8 E# }" K$ v- z2 t9 F9 Y+ ]
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。
5 W( F; N4 ]) O4 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 输出,如果想要修改生效,还需要使用下面的函数

' t% t% O4 r) u5 ?
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);// 改变输出值
+ K; W& K! f5 P7 q
9 g& Q$ m+ Z2 _7 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;

, d8 S8 t. E- z2 Q- U5 h! m, u
核心代码:
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);// 延时一毫秒
}
}

. w: A* V+ Z" ^& X; r( Z: A# u
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。

- x! d: Y' b9 d8 u
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。

) g% j5 B# c7 Y
微信图片_20241122165909.png
, [# o' t! {  z( h  E

/ |& G2 u; N) B: p5 `7 M
▲ 实验现象
0 ]: |7 P/ y" T* Z7 I' P
2、定时器触发 DMA 传输 DAC 输出实验

0 P4 g5 `# p5 e* g) x* w4 Y
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png 9 y( Q  \4 ~" ~3 r3 m

( o+ H) p. X( Y
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png 6 k' y3 {5 G3 b& C: i; H
" {: Z6 l2 A1 N& z6 D% }
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png
. I, C. I. Q& H6 j  Q3 _8 I/ |

1 Y# F/ b! ~- Y+ O8 i
▲ CubeMX 进行 TIM4 配置

2 y* i5 f# A3 D
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。
2 t9 _7 ?" r, |: f8 k/ Y
相关操作函数说明:
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 方式设置输出值

6 o/ a( v+ b6 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
3 y2 }- D2 y. p6 \% b" T' b6 x3 N
以上为正弦表定义。
: A7 C1 ^) T2 L
if (HAL_TIM_Base_Start(&htim4) != HAL_OK)//开启定时器 4
{
Error_Handler();
}
if (HAL_DAC_Start_DMA(&hdac1, DAC_CHANNEL_1,(uint32_t
*)dac_wave1,SAWTOOTH_NB_STEPS,DAC_ALIGN_12B_R) != HAL_OK) //开始 DMA 传输
{
Error_Handler();
}
4 `' ]0 Z  W& K' Y  E
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。
  X: p3 C3 s: S
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png
1 y; y  l' O6 s4 Z7 z/ E( Q
2 D% M* ~7 d5 |# g  I
▲ 实验现象

6 v4 m/ e- W1 T/ o" C5 I. l# M
3、定时器触发 DAC 输出噪声实验
. r7 k0 _0 H  V* S, J4 U
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png 7 M7 V$ V2 s. h9 Q0 ?7 x& ^+ i3 _
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png
# o( p1 Z2 }, k. p( R

7 J3 a" D' o* v* v/ L( o
▲ CubeMX 进行 TIM2 配置
# a' t3 e) g5 H+ G4 u5 L5 m; ]2 R
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。

, U/ M- f5 Q- z: a$ q
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC
# y' G2 y3 s' B2 }; ^( }- g
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。

) J% G8 W# ~* R# |) R8 ?
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png
2 m/ x' W# ?  V( U2 K  M9 n
▲ 实验现象

3 S( a: j2 Q5 o& ]6 @' ~
如有侵权请联系删除

: D, e+ \- V6 d( }+ v
转载自:AI电堂1 k( x, f. [+ d1 ^

' T" [5 ]$ j9 i7 f
赞 收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版