STM32内部是有温度传感器的,以F1为例,它的温度采集范围是-40度到125度,精度为正负2度,采样通道为ADC1_INI6,上电控制位为TSVREFE位。
温度计算方式为:T(摄氏度) = (V25 - Vsense) / Avg_Slope + 25,其中V25为25摄氏度时的Vsense数值,一般取1.43;Avg_slope为温度与Vsense曲线的平均斜率,一般取0.0043;Vsense是内部传感器采集到的电压值。(以F1为例)
实验要求:ADC1通道16采集芯片内部温度传感器的电压,将电压转算为温度后显示在液晶屏上。
我们通过下表可以知道DMA1通道1的外设对应的就是ADC1的读取。
首先确定我们的最小刻度,Vref = 3.3V,所以0V <= Vin <= 3.3V,所以最小刻度是3.3V / 4096(2^12)。
接下来确定转换时间。采样时间239.5个ADC时钟周期为例,可以得到转换时间为21us。
时间转换公式参考如下公式:Tcvtmin=(12.5+X)周期=(12.5 + X)/(12MHz)=21us。
接下来编写实验代码:
先编写函数文件adc_t.c:
#include "./BSP/ADC_T/adc_t.h"
ADC_HandleTypeDef g_adc_handle;
void adc_temperature_init(void){
ADC_ChannelConfTypeDef adc_ch_conf;
g_adc_handle.Instance = ADC1;
g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐
g_adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE; //不扫描
g_adc_handle.Init.ContinuousConvMode = DISABLE; //单次模式
g_adc_handle.Init.NbrOfConversion = 1; //转换通道数为1,单通道
g_adc_handle.Init.DiscontinuousConvMode = DISABLE; //不用间断模式
g_adc_handle.Init.NbrOfDiscConversion = 0; //无间断模式则无间断通道
g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; //外部软件触发
HAL_ADC_Init(&g_adc_handle);
HAL_ADCEx_Calibration_Start(&g_adc_handle);
adc_ch_conf.Channel = ADC_CHANNEL_1;
adc_ch_conf.Rank = ADC_REGULAR_RANK_1; //转换顺序
adc_ch_conf.SamplingTime = ADC_SMAPLINGTIME_239CYCLES_5; //设置为最大值
HAL_ADC_ConfigChannel(&g_adc_handle, &adc_ch_conf);
}
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc){
if(hadc->Instance == ADC1){
GPIO_InitTypeDef gpio_init_struct;
RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能ADC时钟
__HAL_RCC_ADC1_CLK_ENABLE(); //使能GPIO时钟
gpio_init_struct.Pin = GPIO_PIN_1;
gpio_init_struct.Mode = GPIO_MODE_ANALOG; //模拟模式
HAL_GPIO_Init(GPIOA, &gpio_init_struct);
adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC; //选择ADC外设时钟设置
adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6; //选择6分频,72/6=12MHz
HAL_RCCEx_PeriphCLKConfig(&adc_clk_init, &g_adc_handle);
}
}
uint32_t adc_get_result(void){
HAL_ADC_Start(&g_adc_handle);
HAL_ADC_PollForConversion(&g_adc_handle, 10); //第二个参数比1大就行
return (uint16_t)HAL_ADC_GetValue(&g_adc_handle);
}
short adc_get_temperature(void){
uint32_t adcx;
short result;
double temperature;
adcx = adc_get_result();
temperature = adcx * (3.3 / 4096);
temperature = (1.43 - temperature) / 0.0043 + 25;
result = temperature *= 100;
return result;
}
接下来编写函数头文件代码adc_t.h:
#ifndef __ADC_T_H
#define __ADC_T_H
#include "./SYSTEM/sys/sys.h"
void adc_temperature_init(void);
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc);
uint32_t adc_get_result(void);
short adc_get_temperature(void);
#endif
接下来编写主函数代码main.c:
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/ADC/adc.h"
#include "./BSP/ADC_T/adc_t.h"
int main(void)
{
short temp;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
lcd_init(); /* 初始化LCD */
adc_temperature_init(); /* 初始化ADC内部温度传感器采集 */
lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
lcd_show_string(30, 70, 200, 16, 16, "Temperature TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(30, 120, 200, 16, 16, "TEMPERATE: 00.00C", BLUE);
while (1)
{
temp = adc_get_temperature(); /* 得到温度值 */
if (temp < 0)
{
temp = -temp;
lcd_show_string(30 + 10 * 8, 120, 16, 16, 16, "-", BLUE); /* 显示负号 */
}
else
{
lcd_show_string(30 + 10 * 8, 120, 16, 16, 16, " ", BLUE); /* 无符号 */
}
lcd_show_xnum(30 + 11 * 8, 120, temp / 100, 2, 16, 0, BLUE); /* 显示整数部分 */
lcd_show_xnum(30 + 14 * 8, 120, temp % 100, 2, 16, 0X80, BLUE); /* 显示小数部分 */
LED0_TOGGLE(); /* LED0闪烁,提示程序运行 */
delay_ms(250);
}
}
到这里我们的函数代码就写完了。