stm32中热敏电阻模块在OLED上实时显示温度


采用stm32f103c8t6芯片的A0引脚连接热敏电阻模块。采用ADC1的通道0,使用标准库实现。

实现功能所使用的常量为:

//温度传感器参数
#define VREF 3.3f  // ADC参考电压 3.3V
#define R1 10000.0f  // 电压分压阻值为10KΩ,与热敏电阻串联,用于计算热敏电阻的阻值
#define B 3950.0f  // 热敏电阻的 B 常数,单位为开尔文(K),用于计算热敏电阻的温度
#define T0 298.15f  // 参考温度,单位为开尔文(K),298.15K即 25°C
#define R0 10000.0f  // 热敏电阻在参考温度 T0 下的阻值,用于计算热敏电阻在当前温度下的阻值

// DMA内存存入位置
#define ADC_BUFFER_SIZE 10
uint16_t ADC_ConvertedValue[ADC_BUFFER_SIZE];

GPIO引脚配置:

void GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    // 使能GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

    //配置PA0为模拟输入用于温度传感器
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

ADC配置:

void ADC_Config(void)
{
    ADC_InitTypeDef ADC_InitStructure;

    // 使能ADC1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    
    // 配置 ADC1 的基本参数
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 								//配置为独立模式因芯片只有ADC1
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;									//启用连续扫描,这里因只开一个通道,是否启用连续扫描都不影响结果
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;								//启用连续转换,每次读入模拟量就进行转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;				//不适用外部触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;							//数据选择右对齐,转换结果低12位有效
    ADC_InitStructure.ADC_NbrOfChannel = 1;											//转换通道数设置为1
    ADC_Init(ADC1, &ADC_InitStructure);

    // 配置 ADC1 的通道,设置通道在规则组中的转换顺序为第 1 个,设置采样时间为 239.5 个时钟周期
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);

    // 启用 ADC1 的 DMA 功能,可以通过DMA实现高速转换
    ADC_DMACmd(ADC1, ENABLE);

    // 启用 ADC1
    ADC_Cmd(ADC1, ENABLE);

    // 校准 ADC1,消除 ADC 的偏移误差
    ADC_ResetCalibration(ADC1);						//复位 ADC1 的校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC1));		//等待复位校准完成,完成置0
    ADC_StartCalibration(ADC1);						//启动 ADC1 的校准
    while(ADC_GetCalibrationStatus(ADC1));			//等待完成

    // 启动 ADC1 转换,使用软件触发转换功能,将结果通过DMA传输刀内存中
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}

DMA模块实现:

void DMA_Config(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    
    // 使能 DMA1 时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    // 配置 DMA1 通道1
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;				//配置DMA读取数据位置为ADC1的DR寄存器中(每次通过A0引脚读入的值都放在DR中所以DMA通过DR读数据)
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue;		//配置DMA内存地址为ADC_ConvertedValue,即上方常量的地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;							//传输方向为外设到内存
    DMA_InitStructure.DMA_BufferSize = ADC_BUFFER_SIZE;							//缓冲区大小为每次DMA传输的数据量,即上方常量中的值
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;			//禁用外设地址自增,ADC 数据寄存器地址是固定的
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;						//启用内存地址自增,数组的每个元素地址是连续的
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //设置外设数据大小为半字(16位)
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;			//设置内存数据大小为半字(16位),与 ADC 数据寄存器一致
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;								//设置 DMA 模式为循环模式,即 DMA 传输完成后会自动重新开始
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;							//设置 DMA 通道的优先级为高(因为就一个通道,不设置也没关系)
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;								//禁用内存到内存的传输模式
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    
    // 使能 DMA1 通道1
    DMA_Cmd(DMA1_Channel1, ENABLE);
}

将模拟量转换为温度:

float GetTemperature(void)
{
    uint32_t sum = 0;
    uint8_t i;
    float voltage, rt, temperature;
    uint16_t adc_value; 
    // 计算10个样本的平均值 ADC_BUFFER_SIZE为10
    for(i = 0; i < ADC_BUFFER_SIZE; i++) {
        sum += ADC_ConvertedValue[i];
    }
    adc_value = sum / ADC_BUFFER_SIZE;
    
    // 将ADC值转换为电压 12位为4096
    voltage = (float)adc_value * VREF / 4096.0f;

    // 计算热敏电阻阻值
    rt = R1 * voltage / (VREF - voltage);

    // 使用Steinhart-Hart公式计算温度
    temperature = 1.0f / (1.0f/T0 + log(rt/R0)/B) - 273.15f;

    return temperature;
}

温度T的计算公式:
$$
T=\frac{1}{\frac{1}{T_0}+\frac{\frac{ln(R_t)}{R_0}}{B}}
$$

公式中的参数
  • T:参考温度,通常为 25°C(即 298.15K)。
  • R0:热敏电阻在参考温度 T0T0 下的阻值,通常为 10kΩ。
  • Rt:热敏电阻在当前温度下的阻值,通过分压电路和 ADC 测量得到。
  • B:热敏电阻的 B 常数,通常由热敏电阻的规格书提供,例如 3950。

通过以上的函数调用即可实现热敏电阻读取温度,最后在main函数中使用OLED显示温度:

int main(void)
{
    // 初始化
    GPIO_Config();
    DMA_Config();
    ADC_Config();
    
    // 初始化 OLED(OLED的代码需要自行去搜索获取)
    OLED_Init();
    OLED_Clear();
    
    while(1)
    {
        uint32_t i;
        // 获取温度
        float temperature = GetTemperature();
        char temp_str[16];
        sprintf(temp_str, "Temp:%.1fC", temperature); //格式化字符串
        OLED_ShowString(2, 1, temp_str);			  //OLED显示温度
    }
}

文章作者: LsWorld
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 LsWorld !
评论
  目录