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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验
  Y: |- `* {" [, q; r0 r实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。
" h- s  x4 I! e* ^3 l: v9 y

3 ?* B" G$ @( I* c. l1 h1、软件模拟 SPI 驱动 TFT 实验0 y, i- I, a. F
CubeMX 配置如下,保存后生成对应的配置代码:' L" o2 T% t# P. q, U4 e( M" H9 x2 N
13.png
6 u% t4 O' ~& |8 j2 j5 N6 |$ U

: A/ z& L5 Y4 }
▲ CubeMX 配置

8 i" y9 ^8 B( J2 j1 ]
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。' D4 s0 h4 B) x8 d- t) F
6 J; t6 K$ a  Z# s3 G
相关操作函数说明:
0 h# P/ S& E6 I, r' Qvoid Lcd_Reset(void)
& M& l  V# m8 x, _' M. u* o
) P$ {6 o5 X8 j' v8 V/ }, Q: U
功能:液晶硬复位函数;
: f) w- A$ U9 ~5 X' [参数:无;
# P8 v0 u0 V2 I5 g* g; E" O返回:无;
1 v/ c. N( w! ~$ n& z; R% P+ s说明:液晶初始化前需执行一次复位操作
& v+ l# K1 r; Gvoid LCD_Initial(void)' U7 Q6 r# h  E% D$ p$ e
功能:初始化液晶;
( w8 u7 @' d! R8 t% u- k( ^* Q参数:无;
" T5 N* Z! ~% [$ a% T" M! E返回:无;% N5 o# \8 o7 p$ [! t
说明:在对液晶写入内容前需要进行初始化配置;
, L' K8 U+ `0 j+ Avoid Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
1 Y  x/ q: S6 Z
3 @" x/ U0 ]# m& T) K  p/ M
功能:Lcd 矩形填充函数;
% b  E1 K6 `3 f( L8 w参数 1:x 方向的起始点;
5 F# C* e, [9 r* f0 I参数 2:y 方向的起始点;, h! X5 R, ]: \  b8 Y' |
参数 3:x 方向的长度;8 I# ]$ h; G5 z4 b/ h- J  Q: h4 A
参数 4:y 方向的长度;" t# \0 J8 F1 `3 y" l2 x
参数 5:填充的颜色;9 y! \# j, t9 S2 i
返回:无;& W0 F4 r- ]+ [1 n- ~
说明:将指定区域内填充指定颜色,常用于清屏
4 S* u7 s9 I% P3 n9 s7 V: |, Svoid BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend)0 P# @' K1 B3 q, A0 I0 F9 L- d, j
, D9 D5 ?% n# j; _
功能:在一个指定位置开一个矩形框;8 d; e, U5 }7 m
参数 1:x 方向的起始点;
+ d7 |0 Z+ a4 e. H参数 2:x 方向的终点;
8 d+ J# s6 Y* P7 M( _- B! n参数 3:y 方向的起始点;; J" _8 g7 d; [) [3 k7 t' K% ~
参数 4:y 方向的终点;' L+ e8 {6 w9 [& }% }3 M
返回:无;
- E# O$ s: S  y8 Z6 G; L说明:开一个矩形框,方便接下来往这个框填充数据;
  L' J9 W* e( F* ^( {& pvoid DrawPixel(unsigned int x, unsigned int y, int Color): n9 G! t1 C5 L+ n
功能:在 x,y 坐标上打一个颜色为 Color 的点;  u' M1 P8 s3 P- b! ^
参数 1:x 坐标;1 H' ?' Q! t. A4 }7 J. w
参数 2:y 坐标;
* K  ]+ C% c- ]+ k) l' B参数 3:点的颜色;9 {$ F& P; B+ o8 ^6 z' y
返回:无;
% |' v6 ]5 Y5 ?) g* X; t1 _void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)3 B, `7 B2 e) C) q

) `. N+ N- w* {* L. G" V( i& [0 w功能:显示一个字符串;/ f) Z  W5 X; v  k. F  K/ q
参数 1:起始点 x 坐标;
7 t5 ?9 [1 \, ~7 Y7 [1 w( ~6 ?参数 2:起始点 y 坐标;
& _$ b3 u: N  r4 C6 @$ f+ E* e  ~参数 3:字符串指针;' k" i, F9 e: X/ Y  P  U
参数 4:前景色;" c. h: w! W  ^  y# V
参数 5:背景色;
7 I" i; O2 t0 d5 A0 W. V参数 6:有无背景色;
( I& e- M2 O+ W返回:无' A( T" ~9 B7 a' Q

% s. }9 R5 F/ i
; |5 u; u, B3 `+ _# S  U) m% t" S
核心代码:
" u& R# d  o+ C- o+ aLCD_Initial();% p, |& \- D# T0 G; p# R0 o% _
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏7 _: w' E$ \7 w( m7 ]; a# T; m
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
$ P- c+ y9 n, y7 c% T6 LLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏7 }8 S0 q( V& ^, E% y) Z
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏3 j% [- K+ o" s7 h; j' m
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
% n! e& d, s' C8 L4 X" e" f/ I+ _6 c5 {7 e+ o+ K: U! {
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。" m- k1 t, E$ W3 O; l7 s7 b

. {( _! g+ h* V: X* [! a. K- P

1 o/ i! }3 B0 ]& w' V5 _实验现象:& j' e7 e1 q3 j; x  Z4 z+ K" ^
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
8 ?3 m5 ]3 T! ^
) x% O1 y  `5 M& n

0 N" G3 `) i7 w1 Q7 l4 a( ^( I2、硬件 SPI 驱动 TFT 实验
% h* g1 K1 U$ W' z, q# z  QCubeMX 配置如下,保存后生成对应的配置代码:2 `7 W$ x0 t( G  {- c: R
: O' u- ?  l! h, Y8 q0 s) q; W; [
12.png : T- `( L' o6 Q" G8 {% X; M# ^
& O5 @- M& m. @6 Y, v2 N
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png
: `. {8 v3 X' q  @

' n9 r+ v5 ^8 k. _/ f' X
▲ CubeMX 进行 IO 速度配置% y& A! Y7 j, B$ S" a& Y& i4 M5 |, s
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。
2 _1 h2 k) e  [1 ?% u! R' G* N; F
. M$ I1 J1 [0 \: s1 q# x7 Y
- o* G$ r' ^( Y/ s" c/ b0 }

( D* R; V( D' V1 ]" \8 q
相关操作函数说明:
& z8 j7 |! ^0 x* h. F! z
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
5 B3 X7 J/ H) Q. Z8 C2 ]
功能:通过硬件 SPI 发送一组数据;

7 l* {. Z1 h7 ^3 z! j  M# r8 m
参数 1:SPI 句柄,根据实际需要填写;

0 p/ H1 t: U# t5 a
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
) }' [7 r# |6 n4 s/ G
参数 3:发送数据长度,单位字节;

* G: f3 G( o4 P# C) M6 }
参数 4:发送超时时间,单位 ms;

! d: [+ {& P# D5 u2 |& U; O7 e
返回:操作结果,HAL_OK,HAL_ERROR;

% U4 L6 C7 I9 C/ ~! S& ~3 J9 ^
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据

5 t7 B! H. W5 C+ E  Z% C
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

4 N6 D0 x% y9 a0 i) _$ {
功能:通过硬件 SPI 接收一组数据;
8 E, W* p0 _' i; Y  V$ Y
参数 1:SPI 句柄,根据实际需要填写;
* P9 T& l/ }5 Z- N' U; t! U: R9 b: f
参数 2:要接收数据保存指针;

. s) B" {1 ~" Y
参数 3:接收数据长度,单位字节;
- Y7 |# K% i0 R+ q
参数 4:接收超时时间,单位 ms;
: y- q1 t1 I( `$ h2 H$ D
返回:操作结果,HAL_OK,HAL_ERROR;

& k0 V* p- Q% \2 ]& H
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
. Q7 a  C7 ^4 E( O  U
功能:通过硬件 SPI 交换一组数据;
4 S. r/ c  A, ]3 Q5 @4 @: L" l
参数 1:SPI 句柄,根据实际需要填写;

3 E  f5 F0 d2 u9 U8 z* ~, L
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
) h9 u# K/ n5 h3 A
参数 3:要接收数据的指针,接收数据数组的首地址;

! B+ r' u& L8 W' B7 n
参数 4:数据长度,单位字节;

( }' g1 m* x% G
参数 5:超时时间,单位 ms;

& s+ P( `# z" [/ T% g9 K
返回:操作结果,HAL_OK,HAL_ERROR;
* @# ^9 L. Y4 q0 G5 X) D; I
: c+ C% M3 }0 n8 M5 ?, F

' }: d& ]2 C' `* G  q
核心代码:
3 B2 e5 u/ [/ k& Q7 |& s
LCD_Initial();

, I6 A! |4 |% b& W; C: q& S
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
1 d4 p1 b7 L) n+ b
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏

/ q+ i5 O6 G0 }  V
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏

! @1 ]9 }4 \2 `/ r3 v
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏

( m- d" \: q! [! x
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
0 C5 N: l4 j( i, _% L8 Y

7 j3 l: F1 J3 d/ i1 L, u: J

( o! v) }' m7 @
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

3 t  [) \6 u0 D

9 v! d  i/ ?) |' }2 k
. S: Q% S' Y7 {, E# c
实验现象:
) J6 D1 z; Y) L8 P* U
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

! k4 T; {* x1 s, f6 F9 D5 W* U

4 [) z, _7 ?5 T& x" i
' N4 w$ Q) `, Q5 M
3、硬件 SPI 驱动 TFT 实验(DMA)
8 c2 ?. y' V2 P& Z0 B3 b7 T
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png

1 v' }6 S% t; y9 B( U" ~; H7 _
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。
4 Y% M$ J6 G9 ~
相关操作函数说明:
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)

; d; i; k( _# F! M  a. b
功能:通过硬件 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)
+ a. r9 o$ z! `0 [
功能:通过硬件 SPI 的 DMA 方式交换一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
参数 3:要接收数据的指针,接收数据数组的首地址;
参数 4:数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
注意:使用相应 DMA 时需要对该 DMA 请求进行配置;
2 N+ E% N- v, o2 m& ~) z6 n. P4 x
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}
: I5 d0 S; Y1 P+ V8 \
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。
  B" Z; D! s5 ]
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);
}

  j' |+ c4 T2 _
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。

2 I6 e8 _3 d$ @
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);//显示字符

. ?  a7 l7 Y# J, n6 k5 J: Q# U
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
( P) q2 A' u" s! b. _$ }6 R% N
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

+ F5 m, N  f1 u4 P4 R5 a0 E7 ~. Y0 U$ t8 S, ~# g- s$ |% ?! M; d
七、IIC实验

- t) S6 v0 ]; p0 Q
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。

1 m) S+ d# ~* s/ w
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:
' ^0 Z6 x+ G: H: c; I
4.png / b' N0 e1 |' {

+ D7 j3 V4 o9 e& l3 t
▲ CubeMX 进行软件 IIC 的 IO 配置

9 ~# B$ O5 I" |
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。

- d- {* l( |" x' g. d
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式

7 {" G5 Y  F# t4 j2 c5 q, \  p
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式

0 e4 ]4 P/ S  h% V5 e' U# R. P* {
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;
3 i) }) l& V3 Y" l: z& T2 B
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;
- _, C" e( X, L$ Z
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;

0 I% {8 O( U! w( u0 _
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;
: B! m# o& e- Q* p
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
数:无;
返回:无;
  a$ _$ T, y$ d+ G
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;
( Y- t4 n+ H+ X
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;

4 ]0 ^  Q& N4 Y$ i
核心代码:
//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();//停止信号
}

- z. E$ Y: s* ^; ?! n/ s
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。

/ e# O6 o5 K( Z& ~/ ~/ N8 P
I2CInit();
uint32_t i;

& E* v) _7 x- K4 M* O/ C5 k
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);
2 R7 I6 A; Q- q
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");

( T) j; [/ l0 C- t6 r
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");
}

( W4 X& @+ F/ z2 k) [% Y8 V; J
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
: k7 A9 x# k) l0 n/ E& a; a1 V7 o5 C
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
  [5 e( v4 J+ \  E. i
微信图片_20241122152540.png 4 u: h9 a4 P0 }& X5 k

7 W; Y: C% e% x' X1 f6 X8 Z
▲ 实验现象
& L# i  u+ Y1 Z6 z
9 n: J8 e2 h7 [: Z9 z3 ]2 x6 j: h
2、硬件 IIC 驱动 24C02 实验

3 f! g7 x, l. L2 X2 s2 ]
CubeMX 配置如下,保存后生成对应的配置代码:

. X) F6 H1 R/ L! I3 D9 }
微信图片_20241122152543.png , Z0 ]" Q' h+ v1 w- W5 g7 D- ~
7 N9 h# p# Z& `
▲ CubeMX 进行 IIC 配置

) L' w+ M+ _2 W: E
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。

' f4 v+ A& E; _2 k% 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;
0 J2 N, q4 y; \) _, w% f: K. ]# t
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;

& i' ]; [: \% E- R% q/ l  b
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 地址读取数据;

4 |( a1 `$ y6 q8 {3 z

  X. U$ v% A! s3 y% p8 G6 G* {$ _
核心代码:
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");
}
, M6 T. F- C, k. |4 A
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

& e' y3 g/ b6 \1 ~
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

( q: M& p: Z2 c0 Y5 Z5 f$ f
微信图片_20241122152546.png ( Z! O$ a& j) `" W- M# u
▲ 实验现象
& p& x& Q0 i6 g. V$ s
; m9 G% Y5 J# e: w( X1 A
七、ADC实验
9 m% C2 |5 ]# p: O5 v
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。
; f9 X! |8 l* @4 B7 l2 z+ N
1、ADC 查询方式单路采集实验

, e, U5 i* D( J. g- n- X4 }# }# I
CubeMX 配置如下,保存后生成对应的配置代码:
1 u' L1 ~" {3 b, |. Z
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置
/ @+ m* _0 G. ^1 N7 p% \
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。
. X2 K  l" s% m  N' K  P
相关操作函数说明:
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 进行单端采样模式下的校准;
' [. u% H: v5 Z
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换
- f6 Q- I  m, b' \
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
" X: F' o* s7 Q( \3 S- 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); //等待转换完成

* d0 ?9 x4 E, W  N" }7 [3 n
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
, \8 M5 j! g: E- t6 X
核心代码:
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);
}
3 q: d% H( e  f* C0 c$ O' d, C
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。
. d% m5 _! T, N
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
; ^, J' I4 H' a! G/ p  U
微信图片_20241122152553.png
$ t& A8 O& v& r% T# e6 E/ v
% l3 X* m2 E. i
▲ 实验现象

4 W, m0 k0 H: R  X

- b0 W7 m5 a6 c& A. E
2、ADC 中断方式单路采集实验

# C( [/ R# C- y5 x
CubeMX 配置如下,保存后生成对应的配置代码:

, s# Y5 p* M) }2 h
微信图片_20241122152556.png
▲ CubeMX 进行中断配置

3 W/ ]$ @1 f* {& K* ~$ u
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。
8 ]6 r. l; X1 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 转换完成之后会触发中断,中断中读取采样数据
0 D8 W3 J! B# s' ~: {
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
6 }: ]. [5 a4 \
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}
8 ]" j( u0 U1 W$ m
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。

6 o) t# [' P' S" ?
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); //通过串口发送
}
}
' V! u' q! g  t/ {9 Y6 |3 E  P
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。

( r4 Z) e* k5 S" r, Z
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6 C0 L( `2 `0 Y' V
微信图片_20241122152600.png
7 z& \9 S  X0 p; X+ I
6 K# ?* U8 X) y3 K7 O; V# b
▲ 实验现象
# T" g) V) H4 p9 a7 {1 s! n
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
5 Z' N6 F$ T2 S
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置
" f1 ~: @2 w/ t1 h, O0 t' f2 ~
微信图片_20241122152610.png 3 p+ w. ^& h3 N8 O& |' T0 q; e' X# \
▲ CubeMX 进行 DMA 配置

: z; F, \- }! n! {% Q2 d
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。
& E8 l8 N1 h# f+ f3 k# v
相关操作函数说明:
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 传输;
( s9 Z# L# w( b7 n) H; H; ~
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

5 T/ w9 Z! r8 s. N0 f
核心代码:
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();
}
2 q" Z4 Z  q% m
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。

3 ^" \( A+ l' A$ F
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 转换。
  S9 w8 h( b9 |, i3 a1 g
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}
( O& S$ L1 G7 I2 E
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。

# f& y2 W: d6 w* U* Y' k0 R
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

! V( v. {  g7 S% P' d
微信图片_20241122152613.png " u' ]! n/ R) E
6 d* T% H& a: |* y
▲ 实验现象
0 p: F2 C" c2 D: L. }
4、内部温度采集实验
2 a' m8 @, N& x5 N. S; @
CubeMX 配置如下,保存后生成对应的配置代码:

- i1 e3 h* ]7 T% N/ b
微信图片_20241122152616.png & b0 u; E1 ^. t2 I  _" g
  C/ F( }/ Y2 D$ Z3 X- X: l! D8 l
▲ CubeMX 进行温度传感器 ADC 配置
: |% e2 n% t- K
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。
0 G( `0 S1 y' O" n; Q' ]1 g
相关操作函数说明:
__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);//转换温度
0 V. `0 b  G+ u9 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);
}

3 V/ E9 ?) @  j6 k6 W3 h
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。
$ n& ?9 l- H$ q* ?" F
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。

( B: P9 n7 ~$ c% {) ^
微信图片_20241122152619.png ( i$ T: q/ a! o" g. f
▲ 实验现象
8 \* e. m6 c) W# n
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:

) g* @" G( x/ B7 |. Q
微信图片_20241122152621.png . z2 T! w3 n" ~# {7 a3 ^" Y+ I

! J8 R& M) ^& g8 U% F
▲ CubeMX 进行 ADC 配置

$ s( E1 O  e  }" }7 d) d1 k7 k
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。
& H% J9 _( ?6 q8 z5 R
核心代码:
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 p: e- f# I) M
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。

! U. }, d9 @# ]% S8 T/ \9 C
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
5 V3 u( s! m0 Z+ Z. w: Z2 E
微信图片_20241122152624.png
▲ 实验现象
8 X5 e2 B4 f9 N  w1 d( y' |
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png ) L- y/ i# z' S* ~3 ~  O

) o9 O8 y* E7 f4 B( @) Q) D
▲ CubeMX 进行温度传感器 ADC 配置

2 g/ H1 i0 [6 t7 N. L1 o
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。
- B' s' y1 `* s3 c/ O' W1 a: ?  |
相关操作函数说明:
__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+
5 M6 g2 ?. Q( P5 q: 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 值
VREF_MV =
__HAL_ADC_CALC_VREFANALOG_VOLTAGE(ADC_Value,ADC_RESOLUTION_12B);//转换 VREF+
printf("VREF+: %d mV \r\n", VREF_MV); //通过串口发送
HAL_Delay(500);
}

9 }+ C( q, y( j, T% \6 c; S( U7 [
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。

. V; d5 y1 c: f& L5 }
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。

) k( q9 p/ v5 R# ~/ `
微信图片_20241122152630.png
) h+ Z; r( J* Q' c) ^& M

. ~" O- F9 g! S' n- i2 y9 a
▲ 实验现象

! W$ |( E4 `) f- a, C4 A! b: o
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png * ?9 F8 ^) p* U7 }, [, c  z
: S' s, m/ i1 i. w4 d1 W
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png
& _" a8 q& m" o* E
" l  B/ V" H- x. w& J2 b; g2 _" B
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png
) L8 ?" G6 q6 ]

4 g2 H8 K; q) ]! ?8 ?. T" U/ ^# Y! K
▲ CubeMX 进行中断配置

4 J, l' Q. |2 j4 N3 j5 X
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。

: {, u- f: ]4 g! f  c, o
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据

' C! v8 b7 ]! s$ T4 p+ o
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
- g1 Z! F) ?9 c2 c
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1
& ~* p3 ?9 H, }2 d: X0 ~2 w
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。
+ U% C- O7 H: ~
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); //通过串口发送
}
}

# r1 U' z0 ~# l' F* G9 E
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
, n& u6 d$ j' l5 Y! V0 k; `5 @- _
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png / f/ m- _& G/ G, v& a) {0 `

. j3 n& a  v6 x# `6 l8 o& H2 q
▲ 实验现象
九、DAC实验

9 p+ }7 A$ Z6 b; z( e" B' w0 v, H
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。
! s- k5 Q" [3 d* b& a. @9 k
1、DAC 软件触发输出实验
! P$ n; [5 K( v
CubeMX 配置如下,保存后生成对应的配置代码:
( `) _3 h) v6 T0 |) L' }
微信图片_20241122152645.png
8 R/ g$ y, R; e  _# {/ P: h0 {  X

; |* h5 N# E" R: k  ?  j# C* k
▲ CubeMX 进行 DAC 输出配置
% k3 y( ]6 d( ?8 X7 x8 x
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。
; Y: e0 Z/ J- D& d, |3 C. |: O
相关操作函数说明:
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 输出,如果想要修改生效,还需要使用下面的函数
2 f; H& l6 s8 Y3 a5 R
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);// 改变输出值; n1 D7 Y/ P( L$ h& ?8 r: p) {) d

: k- z1 F/ c3 _. q' o! ^* @$ B8 ]
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;

( p4 E, `8 ?- A- ^
核心代码:
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);// 延时一毫秒
}
}

$ ]- ^% x! ^: b0 k8 o/ {, h
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。

  J" d+ O9 S! x" ]
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。

( n1 N4 Y# A; i/ N' v: n  T
微信图片_20241122165909.png
4 r% {$ u/ [8 y8 l( M" K7 ^

. `' Q) {5 ^; [" n; e$ W
▲ 实验现象

+ S9 ?* u4 x1 {, `/ o+ K
2、定时器触发 DMA 传输 DAC 输出实验
$ K  R, D& C2 x, g, _
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png
* ~! y/ Z, o9 _2 ~8 X

; m  i8 x0 W# j( T; z- D
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png
5 j# l- B& H& i) ^. Z

' p2 b% e2 P3 W# {% {1 y
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png
7 }" x2 G* N5 u1 Z

; L1 K$ u, e! R2 h" N/ }' W9 a: J9 n
▲ CubeMX 进行 TIM4 配置
$ R2 ~$ Q! |" t! w
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。
, T. z' o: ?! x2 u; ^3 D/ 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 方式设置输出值
( e2 W9 P0 E, m9 q: [# Z! |2 U" h) {& {
核心代码:
//正弦表
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
- J$ |+ t5 G2 c8 v/ t
以上为正弦表定义。
5 o3 n# q8 V! U
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();
}
! s: k' e8 u5 N7 d  n" p
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。
% z0 Y: ?9 d2 Z- W/ N& f3 M
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png
4 F2 l2 V# C% R/ q* x
5 V$ X4 G, Q- s% K) N2 O* U: B
▲ 实验现象
4 d% M% B: M4 Q5 ^! k
3、定时器触发 DAC 输出噪声实验

4 n8 h; s8 }5 F8 f
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png
) _) r9 q! s, L9 l; g
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png
$ w8 i3 m. y# ^! ]( l2 K3 d* \

) ~9 o& |$ v5 k0 l3 r
▲ CubeMX 进行 TIM2 配置
& {7 K/ v* `) M% o+ b: Y/ I
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。
$ v& C% y( h$ H' B& j
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC
* a. N4 z+ Y7 }
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。
3 }% E( ~) q6 R( O/ e) c9 o
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png
* ~# U6 k- B" N4 H
▲ 实验现象

5 |+ @8 X" l& Y
如有侵权请联系删除

, c- ~5 C& k! H4 l. ~- ^) k
转载自:AI电堂
1 [, c8 b% A; e" T
( u* L) P$ p! u. w5 ^/ G: f
收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似分享

官网相关资源

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