【本文发布于https://blog.csdn.net/Stack_/article/details/113827555,未经许可不得转载,转载须注明出处】
在学校里学习时,测量温湿度多用DHT22模块,因为这模块容易上手。但是这个模块很贵,且各DHT22模块温湿度数值不统一还容易坏:手上的几个DHT22湿度误差最大能到20%,且有个别久放之后读到的湿度一直是99%。性价比太低。
用热敏电阻和湿敏电阻测量温湿度是个值得研究的方案。
热敏电阻测温实现起来不难,难在湿敏电阻的使用经验分享是少之又少,花了不少功夫去查资料、研究。
数据手册提供的这张电路图,其测量湿敏电阻阻值的过程简单来说就是:
1、所有IO设为输出,拉低,将电容余电放尽;
2、检测电平IO和湿敏电阻IO设为输入,10K电阻IO设为输出并拉高,同时开始计时。电容充电中;
3、检测电平IO变为高电平时(检测电平IO有上升沿中断功能更好),停止计时,记录下这个时间T1;
4、重复1、2、3的步骤,只是步骤2的通过10K电阻充电改为通过湿敏电阻充电,记录下充电时间T2;
5、根据关系式T1 / 10K = T2 / R湿敏,计算出湿敏电阻阻值,查表得到湿度值。
(充放电都确保电流流经湿敏电阻,满足交流的要求应该能大大延长湿敏电阻寿命)
【参考资料】
==============================================================================
上述方法我未实践过,只实践过下面这个:采用IO模拟交流输出,AD采样的方法。【参考资料】
.
.
/**
* @brief 产生1KHz交流方波
* @note 固定电阻端和湿敏电阻端IO此高彼低产生交流方波
* 此函数在main中循环,循环中没有死等的延时,time2_cnt在250us定时中断中递增
* 如果单片机速度足够快,该函数可直接放置于250us中断中执行
* @param None
* @retval None
* @author PWH
* @ CSDN Tyrion.Mon
* @date 2021/2
*/
void humd_create_1KHzAndStartAdc(void)
{
static uint32_t time = 0;
static uint8_t flag = 1;
if ((time2_cnt - time) > 0) //time2_cnt每250us加1
{
time = time2_cnt;
if (flag == 1) //1KHz开始,固定电阻端拉高,湿敏电阻端拉低
{
flag = 2;
SENSOR_HUMID_10K_GPIO->ODR |= (uint8_t)SENSOR_HUMID_10K_PIN;
SENSOR_HUMID_RH_GPIO->ODR &= (uint8_t)(~SENSOR_HUMID_RH_PIN);
return;
}
else if (flag == 2) //高电平二分之一处采样
{
flag = 3;
if (humdHasStart == 1)
{
/* Clear the ADC1 channels */
ADC1->CSR &= (uint8_t)(~ADC1_CSR_CH);
/* Select the ADC1 channel */
ADC1->CSR |= (uint8_t)(ADC1_CHANNEL_3);
ADC1->CR1 |= ADC1_CR1_ADON;
humdHasStart = 2;
}
return;
}
else if (flag == 3) //翻转,固定电阻端拉低,湿敏电阻端拉高
{
flag = 4;
SENSOR_HUMID_RH_GPIO->ODR |= (uint8_t)SENSOR_HUMID_RH_PIN;
SENSOR_HUMID_10K_GPIO->ODR &= (uint8_t)(~SENSOR_HUMID_10K_PIN);
return;
}
else if (flag == 4)
{
flag = 1;
return;
}
}
}
根据电路设计和湿度-阻值表算出各温湿度、各阻值下的ADC值。CM-R和HR202的曲线较为相似,据说C5-M3可被CM-R替代【HR202手册】【CM-R手册】
解释一下这里的计算公式:
/* 各温度下20% 25% 30% 。。。95%对应的ADC值(10位AD) */
@ CSDN Tyrion.Mon
uint16_t const humd_adc[11][16] =
{
/* 0℃ */
1023, 1023, 1022, 1020, 1016, 1009, 997, 972, 937, 881, 810, 713, 630, 531, 438, 350,
/* 5℃ */
1023, 1022, 1021, 1019, 1014, 1003, 986, 955, 915, 850, 785, 658, 564, 470, 350, 271,
/* 10℃ */
1023, 1022, 1020, 1016, 1009, 994, 970, 935, 889, 823, 739, 622, 512, 421, 332, 259,
/* 15℃ */
1022, 1021, 1019, 1014, 1004, 986, 955, 912, 853, 777, 682, 568, 461, 391, 307, 236,
/* 20℃ */
1022, 1020, 1018, 1012, 999, 976, 936, 883, 815, 726, 622, 522, 428, 332, 259, 198,
/* 25℃ */
1021, 1019, 1016, 1008, 990, 960, 911, 850, 774, 682, 600, 470, 379, 287, 224, 170,
/* 30℃ */
1021, 1018, 1014, 1004, 987, 953, 899, 834, 750, 630, 536, 435, 345, 265, 198, 156,
/* 35℃ */
1020, 1017, 1012, 1000, 982, 945, 883, 801, 713, 590, 490, 387, 307, 224, 163, 133,
/* 40℃ */
1019, 1014, 1008, 993, 971, 919, 856, 768, 664, 552, 435, 350, 265, 191, 141, 109,
/* 45℃ */
1018, 1012, 1006, 986, 950, 896, 823, 722, 617, 498, 387, 297, 224, 163, 125, 93,
/* 50℃ */
1016, 1009, 1000, 972, 938, 868, 785, 670, 566, 448, 336, 254, 211, 141, 109, 84
};
/**
* @brief 计算并查表得出湿度值
* @note
* @param None
* @retval None
* @author PWH
* @ CSDN Tyrion.Mon
* @date 2021/2
*/
uint16_t humd_get(void)
{
uint16_t adcVal = 0;
int8_t i = 0;
uint16_t tempVal = 0;
uint8_t row = 0;
adcVal = humd_getAdcValue(); //当前湿度ADC值
if (!adcVal)
{
return 0xffff; //AD转换未完成
}
tempVal = temp_get_static(); //当前温度值(为实际温度的10倍)
if (tempVal & 0x8000) //温度为负
{
row = 0;
}
else
{
row = tempVal / 10 / 5;
}
if (row > 10)
{
return 0xffff;
}
for (i = 15; i > -1; i--)
{
if (adcVal <= humd_adc[row][i])
{
return (20 + i * 5) * 10;
}
}
return 0xffff;
}
在这个温湿度下测试结果很理想,和DHT22的数值很接近:温度误差1℃内,湿度5%内。
【该代码没有引入插值算法,如果需要小数部分以作更为精确的测量,可以到我主页找NTC温度采集的文章,参考里面的插值算法】
【电路设计上切记远离热源,尤其是LDO等电源芯片】
(代码写得很随意,上面的描述已经很全了,我整理的文件并不比上面多多少,上面这个上位机也是我简单编写的,酌情下载)
【硬软、文档、调试上位机】