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

16:(标准库)ADC三:使用外部触发启动ADC/模拟看门狗

使用外部触发启动ADC

  • 1、外部中断线EXTI11触发ADC
  • 2、外部定时器TIM2_CH2触发ADC
  • 3、ADC中模拟看门狗的使用

1、外部中断线EXTI11触发ADC

ADC的触发方式有很多,一般情况都是使用软件触发反式启动ADC转换。除了软件触发方式还能使用外部事件触发启动ADC转换。如下图所示:
在这里插入图片描述

①EXTI.c文件的代码如下:

#include "EXTI.h"/*** 初始化外部中断线EXTI11,将配置为上升沿触发事件模式*/
void EXTI11_Init(void)
{/* 1、使能GPIOA时钟,AFIO时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);/* 2、配置PA11为下拉输入 */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;GPIO_Init(GPIOA, &GPIO_InitStructure);/* 3、配置EXTI11为上升沿触发事件 */GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource11);	//选择PA11通道进行外部中断EXTI_InitTypeDef EXTI_InitStructure;EXTI_InitStructure.EXTI_Line = EXTI_Line11;					//选择EXTI11EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Event;             //触发事件模式EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;		//上升沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);/* 4、配置NVIC *///事件无需配置NVIC
//    NVIC_InitTypeDef NVIC_InitStructure;
//    NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
//    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
//    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
//    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//    NVIC_Init(&NVIC_InitStructure); 
}

②ADC.c文件的代码如下:

#include "ADC.h"
#include "UART.h"/*** ADC1初始化函数*/
void ADC1_Init(void)
{/* 1、使能GPIOA和ADC时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  //使能ADC1时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);                     //对ADC时钟源分频/* 2、对PA0(ADC1的通道0引脚)进行引脚配置 */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;     //PA0 作为模拟通道输入引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚GPIO_Init(GPIOA, &GPIO_InitStructure);/* 3、配置ADC1工作模式 */ADC_InitTypeDef ADC_InitStructure;ADC_DeInit(ADC1);                                                       //将外设ADC1的全部寄存器重设为缺省值ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                      //ADC1和ADC2工作在独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE;                           //非扫描(单通道)模式ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                     //非连续模式
//  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;     //使用软件触发ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_Ext_IT11_TIM8_TRGO;     //使用外部中断线EXTI11触发ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                  //ADC1数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 1;                                 //转换的ADC通道的数目,只有PA0ADC_Init(ADC1, &ADC_InitStructure);                                     //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器/* 4、配置规则组*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //ADC1,ADC通道,盒子序列1,采样时间为55.5周期/* 5、使能EOC中断,NVIC的配置 */ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = ADC1_2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);/* 使能ADC的外部触发转换 */ADC_ExternalTrigConvCmd(ADC1,ENABLE);			//这一步很重要,不要忘记ADC_Cmd(ADC1, ENABLE);               			//使能ADC1/* 5、ADC校准 */ADC_ResetCalibration(ADC1);                     //使能复位校准while (ADC_GetResetCalibrationStatus(ADC1));    //等待复位校准结束ADC_StartCalibration(ADC1);                     //开启AD校准while (ADC_GetCalibrationStatus(ADC1));         //等待校准结束//    /* 6、软件触发 */
//    ADC_SoftwareStartConvCmd(ADC1, ENABLE);       //启动ADC转换
}/*** ADC单通道转换完成的中断服务函数*/
uint16_t Data = 0;
uint8_t Satatus_Flag = 0;
void ADC1_2_IRQHandler (void)
{if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == SET)//转换完成标志位EOC置1{ADC_ClearFlag(ADC1, ADC_FLAG_EOC);  		//清除标志位EOCData = ADC_GetConversionValue(ADC1);		//获取结果寄存器中的数据Satatus_Flag = 1;                   		//转换完成标志位}
}

③ADC.h文件的代码如下:

#ifndef __ADC_H
#define __ADC_H
#include "stm32f10x.h" extern uint16_t Data;
extern uint8_t Satatus_Flag;
void ADC1_Init(void);#endif

④主函数main.c文件的代码如下:

#include "stm32f10x.h"                 
#include "UART.h"
#include "ADC.h"
#include "EXTI.h"int main(void)
{float ADC_Value = 0;UART1_Init();ADC1_Init();EXTI11_Init();printf("ADC电压测量\r\n");while(1){if(Satatus_Flag){Satatus_Flag = 0;printf("结果寄存器数值为:%d\r\n",Data);ADC_Value = Data * 3.3 / 4095;              //将二进制计数为电压电压值printf("测量到的电压为:%0.2f\r\n",ADC_Value); }}
}

在这里插入图片描述

2、外部定时器TIM2_CH2触发ADC

①TIM.c文件的代码如下:

#include "TIM.h"/*** 定时器TIM2的初始化:使用PWM模式1产生上升沿触发ADC*/
void TIM2_Init(void)
{/* 1、使能TIM2的时钟 */RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);/* 2,对时基单元的初始化 */TIM_InternalClockConfig(TIM2);                                 //选择内部时钟源TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;       //时钟源分频,则为72MHzTIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;   //向上计数TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1;               //预分频器,计数分辨率为0.1msTIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;                 //重装载值为10000,则计数周期为1sTIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0;              //重复计数器(高级定时器才配置)TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);               /* 3、对TIM2的输出比较单元CH2进行配置 */TIM_OCInitTypeDef TIM_OCInitStruct;TIM_OCStructInit(&TIM_OCInitStruct);                            //给结构体默认初始值TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;                  //选择PWM1模式TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;          //有效值配置极性为低电平TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;      //通道使能TIM_OCInitStruct.TIM_Pulse = 5000;                              //CCR的初始值TIM_OC2Init(TIM2, &TIM_OCInitStruct);                           //配置CH2TIM_Cmd(TIM2,ENABLE);                                           //使能定时器}

②ADC.c文件的代码如下:

#include "ADC.h"/*** ADC1初始化函数*/
void ADC1_Init(void)
{/* 1、使能GPIOA和ADC时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  //使能ADC1时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);                     //对ADC时钟源分频/* 2、对PA0(ADC1的通道0引脚)进行引脚配置 */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;     //PA0 作为模拟通道输入引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚GPIO_Init(GPIOA, &GPIO_InitStructure);/* 3、配置ADC1工作模式 */ADC_InitTypeDef ADC_InitStructure;ADC_DeInit(ADC1);                                                       //将外设ADC1的全部寄存器重设为缺省值ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                      //ADC1和ADC2工作在独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE;                           //非扫描(单通道)模式ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                     //非连续模式
//  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;     //使用软件触发ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;   //使用TIM2_CH2触发ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                  //ADC1数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 1;                                 //转换的ADC通道的数目,只有PA0ADC_Init(ADC1, &ADC_InitStructure);                                     //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器/* 4、配置规则组*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //ADC1,ADC通道,盒子序列1,采样时间为55.5周期/* 5、使能EOC中断,NVIC的配置 */ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = ADC1_2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);/* 使能ADC的外部触发转换 */ADC_ExternalTrigConvCmd(ADC1,ENABLE);//这一步很重要,不要忘记ADC_Cmd(ADC1, ENABLE);               //使能ADC1/* 5、ADC校准 */ADC_ResetCalibration(ADC1);                     //使能复位校准while (ADC_GetResetCalibrationStatus(ADC1));    //等待复位校准结束ADC_StartCalibration(ADC1);                     //开启AD校准while (ADC_GetCalibrationStatus(ADC1));         //等待校准结束//    /* 6、软件触发 */
//    ADC_SoftwareStartConvCmd(ADC1, ENABLE);       //启动ADC转换
}/*** ADC单通道转换完成的中断服务函数*/
uint16_t Data = 0;
uint8_t Satatus_Flag = 0;
void ADC1_2_IRQHandler (void)
{if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == SET)//转换完成标志位EOC置1{ADC_ClearFlag(ADC1, ADC_FLAG_EOC);  //清除标志位EOCData = ADC_GetConversionValue(ADC1);//获取结果寄存器中的数据Satatus_Flag = 1;                   //转换完成标志位}
}

③主函数main.c文件的代码如下:

#include "stm32f10x.h"                 
#include "UART.h"
#include "ADC.h"
#include "TIM.h"int main(void)
{float ADC_Value = 0;UART1_Init();ADC1_Init();TIM2_Init();printf("ADC电压测量\r\n");while(1){if(Satatus_Flag){Satatus_Flag = 0;printf("结果寄存器数值为:%d\r\n",Data);ADC_Value = Data * 3.3 / 4095;              //将二进制计数为电压电压值printf("测量到的电压为:%0.2f\r\n",ADC_Value); }}
}

在这里插入图片描述
使用定时器的PWM模式触发,每隔1s触发一次,因为定时器的定时器周期配置的为1s。

3、ADC中模拟看门狗的使用

在这里插入图片描述
如图:在ADC中有一个模拟看门狗,用于监测着结果寄存器的数值。用户可以设定一个寄存器的上限值和下限值,当寄存器的值大于上限值/小于下限值时,看门狗就会将标志位AWD置1,若开启了模拟看门狗中断,则会进入ADC中断。
①ADC.c文件的代码如下:

#include "ADC.h"
#include "UART.h"/*** ADC1初始化函数*/
void ADC1_Init(void)
{/* 1、使能GPIO和ADC时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  //使能ADC1时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6);//对ADC时钟源分频/* 2、对PA0(ADC1的通道0引脚)进行引脚配置 */GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;     //PA0 作为模拟通道输入引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚GPIO_Init(GPIOA, &GPIO_InitStructure);/* 3、配置ADC1工作模式 */ADC_InitTypeDef ADC_InitStructure;ADC_DeInit(ADC1);                                                       //将外设ADC1的全部寄存器重设为缺省值ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                      //ADC1和ADC2工作在独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE;                           //非扫描(单通道)模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                      //连续模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;     //转换由软件而不是外部触发启动ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                  //ADC1数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 1;                                 //转换的ADC通道的数目,只有PA0ADC_Init(ADC1, &ADC_InitStructure);                                     //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器/* 4、配置规则组*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //ADC1,ADC通道,盒子序列1,采样时间为55.5周期/* 5、配置模拟看门狗:上限为3.0v,下限为2.0v */ADC_AnalogWatchdogThresholdsConfig(ADC1,0x09B1,0x0EBA);         //配置监测的上下限,注意:监测的是结果寄存器的值ADC_AnalogWatchdogSingleChannelConfig(ADC1,ADC_Channel_0);      //监测通道0ADC_AnalogWatchdogCmd(ADC1,ADC_AnalogWatchdog_SingleRegEnable); //使能单个规则组模拟看门狗/* 6、使能EOC和AWD中断,NVIC的配置 */ADC_ITConfig(ADC1, ADC_IT_AWD, ENABLE);             //使能看门狗中断ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);             //使能ADC转换完成中断NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel = ADC1_2_IRQn;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);ADC_Cmd(ADC1, ENABLE);                          //使能ADC1/* 7、ADC校准 */ADC_ResetCalibration(ADC1);                     //使能复位校准while (ADC_GetResetCalibrationStatus(ADC1));    //等待复位校准结束ADC_StartCalibration(ADC1);                     //开启AD校准while (ADC_GetCalibrationStatus(ADC1));         //等待校准结束/* 8、软件触发 */ADC_SoftwareStartConvCmd(ADC1, ENABLE);         //启动ADC转换
}/*** ADC单通道转换完成和模拟看门狗的中断范围函数*/
void ADC1_2_IRQHandler (void)
{/* 转换完成 */if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC))   //转换完成标志位EOC置1{ADC_ClearFlag(ADC1, ADC_FLAG_EOC);      //清除标志位EOCprintf("结果寄存器数值为:%d\r\n",ADC_GetConversionValue(ADC1));                //打印结果寄存器的值printf("测量到的电压为:%0.2f\r\n",ADC_GetConversionValue(ADC1) * 3.3 / 4095);  //打印电压值}/* 模拟看门狗监测到超过阈值 */if(ADC_GetFlagStatus(ADC1, ADC_FLAG_AWD)){ADC_ClearFlag(ADC1, ADC_FLAG_AWD);      //清除标志位AWD//LED翻转  }
}

②主函数main.c文件的代码如下:

#include "stm32f10x.h"                 
#include "ADC.h"int main(void)
{ADC1_Init();printf("ADC电压监测\r\n");while(1){}
}

http://www.mrgr.cn/news/77969.html

相关文章:

  • 【大数据学习 | Spark-Core】Spark的分区器(HashPartitioner和RangePartitioner)
  • LeetCode 3244.新增道路查询后的最短距离 II:贪心(跃迁合并)-9行py(O(n))
  • 读书笔记_《创华为.任正非传》_精华书摘
  • 哈工大计算机系统大作业——程序人生-Hello’s P2P
  • 字符三角形
  • 简单的MCU与FPGA通过APB总线实现通讯(fpga mcu APB):乘法器为例
  • [OpenHarmony5.0][环境][教程]OpenHarmony 5.0源码在WSL2 Ubuntu22.04 编译环境搭建教程
  • C++设计模式-策略模式-StrategyMethod
  • 分割一切2.0,SAM2详解
  • 接口性能优化宝典:解决性能瓶颈的策略与实践
  • java 二分查找 方法 详解
  • 虚幻引擎---术语篇
  • 4.SynchronousMethodHandler
  • Spring Boot 动态数据源切换
  • 十一、排他思想、window、延时定时器、间歇函数、时间戳、location、navigator、history、本地存储localStorage
  • C++设计模式-享元模式
  • 安装 Docker(使用国内源)
  • 从0开始学PHP面向对象内容之常用设计模式(适配器,桥接,装饰器)
  • 大模型系列11-ray
  • 疑难Tips:NextCloud域名访问登录时卡住,显示违反内容安全策略
  • k8s网络服务
  • C#设计模式——抽象工厂模式(重点)
  • Vue3响应式原理
  • Springboot项目搭建-Maven打包编译
  • 演示如何使用 `nn.CrossEntropyLoss` 来计算交叉熵损失,计算损失值的演示代码,和讲解 ,CrossEntropyLoss 损失数值等于零的原因
  • hugo文章支持数学公式