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

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;					//选择EXTI11
    EXTI_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通道的数目,只有PA0
    ADC_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);  		//清除标志位EOC
        Data = 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;       //时钟源分频,则为72MHz
    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;   //向上计数
    TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1;               //预分频器,计数分辨率为0.1ms
    TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1;                 //重装载值为10000,则计数周期为1s
    TIM_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);                           //配置CH2

	TIM_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通道的数目,只有PA0
    ADC_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);  //清除标志位EOC
        Data = 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通道的数目,只有PA0
    ADC_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);      //监测通道0
    ADC_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);      //清除标志位EOC
        printf("结果寄存器数值为:%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.kler.cn/a/408713.html

相关文章:

  • PyQt学习笔记
  • HTML5好看的音乐播放器多种风格(附源码)
  • C++ 中数组作为参数传递时,在函数中使用sizeof 为什么无法得到数组的长度
  • Spring |(四)IoC/DI配置管理第三方bean
  • Unity-添加世界坐标系辅助线
  • RabbitMQ实现异步下单与退单
  • CTF之密码学(Polybius密码)
  • 241124_基于MindSpore学习GPT2
  • C++ std::unique_ptr的使用及源码分析
  • 【Spring源码核心篇-03】精通spring的aop的底层原理和源码实现
  • c++(入门)
  • 群核科技首次公开“双核技术引擎”,发布多模态CAD大模型
  • 从零开始:使用 Spring Boot 开发图书管理系统
  • pip 与当前python环境版本不匹配, pyenv, pipenv, conda
  • 速盾:海外服务器使用CDN加速有什么优势?
  • [Python3学习笔记-基础语法] Python3 基础语法
  • Excel如何批量导入图片
  • UE5中T_noise 纹理的概述
  • 前端把dom页面转为pdf文件下载和弹窗预览
  • C语言蓝桥杯组题目
  • transformer.js(一):这个前端大模型运行框架的可运行环境、使用方式、代码示例以及适合与不适合的场景
  • C#里怎么样使用多线程读取多文件?
  • 深度学习实战图像缺陷修复
  • 二分查找的几种寻找情况
  • 逻辑像素与物理像素——canvas缩放后绘图区域的长宽究竟是多少
  • draggable的el-dialog实现对话框标题可以选择