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

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

[复制链接]
攻城狮Melo 发布时间:2024-11-22 15:27
六、SPI 实验
" c% v1 y% b# B+ a1 G7 b: N4 _实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。
* F" D9 p: U+ }& Y1 X! S7 k5 P
/ h0 z& [+ O" F# ~: i
1、软件模拟 SPI 驱动 TFT 实验
& E9 U, y# l' ^6 q/ H! P, q) n1 FCubeMX 配置如下,保存后生成对应的配置代码:
1 F  f% D) w' y; m4 L
13.png 1 [$ e$ V. y- `2 M4 x/ Z

& d% G7 M2 }& S! S0 R
▲ CubeMX 配置

, X4 M8 x# z0 E+ k. y' K
本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。+ Z. ~' l3 s! Y/ [- I
0 w+ d5 K3 r5 m! q  d5 K7 F% h. L
相关操作函数说明:5 \, p0 z1 v: H
void Lcd_Reset(void)
# b. g# [0 Q6 Z) P" ^6 H
" F& z) d& P8 D3 j9 n. ?3 z
功能:液晶硬复位函数;
* \' t! S$ f# q  M$ U& @3 h  M' U参数:无;
, V' ?7 w, Q9 P/ R6 Q% ]返回:无;6 S7 y+ P6 h. X4 _' j; a: T
说明:液晶初始化前需执行一次复位操作
) l, |" Q% a' W  tvoid LCD_Initial(void); U2 B' @* m1 j8 \
功能:初始化液晶;) ?( K4 w; N! X
参数:无;
" M7 a$ _, @1 K/ }返回:无;9 P6 ~1 `2 [6 [. V! Q' A& N: H3 y
说明:在对液晶写入内容前需要进行初始化配置;# v3 w' V* I8 K% O4 U
void Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color)
) `4 b+ N) W2 m4 Y% n; c

. L3 M. j2 o% w- k2 m! f4 y, v" Z3 G功能:Lcd 矩形填充函数;3 h6 B: v& ?" O. C4 F' ~
参数 1:x 方向的起始点;/ @5 I8 q  @0 _, @4 s
参数 2:y 方向的起始点;% |* S) j# ~% [! [2 R
参数 3:x 方向的长度;
9 v2 N& B8 I. F% V& h* h- [参数 4:y 方向的长度;* t; \; O- O7 U8 o+ G/ l- z
参数 5:填充的颜色;/ O/ {' ^  F2 ^) Z
返回:无;
. r7 j1 ]4 t3 e9 W说明:将指定区域内填充指定颜色,常用于清屏
/ f- x0 p2 t3 b# ovoid BlockWrite(unsigned int Xstart,unsigned int Xend,unsigned int Ystart,unsigned int Yend)
: f$ v; o& O( Y
1 ]0 b; T: h% z功能:在一个指定位置开一个矩形框;
6 C9 s  }7 E$ q& f7 `" Z$ |参数 1:x 方向的起始点;
5 H3 ~6 ?) f. `) I+ B" i! @参数 2:x 方向的终点;. B" y- W4 t8 R7 b( B+ v
参数 3:y 方向的起始点;
; R  H8 y: ~2 }5 c参数 4:y 方向的终点;
) I# x5 {) o6 ?' H/ G5 C返回:无;
9 ^/ i+ u, v; R! ?说明:开一个矩形框,方便接下来往这个框填充数据;! Z3 z* R- Q+ P1 E
void DrawPixel(unsigned int x, unsigned int y, int Color)
  t) _1 i' W. o) ]" Q功能:在 x,y 坐标上打一个颜色为 Color 的点;
0 p. A" X1 H+ G2 q# {0 r# c参数 1:x 坐标;. w1 p9 R! n7 C, f/ n& k
参数 2:y 坐标;% f7 R$ q# b5 x( O: n, P
参数 3:点的颜色;
' n) A8 |2 {6 L  N4 n! R; _返回:无;; |7 U! d' ?% g5 r+ M
void LCD_PutString(unsigned short x, unsigned short y, char *s, unsigned int fColor, unsigned int bColor,unsigned char flag)  z/ g; i- I) g. {( V. Q; Z' A$ {% v
& G+ D5 v4 o  @4 I* l
功能:显示一个字符串;
6 `' ]- K& A$ v) W! Q参数 1:起始点 x 坐标;& v8 v1 `( I. f
参数 2:起始点 y 坐标;) }* ^5 ~0 u7 q$ c% K6 U
参数 3:字符串指针;
: i9 l" c3 X8 l5 l+ i3 i4 m参数 4:前景色;8 P9 \7 y( p' d9 a9 k. f4 |; f2 P
参数 5:背景色;
6 `  g% z& f8 P参数 6:有无背景色;1 p# c1 L8 m( E; I6 w2 V
返回:无
7 {' l6 H. n3 d* O; x$ h: R; z  q( N: K* e- X" P

. n5 @1 v' G0 g' ~核心代码:
8 _9 Q. x' f9 z& s5 L% PLCD_Initial();
/ m' I2 V, D8 `- vLcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏8 k$ z4 L! K( O2 G5 Z
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏9 D) x* [1 M2 c# n0 H
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏7 [! |  p6 g5 J& F# U8 g6 Y) W
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏9 |' K  Y0 l4 |! f( Q) q
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符6 b- E" X  U( }4 X: ^( I( |
7 d2 Z( w4 I9 W+ P, |1 N4 ~
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。/ B7 [% A& x4 q9 u9 K7 W8 m( m1 e
6 X1 g* q% T: s

  r% P/ z7 _# {: Z实验现象:
* M) b4 M' p& `6 P" V下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
6 ^; u1 i1 }! M. A* Q
5 E/ y" q; S9 \( O7 a  M
  C" ?6 x+ ^7 X( z1 {+ Q+ ]
2、硬件 SPI 驱动 TFT 实验
. O$ \! ]$ j+ o: a$ G% hCubeMX 配置如下,保存后生成对应的配置代码:
/ Z2 u8 C% g/ f# }+ G5 \
& R; G! ], A7 B/ y  R4 b! R9 r6 a1 z( A
12.png
+ w1 }) x+ h) E

8 }! u0 D2 l, w9 Q5 q8 M% ]# E
▲ CubeMX 进行 SPI 配置
微信图片_20241122152531.png ) D0 e% |  S  H7 O8 y( s

& w' @7 Z9 G1 h5 r
▲ CubeMX 进行 IO 速度配置% F; B. X) j  j0 u  q
本实验使用硬件 SPI,需要配置 SPI 的时钟分频,配置出合适的时钟速率,另外需要注意设置时钟信号的空闲电平以及采样边沿,还需要将高速的信号 IO 速度进行配置,其他 IO配置与软件模拟 SPI 相同。

# K! F3 y/ I% N; M4 u6 X; e

: f/ D, v, a* u: E# t1 \

% q0 m% t' b) F0 K# Z

& I" v( @( p- z3 e
相关操作函数说明:

" @" _' ?6 u" r
HAL_StatusTypeDef HAL_SPI_Transmit(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

( g+ X0 ~' U5 T* x; H2 V
功能:通过硬件 SPI 发送一组数据;
* I0 M# @9 x$ }# V7 j
参数 1:SPI 句柄,根据实际需要填写;

9 j0 F0 A" Q+ X  U* ^
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
: f+ m+ J( a/ t+ c$ y3 R  v
参数 3:发送数据长度,单位字节;

) B  Y  h$ u/ A8 u" t$ b4 a
参数 4:发送超时时间,单位 ms;
! m% d: u+ L% S4 J
返回:操作结果,HAL_OK,HAL_ERROR;

; z( N* b0 J& f- O; g, [' g' y
示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据

- x& Z9 P2 h0 @
HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)

, T# p: L8 `1 {- q
功能:通过硬件 SPI 接收一组数据;
7 c: E% c6 I5 B) D% N3 a1 R& {
参数 1:SPI 句柄,根据实际需要填写;

* ]0 Y0 j; B. Z+ c' C  I5 C' |: z8 f
参数 2:要接收数据保存指针;
# w8 [: M7 k' O. ]" X
参数 3:接收数据长度,单位字节;
* U7 }0 {' H5 w& a2 A4 @( [
参数 4:接收超时时间,单位 ms;

7 e& O, F' d+ l% y/ z2 \# s8 B
返回:操作结果,HAL_OK,HAL_ERROR;

0 z  x8 r! ~8 x& @7 ^$ h; ^
HAL_StatusTypeDef HAL_SPI_TransmitReceive(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size, uint32_t Timeout)

) Z8 t4 Y+ ~8 B$ s, d
功能:通过硬件 SPI 交换一组数据;
; \. T0 y' \, l6 ~4 ]
参数 1:SPI 句柄,根据实际需要填写;

/ t8 O3 I  u! F. G7 \
参数 2:要发送数据的指针,常见为发送数据数组的首地址;

0 d" X* `" G, o4 j/ ?+ s' n
参数 3:要接收数据的指针,接收数据数组的首地址;

3 K, P( Z' ~0 g& K
参数 4:数据长度,单位字节;

2 c+ [8 Q: _( e4 T  f8 _
参数 5:超时时间,单位 ms;

; \) q3 n' Q* w" T( z5 ~6 _  c
返回:操作结果,HAL_OK,HAL_ERROR;
% A( K7 r0 K( ]0 Z
, J2 ?: b4 o/ O/ V- e' M
6 k" @  U' f1 z3 I2 V
核心代码:
$ k8 I4 V4 M* Q  n
LCD_Initial();

3 F0 t$ B9 d  t
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏
; a/ G+ N. |) u9 S  y0 w
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Red);//用红色清屏
. {% i8 x& e! @8 a* J
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Green);//用绿色清屏

' o* k8 b0 j8 P. O1 k% P
Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,White);//用白色清屏
1 a" x' j% B, o. N5 a+ T" _
LCD_PutString(10,10,"STM32G474Test",Red,White,0);//显示字符

, O5 m+ s; W2 E& ~9 c  O
, }& r: r. j- |* @5 f# \9 M
9 b' b  b9 w4 L' b+ h- q' F
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
# x4 a0 f1 x' y: }4 C

4 r  m, C- P; Z; t3 x, M1 l  s+ _

& q8 L& v0 h! S) r" L
实验现象:
& a) R6 l/ O9 `* R, H
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。
5 q- i. y* f! F0 T( q3 f6 v
, ]# E2 Z! u5 Q2 ]* X- L

& K- l2 w& v: R: C* E
3、硬件 SPI 驱动 TFT 实验(DMA)

+ P7 C& ^% c8 G- h
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152534.png

$ J5 q, G) k2 @9 P; c/ x1 f' Q3 l
▲ CubeMX 进行 SPI 的 DMA 配置
本实验使用硬件 SPI,使用 DMA 进行发送。
$ k) h3 I1 r" D* x" A& @
相关操作函数说明:
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)
, ^( S) G1 [# Z% X- d
功能:通过硬件 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)
4 o) v2 P. `- ~$ u( {! n/ q
功能:通过硬件 SPI 的 DMA 方式交换一组数据;
参数 1:SPI 句柄,根据实际需要填写;
参数 2:要发送数据的指针,常见为发送数据数组的首地址;
参数 3:要接收数据的指针,接收数据数组的首地址;
参数 4:数据长度,单位字节;
返回:操作结果,HAL_OK,HAL_ERROR;
注意:使用相应 DMA 时需要对该 DMA 请求进行配置;
2 s% u8 B" X- S: v& ]2 ]' d2 c
核心代码:
//发送函数修改
if((temp+1) % xLong == 0)
{
HAL_SPI_Transmit_DMA(&hspi4,data_color,2*xLong);
while(!dma_flag_temp);
dma_flag_temp = 0;
}
. k) }' ]2 P& J( C# M7 V
使用 DMA 方式进行发送时需要确保上一次 DMA 发送已经完成,要避免重复请求。

6 T* X# Q- p- ~
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);
}

4 g9 o& T) O5 f) v* m
在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。

! a2 Y$ m0 `( l3 |' W2 U4 h
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);//显示字符
/ N3 \$ ]6 m0 a$ \4 C
在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。
: \5 W6 ?/ g+ r4 i
实验现象:
下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。

* m9 E, S! Z8 |9 Y1 y) J* e; Z: o2 l
七、IIC实验
, \8 x% p  \. u% p  C8 f9 w
实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。

5 N: ^3 G- P% ?' O& c1 S& M
1、软件模拟 IIC 驱动 24C02 实验
CubeMX 配置如下,保存后生成对应的配置代码:

8 N& ]! T0 X8 }; o+ }) Q1 Z0 |* q! K
4.png . B5 y& S' s0 l8 X* f2 ], Z
3 b1 O5 |' h7 B8 Q  F( m6 `( ?! z* X
▲ CubeMX 进行软件 IIC 的 IO 配置
# ]* ~, r: Y7 |! `7 i; G. E/ ~! V; z- _
本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。

: A: {5 P9 {, r( h; v' G
相关操作函数说明:
void SDA_Input_Mode()
功能:将 SDA 切换到输入模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据读取时需要切换到输入模式
1 E9 S! ?* E! ^$ k( G' X. N9 q
void SDA_Output_Mode()
功能:将 SDA 切换到输出模式;
参数:无;
返回:无;
说明:SDA 是双向的,在进行数据发送时需要切换到输出模式
3 m# k; h3 q$ u  N% \
void I2CStart(void)
功能:模拟 IIC 的起始信号;
参数:无;
返回:无;
( S# I0 s: p5 c5 F# {# w* s% O7 H* t
void I2CStop(void)
功能:模拟 IIC 的停止信号;
参数:无;
返回:无;

! t" ~' l' K( x! J
unsigned char I2CWaitAck(void)
功能:模拟 IIC 等待应答;
参数:无;
返回:应答结果,ERROR 或 SUCCESS;
/ }+ f- v+ k" d, e  ^
void I2CSendAck(void)
功能:模拟 IIC 的应答信号;
参数:无;
返回:无;
* f; I# C9 O# R! u
void I2CSendNotAck(void)
功能:模拟 IIC 的非应答信号;
数:无;
返回:无;
; B1 J8 Z% [7 m# |: f
void I2CSendByte(unsigned char cSendByte)
功能:通过模拟 IIC 发送一个字节;
参数:需要发送的字节;
返回:无;
  |# W2 L4 `% A; `5 ^
unsigned char I2CReceiveByte(void)
功能:通过模拟 IIC 接收一个字节;
参数:无;
返回:接收到的字节;

- O2 C8 K: Q1 h1 ?7 @+ R& B
核心代码:
//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();//停止信号
}
. B2 a$ R6 Y; U
上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。

* g3 @, T0 F6 `& r8 M8 D
I2CInit();
uint32_t i;
6 }9 E) _+ F8 }- n: w+ M+ Z
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);

; @" ^- h/ U* o& P6 f- u
//从 0x00 内存地址读出数据
for(i = 0; i < DataSize; i++)
Data_R=x24c02_read(i);
printf(" 24C02 Read ok\r\n");

9 l; Y+ M" `1 m; I2 s, `
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");
}

! t2 l) t& b8 P% w- d5 J& p
以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
% Q2 V& l4 p% S8 T, t
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

% `0 E) y+ Y7 {( }& B' ]
微信图片_20241122152540.png
9 H7 Z7 u! t: M. X3 N) z, @

* C. ?& ]3 i# o, ]
▲ 实验现象

4 B) i" [+ {9 w4 _
3 H! G( d7 F8 g# Y) g$ z7 f' ~) u
2、硬件 IIC 驱动 24C02 实验

1 I) N' `- p8 G) Q8 u
CubeMX 配置如下,保存后生成对应的配置代码:
. h! g- j! q/ \2 O7 K
微信图片_20241122152543.png
# Y% M5 p7 F9 j. e. n2 Q

; A9 N! K- d& c
▲ CubeMX 进行 IIC 配置
9 `) K" H* |# K2 ?4 q
本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。
4 H* Q) T0 ~1 W, h1 r
相关操作函数说明:
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 h: f! S1 ^/ c: p& y$ H) t
示例:
HAL_I2C_Mem_Write(&hi2c3,Addr_W,0x01,I2C_MEMADD_SIZE_8BIT,Data_T,DataSize,0xFF);//通过 IIC 向目标器件的 0x01 地址写入待发送数据;
+ {1 m" H, q% P" P; H, ^
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 地址读取数据;

0 R3 T# M2 i6 i7 G0 H. u. m

/ h" ^: U  y& O5 N1 g7 e
核心代码:
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");
}
7 ~9 W( f7 L' W5 d% I
以上为 main 函数中外设初始化结束后的部分,通过硬件 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。
  m: r/ B! n1 B# F
实验现象:
下载烧录后可以观察到上位机串口助手打印测试数据。

( M2 i8 p0 ^- a5 B  N4 ~5 P% s
微信图片_20241122152546.png
6 ]1 U* u. g$ |; B% G* T) G! B
▲ 实验现象
8 s  s" o, R* _1 k9 }6 |
5 ?& E7 O* C% S
七、ADC实验
4 S$ O, M6 b4 B6 T5 O8 u
实验目的:掌握和熟悉 ADC 单路采集和多路采集的使用和配置方法,包含查询,中断,DMA等方式。
5 P+ ?& Y+ g$ W  M" A$ I9 S
1、ADC 查询方式单路采集实验

+ `# L4 [% g" V: S8 J" S
CubeMX 配置如下,保存后生成对应的配置代码:

& w, C6 _( i& w! n
微信图片_20241122152549.png
▲ CubeMX 进行 ADC 配置

0 t) j/ n8 l' x+ U5 {8 H, Q* o& ]7 E
本实验进行单通道 ADC 软件触发采样,只需要对 ADC 进行简单配置即可,同时使用串口进行数据输出,串口与时钟系统配置上文已经展示,参照上文实验进行配置。
1 e: d* R- t4 N, e9 h8 T
相关操作函数说明:
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 进行单端采样模式下的校准;

) B. C' F4 l0 C2 E$ q
HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef *hadc)
功能:使能 ADC,开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR,HAL_BUSY;
示例:HAL_ADC_Start(&hadc1); //开启 ADC1 转换
注意:如果不是工作在连续模式,运行一次该函数进行一次转换

% O% p# d% V' @1 n4 Q+ H
HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;

5 A6 m9 i" c* B* E0 M: C" L' h
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); //等待转换完成
5 y1 b8 T7 [) A' f% }: h7 T
uint32_t HAL_ADC_GetValue(const ADC_HandleTypeDef *hadc)
功能:读取 ADC 规则组转换结果;
参数 1:ADC 句柄,根据实际需要填写;
返回:转换结果,ADC 采样寄存器值;
示例:ADC_Value = HAL_ADC_GetValue(&hadc1);// 读取转换的 AD 值

/ @$ S- P) A5 ^0 D
核心代码:
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);
}

0 L; A2 B- S5 [' }& P" e& l) i
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,最后通过串口打印至 PC,每 50ms 进行一次测量。

" {2 w8 c9 x1 S
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

9 U  d9 g$ n' r1 G
微信图片_20241122152553.png
& G6 N  Z8 n- e5 ]4 U# P& r% v

. w5 S- y% S6 C  [; S. Q' |* t
▲ 实验现象
( _% N9 n/ y* z: _
- L2 U* s: B$ f  Z
2、ADC 中断方式单路采集实验

  l* a" b: `2 T5 f
CubeMX 配置如下,保存后生成对应的配置代码:

% p; s# G* ~" j+ f3 k1 W8 V1 u
微信图片_20241122152556.png
▲ CubeMX 进行中断配置

! x2 e- Q$ f0 S. K/ r
CubeMX 中的 ADC 基本配置与上例相同,这里需要开启 ADC1 的中断。
9 w. Y+ X# j/ u
相关操作函数说明:
HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc)
功能:使能 ADC,以中断开启 ADC 规则组转换;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERROR;
示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换
注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据

: d! G! N& G, j" _# A/ Y% ?8 C
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

9 W, I- y/ C2 `
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
while (1)
{
HAL_ADC_Start_IT(&hadc1); //中断方式启动 ADC
HAL_Delay(50);
}

) \7 H7 ^/ |! _! y1 D/ {
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中中断模式开启 ADC 转换,每 50ms 进行一次测量。
0 u1 t. K6 d0 Y+ [
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); //通过串口发送
}
}

. S5 k( A  @/ u2 C; y1 K3 U! x  [
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
; H" X, H) |! j
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
7 r7 \9 U7 F% i2 l1 _$ u' y
微信图片_20241122152600.png
2 e8 N2 p7 Q- s* q

( q3 p  R% p, `$ v
▲ 实验现象
! {* `. f; K0 u8 I
3、ADC 使用 DMA 方式单路采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
5 r1 Q, i2 @# c2 |7 m( ?- ?
微信图片_20241122152607.png
▲ CubeMX 进行 ADC 配置

$ ^: b. }2 _: F- r$ W
微信图片_20241122152610.png
& U; i; I6 m. i% n
▲ CubeMX 进行 DMA 配置
9 k) ^3 p& f  e" e& R9 h3 ~
CubeMX 中的 ADC 基本配置需要开启连续转换模式,使能 DMA 请求,然后需要对 ADC1的 DMA 进行配置,使用连续传输模式,半字传输。
: M8 f/ y' P+ A+ `
相关操作函数说明:
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 传输;
6 V; U0 x  q0 Y2 W& k- Q- w
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
% T$ a' Z3 X3 n8 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();
}
3 k: x2 D; b8 h
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后开启 ADC,使用 DMA 进行传输。
  v* A( }) F* Q0 @
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 转换。

0 I1 z/ s# _; E8 [) ~$ Y# W  J
void DMA1_Channel1_IRQHandler(void)
{
ADC_DMA_Handle();
HAL_DMA_IRQHandler(&hdma_adc1);
}
. y3 R, g, j8 u3 I; a0 u; R! I
以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。
( z0 e7 |1 b9 _- ^+ t
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

, l6 x# v) W5 Z3 _- |; |
微信图片_20241122152613.png % C5 X4 @% v  p5 g. ?0 @- B- ~
$ P# d$ C2 `, ?1 `& `
▲ 实验现象

( y  [# ?% ?7 u/ w. O! b( [
4、内部温度采集实验
" ~' e, ^. t$ I/ C, ~9 V
CubeMX 配置如下,保存后生成对应的配置代码:
4 f" O* b- l( S2 q1 G* }+ e0 p
微信图片_20241122152616.png
  E/ y/ w# `8 t1 r5 G' y- ]3 [

0 c# ]5 H! T, I3 n! r& O& t- ]
▲ CubeMX 进行温度传感器 ADC 配置
: a  U% I+ |4 v, u2 c6 J' F
本实验进行内部温度传感器读取,需要注意采样时间需要给足,手册要求最小采样时间 5us,根据时钟频率进行换算。
2 V) H. o# e; Y$ Z2 u* T% B
相关操作函数说明:
__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);//转换温度
+ N% d$ L6 v. ~6 x+ U/ j  ]! j
核心代码:
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);
}
8 h; ]/ L0 N6 [' V' O% m8 W8 @
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。
( N$ n! I5 p  E+ h
实验现象:
下载烧录后可以观察到上位机串口助手打印温度测量数据。
. ]% A, X* l5 g' v  q/ q1 V
微信图片_20241122152619.png " e6 e9 u' T$ I2 V
▲ 实验现象

+ T  N* Y# M* P3 }
5、VABT 电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
: Z2 U3 [" E8 l/ t
微信图片_20241122152621.png
6 G/ P7 }4 v7 y7 K1 ~$ H
# t8 y. u; A  `. e
▲ CubeMX 进行 ADC 配置

; C- Y8 g; k6 c/ g$ l9 L' S
本实验进行 VBAT 电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 12us,根据时钟频率进行换算。

  [0 l* o( j; ]* W$ n- c, l
核心代码:
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);
}

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

* T5 k6 L- i$ O7 {
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。

* p3 n. A' p$ Z' K1 H9 F
微信图片_20241122152624.png
▲ 实验现象

# P9 F$ z7 Q7 i, D
6、内部基准电压采集实验
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152627.png
: \" H3 _0 H# D0 z" ]% j
# K, l0 W/ ^4 u% J, f" v
▲ CubeMX 进行温度传感器 ADC 配置
+ K& b4 z* d. M- K+ y, [
本实验进行内部参考电压读取,基本配置与例 3.8.1 相同,需要注意采样时间需要给足,手册要求最小采样时间 4us,根据时钟频率进行换算,读取之后通过内部参考电压反算外部参考电压。

4 Z1 G1 Q0 `# u3 i4 y
相关操作函数说明:
__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 F# C7 M! S* s+ ?; [: 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 值
VREF_MV =
__HAL_ADC_CALC_VREFANALOG_VOLTAGE(ADC_Value,ADC_RESOLUTION_12B);//转换 VREF+
printf("VREF+: %d mV \r\n", VREF_MV); //通过串口发送
HAL_Delay(500);
}

; G( v5 V0 j  s2 k- m  n
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。

) P  Z  R2 m* f
实验现象:
下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。

+ C: N4 J* m1 d* N* ~5 T( L% ~
微信图片_20241122152630.png $ M7 x. f1 w( P9 t, I& R4 v
* r3 @2 J/ v: c
▲ 实验现象

9 |: U5 q% x( x; l
7、定时器触发单通道 ADC 采样
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152633.png
! Y0 U. U* R0 ^3 ~4 q: l1 x# D

8 y0 o( w: W" z
▲ CubeMX 进行 ADC 触发配置
微信图片_20241122152635.png
" Y  h+ G4 K" A6 w) i6 \

- o1 I/ M7 r7 w1 e% q0 M
▲ CubeMX 进行定时器配置
微信图片_20241122152638.png # n8 T; v. c3 g) n; q9 d

0 u- ?3 @  Y" u6 e# ^
▲ CubeMX 进行中断配置

, w  B1 k: t1 p+ J8 c
CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。
. [8 T$ y1 n0 t, d- O& k7 x3 q7 s3 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 转换完成之后会触发中断,中断中读取采样数据

' l$ N9 a& J  w4 Z! t% y' F
HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef *hadc)
功能:关闭 ADC,停止规则组转换,关闭转换结束中断;
参数 1:ADC 句柄,根据实际需要填写;
返回:操作结果,HAL_OK,HAL_ERRORT;

& A& h4 _! Y7 r9 j3 l  e
核心代码:
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED); //矫正
HAL_ADC_Start_IT(&hadc1);//中断方式启动 ADC
HAL_TIM_Base_Start(&htim1);//启动 TIM1
% H) \- O, u; f0 N" N
以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后中断方式开启ADC 转换,这里主要是要开启 ADC 并且使能中断,然后开启 TIM1,通过 TIM 触发 ADC进行转换。
) Z- y4 i# s1 Z/ |7 N1 H! T
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 Q' |4 d+ X! w  x4 U+ K: E
以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。
$ J9 K' @# c6 f% {* U
实验现象:
下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。
6.png ; c1 A! K; M: e1 _4 m" E9 Y

: G: W( U1 E  s: I1 C7 g# ]4 W
▲ 实验现象
九、DAC实验
0 {  h  D2 I2 i* Z  J. y0 x" @  r
实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。

: e  v/ k+ R0 M6 i0 k' a( X  Z
1、DAC 软件触发输出实验

* A0 i9 a) S, ]% ]! F7 r+ h2 S
CubeMX 配置如下,保存后生成对应的配置代码:

) E0 I- y7 f* v5 y1 t; E: P
微信图片_20241122152645.png
: @: a+ D7 e1 o) s1 ?0 x7 T7 B
- L5 a$ N3 m+ J/ p4 N
▲ CubeMX 进行 DAC 输出配置

- G! f* i, k# L5 D: f7 _# I
本实验进行软件触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为软件触发。

; _6 r- G$ y, A& `0 m
相关操作函数说明:
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 输出,如果想要修改生效,还需要使用下面的函数
! f* r7 X+ m) b4 e" g2 `
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);// 改变输出值
. P  r: P# _' D% g4 n6 {1 s0 k

  M/ I3 O  g2 V( S1 N  j
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;
4 E+ h& k0 y0 m/ {+ H: o0 l
核心代码:
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);// 延时一毫秒
}
}

, M2 ?5 x: l# i! d1 k% E; C6 X
以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。

9 t) `+ N  c9 T- F, v" B7 ~; {# C" q
实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。
" U6 H* m( ?( w$ ?, K: G
微信图片_20241122165909.png
2 e2 q" c& S  I) ?

1 T7 r; u9 L; V- B
▲ 实验现象
3 i. u1 c  o+ u; \. E. U
2、定时器触发 DMA 传输 DAC 输出实验

2 U" z1 m7 N3 D- J1 I) U
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152650.png 7 T) q5 H, Q  I4 L1 s1 y6 c9 ~  F

& _% ^) z% t" {" _* t8 e) i
▲ CubeMX 进行 DAC 基本配置
微信图片_20241122152652.png ' B* w% ~" p# _* w' D0 p. j

, {- h/ e+ _& S" ^' s' k
▲ CubeMX 进行 DMA 配置
微信图片_20241122152654.png
1 z3 F. ~$ }0 O* F
- I7 _3 z9 D; w
▲ CubeMX 进行 TIM4 配置
4 h8 @- j' w7 D# p9 W) i0 e' y* ?
本实验进行定时器触发 DAC 输出,开启 DAC1 的 OUT1 输出,使用外部输出引脚,使用普通模式,并且使能输出缓冲,将触发设置为 TIM4 触发,配置 DMA,使用循环模式,整字传输,配置 TIM4,设置定时器周期为 1ms。

  Z2 ?" J( _4 Y) q9 O9 h
相关操作函数说明:
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 方式设置输出值
5 w& z# Q2 l7 C- J2 i
核心代码:
//正弦表
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
6 N. \) F! ~2 ^8 j+ ?2 m4 `3 n
以上为正弦表定义。
7 p! i* U' L2 r  C  q6 _, ~
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();
}
1 c! ?- W$ f" U3 U! g* U
以上为 main 函数中外设初始化结束后的部分,开启 TIM4 进行触发,以 DMA 方式开启DAC 转换输出。

1 ^1 x! T3 e2 K/ ]  r
实验现象:
下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 12.5Hz。
微信图片_20241122152657.png
9 ?8 h+ o+ j5 h  b

6 O' }6 b* L# Y- x4 _  T
▲ 实验现象
$ |0 H# i5 k. Y8 m! s$ B
3、定时器触发 DAC 输出噪声实验
8 i9 I' ^  f% x4 x7 A
CubeMX 配置如下,保存后生成对应的配置代码:
微信图片_20241122152659.png 8 o) G" A5 X- S: x4 H; n  m
▲ CubeMX 进行 DAC 输出配置
微信图片_20241122152701.png ) C, W' G* c( z

+ j$ R* b( p- `/ [6 d" C0 C
▲ CubeMX 进行 TIM2 配置

5 d2 v3 [1 O8 z  V0 k6 A+ f
本实验使用 TIM2 触发 DAC 进行输出,输出内容由 DAC 随机生成,产生噪声。

: ], ]. E$ I, i: Y4 d  J6 j) {
核心代码:
HAL_DAC_Start(&hdac1,DAC_CHANNEL_1);//启动 DAC 输出
HAL_TIM_Base_Start(&htim2);//启动 TIM2 触发 DAC

9 Q9 B9 [* b+ \, ]3 H! d
以上为 main 函数中外设初始化结束后的部分,只需要开启 DAC 输出和定时器即可。

' K6 B9 R% R* s3 @) j: e! [
实验现象:
下载烧录后可以观察到 PA4 输出随机噪声。
微信图片_20241122152703.png
  g. x' Z- ~. F  m
▲ 实验现象
' w# F8 m/ s6 E* B. r
如有侵权请联系删除
9 E/ [' [! K. i# O1 P% X, @# F
转载自:AI电堂
% G; e. s3 T* d, E! `8 \0 U

  P0 G; [/ T# f2 \
收藏 评论0 发布时间:2024-11-22 15:27

举报

0个回答

所属标签

相似分享

官网相关资源

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