当前位置: 首页 > article >正文

STM32HAL库快速入门教程——常用外设学习(2)

目录

一、STM32HAL库开发(8)——CubeMX配置DMA

1.1、什么是DMA?

1.2、内存内存之间的传输(单次)

​编辑

1.3、内存外设之间的传输(ADC)

二、STM32HAL库开发(9)——CubeMX配置RTC

2.1、RTC实时重要一环——BKP 寄存器

2.2、RTC实时时钟

三、STM32HAL库开发(10)——单片机工作模式

3.1、低功耗睡眠模式(Sleep)

3.2、低功耗停止模式(Stop)

3.3、低功耗待机模式(StandBy)

四、STM32HAL库开发(11)——看门狗

4.1、独立看门狗

4.2、窗口看门狗


前言:前面已经更新了7个常用外设了,所以这个文章就从8开始了!

一、STM32HAL库开发(8)——CubeMX配置DMA

1.1、什么是DMA?

DMA(Direct Memory Access),即直接存储器访问。 DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路, 能使 CPU 的效率大为提高。

STM32F103C8T6内部有 2 个 DMA 控制器(DMA2 仅存大容量产品中), DMA1 有 7 个通道。DMA2 有 5 个通道。每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。

众所周知,DMA中有另种模式,①内存内存之间,②内存外设之间

内存很多外设之间都有,比如:

还有更多的可以去看芯片手册!

② 通道:DMA 具有 12 个独立可编程的通道,其中 DMA1 有 7 个通道, DMA2 有 5 个通道,每个通道对应不同的外设的 DMA 请求。虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

所以为什么同一时间只能接收一个通道呢?假如一次性有两个通道要转换,谁先谁后呢?为什么这么有规则呢?是因为有着一个大哥管理着:仲裁器

③ 仲裁器:当发生多个 DMA 通道请求时,就意味着有先后响应处理的顺序问题,这个就由仲裁器管理谁优先执行。

1.2、内存内存之间的传输(单次)

实验现象:

声明两个数组uint8_t DataA[]={1,2,3,4};uint8_t DataB[]={0,0,0,0};,刚开始显示1234和0000,经过DMA转运后,显示1234和1234!(将DataA的值传输给了DataB)

CubeMX配置:

1. 选择 DMA1 的通道 1
2. 地址选择自增
3. 传输数据宽度为 Byte

byte:字节,通用8位,与u8相同

word:字长,与硬件的位数相同,STM32是32位,所以对应是u32

Half Word:半个字长,所以对应是u16

代码实现:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2C2_Init();
  /* USER CODE BEGIN 2 */
	OLED_Init();//OLED初始化
	OLED_CLS();
	
  //显示转运前数据DataA、DataB
	uint8_t DataA[]={1,2,3,4};
	uint8_t DataB[]={0,0,0,0};
	
	OLED_ShowStr(0,0,"DataA:",2);			//显示字符串
  OLED_ShowStr(0,10,"DataB:",2);			//显示字符串
	
	OLED_ShowNum(50, 0, DataA[0], 1, 16);
	OLED_ShowNum(60, 0, DataA[1], 1, 16);
	OLED_ShowNum(70, 0, DataA[2], 1, 16);
	OLED_ShowNum(80, 0, DataA[3], 1, 16);
	
	OLED_ShowNum(50, 10, DataB[0], 1, 16);
	OLED_ShowNum(60, 10, DataB[1], 1, 16);
	OLED_ShowNum(70, 10, DataB[2], 1, 16);
	OLED_ShowNum(80, 10, DataB[3], 1, 16);
	
	// 启动DMA传输
	HAL_DMA_Start(&hdma_memtomem_dma1_channel1, (uint32_t)&DataA,(uint32_t)&DataB, 4);
	
	// 等待传输完成
  HAL_DMA_PollForTransfer(&hdma_memtomem_dma1_channel1,HAL_DMA_FULL_TRANSFER, HAL_MAX_DELAY);
	
	HAL_Delay(1000);//延时显示,方便观看数字变化
	
  OLED_ShowStr(0,0,"DataA:",2);			//显示字符串
  OLED_ShowStr(0,10,"DataB:",2);			//显示字符串
	
	OLED_ShowNum(50, 0, DataA[0], 1, 16);
	OLED_ShowNum(60, 0, DataA[1], 1, 16);
	OLED_ShowNum(70, 0, DataA[2], 1, 16);
	OLED_ShowNum(80, 0, DataA[3], 1, 16);
	
	OLED_ShowNum(50, 10, DataB[0], 1, 16);
	OLED_ShowNum(60, 10, DataB[1], 1, 16);
	OLED_ShowNum(70, 10, DataB[2], 1, 16);
	OLED_ShowNum(80, 10, DataB[3], 1, 16);
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

		

   }
  /* USER CODE END 3 */
}

现象:

1.3、内存外设之间的传输(ADC)

前面讲解ADC的时候已经演示过了:STM32HAL库入门教程——常用外设学习(1)

二、STM32HAL库开发(9)——CubeMX配置RTC

2.1、RTC实时重要一环——BKP 寄存器

BKP寄存器简介
BKP(Backup Registers)备份寄存器
BKP可用于存储用户应用程序数据。当VDD(2.03.6V)电源被切断,他们仍然由
VBAT(1.83.6V)维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时他们也不会被复位
TAMPER引脚产生的侵入事件将所有备份寄存器内容清除
RTC引脚输出RTC校准时钟、RTC闹钟脉冲或者秒脉冲
存储RTC时钟校准寄存器
用户数据存储容量:
20字节(中容量和小容量)/ 84字节(大容量和互联型)

小实验将要实现的现象:单片机掉电后,不会遗忘BKP寄存器中的数值!

硬件连接:(需要额外供电给VB引脚)

第一次先写:

HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,100);
uint32_t Ret= HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1);//断电后靠VBAT供电

OLED_ShowNum(0, 0, Ret, 4, 12);

运行后,第二次注释掉HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,100);并且把单片机供电拔了,继续运行,按道理说,这个Ret数值就会随着单片机断电变成0,但是当VDD电源被切断,他仍然由VBAT维持供电!所以数值会维持不变!

CubeMX配置简单使用BKP寄存器:

BKP 寄存器通常与 RTC 一起使用,在CubeIDE中假如需要使用BKP寄存器,需要先打开RTC

代码实现:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C2_Init();
  MX_RTC_Init();
  /* USER CODE BEGIN 2 */
	OLED_Init();//OLED初始化
	OLED_CLS();
	

//	HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,100);//写BKP
  uint32_t Ret= HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1);//断电后靠VBAT供电。读BKP

  OLED_ShowNum(0, 0, Ret, 4, 12);//显示数值


  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
			
   }
    /* USER CODE END 3 */
}

2.2、RTC实时时钟

CubeMX配置:

1、打开RTC并设置时间

2 、打开外部低速时钟
配置 RTC 时钟源为 LSE 外部低速时钟
代码实现:
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_RTC_Init();
  MX_I2C2_Init();
  /* USER CODE BEGIN 2 */
  RTC_TimeTypeDef RTC_Time ;//时分秒
  RTC_DateTypeDef RTC_Date; //年月日
	
	OLED_Init();
	OLED_CLS();
	OLED_ShowStr(0, 0, "Data:20  -   -", 2);
	OLED_ShowStr(0, 2, "Time:", 2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		HAL_RTC_GetDate(&hrtc, &RTC_Date, RTC_FORMAT_BIN);
		HAL_RTC_GetTime(&hrtc,&RTC_Time, RTC_FORMAT_BIN);
		OLED_ShowNum(57, 0, RTC_Date.Year, 2, 16);
		OLED_ShowNum(78, 0, RTC_Date.Month, 2, 16);
		OLED_ShowNum(100, 0, RTC_Date.Date, 2, 16);
		
		OLED_ShowNum(57, 2, RTC_Time.Hours , 2, 16);
		OLED_ShowNum(78, 2, RTC_Time.Minutes, 2, 16);
		OLED_ShowNum(100, 2, RTC_Time.Seconds, 2, 16);
  }
  /* USER CODE END 3 */
}

效果:

三、STM32HAL库开发(10)——单片机工作模式

3.1、低功耗睡眠模式(Sleep)

使用
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);

打开睡眠模式。由Hal库与标准库在管理系统时钟和低功耗模式时的处理方式不同,Hal库中需要多手动关闭SysTick定时器,因为SysTick定时器会周期性触发中断,会唤醒睡眠模式。

HAL_SuspendTick();//关闭SysTick定时器
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);
HAL_ResumeTick();//恢复SysTick定时器

3.2、低功耗停止模式(Stop)

HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON,PWR_STOPENTRY_WFI);//进入Stop模式
SystemClock_Config();//恢复时钟

3.3、低功耗待机模式(StandBy)

配置 PA0 为唤醒引脚:
代码:
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

while(1)
{
  __HAL_RCC_PWR_CLK_ENABLE();
  HAL_PWR_EnterSTANDBYMode();
}

四、STM32HAL库开发(11)——看门狗

4.1、独立看门狗

打开独立看门狗并设置预分频器和重装值:
HAL_IWDG_Refresh(&hiwdg);//初始化完成后执行一次喂狗
//获取当前的复位是IWDG造成的复位还是按Rst键造成的复位
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET) 
{
    // IWDG reset flag is set
    OLED_ShowString(2, 1, "IWDGRST"); //OLED闪烁IWDGRST字符串
    HAL_Delay(500);
    OLED_ShowString(2, 1, " ");
    HAL_Delay(100);
    __HAL_RCC_CLEAR_RESET_FLAGS();
}
else
{
    OLED_ShowString(3, 1, "RST"); //OLED闪烁RST字符串
    HAL_Delay(500);
    OLED_ShowString(3, 1, " ");
    HAL_Delay(100);
}

while (1)
{
    HAL_IWDG_Refresh(&hiwdg);//喂狗
    HAL_Delay(1100);
}

4.2、窗口看门狗

代码:

//获取当前的复位是WWDG造成的复位还是按Rst键复位,这里代码有大耗时,需要在
MX_WWDG_Init(); 之前
if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET) 
{
    // IWDG reset flag is set
    OLED_ShowString(2, 1, "WWDGRST"); //OLED闪烁IWDGRST字符
    HAL_Delay(500);
    OLED_ShowString(2, 1, " ");
    HAL_Delay(100);
    __HAL_RCC_CLEAR_RESET_FLAGS();
}
else
{
    OLED_ShowString(3, 1, "RST"); //OLED闪烁RST字符
    HAL_Delay(500);
    OLED_ShowString(3, 1, " ");
    HAL_Delay(100);
}

MX_WWDG_Init();
while (1)
{
    HAL_Delay(40);
    HAL_WWDG_Refresh(&hwwdg);//喂狗
    HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);//开
}


http://www.kler.cn/a/545947.html

相关文章:

  • nginx播放视频(auth_request鉴权)
  • Unity3D 类MOBA角色控制器 开箱即用
  • 调用DeepSeek API接口:实现智能数据挖掘与分析
  • 腾讯发布混元-3D 2.0: 首个开源高质3D-DiT生成大模型
  • 机器视觉--Halcon变量的创建与赋值
  • 【ICP/EDI教程】增值电信年报网络信息安全表存档记录 申请的时候对着抄
  • 两步在 Vite 中配置 Tailwindcss
  • 【git-hub项目:YOLOs-CPP】本地实现02:跑通项目了
  • Humanoid Robot Price Break 人形机器人价格突破
  • nats 消息系统架构
  • 【个人开发】cuda12.6安装vllm安装实践【内含踩坑经验】
  • 【自学笔记】人工智能基础知识点总览-持续更新
  • xpath语法以及基本使用
  • npm安装时无法访问github域名的解决方法
  • 视觉定位VPS的现状与未来
  • 华纳云:如何从服务器日志中发现僵尸进程?
  • unity 实时光为什么无法切换为烘焙光
  • html css js网页制作成品——HTML+CSS+js茉酸奶的茶网页设计(5页)附源码
  • 深度整理总结MySQL——Expalin指南(一)
  • OpenCV机器学习(3)期望最大化(Expectation-Maximization, EM)算法cv::ml::EM