栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

STM32复习笔记(十二) —— ADC(EXTI事件触发)采集电压

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

STM32复习笔记(十二) —— ADC(EXTI事件触发)采集电压

STM32复习笔记(十二) —— ADC(EXTI事件触发)采集电压

1.ADC 模块框图 (STM32F10xxx参考手册 图24 单个ADC框图)


2.ADC 引脚 (STM32F10xxx参考手册 表62 ADC引脚)

3.本例程软件设计思路

1)使用软件触发 ADC (连续)转换,通过 (规则) 通道1检测加于此通道引脚的电压值
2)开启转换完成中断,在中断中读取转换后的电压 AD 值
3)通过计算,将 AD 值转换成真实电压值输出

注意:此处测量的电压范围仅适用于 0 - 3.3V,不得高于 3.3V

4.代码编写

于 main.c 中编写代码

#include "stm32f10x.h"
#include "dr_usart.h"


uint16_t ADC_CurrentValue = 0;


float ADC_RealValue = 0.0;


static void delay_(uint32_t count);

static void ADC_NVIC_Config(void)
{
  
  NVIC->IP[18] = ((uint8_t)6 << 4);
	
  
  NVIC->ISER[0]|=((uint32_t)0x01 << 18);
}

void ADC1_GPIO_Config(void)
{
  
  RCC->APB2ENR |= ((uint16_t)0x01 << 2);
	
  
  GPIOA->CRL &= ~((uint32_t)0x0f << 4);
  GPIOA->CRL |=  ((uint32_t)0x00 << 4);
}

void ADC1_Config(void)
{
  
  ADC1_GPIO_Config();
	
  
  RCC->APB2ENR |= ((uint16_t)0x01 << 9);
	
  
  ADC1->CR1 &= ~((uint32_t)0x0f << 16);
	
  
  ADC1->CR1 &= ~((uint32_t)0x01 << 8);
	
  
  ADC1->CR2 &= ~((uint32_t)0x01 << 20);
	
  
  ADC1->CR2 &= ~((uint32_t)0x01 << 11);	
	
  
  ADC1->CR2 |= ((uint32_t)0x01 << 1);
	
  
  ADC1->SQR1 &= ~((uint32_t)0x0f << 20);
	
  
  RCC->CFGR |= ((uint32_t)0x03 << 14);
	
  
  ADC1->SMPR2 |= ((uint32_t)0x07 << 3);
	
  
  ADC1->SQR3 |=  ((uint32_t)0x01 << 0);

  
  ADC1->CR1 |= ((uint32_t)0x01 << 5);

  
  ADC1->CR2 |=  ((uint32_t)0x01 << 0);
	
  
  ADC1->CR2 |= ((uint32_t)0x01 << 3);

  
  while(0 != (ADC1->CR2 & ((uint32_t)0x01 << 3)));
	
  
  ADC1->CR2 |= ((uint32_t)0x01 << 2);

  
  while(0 != (ADC1->CR2 & ((uint32_t)0x01 << 2)));

  
  ADC1->CR2 |=  ((uint32_t)0x01 << 0);
}

int main(void)
{
  User_Init(); 

  
  ADC1_Config();

  
  ADC_NVIC_Config();
	
  while(1)
  {
    
    ADC_RealValue = (float)ADC_CurrentValue/4096*3.3 + 0.005;

    
    printf("ADC_CurrentValue = %d.rn", ADC_CurrentValue);	

    
    printf("ADC_RealValue = %.2f V.rn", ADC_RealValue);

    
    delay_(100);
  }
}

void ADC1_2_IRQHandler(void)
{
  
  if(2 == (ADC1->SR & ((uint32_t)0x01 << 1)))
  {
    
    ADC_CurrentValue = (uint16_t)ADC1->DR;
  }
}


static void delay_(uint32_t count)
{
  __IO uint32_t delay_count = (12000 * count);
	
  while(delay_count--);
}

点击编译,如无错误可进入仿真界面

查看 ADC DR 寄存器,此寄存器存储了规则通道转换后的 AD 值

可以看出,目前此处值为0

点击运行,此处仍为0 (检测电压的 IO 口此时并未连接要测量的电压)

打开串口,此时串口输出为0

将 1V 电压加于此通道,观察 ADC DR 寄存器值 and 串口输出值,此时已测出电压值


将电压加到 2V,可以看出 ADC DR 寄存器值 and 串口输出值已经改变


停止并退出仿真界面,修改程序为使用外部事件触发转换 (EXTI 中断线11触发)

于 main.c 中编写代码 (单次转换模式)

uint16_t ADC_CurrentValue = 0;


float ADC_RealValue = 0.0;


static void delay_(uint32_t count);

static void ADC_NVIC_Config(void)
{
  
  NVIC->IP[18] = ((uint8_t)6 << 4);
	
  
  NVIC->ISER[0]|=((uint32_t)0x01 << 18);
}

void ADC1_GPIO_Config(void)
{
  
  RCC->APB2ENR |= ((uint16_t)0x01 << 2);
	
  
  GPIOA->CRL &= ~((uint32_t)0x0f << 4);
  GPIOA->CRL |=  ((uint32_t)0x00 << 4);
}

static void ADC_EXTI_Config(void)
{
  
  RCC->APB2ENR |= ((uint16_t)0x01 << 2);
	
  
  GPIOA->CRH &= ~((uint32_t)0x0f << 12);
  GPIOA->CRH |=  ((uint32_t)0x04 << 12);
	
  
  RCC->APB2ENR |= ((uint16_t)0x01 << 0);
	
  
  AFIO->EXTICR[3] &= ~((uint32_t)0x0f << 12);
	
  
  AFIO->MAPR &= ~((uint32_t)0x01 << 18);
	
  
  EXTI->EMR |= ((uint32_t)0x01 << 11);
	
  
  EXTI->FTSR |= ((uint32_t)0x01 << 11);
}

void ADC1_Config(void)
{
  
  ADC1_GPIO_Config();
	
  
  RCC->APB2ENR |= ((uint16_t)0x01 << 9);
	
  
  ADC1->CR1 &= ~((uint32_t)0x0f << 16);
	
  
  ADC1->CR1 &= ~((uint32_t)0x01 << 8);
	
  
  ADC1->CR2 |= ((uint32_t)0x0e << 17);
	
  
  ADC1->CR2 &= ~((uint32_t)0x01 << 11);	
	
  
  ADC1->CR2 &= ~((uint32_t)0x01 << 1);
	
  
  ADC1->SQR1 &= ~((uint32_t)0x0f << 20);
	
  
  RCC->CFGR |= ((uint32_t)0x03 << 14);
	
  
  ADC1->SMPR2 |= ((uint32_t)0x07 << 3);
	
  
  ADC1->SQR3 |=  ((uint32_t)0x01 << 0);

  
  ADC1->CR1 |= ((uint32_t)0x01 << 5);

  
  ADC1->CR2 |=  ((uint32_t)0x01 << 0);
	
  
  ADC1->CR2 |= ((uint32_t)0x01 << 3);

  
  while(0 != (ADC1->CR2 & ((uint32_t)0x01 << 3)));
	
  
  ADC1->CR2 |= ((uint32_t)0x01 << 2);

  
  while(0 != (ADC1->CR2 & ((uint32_t)0x01 << 2)));
}

int main(void)
{
  User_Init(); 

  
  ADC1_Config();
	
  
  ADC_EXTI_Config();

  
  ADC_NVIC_Config();
	
  while(1)
  {
    
    ADC_RealValue = (float)ADC_CurrentValue/4096*3.3 + 0.005;

    
    printf("ADC_CurrentValue = %d.rn", ADC_CurrentValue);	

    
    printf("ADC_RealValue = %.2f V.rn", ADC_RealValue);

    
    delay_(100);
  }
}

void ADC1_2_IRQHandler(void)
{
  
  if(2 == (ADC1->SR & ((uint32_t)0x01 << 1)))
  {
    
    ADC_CurrentValue = (uint16_t)ADC1->DR;
  }
}


static void delay_(uint32_t count)
{
  __IO uint32_t delay_count = (12000 * count);
	
  while(delay_count--);
}

点击编译,如无错误再进入仿真界面,点击运行 (外加 3V 电压)

此时并未触发转换,所以未能读出 AD 值,显示为0

通过 EXTI 中断线11触发 (可以是外接的按键按下一次) 一次转换,此时再查看输出值

可以看出输出值已经改变,此时将外加电压调至 3.3 V,但并不会改变输出值,因为此处设定的为单次转换模式,即触发一次只转换一次

先查看电压是否已调至 3.3V


可以看出,引脚上电压值已变为 3.3V,但输出值仍为 3V

此时再触发一次转换,输出值已经改变

5.本篇总结

共设计了两个例程:1) 软件触发 ADC 转换 2) EXTI 外部事件触发 ADC 转换

经验证,程序运行结果均与预想一致

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/330118.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号