今天需要了解下A/D转换模块。大概就是ADC或者DAC。

一般来说除了老版的51单片机,现在的单片机大多都是自带AD转换的。主要是电压的变化,弄成数字变化,就可以进行编程了。

详细的说明就:

ADC:将时间和幅值连续的模拟量转化为时间和幅值离散的数字量,A/D转换一般要经过采样、保持、量化、编码4个步骤。

其中常用的一般类型就不再赘述了。反正也记不住。一般我们考虑的就是用到的时候在取看一下手册。

一般来讲有以下几个基本的技术指标:

量程:即它可以测量的电压范围,信号类型这种参考类的参数。信号包括了单极性和双极性。

转换位数:量化过程中的量化位数n(听不懂没啥,就是AD转换之后A/D用多少位来表示):比如10位AD就是0-1023;

分辨率:能分辨的最小变化量。分辨率=量程/2n;有些低功耗的物件,需要更小的电压变化量,这时候你就需要更高转换位数的AD了。

转换时间:一次AD转换的全过程所需要的时间。

那么接下来讲讲AD转换的基本过程:

采样:把连续的模拟信号,编程一种数字信号,就是一根一根的。这个东西我记得《信号与系统》或者《自动化原理》里都有讲,所以需要大家去学习一下。

之后就开始保持信号状态,然后进行量化和编码。就慢慢从模拟信号编程数字信号了。

咋解释呢,就是我通过傅里叶拉氏变换这些变化之后,现在我的信号已经变成离散的了。我需要一点一点来得出每一部分的一个数字信号,这个过程就需要我的信号在一段时间内保持住才可以。

当然这个过程,可以理解为啥函数每一个点来求微分的一个过程,只不过用滤波的思维去思考感觉会好一点。

然后整个过程是存在量化和编码误差的,这无法避免。不过分辨率越高,整个过程就误差越小。

一般来说,ADC的一个采样可以通过反馈的数据,来得到目前的电压值。我们可以简单讲一讲。因为我记得这个是我本科EDA需要学的东西.系统里可以通过现有的程序,已经给你算好了。不过同样的可以理解下,加深印象。

比如,一个温度传感器模块,范围为0-100度,参考电压是5V,AD转换器是8位的,0度是测得温度1.8V,100度时测的温度时4.3V,这时候我们需要求他的分辨率以及采集数据比如说时10010001的时候,多大的电压和温度?

电压分辨率:5 X 1/28=0.0195V;

温度分辨率:0.0195 X 40=0.78℃;

假设变化时Y=kX+B这样的线性变化;

求一下斜率k=(100-0)/(4.3-1.8)=40;

所以说就可以求的Y=40 X (x - 1.8);

所以说最后求的温度时(二进制)10010001=(十进制)145;

所以:0.0195 X 145=2.83V;

所以:(2.83-1.8)X 40=41.2℃;

STM32的ADC资源

(以下来自其他的资料,简单阐述下)一般来说,这个我们可以看芯片手册上的东西。比如STM32F103上面就有ADC1/2/3的共三个12位逐次逼近型模数转换器。具有18个测量通道。可以测量16个外部和2个内部的信号。其中呢,只有ADC1可以测量这两个信号源。

各个ADC通道中,A/D转换可以单次、连续、扫描、间断模式进行执行。

按照A/D转换的组织形式来说,ADC的模拟输入通道分为规则组和注入组:

规则组:ADC可以对一组最多16个通道按照指定的一个顺序进行逐个转换,这组指定通道称为规则组。

注入组:如果说需要中断规则组的转换,临时对某些通道进行转换,好像这些通道注入了原来的规则组,就称为注入组。一般来说,没咋用。最多有4个。

那么接下来,我们来配置一下。

ADC:一般来说12位,右对齐,然后使能个中断就行了。

然后需要了解下AD的一个查询方式。

一般来说ADC和USART一样,存在阻塞式的查询方式和非阻塞式的查询方式。

主要来看看这两种函数的结构:

阻塞式:

Uint_16 ADC_Value = 0;

HAL_ADC_Start(&hadc);

If(HAL_OK == HAL_ADC_PollForConversion(&hadc,10))

{

ADC0_Value = HAL_ADC_GetValue(&hadc);

}

非阻塞式:

Uint_16 ADC_Value(&hadc);

Void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef*hadc1)

{

ADC0_Value = HAL_ADC_GetValue(&hadc);

那么接下来,同样的做一个简单的例子。用到采样来实现功能。

首先ADC设置为12位,右对齐,中断使能

分别使用查询和中断,每0.5S检测ADC数据

每次读取的ADC采样值转换为电压值发送到上位机

LED1作为采样的指示灯,在ADC转换中点亮,其余时间熄灭。

那么接下来,根据题目,我觉得需要配置一个0.5s的定时器,一个LED的输出,ADC以及串口发送数据。那么大致我看来就是这几个操作。

接下来,我把核心的代码发在下面,大家作为一个参考。

#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"

void SystemClock_Config(void);
#define LED1_ON() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_RESET);//两个宏定义,用于定义LED的开关亮灭
#define LED1_OFF() HAL_GPIO_WritePin(GPIOC,GPIO_PIN_2,GPIO_PIN_SET);

uint16_t ADC_Value =0,ADC_Volt =0;//这是初始化的两个值,分别用于计算采样值和电压值
uint8_t str_buff[64];//用于字符串的格式化
void UR1_Send_Info()
{
	sprintf((char*)str_buff,"采样值: %d,电压值: %d.%d%dV\r\n",ADC_Value,ADC_Volt/100,(ADC_Volt%100)/10,ADC_Volt%10);
	
	HAL_UART_Transmit(&huart1,str_buff,sizeof(str_buff),10000);
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){
	
	if(hadc->Instance == ADC1)
	{
		ADC_Value = HAL_ADC_GetValue(&hadc1);
		ADC_Volt =ADC_Value*330/4096;
		UR1_Send_Info();
		LED1_OFF();
	}
}




/*下面我进行注释的时通过查询的方式进行的采样*/
/*void ADC0_GET_VALUE()
{
	HAL_ADC_Start(&hadc1);//初始化
	LED1_ON();//初始化后点灯
	if(HAL_ADC_PollForConversion(&hadc1,10)==HAL_OK)//如果ADC转换查询正常
	{
		ADC_Value = HAL_ADC_GetValue(&hadc1);//那么就读取ADC此时的值
		ADC_Volt = ADC_Value * 3300/4096;//计算电压值,3300就是3300mV,4096就是2的12次方
	}
	UR1_Send_Info();
	LED1_OFF();
	HAL_ADC_Stop(&hadc1);


}*/


/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();

  while (1)
  {
    /* USER CODE END WHILE */
	/*ADC0_GET_VALUE();
	HAL_Delay(500);*/
	
	  
	LED1_ON(); 
	HAL_ADC_Start_IT(&hadc1);
	HAL_Delay(500);
  }
}

今天在实验室加班到了11:00,现在还没下班,点个赞吧