要使用传感器,请执行以下操作:
选择 ADC1_IN16 或 ADC1_IN18 输入通道。
选择一个采样时间,该采样时间要大于数据手册中所指定的最低采样时间。
在 ADC_CCR 寄存器中将 TSVREFE 位置 1,以便将温度传感器从掉电模式中唤醒。
通过将 SWSTART 位置 1(或通过外部触发)开始 ADC 转换
读取 ADC 数据寄存器中生成的 V SENSE 数据
使用以下公式计算温度:
温度(单位为 °C)= {(V SENSE — V 25 ) / Avg_Slope} + 25
其中:
— V 25 = 25 °C 时的 V SENSE 值
— Avg_Slope = 温度与 V SENSE 曲线的平均斜率(以 mV/°C 或 μV/°C 表示)
由于ADC寄存器的相关配置相对比较简单,这里直接附上测量温度相关的ADC初始化和中断程序:
void ADC_Init()
{
u32 prigroup = 0;
u32 priority = 0;
RCC->APB2ENR |= 1<<8; //开ADC1时钟
ADC->CCR = 0;
ADC->CCR |= 1<<23; //使能温度传感器和 V REFINT 通道
ADC->CCR |= 1<<16; //ADCCLK=21mHZ
ADC1->CR1 = 0;//分辨率12位
ADC1->CR2 = 0; //数据右对齐
ADC1->CR2 |= 1<<10; //通道只要转换结束,则将EOC置1,使能溢出检测
ADC1->SMPR1 =0; //通道16采样时间3T
ADC1->SQR3 |= 16<<0;
ADC1->CR1 |= 1<<5; //使能EOC中断
ADC1->SR &=~ (1<<1); //清中断标记33
prigroup = NVIC_GetPriorityGrouping(); //得到优先级分组
priority = NVIC_EncodePriority(prigroup,1,2); //优先级编码
NVIC_SetPriority(ADC_IRQn,priority); //设置中断优先级
NVIC_EnableIRQ(ADC_IRQn); //使能ADC中断
ADC1->CR2 |= 1<<0; //使能ADC
Delay_us(3);
ADC1->CR2 |= 1<<30; //启动AD转换
}
u16 ADC1_Value={0}; //定义二维数组,按行存入三个通道的转换结束
u8 ADC1_OK = 0;
//中断处理函数
void ADC_IRQHandler()
{
if(ADC1->SR & (1<<1))
{
ADC1->SR &=~ (1<<1); //写0,请标记
ADC1_Value = ADC1->DR; //按行依次存入各通道的转换结果
ADC1_OK = 1; //采集完成结束标记置1
}
}
接着编写主函数测试
#include "stm32f4xx.h"
#include "usart.h"
#include "delay.h"
#include "stdio.h"
#include "ADC.h"
extern u8 ADC1_OK;
extern u16 ADC1_Value;
int main()
{
float wendu = 0;
NVIC_SetPriorityGrouping(7-2);
Usart1_Init(115200);
ADC_Init();
while(1)
{
if(ADC1_OK == 1)
{
ADC1->SR &=~ (1<<1); //清中断标记
ADC1_OK = 0;
wendu = 3.3*ADC1_Value/4095; //求温度数字值对应的模拟电压值
wendu = (wendu -0.76)*1000/2.5+25; //计算温度值
printf("温度AD值:%d wendu = %.lf°C ",ADC1_Value,wendu);
ADC1->CR2 |= 1<<0; //再次开启ADC1
Delay_us(3);
ADC1->CR2 |= 1<<30; //触发一次转换
}
Delay_ms(1000);
}
}
从串口可以看到ADC读取的温度值,ADC温度测量成功。
对于电池电压或者其他外部模拟量的测量,配置方法与温度测量类似,这里不再赘述。如果想要让CPU更多地用于算法或者其他功能的处理,同样可以配置DMA进行数据传输。