5 STM32F407ZG连接MODBUS模块实现ADC模数转换

0 实现结果说明

STM32F407ZG的adc模数转换,采集modbus模块的模拟量,把采集的数据通过串口通信发到串口小助手。每次采集的时候,led都会闪一下。

1 视频

https://www.bilibili.com/video/BV1uB4y1y78H/

STM32F407adc模数转换,采集modbus模块的模拟量,把采集的数据通过串口通信发到串口小助手。每次采集的时候,led都会闪一下。

2 ADC的基本原理

ADC是Analog-to-Digital Converter的缩写。指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。
典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。

2.1 ADC的特点

在这里插入图片描述

2.2 STM32F40x系列ADC外部通道和引脚对应关系

在这里插入图片描述

2.3 ADC引脚

在这里插入图片描述

2.4 STM32通道组

  1. 规则通道组:相当正常运行的程序。最多16个通道。规则通道和它的转换顺序在ADC_SQRx寄存器中选择,规则组转换的总数应写入ADC_SQR1寄存器的L[3:0]中
  2. 注入通道组:相当于中断。最多4个通道。注入组和它的转换顺序在ADC_JSQR寄存器中选择。注入组里转化的总数应写入ADC_JSQR寄存器的L[1:0]中。
  3. 如图在这里插入图片描述

2.5 单次转化VS 连续转换

STM32F4的ADC的各通道可以单次,连续,扫描
或者间断模式执行。

在这里插入图片描述
在这里插入图片描述

2.6 扫描模式

在这里插入图片描述

3 ADC相关的寄存器

3.1 ADC_CR1控制寄存器1

在这里插入图片描述
在扫描模式下,由ADC_SQRx或者ADC_JSQRx寄存器选中的通道被转换。如果设置了EOCIE或者JEOCIE为0,在最后一个通道转换完毕后才会产生EOC或者JEOC中断。

结构体里面的成员 : ADC_ScanConvMode在这里插入图片描述

STM官方定义
在这里插入图片描述

3.2 ADC_CR2寄存器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
STM官方定义
在这里插入图片描述

3.3 ADC_SMPR1/2寄存器

在这里插入图片描述

3.4 ADC_SQR1/SQR2/SQR3规则序列寄存器

在这里插入图片描述

3.5 ADC_JSQR注入系列寄存器

在这里插入图片描述

4 ADC的采样时间

在这里插入图片描述
最小采样时间0.42us(ADC时钟=36MHz,采样周期为3周期下得到)

5 ADC函数说明

5.1 ADC通用初始化函数ADC_CommonInit

void ADC_CommonInit(ADC_CommonInitTypeDef* ADC_CommonInitStruct);

typedef struct 
{
  uint32_t ADC_Mode;//多重ADC模式选择
 uint32_t ADC_Prescaler;  //ADC预分频                              
  uint32_t ADC_DMAAccessMode;   //DMA访问模式        
  uint32_t ADC_TwoSamplingDelay; //2个采样阶段之间的延迟       
}ADC_CommonInitTypeDef;

这些参数用来配置ADC_CCR寄存器的相关参数
例:

ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟    ADC_CommonInitStructure.ADC_DMAAccessMode  = ADC_DMAAccessMode_Disabled; //DMA失能
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
ADC_CommonInit(&ADC_CommonInitStructure);

5.2 ADC初始化函数ADC_Init

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);

typedef struct
{
 uint32_t ADC_Resolution;//ADC分辨率
  FunctionalState ADC_ScanConvMode; //是否使用扫描模式。ADC_CR1位8:SCAN位 
  FunctionalState ADC_ContinuousConvMode; //单次转换OR连续转换:ADC_CR2的位1:CONT
  uint32_t ADC_ExternalTrigConvEdge; //外部触发使能方式:ADC_CR2的位29:28,EXTEN
  uint32_t ADC_ExternalTrigConv;  //触发方式:ADC_CR2的位[19:17] :EXTSEL[2:0]                
  uint32_t ADC_DataAlign;   //对齐方式:左对齐还是右对齐:ADC_CR2的位11:ALIGN         
  uint8_t ADC_NbrOfChannel;//规则通道序列长度:ADC_SQR1的位[23:20]: L[3:0]       
}ADC_InitTypeDef;

例:

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式	
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐	
  ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中 
  ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化

5.3 ADC使能函数 ADC_Cmd();

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
例:

ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC1

5.4 ADC使能软件转换函数 ADC_SoftwareStartConvCmd

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState)
例:

ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能ADC1的软件转换启动

5.5 ADC 获取转换结果函数ADC_GetConversionValue

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
例:

ADC_GetConversionValue(ADC1);//获取ADC1转换结果

6 设置ADC的步骤:

  1. 开启PA口时钟和ADC1时钟,设置PA1为模拟输入。
    RCC_AHB1PeriphClockCmd (RCC_AHB1Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    GPIO_Init();
  2. 复位ADC1,同时设置ADC1分频因子。
    ADC_DeInit(ADC1);
  3. 初始化ADC_CCR寄存器。
    ADC_CommonInit();
  4. 初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息。
    void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
  5. 使能ADC。
    ADC_Cmd(ADC1, ENABLE);
  6. 配置规则通道参数:
    ADC_RegularChannelConfig();
  7. 开启软件转换:ADC_SoftwareStartConvCmd(ADC1);
  8. 等待转换完成,读取ADC值。
    ADC_GetConversionValue(ADC1);

7 具体实现代码:

adc.h

#ifndef __ADC_H
#define __ADC_H
#include "sys.h" 

#define ADC_CH5 5 //通道 5 
void Adc_Init(void); //ADC 初始化
u16 Get_Adc(u8 ch); //获得某个通道值
u16 Get_Adc_Average(u8 ch,u8 times);//得到某个通道给定次数采样的平均值 
#endif

adc.c

#include "adc.h"
#include "sys.h"
#include "delay.h"


void Adc_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStruct;
	ADC_InitTypeDef  ADC_InitStructure;

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//使能ADC1时钟
 	//ADC1端口配置
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //GPIOA5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //上拉
	GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA5
  //adc复位
  ADC_DeInit();
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);	  //ADC1复位
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);	//复位结束	 
 
  ADC_CommonInitStruct.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;//DMA失能
	ADC_CommonInitStruct.ADC_Mode=ADC_Mode_Independent; //独立模式
	ADC_CommonInitStruct.ADC_Prescaler=ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz 
	ADC_CommonInitStruct.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟

  ADC_CommonInit(&ADC_CommonInitStruct); //初始化
  

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式	
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐	
  ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中 也就是只转换规则序列1 
  ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化
	
  ADC_Cmd(ADC1,  ENABLE);//开启AD转换器	
}

//获得ADC值
//ch: @ref ADC_channels 
//通道值 0~16取值范围为:ADC_Channel_0~ADC_Channel_16
//返回值:转换结果
u16 Get_Adc(u8 ch)
{
//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1,  ch,  1, ADC_SampleTime_480Cycles);//ADC1,ADC通道,480个周期,提高采样时间可以提高精确度
	ADC_SoftwareStartConv(ADC1);		//使能指定的ADC1的软件转换启动功能	
	 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}

//获取通道ch的转换值,取times次,然后平均 
//ch:通道编号
//times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_Adc_Average(u8 ch, u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val +=Get_Adc(ch);
		delay_ms(5);
	}
	return temp_val/times;

}

main.c

#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "r232.h"
#include "adc.h"
#include "led.h"

void USART2_IRQHandler(void);

//中断处理函数
void USART2_IRQHandler(void)
{
	u16 adcx;
  u8 res;

	 if (USART_GetFlagStatus(USART2, USART_FLAG_PE) != RESET)
   {
     USART_ReceiveData(USART2);
     USART_ClearFlag(USART2, USART_FLAG_PE);
   }
    
   if (USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)
   {
     USART_ReceiveData(USART2);
     USART_ClearFlag(USART2, USART_FLAG_ORE);
   }
    
    if (USART_GetFlagStatus(USART2, USART_FLAG_FE) != RESET)
   {
      USART_ReceiveData(USART2);
      USART_ClearFlag(USART2, USART_FLAG_FE);
   }

	if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET )
	{
		GPIO_ResetBits(GPIOF,GPIO_Pin_13);
		adcx=Get_Adc_Average(ADC_Channel_5,30);//获取通道5的转换值,30次取平均
		USART_SendData(USART2,adcx);
		GPIO_ResetBits(GPIOF,GPIO_Pin_14);
		delay_ms(250);
		USART_ClearFlag(USART2,USART_IT_RXNE);
  }
	
	GPIO_SetBits(GPIOF, GPIO_Pin_14 );
}

int main(void)
{
 //配置中断优先分组

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	delay_init(50); 
	LED_Init();
	My_USART2_Init();
	Adc_Init();

	while(1)
	{
		
	}
}

8 ADC模数转换项目文件下载

https://download.csdn.net/download/qq_50808730/85574161

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

常驻客栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值