
六、SPI 实验 实验目的:掌握和熟悉 SPI 软件模拟和硬件控制的使用和配置方法。 1、软件模拟 SPI 驱动 TFT 实验0 y, i- I, a. F CubeMX 配置如下,保存后生成对应的配置代码:' L" o2 T% t# P. q, U4 e( M" H9 x2 N ![]() ▲ CubeMX 配置 本实验使用软件模拟 SPI,只需要对相应 IO 进行配置即可,注意需要配置 IO 速度等级,CLK 信号和 SDA 信号频率较高,需要配置为 very high。' D4 s0 h4 B) x8 d- t) F 6 J; t6 K$ a Z# s3 G 相关操作函数说明: void Lcd_Reset(void) ) P$ {6 o5 X8 j' v8 V/ }, Q: U 功能:液晶硬复位函数; 参数:无; 返回:无; 说明:液晶初始化前需执行一次复位操作 void LCD_Initial(void)' U7 Q6 r# h E% D$ p$ e 功能:初始化液晶; 参数:无; 返回:无;% N5 o# \8 o7 p$ [! t 说明:在对液晶写入内容前需要进行初始化配置; void Lcd_ColorBox(unsigned int xStart,unsigned int yStart,unsigned int xLong,unsigned int yLong,unsigned int Color) 3 @" x/ U0 ]# m& T) K p/ M 功能:Lcd 矩形填充函数; 参数 1:x 方向的起始点; 参数 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- ~ 说明:将指定区域内填充指定颜色,常用于清屏 void 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 方向的起始点; 参数 2:x 方向的终点; 参数 3:y 方向的起始点;; J" _8 g7 d; [) [3 k7 t' K% ~ 参数 4:y 方向的终点;' L+ e8 {6 w9 [& }% }3 M 返回:无; 说明:开一个矩形框,方便接下来往这个框填充数据; void 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 坐标; 参数 3:点的颜色;9 {$ F& P; B+ o8 ^6 z' y 返回:无; 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 功能:显示一个字符串;/ f) Z W5 X; v k. F K/ q 参数 1:起始点 x 坐标; 参数 2:起始点 y 坐标; 参数 3:字符串指针;' k" i, F9 e: X/ Y P U 参数 4:前景色;" c. h: w! W ^ y# V 参数 5:背景色; 参数 6:有无背景色; 返回:无' A( T" ~9 B7 a' Q ; |5 u; u, B3 `+ _# S U) m% t" S 核心代码: LCD_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);//用红色清屏 Lcd_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);//显示字符 " f/ I+ _6 c5 {7 e+ o+ K: U! { 在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。" m- k1 t, E$ W3 O; l7 s7 b 实验现象:& j' e7 e1 q3 j; x Z4 z+ K" ^ 下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。 2、硬件 SPI 驱动 TFT 实验 CubeMX 配置如下,保存后生成对应的配置代码:2 `7 W$ x0 t( G {- c: R : O' u- ? l! h, Y8 q0 s) q; W; [ ![]() ▲ CubeMX 进行 SPI 配置 ![]() ▲ 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 }相关操作函数说明: & z8 j7 |! ^0 x* h. F! zHAL_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 发送一组数据; 参数 1:SPI 句柄,根据实际需要填写; 参数 2:要发送数据的指针,常见为发送数据数组的首地址; ) }' [7 r# |6 n4 s/ G参数 3:发送数据长度,单位字节; 参数 4:发送超时时间,单位 ms; 返回:操作结果,HAL_OK,HAL_ERROR; 示例:HAL_SPI_Transmit ( &hspi4,data_color,2*xLong,10 );//通过 SPI4 发送颜色数据 HAL_StatusTypeDef HAL_SPI_Receive(SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout) 功能:通过硬件 SPI 接收一组数据; 8 E, W* p0 _' i; Y V$ Y参数 1:SPI 句柄,根据实际需要填写; * P9 T& l/ }5 Z- N' U; t! U: R9 b: f参数 2:要接收数据保存指针; 参数 3:接收数据长度,单位字节; - Y7 |# K% i0 R+ q参数 4:接收超时时间,单位 ms; : y- q1 t1 I( `$ h2 H$ D返回:操作结果,HAL_OK,HAL_ERROR; 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 句柄,根据实际需要填写; 参数 2:要发送数据的指针,常见为发送数据数组的首地址; ) h9 u# K/ n5 h3 A参数 3:要接收数据的指针,接收数据数组的首地址; 参数 4:数据长度,单位字节; 参数 5:超时时间,单位 ms; 返回:操作结果,HAL_OK,HAL_ERROR; * @# ^9 L. Y4 q0 G5 X) D; I: c+ C% M3 }0 n8 M5 ?, F 核心代码: 3 B2 e5 u/ [/ k& Q7 |& sLCD_Initial(); Lcd_ColorBox(0,0,XSIZE_PHYS,YSIZE_PHYS,Blue);//用蓝色清屏 1 d4 p1 b7 L) n+ bLcd_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);//显示字符 0 C5 N: l4 j( i, _% L8 Y在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。 实验现象: ) J6 D1 z; Y) L8 P* U下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。 3、硬件 SPI 驱动 TFT 实验(DMA) 8 c2 ?. y' V2 P& Z0 B3 b7 TCubeMX 配置如下,保存后生成对应的配置代码: ![]() ▲ 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) 功能:通过硬件 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); } 在 DMA 中断中判断是否发生了 DMA 传输完成事件,如果 DMA 传输完成则将相应标志位置位,并清除标志。 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);//显示字符 在 main 函数中进行过外设初始化之后,对 LCD 进行初始化,然后分别用四种颜色清屏,最后显示测试字符。 ( P) q2 A' u" s! b. _$ }6 R% N 实验现象: 下载烧录后可以观察到屏幕分别刷新蓝红绿白四种颜色,最后显示测试字符STM32G474Test。 0 U$ t8 S, ~# g- s$ |% ?! M; d 七、IIC实验 实验目的:掌握和熟悉 IIC 软件模拟和硬件控制的使用和配置方法。 1、软件模拟 IIC 驱动 24C02 实验 CubeMX 配置如下,保存后生成对应的配置代码: ' ^0 Z6 x+ G: H: c; I![]() ▲ CubeMX 进行软件 IIC 的 IO 配置 本实验使用软件 IIC 模拟,只需要配置 IO,初始 IO 配置都配置为输出 IO 即可,24C02 外围电路有上拉电阻,不需要配置内部上拉。 相关操作函数说明: void SDA_Input_Mode() 功能:将 SDA 切换到输入模式; 参数:无; 返回:无; 说明:SDA 是双向的,在进行数据读取时需要切换到输入模式 void SDA_Output_Mode() 功能:将 SDA 切换到输出模式; 参数:无; 返回:无; 说明:SDA 是双向的,在进行数据发送时需要切换到输出模式 void I2CStart(void) 功能:模拟 IIC 的起始信号; 参数:无; 返回:无; 3 i) }) l& V3 Y" l: z& T2 Bvoid I2CStop(void) 功能:模拟 IIC 的停止信号; 参数:无; 返回:无; - _, C" e( X, L$ Zunsigned char I2CWaitAck(void) 功能:模拟 IIC 等待应答; 参数:无; 返回:应答结果,ERROR 或 SUCCESS; void I2CSendAck(void) 功能:模拟 IIC 的应答信号; 参数:无; 返回:无; : B! m# o& e- Q* pvoid I2CSendNotAck(void) 功能:模拟 IIC 的非应答信号; 参数:无; 返回:无; a$ _$ T, y$ d+ Gvoid I2CSendByte(unsigned char cSendByte) 功能:通过模拟 IIC 发送一个字节; 参数:需要发送的字节; 返回:无; ( Y- t4 n+ H+ Xunsigned char I2CReceiveByte(void) 功能:通过模拟 IIC 接收一个字节; 参数:无; 返回:接收到的字节; 核心代码: //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();//停止信号 } 上述两个函数为 24C02 的读写函数,写器件地址为 0xA0,读器件地址为 0xA1,地址由外部电路连接决定。 I2CInit(); uint32_t i; printf(" 24C02 Test ....\r\n\r\n"); //向 0x00 内存地址写入数据 for(i = 0; i < 6; i++) { x24c02_write(i,Data_T); } printf(" 24C02 Write ok\r\n"); HAL_Delay(100); 2 R7 I6 A; Q- q//从 0x00 内存地址读出数据 for(i = 0; i < DataSize; i++) Data_R=x24c02_read(i); 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"); } 以上为 main 函数中外设初始化结束后的部分,通过软件模拟 IIC 向 24C02 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。 : k7 A9 x# k) l0 n/ E& a; a1 V7 o5 C实验现象: 下载烧录后可以观察到上位机串口助手打印测试数据。 [5 e( v4 J+ \ E. i ![]() ▲ 实验现象 9 n: J8 e2 h7 [: Z9 z3 ]2 x6 j: h 2、硬件 IIC 驱动 24C02 实验 CubeMX 配置如下,保存后生成对应的配置代码: ![]() ▲ CubeMX 进行 IIC 配置 本实验使用硬件 IIC,启用之后 IIC 的配置不需要改变。 相关操作函数说明: 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 地址写入待发送数据; 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 地址读取数据; 核心代码: 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 内存地址写入一段设定好的数据,然后将这段数据读出,最后进行对比。 实验现象: 下载烧录后可以观察到上位机串口助手打印测试数据。 ![]() ▲ 实验现象 & 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+ N1、ADC 查询方式单路采集实验 CubeMX 配置如下,保存后生成对应的配置代码: 1 u' L1 ~" {3 b, |. Z![]() ▲ 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 ZHAL_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- VHAL_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); //等待转换完成 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![]() ▲ 实验现象 2、ADC 中断方式单路采集实验 CubeMX 配置如下,保存后生成对应的配置代码: ![]() ▲ CubeMX 进行中断配置 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 进行一次测量。 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 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。 实验现象: 下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。 6 C0 L( `2 `0 Y' V![]() ▲ 实验现象 # T" g) V) H4 p9 a7 {1 s! n3、ADC 使用 DMA 方式单路采集实验 CubeMX 配置如下,保存后生成对应的配置代码: 5 Z' N6 F$ T2 S![]() ▲ CubeMX 进行 ADC 配置 " f1 ~: @2 w/ t1 h, O0 t' f2 ~![]() ▲ CubeMX 进行 DMA 配置 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 核心代码: 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 进行传输。 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 gvoid DMA1_Channel1_IRQHandler(void) { ADC_DMA_Handle(); HAL_DMA_IRQHandler(&hdma_adc1); } ( O& S$ L1 G7 I2 E 以上为 DMA 中断处理函数,在其中添加 ADC_DMA_Handle();。 实验现象: 下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。 ![]() ▲ 实验现象 0 p: F2 C" c2 D: L. }4、内部温度采集实验 2 a' m8 @, N& x5 N. S; @CubeMX 配置如下,保存后生成对应的配置代码: ![]() ▲ 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); } 以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的温度转换函数将 ADC 采样值转换为温度,最后通过串口打印至 PC,每 500ms 进行一次测量。 $ n& ?9 l- H$ q* ?" F实验现象: 下载烧录后可以观察到上位机串口助手打印温度测量数据。 ![]() ▲ 实验现象 8 \* e. m6 c) W# n5、VABT 电压采集实验 CubeMX 配置如下,保存后生成对应的配置代码: ![]() ▲ CubeMX 进行 ADC 配置 本实验进行 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); } 以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将结果转换为浮点数电压值,需要注意的是,VBAT 采样在内部进行了 1/3 分压,因此最终电压计算结果需要乘 3,最后通过串口打印至 PC,每 500ms 进行一次测量。 实验现象: 下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。 5 V3 u( s! m0 Z+ Z. w: Z2 E![]() ▲ 实验现象 8 X5 e2 B4 f9 N w1 d( y' |6、内部基准电压采集实验 CubeMX 配置如下,保存后生成对应的配置代码: ![]() ▲ CubeMX 进行温度传感器 ADC 配置 本实验进行内部参考电压读取,基本配置与例 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); } 以上为 main 函数中外设初始化结束后的部分,首先对 ADC 进行校准,然后进入主循环,循环中开启 ADC 转换,等待转换完成后读取转换结果,然后将调用自带的电压转换函数将内部参考电压 ADC 采样值转换为实际外部参考电压输入,最后通过串口打印至 PC,每500ms 进行一次测量。 实验现象: 下载烧录后可以观察到上位机串口助手打印外部参考电压测量数据。 ![]() ▲ 实验现象 7、定时器触发单通道 ADC 采样 CubeMX 配置如下,保存后生成对应的配置代码: ![]() ▲ CubeMX 进行 ADC 触发配置 ![]() ▲ CubeMX 进行定时器配置 ![]() ▲ CubeMX 进行中断配置 CubeMX 中的 ADC 基本配置单通道采样相同,这里需要开启 ADC1 的中断,并且修改转换触发源,原来的软件触发改为使用定时器时间进行触发,TIM1 配置周期为 10ms,即每 10ms触发一次 ADC 转换。 相关操作函数说明: HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef *hadc) 功能:使能 ADC,以中断开启 ADC 规则组转换; 参数 1:ADC 句柄,根据实际需要填写; 返回:操作结果,HAL_OK,HAL_ERROR; 示例:HAL_ADC_Start_IT(&hadc1); //开启 ADC1 转换 注意:在 ADC 转换完成之后会触发中断,中断中读取采样数据 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); //通过串口发送 } } 以上为 ADC 转换完成中断回调函数,该函数为 ADC 共用的,进入此函数首先要判断是哪个 ADC 转换完成了,然后读取相应 ADC 的数据寄存器,转换为浮点数电压,通过串口发送到上位机。 , n& u6 d$ j' l5 Y! V0 k; `5 @- _实验现象: 下载烧录后可以观察到上位机串口助手打印 ADC 测量数据。 ![]() ▲ 实验现象 九、DAC实验 实验目的:掌握和熟悉 DAC 单路输出的软件触发和定时器触发配置方法,配合 DMA 输出波形。 ! s- k5 Q" [3 d* b& a. @9 k1、DAC 软件触发输出实验 ! P$ n; [5 K( vCubeMX 配置如下,保存后生成对应的配置代码: ( `) _3 h) v6 T0 |) L' } ![]() ▲ 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 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; 核心代码: 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);// 延时一毫秒 } } 以上为 main 函数中外设初始化结束后的部分,主循环中根据正弦表切换 DAC 电压输出,1ms 进行一次切换,正选表一共 60 个点。 实验现象:下载烧录后可以观察到 PA4 输出一个正弦波,频率约为 8.333Hz。 ![]() ▲ 实验现象 2、定时器触发 DMA 传输 DAC 输出实验 $ K R, D& C2 x, g, _CubeMX 配置如下,保存后生成对应的配置代码: ![]() ▲ CubeMX 进行 DAC 基本配置 ![]() ▲ CubeMX 进行 DMA 配置 ![]() ▲ 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! Uif (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。 ![]() ▲ 实验现象 4 d% M% B: M4 Q5 ^! k3、定时器触发 DAC 输出噪声实验 CubeMX 配置如下,保存后生成对应的配置代码: ![]() ▲ CubeMX 进行 DAC 输出配置 ![]() ▲ 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 输出随机噪声。 ![]() ▲ 实验现象 如有侵权请联系删除 转载自:AI电堂 ( u* L) P$ p! u. w5 ^/ G: f |
STM32固件库分享,超全系列整理
STM32G系列RS485自动收发控制以及自适应波特率实战
【学习指南】基于STM32G474VET6 开发板实验经验分享(三)
【学习指南】基于STM32G474VET6 开发板基础实验经验分享一
【学习指南】基于STM32G474软件平台安装与使用教程
【学习指南】基于STM32G474VET6 开发板硬件资源解析
STM32 Explore | 基于STM32G474的STM32Cube生态系统线下培训
STM32G47x 双 Bank 模式下在线升级
基于STM32G473ZET6开发板设计经验分享
详细讲解STM32G4的软件工具和环境搭建