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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验
3 `/ ~) C# C+ X% K$ t实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。+ M$ W' X9 N+ o1 }9 O) k

( C8 v8 R# u+ v$ n4 I& L4 V1、软件模拟 SPI 驱动 TFT 实验
* ~+ m! t! g5 `4 s: X' `CubeMX 配置如下,保存后生成对应的配置代码:
! [. L0 H% a# W8 d
13.png
% ~+ W- ^  x9 `3 B6 x" m$ `

- W7 A6 t% g: |
▲ CubeMX 配置
0 l/ ^; x9 g7 P9 z1 y
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。1 T9 J% E% e) j+ Q* g
0 q2 ]7 l: g* R
相关操作函数说明:9 F, N* |2 H" Z
void Lcd_Reset(void)
: j$ Q. V2 X' S* f

: T3 g+ W( G6 ^$ n+ @功能:液晶硬复位函数;- u8 `, t+ h- P! F& x; D7 N
参数:无;
2 S9 J7 w2 A/ @返回:无;
6 ^( s. I1 I0 V( J, r说明:液晶初始化前需执行一次复位操作
8 x5 v# m# p& ?4 F( Y+ u) K6 B$ Svoid LCD_Initial(void)8 j- H; q4 q1 n0 \7 y
功能:初始化液晶;
- p; l3 o/ O1 T; v, b5 L参数:无;5 R  C0 e  y& P9 E
返回:无;
( o3 R, H4 o# T5 ^$ R2 \说明:在对液晶写入内容前需要进行初始化配置;
9 l- z/ f3 J  d! P  n5 S! e8 _6 \: cvoid Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
( J2 ]; U6 y/ t. v5 @* f5 E
- @, A+ e4 Y# e
功能:Lcd 矩形填充函数;- J) K  j1 @- l4 e# q! Q
参数 1:x 方向的起始点;5 f  x# a" W7 t/ n6 O' R
参数 2:y 方向的起始点;
; `" F9 \% e' a参数 3:x 方向的长度;
' h$ o! [- ^9 D2 B7 r" C参数 4:y 方向的长度;% m0 w( Z/ Q! n4 H1 ]
参数 5:填充的颜色;0 ~: x5 P0 P% j+ i8 f
返回:无;
: k7 ]2 y. ?6 {7 a4 j说明:将指定区域内填充指定颜色,常用于清屏; z7 \% Y9 S' j! z
void BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend)
) X+ w" _# E7 r5 x( W+ H+ h1 Z) D; {; m) c6 E, W8 g
功能:在一个指定位置开一个矩形框;% Z; t/ K* @3 Q$ M$ w5 X) ?6 h- P
参数 1:x 方向的起始点;! E: |" t; ~" L1 @- |, Z
参数 2:x 方向的终点;
( N* b" |/ e) i( s. s$ k3 x6 C; r参数 3:y 方向的起始点;8 V/ e1 e3 \: N" `* ^$ B' e
参数 4:y 方向的终点;! n- h( ~! b# b$ m
返回:无;
0 \; W/ j6 x/ y说明:开一个矩形框,方便接下来往这个框填充数据;
) `7 _9 o( e; L! v% M. d4 f) wvoid DrawPixel(unsigned int x, unsigned int y, int Color), s2 ^! Y' S. ?% I6 K5 J  h
功能:在 x,y 坐标上打一个颜色为 Color 的点;( N  }4 K/ Z3 {7 c3 t$ I9 c
参数 1:x 坐标;
: c1 ^+ q5 f/ F1 d1 b# C参数 2:y 坐标;( h9 {# e+ y% ^, J. A8 }) K. G
参数 3:点的颜色;# ~6 V9 F" i+ Y9 p) a+ Q
返回:无;
$ w: R# O. V: x4 Q+ O( v/ |void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)
% M; }* I# a) Z, V* S3 p* q% p  {6 t* P& [+ x
功能:显示一个字符串;
/ w' h2 |) h3 b: p: `参数 1:起始点 x 坐标;- j' r1 M7 E) m- c
参数 2:起始点 y 坐标;% F  f- m: H& [" `7 @
参数 3:字符串指针;
% Z/ r: V. t8 N4 e# z  w参数 4:前景色;* X. l! D+ b) _7 r" D  [, O
参数 5:背景色;# q" p; M1 s- M: P6 e5 c
参数 6:有无背景色;5 D( ?1 D: ?6 `* c2 K8 F! {
返回:无9 n" [* u$ _, A4 _' B7 p- `

6 k: K/ C6 r  b5 x# N. R$ h" {

8 C" O4 S/ D1 m, `核心代码:: `2 d% H2 d* N! V8 N
LCD_Initial();: u  W4 ~0 ^: `* ?# _' Z, `
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
5 p0 X) {7 S, I' jLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏+ ~* p3 {- y7 G0 X( f: G
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏" [# n  q1 L) R. ], g! c
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏
( M$ h6 \$ O. Y8 E' l, b) R( `' ]LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
# E4 o# B. I/ o- i: j% P+ ^$ k7 S5 u+ V, W% l' W
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
$ [' n0 t! E9 m8 t7 ?$ L' D, b/ P3 q

! k8 o, F  ~5 I% h8 b, K1 U7 [实验现象:1 |7 j4 N7 ^/ E% e9 Y9 j0 n
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。, p0 e9 K0 V6 U( i  T6 Z' h

2 y' x+ ?0 k( y! H- R4 W

0 h/ f( A- i  U; {( h) e/ w1 N2、硬件 SPI 驱动 TFT 实验
& j( m3 c1 w$ J' XCubeMX 配置如下,保存后生成对应的配置代码:
6 h( N2 L, v: W+ o: V( V3 [
7 N8 E# C. R# e, W4 m% ~3 F3 l
12.png 8 ]8 c* w) Q) s1 X# [! Q
8 Z2 V+ r. K; h: V
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png   P' U" }0 A( v
( g9 b5 t7 H; `7 F; \. d
▲ CubeMX 进行 IO 速度配置6 M: m( Y# Y! y- R* l
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。
: F6 J) ]5 r) y1 ?! Q5 |6 J

- O  X/ C) h6 R  a. \2 U& h, d

; ?, K( |! e, ^
9 v5 s/ z$ g3 U' M+ a
相关操作函数说明:
; _. a& l1 Q2 D+ r$ ]# j
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
5 A* U$ s! [0 ?% h. v% c
功能:通过硬件 SPI 发送一组数据;

# i5 m- y2 i7 z
参数 1:SPI 句柄,根据实际需要填写;

. k; j3 k* W$ `; X7 r% }# w2 B/ }9 R
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

4 y, P4 `0 W# g  W% p6 ?$ q0 }
参数 3:发送数据长度,单位字节;
, B$ G. f4 |& q  W4 P
参数 4:发送超时时间,单位 ms;

" j+ [% O7 I& b1 W+ ?
返回:操作结果,HAL_OK,HAL_ERROR;

- N1 ^+ B6 |( e! n: u) f  ^
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据
+ w. X( A/ M6 D3 F' w4 P7 R
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
) ~: K% u$ P/ \7 G5 I' Q2 Y& M$ g
功能:通过硬件 SPI 接收一组数据;

5 \8 C0 |. S( E( e/ r& K, G0 M
参数 1:SPI 句柄,根据实际需要填写;
& v* h' q( M  h& ?
参数 2:要接收数据保存指针;

! p. [% o- ?% X+ N* a% |" R' X' I
参数 3:接收数据长度,单位字节;
2 ~' O1 Y9 J" k- \, w' f2 T
参数 4:接收超时时间,单位 ms;

' {% a9 K! u- U; B0 Z  l
返回:操作结果,HAL_OK,HAL_ERROR;

1 `" x, V' U2 {2 D( a
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)
1 ?$ s' L  u0 }5 ~
功能:通过硬件 SPI 交换一组数据;
. s" y4 n$ O- `( l, c$ m  [: w
参数 1:SPI 句柄,根据实际需要填写;

+ P. z0 R' u' |: ?6 h
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

8 R; D4 T/ R8 q& x8 C. C! g
参数 3:要接收数据的指针,接收数据数组的首地址;

3 p# N- e) e; ]3 t/ D
参数 4:数据长度,单位字节;

/ y6 O* Z6 X( \5 x5 b0 E. Z+ y% k
参数 5:超时时间,单位 ms;

* Z  B1 p! X0 e# q5 U& h' @
返回:操作结果,HAL_OK,HAL_ERROR;
) E4 \6 |: d- N8 V& i& y  b$ G, l

& f4 T. X5 }: N3 j3 h

5 z. _9 R+ c: y* Y3 {  g
核心代码:
# ?6 q1 T( K; ~" D$ }) |
LCD_Initial();
& R( H2 t  ]$ d% N* c6 {
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏

# m4 a3 W9 i5 u4 w  ]9 ]2 ?/ k7 H3 L% O
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏

! l  U8 `/ x0 d: {& Q5 k
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏

% \6 g' }0 c0 {
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏

- j1 m; c1 g" c9 [
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符
! N6 j! P9 }# A

  i, q( u9 |( ^7 b/ b7 |! g
. c& I9 X( ~0 R) ~6 o5 h4 @
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。

! v) c% @2 x' y* R. u0 _/ O+ {" E
' P) k. f& z: U* S& r

+ z, r) B- N4 g2 q
实验现象:

- D# w4 B' ~7 ]$ Y
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

+ _0 f7 v  {' C, p

; j  K5 ?, v; v9 j" K  g# ]
0 b6 [$ T3 g9 }$ w7 U
3、硬件 SPI 驱动 TFT 实验(DMA)
( n4 \5 F: f& |, f
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png

8 {' o6 `- A3 ]  T
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。
1 p1 E# d. p- ]0 S/ F) L' T
相关操作函数说明:
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)

: \& h& h) ?2 ^) ?
功能:通过硬件 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)

7 m. I- F& n" j6 }1 f
功能:通过硬件 SPI 的 DMA 方式交换一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
参数 3:要接收数据的指针,接收数据数组的首地址;
参数 4:数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
注意:使用相应 DMA 时需要对该 DMA 请求进行配置;
* t+ l# h( x8 C  N$ J0 R# x1 y% p
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}
1 p, ?$ N6 K4 P8 d& X* c
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。
& {7 h! N8 o6 \( z2 v7 o/ 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);
}

% Y" F8 A- k/ `& X
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。

, G( f' S5 U. G
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);//显示字符
+ b! M7 U5 t) q/ ~
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
1 P9 A; L9 f7 O) A0 ?3 `& u
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

: U5 j7 }1 F1 `6 g; ?
: B- k( \2 u6 x0 g. _, n
七、IIC实验
$ i2 _( V0 Q( K+ ^  q8 y  n4 @9 l
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。

4 u5 Z& j( ?' Q2 @3 ~0 h5 b
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:

- Z3 z  ~5 |  A- f7 o
4.png
  R0 v; w: W  ?9 w

, W, W3 h, S7 v5 m. c
▲ CubeMX 进行软件 IIC 的 IO 配置

8 l( L3 N4 M0 {
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。
8 g1 P' g+ U5 O% K7 ^
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式
$ ]$ X" A3 U1 m
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式

3 h$ h) A" u" U' I
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;
3 X! B! t7 N1 D
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;

9 o* K" b: T4 E5 B5 h5 Y
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;
0 k! p7 L1 C* w- P0 I8 [0 k
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;
! H. l) T+ H  u/ P9 v) p
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
数:无;
返回:无;
  T2 T0 `7 f6 [8 {3 ]& R
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;
; R, C+ Z7 p9 J9 O- q0 u6 |
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;

, _% b0 y( E3 S1 S
核心代码:
//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();//停止信号
}

* E/ r# z4 x5 b; q* l$ [
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。

; {, r4 \% D; r+ U3 `
I2CInit();
uint32_t i;
# Z% P4 z5 `+ a% K% l0 {
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);
7 T# z5 E6 R1 \. p4 x5 m& d: k
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");

/ ~4 A1 N  L. ?' ^& m
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");
}
" l$ i9 p0 ~: c( H
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。

& F( I5 Y  e3 S8 N
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
1 q6 D" l# b3 m4 ]. A
微信图片_20241122152540.png 8 }; Y/ T' q: Y5 d# H& u% M

3 ~7 a5 z6 f- G/ }) \$ E  x( f) M
▲ 实验现象

" G9 ]# H6 m% ~5 I

* Z0 y; a( f9 z1 @6 h
2、硬件 IIC 驱动 24C02 实验
2 D" m1 a5 v: n  B2 q; F1 L9 y8 z
CubeMX 配置如下,保存后生成对应的配置代码:
" l3 Y8 [. Y: K7 x1 h
微信图片_20241122152543.png 1 ~. E5 r* N- [' r# X

! n- E) X4 t1 J" H" q4 P
▲ CubeMX 进行 IIC 配置
3 T4 u2 }! C( [% `+ C5 Y! }* R
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。

' O& {  A* P6 P( q/ b
相关操作函数说明:
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;

; x2 f' S3 B4 r/ P
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;

. B1 X  l1 t" a5 r$ s6 t6 o& ~
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 地址读取数据;

$ y( g+ [7 N- p3 |
# V8 i: P& f! B! Y# f
核心代码:
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");
}

) ]2 Q2 @0 n7 q; e, j
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
5 O2 Y: k( n8 G4 q8 U
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。
" c9 ]3 {4 j: J. F' x+ C( _3 Q
微信图片_20241122152546.png
/ d$ U0 P% g6 e5 h
▲ 实验现象
- A. Q" I# c8 Z! e, {! v  x

9 [0 m1 y9 u) _5 e7 M. |
七、ADC实验

1 u7 ^, O0 ^% z, B! L- e  N& A
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。
6 o2 b8 o' u% L
1、ADC 查询方式单路采集实验
1 y# G! D8 e' L. O
CubeMX 配置如下,保存后生成对应的配置代码:
; m/ {* Y  _1 ^! i6 I* {7 p
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置
3 Q, U/ p( l* V
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。

$ y( S* E: g- [/ g6 V* p& K& b+ k
相关操作函数说明:
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 进行单端采样模式下的校准;
- M! t1 |, Y& ^" A+ l
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换
, E/ D$ J. L, T9 h9 D( n
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;

2 H# b+ C0 G$ T1 m( r5 S: C+ 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); //等待转换完成

& F+ `/ P5 j8 @/ K" p# J
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值

; o+ \! n  V$ F3 a
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正 ADC
while (1)
{
HAL_ADC_Start(&hadc1); //开启 ADC1 转换
HAL_ADC_PollForConversion(&hadc1, 10); //等待转换完成,第二个参数表示超时时间,单位ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
ADC_Vol = ADC_Value*3.3/4096;// 转换为电压
printf("ADC_Vol: %2.4f\r\n", ADC_Vol); //通过串口发送
HAL_Delay(50);
}
* L' y+ j) q2 U& T7 _3 I$ _$ A0 E
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。
9 `. M/ ^6 B1 o- B: e5 Q
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

0 _& d! x2 S( G) ^8 q2 W
微信图片_20241122152553.png & b& j9 M% |/ b. W. E) _3 k3 V

3 ]$ o9 j6 j% \4 c
▲ 实验现象

- @! a5 Q: V  n
; p+ J0 R5 c/ o! E3 E
2、ADC 中断方式单路采集实验
4 Z8 P: ^" H7 c( T7 U/ g. ]
CubeMX 配置如下,保存后生成对应的配置代码:

5 P! A1 e7 W. a8 A
微信图片_20241122152556.png
▲ CubeMX 进行中断配置
( y, d: q, U9 k
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。
: r, a4 b1 o* n7 q7 u  Z' V: q
相关操作函数说明:
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 f  U: U0 T& o' g* u$ U( r3 @0 L
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;
/ H4 o9 l% }, u& }+ J
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}

( G9 j1 M+ o. Y6 U
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。

8 k6 J1 z) T  J0 y: E2 W
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); //通过串口发送
}
}
% ^; c+ W0 J+ n9 o( X9 |) @: B5 L
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
! h& D% H2 ^  C1 n2 z) F
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
$ T' L; @2 t  q4 J) E  N/ r, B2 n
微信图片_20241122152600.png
' l1 Q6 c3 j. ~+ P

$ I) P4 Y. o" q& A
▲ 实验现象
1 f- @( r! K3 u2 V/ i
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
; H1 H) i3 k  \8 m4 ^* ]. d
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置

) n' `! {( w2 Z& a1 k3 E( `
微信图片_20241122152610.png
/ A% `5 {# Y. j4 y9 Z' Z7 h
▲ CubeMX 进行 DMA 配置

3 I, A. E6 J1 o$ {  T6 N
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。
2 Z  G- p' w5 }* P0 k- f# g0 Q$ B
相关操作函数说明:
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 传输;
8 v# U7 N& E2 y) K
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
8 R3 j1 x: g' f1 D5 M
核心代码:
if(HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED) != HAL_OK) //开始
ADC 校准
{
Error_Handler();
}
if(HAL_ADC_Start_DMA(&hadc1,(uint32_t *)ADC_Value,ADC_BUFFER_SIZE) !=HAL_OK) //开始 DMA 传输
{
Error_Handler();
}
/ o0 K4 g7 M0 l& `* M5 y
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。
$ f) H! \6 ?0 e
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 转换。

5 m; u9 E, e# P' y( b
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}

8 r$ F% G+ ?7 B
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。
0 F9 m/ R/ W6 H- t
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

  @6 |  P' p# G  n. E" _& C7 p# T
微信图片_20241122152613.png 5 v2 |. G4 A+ Z& n  T- d/ I7 r+ G
( T( x/ o1 L2 J) O- w2 S
▲ 实验现象
* ^  n' V9 G/ X7 |  A% G' g. D
4、内部温度采集实验

  y# B& K& l/ @7 q5 U$ I
CubeMX 配置如下,保存后生成对应的配置代码:
( m2 n/ d- s, y* M/ s  B
微信图片_20241122152616.png # A% m6 x  \, r5 h

( I% q8 v+ |$ z$ x% p& E9 e
▲ CubeMX 进行温度传感器 ADC 配置

3 i0 L" {6 F) \' E2 G
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。

; h* l7 ?$ {. A( M! E3 c- U
相关操作函数说明:
__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);//转换温度
+ c$ y' B2 P. M. G1 n  |/ S
核心代码:
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 q& q# Y6 j  o2 V: i
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。
' M! J) A1 m1 y8 P
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。
6 J# c7 }: l% {, J8 n$ c. ~
微信图片_20241122152619.png 8 |7 I! I$ u: J3 l' Z
▲ 实验现象
+ E+ v% T- k" r5 n7 |2 Z& n' N  z
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
, |, h" `8 k4 e& {# }
微信图片_20241122152621.png 2 b8 z( T) L, F2 @
& ?$ V8 ?, w/ a
▲ CubeMX 进行 ADC 配置

5 }! S' I. P. i8 T
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。

: b: L6 Y/ f/ m- 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 值
ADC_Vol = 3*ADC_Value*3.3f/4096;// 转换为电压
printf("VBAT: %2.4f V \r\n", ADC_Vol); //通过串口发送
HAL_Delay(500);
}

& _) m  ?" c6 N& r
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。
0 W" `$ j* m- Y% [9 K* _
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

& ?" V- E$ l6 A6 Y1 D) i6 l
微信图片_20241122152624.png
▲ 实验现象
$ X: {" J0 X2 X( F$ {
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png 3 c) Q0 D* q3 U5 O% P
8 d5 R1 t. _% u" o1 S1 k
▲ CubeMX 进行温度传感器 ADC 配置

* x( P. R' H' Y
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。
& e; C- s, @: [: q5 b/ M
相关操作函数说明:
__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+

  l( g" u6 H8 N1 s2 ^5 B
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10); //等待转换完成,第二个参数表示超时时间,单位 ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值
VREF_MV =
__HAL_ADC_CALC_VREFANALOG_VOLTAGE(ADC_Value,ADC_RESOLUTION_12B);//转换 VREF+
printf("VREF+: %d mV \r\n", VREF_MV); //通过串口发送
HAL_Delay(500);
}
# H: b+ X; J% b/ l# ], [
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。
4 G$ h4 E) x( V; ?0 m
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。

( F2 e" g6 f( Y( o4 L( F
微信图片_20241122152630.png % Y1 J9 E, n( g& P, }

# H3 T0 C* o: Q! P3 @- y
▲ 实验现象

! p. U, ?& u+ v+ e
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png 1 o% M$ j- K( K5 ~  K* @
4 H5 Z" r5 M0 q) u
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png
" Z8 h- L; N: ]8 l: ?. G2 r3 F( G
" `: N, q% ?- C
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png
4 M. [1 i  E/ ~0 O3 v

: m/ g% C/ M& R6 w/ ]  T
▲ CubeMX 进行中断配置
) _, A. y  R4 S5 j
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。

, A5 v1 E8 B8 m/ h8 I* |7 @) C
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据
6 F5 w7 U4 z* f3 }3 K! e2 S* M% o
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

& Y5 h0 g5 g5 A1 X
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1

! X$ \% T1 r( y* @
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。
% y5 g9 n$ l3 I7 D8 `: a! E5 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); //通过串口发送
}
}
6 Y. ]6 K6 F8 ?) d6 u4 w& u5 X
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
7 J3 C" a! p  |" L8 _
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png 4 T, ?$ x; Y* O

$ r% @5 N9 ]; w# m. z8 }
▲ 实验现象
九、DAC实验
5 r4 I8 f& l/ ]
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。

( B! f2 v& b  P1 S
1、DAC 软件触发输出实验

1 T1 z5 J5 j  O& Q8 K* J
CubeMX 配置如下,保存后生成对应的配置代码:

5 g8 b8 r7 j# ^/ K6 b
微信图片_20241122152645.png
% R# }. F- J0 S) K, U( D

7 p7 r- ^1 \1 Z' j! o# O, k  D
▲ CubeMX 进行 DAC 输出配置

( _1 U, i2 X3 f- f& R
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。
: r4 D! |4 @$ A
相关操作函数说明:
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 输出,如果想要修改生效,还需要使用下面的函数

, M$ _  n9 d% ~. D- S" m  _& x
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);// 改变输出值" {' N) I) k( w' v' F
- ?/ T5 h6 V5 W1 [
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;

/ |! P" H( `! m
核心代码:
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, H8 d2 _9 e9 e
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。
# @3 v) m3 e! U/ c/ N- O# R6 g
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。

2 ]1 E3 V, \' _1 }
微信图片_20241122165909.png 1 b" c* \3 o: E) M& ^  h

; \  q5 d+ g8 }, R& G$ }" s
▲ 实验现象
2 O& \/ q9 L1 |# l8 I- k
2、定时器触发 DMA 传输 DAC 输出实验

6 c, O* Z4 Z5 a* I
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png
/ C) k. {* K3 ~9 U* Y

/ `& U9 [1 r" r6 U( |9 q: b* B7 o
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png
, i; b/ n3 ^+ U. r" |2 @  u9 J9 W
% e/ x9 g# [. U
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png 3 K; I/ L8 s9 r
$ z4 ]' t" J7 S" k+ a& t
▲ CubeMX 进行 TIM4 配置
" P. a+ [: {# T, g
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。

$ X; ]1 R1 a( 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 方式设置输出值

) a0 H6 @6 h) y+ f
核心代码:
//正弦表
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
4 F1 W2 U& }6 m; q$ y- K/ J
以上为正弦表定义。
. R$ o- d9 @7 o' u9 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();
}
% @+ X$ x+ I9 ~7 M7 d: Q
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。

' k( K# R) `3 F, T: z$ J- S% o
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png
9 f8 Q7 t& f! H# F* ^

6 T1 p& ]# p8 r: @3 Q7 E! k. V
▲ 实验现象
4 m$ {' _% q5 p4 y; Z* t
3、定时器触发 DAC 输出噪声实验

$ m6 v" _+ N- ?% d
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png
' E4 G3 a" O0 [' w2 l7 _
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png
. O7 Z2 \# J) E: c% W' w% _9 K

. C' d# \5 a9 q3 U: J9 k
▲ CubeMX 进行 TIM2 配置

& v' O5 m( x/ C4 y- Q
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。
9 Q. E' H0 T' U5 P4 b; N
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC

& v0 S' A7 {% p1 t6 M) W
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。

! H2 X% t: R! E1 F7 n/ v; e. y
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png
) J, u/ {: T; j, E  i
▲ 实验现象
9 d+ a* S% ^6 @. ]
如有侵权请联系删除

0 s& P, ?* C* y/ p7 \6 y
转载自:AI电堂
' X& J: ]+ x+ v9 ?0 }. |
5 L/ w* G; m; ]+ w; ?
收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32Cube扩展软件包
意法半导体边缘AI套件
ST - 理想汽车豪华SUV案例
ST意法半导体智能家居案例
STM32 ARM Cortex 32位微控制器
关注我们
st-img 微信公众号
st-img 手机版