资讯详情

使用STM8单片机+NTC热敏电阻自制简易温度巡检仪

??最近,在测试设备时,需要监测设备的温度,通常通过红外热成像仪测试,然后手动记录数据。这样测试工作量大,记录数据需要几分钟。所以我想知道我是否可以使用单片机来测试温度,并自动用计算机记录数据。手头刚好有STM8S003单片机和 5K的NTC热敏电阻,所以做了一个简单的温度测试装置,用伏特和位机软件显示温度波形。

??如图所示: 请添加图片描述

??下面分享制作步骤。

??首先设计NTC热敏电阻采样电路。 ??最简答电阻分压电路用于热敏电阻和10K电阻串联分压,然后将电压值直接送到单片机AD采样口,由于热敏电阻的电阻值会随温度而变化,送入单片机口的电压值也会随温度而变化,因此可以通过单片机AD口采样的电压值计算出当前的温度值。

??温度采样电路设计有两条路,输出电压值分别送到单片机AD采样口 19、20引脚,然后通过串口模块将温度数据发送到电脑上,即单片机的串口,即2、3引脚。

??连接完成图如下: ??在小板上焊接两个温度采样电路,然后连接到STM8S在003单片机最小系统上,USB转串口的模块也用杜邦线连接到单片机上。 ??接下来,我们开始编写代码。代码也很简单,所以我们使用它ADC采样和串口部分。

??ADC采样代码如下:

#include "adc.h" #include "main.h"  u16  DATAH = 0;                          //ADC转换值高8位 u16  DATAL = 0;                          //ADC转换值低8位 _Bool ADC_flag = 0;                     //ADC转换成功标志  //AD通道引脚的初始化 void ADC_GPIO_Init( void ) { 
            PD_DDR &= ~( 1 << 2 );              //PD2 设置为输入 电压     PD_CR1 &= ~( 1 << 2 );              //PD2 设置为悬空输入     PD_DDR &= ~( 1 << 3 );              //PD3 设置为输入 电流     PD_CR1 &= ~( 1 << 3 );              //PD3 设置为悬空输入 } //ch 是单片机对应的管脚 void ADC_CH_Init( u8 ch ) { 
            char l = 0;     ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz 禁止单次转换     ADC_CSR  = ch   1;                  //控制状态寄存器 选择要 AD输入通道 如:PD2(AIN3)     ADC_CR2  = 0x00;                    //默认左对齐 读数据时先读高在读低
    ADC_TDRL = ( 1 << ( ch + 1 ) );     //禁止相应通道 施密特触发功能 1左移ch+1位
    ADC_CR1 |= 0x01;                    //使能ADC并开始转换
    ADC_CSR |= 0x20;                    //EOCIE 使能转换结束中断 EOC中断使能
    for( l = 0; l < 100; l++ );         //延时,保证ADC模块的上电完成 至少7us
    ADC_CR1 = ADC_CR1 | 0x01;           //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
}

//采集PD2电压值
u16 ReadVol_CH2( void )
{ 
       
    u16 voltage = 0;
    ADC_CH_Init( 2 );
    if( ADC_flag )
    { 
       
        ADC_flag = 0;
        voltage = ( DATAH << 2 ) + DATAL ;
        ADC_CR1 = ADC_CR1 | 0x01;
    };
    return voltage;
}
//采集PD3电压值
u16 ReadVol_CH3( void )
{ 
       
    u16 voltage = 0;
    ADC_CH_Init( 3 );
    if( ADC_flag )
    { 
       
        ADC_flag = 0;
        voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据 0--1024
        ADC_CR1 = ADC_CR1 | 0x01;          //再次将CR1寄存器的最低位置1 启动下一次转换
    };
    return voltage;
}


//AD中断服务函数 中断号22
#pragma vector = 24 // IAR中的中断号,要在STVD中的中断号上加2
__interrupt void ADC_Handle( void )
{ 
       
    ADC_CSR &= ~0x80;                   // 转换结束标志位清零 EOC
    //默认左对齐 读数据时先读高高8位 再读低8位
    DATAH = ADC_DRH;                    // 读出ADC结果的高8位
    DATAL = ADC_DRL;                    // 读出ADC结果的低8位
    ADC_flag = 1;                       // ADC中断标志 置1
}

  串口相关代码如下:

#include "uart.h"
#include "stdio.h"
#include "main.h"

//在Library Options中将Printf formatter改成Large
//重新定向putchar函数,使支持printf函数
int putchar(int ch)
{ 
       
    while(!(UART1_SR&0X80));//循环发送,直到发送完毕
    UART1_DR = (u8) ch;
    return ch;
}
void Uart1_IO_Init(void)
{ 
       
    PD_DDR |= (1<<5);   //输出模式 TXD
    PD_CR1 |= (1<<5);   //推挽输出

    PD_DDR &= ~(1<<6);  //输入模式 RXD
    PD_CR1 &= ~(1<<6);  //浮空输入
}

//波特率最大可以设置为38400
void Uart1_Init( unsigned int baudrate )
{ 
       
    unsigned int baud;
    baud = 16000000 / baudrate;
    Uart1_IO_Init();
    UART1_CR1 = 0;
    UART1_CR2 = 0;
    UART1_CR3 = 0;
    UART1_BRR2 = ( unsigned char )( ( baud & 0xf000 ) >> 8 ) | ( ( unsigned char )( baud & 0x000f ) );
    UART1_BRR1 = ( ( unsigned char )( ( baud & 0x0ff0 ) >> 4 ) );
    UART1_CR2_bit.REN = 1;                      //接收使能
    UART1_CR2_bit.TEN = 1;                      //发送使能
    UART1_CR2_bit.RIEN = 1;                     //接收中断使能
}

  由于单片机只需要通过串口发送数据,而不需要接收数据,所以这里就没有串口接收相关代码。

  接下来就是最重要的部分了,需要将串口采样到的ADC值转换为对应的温度值。这里需要查阅NTC热敏电阻的资料,将热敏电阻的阻值和温度变化做成一张表,然后单片机通过查表获取温度值。   在网上查找资料,找到了一张NTC热敏电阻的阻值和温度对照表,这张表中温度对应的是电阻阻值,所以还需要将NTC的阻值和单片机ADC采样值对应起来。   由于采样电路是10K固定电阻和NTC分压所得。假设NTC的阻值为R,那么根据分压公式可以算出,两个电阻分压后的电压值为 ,,将热敏电阻的阻值和温度对照表复制到Excel表格中,然后根据分压公式计算出每个温度对应的分压电压值。

  由于单片机采样的AD值并不是电压值,所以还需要将计算出来的电压值转换为单片机的采样值,这里使用的单片机AD精度为10位,所以最大的采样值为2^10=1024,单片机位5V供电,使用公式 ,计算采样值和分压值的对应关系。可以直接在表格中使用公式计算。   这样就将单片机的采样值和温度值对应起来了,为了程序编写的方便,这里温度选择直接从0度开始,0度以下的数据不考虑。   将从0度开始的单片机ADC采样值存在数组中,单片机从AD口读取到数据后,在数组中查找当前采样的数据最接近数组中的哪个数据,然后对应数组的下标刚好就是温度值,比如采样值为340,那么在数组中最接近的数字就是341,而341在数组中第25位,那么当前的温度值就是25℃。 为了减小单片机的计算量,将表格中计算出来的单片机采样值统一变成整数,将转换好的整数存放在数组中。   接下来在主程序中就可以读取ADC采样值,然后查表去找出对应的温度值了。主函数代码如下:

void main( void )
{ 
       
    static u16 temp1 = 100, temp2 = 200;
    static u16 value1 = 0, value2 = 0;
    u16 i = 0, j = 0;
    u32 sum = 0;

    SysClkInit();
    __asm( "sim" );                       //禁止中断
    LED_GPIO_Init();
    delay_init( 16 );
    Uart1_Init( 9600 );
    __asm( "rim" );                       //开启中断
    while( 1 )
    { 
       
        sum = 0;
        for( i = 0; i < 16; i++ )       //测量两路温度数据
        { 
       
            sum += ReadVol_CH3();
            delay_ms( 10 );
        }
        value1 = sum >> 4;
        temp1 = find_by_seq( tem_table, NUM, value1 );       //通过采样值查表计算对应温度值

        sum = 0;

        for( i = 0; i < 16; i++ )
        { 
       
            sum += ReadVol_CH2();
            delay_ms( 10 );
        }
        value2 = sum >> 4;
        temp2 = find_by_seq( tem_table, NUM, value2 );       //通过采样值查表计算对应温度值


        LED = ~LED;
        printf( "%d,%d,%d,%d\r\n", value1, value2, temp1, temp2 );

    }
}

  为了避免采样到的温度值跳变,所以这里每个通道采样16次,然后取平均值,每次采样间隔10ms。计算出采样的平均值之后,通过查找函数检测当前的采样值最接近数组中的那个数字,然后返回对应的下标。这里查找数据使用了最简单的顺序查找法。

/* * 顺序查找法 * @description : 在数组中寻找和数据最接近的那个数字,并返回数字所在数组的下标 * @param - arr : 数组首地址 * @param - length : 数组大小 * @param - num : 要查找的数据 * @return : 最接近的数组所在数组下标 * * 基本思路:数组按照顺序排列好之后,从数组头开始依次比较各个数据。 */
int find_by_seq( int *arr, int length, int num )
{ 
       
    int i;
    int min = abs( *arr - num );        // 要查找的数据和数组中第一个数字的差作为最小值
    int index = 0;

    for( i = 0; i < length; i++ )
    { 
       
        if( abs( arr[i] - num ) < min )
        { 
       
            min = abs( arr[i] - num );
            index = i;
        }
    }

    //return arr[index]; //返回数据
    return index;         //返回下标
}

  虽然顺序查找法效率不高,但是这个程序本身也很简单,同时外部设备温度的变化也比较缓慢,所以使用顺序查找法对系统的运行也没有多大的影响。查找的原理就是采样值依次和数组中的每个数据相减然后求绝对值,最后返回绝对值最小的数据索引。由于数组中的数据是从0度开始的,每次递增一度,所以数组的下标刚好就是温度值,不需要再进行换算。

  最后通过printf()函数将数据从串口发送到 上位机软件上,进行波形显示。在烧水器上少了一杯开水,直接将NTC热敏电阻放到水里面测试。   在上位机软件上测试波形如下:   逐渐上升的两条曲线是采样到的原始值,逐渐下降的两条曲线是查表后换算出来的温度值。可以将波形放大,查看实时显示的值。

  这时波形动态打印效果图。   为了使温度看起来更方便,可以在界面上添加两个温度显示表盘。   通过最右边的两个表盘就可以实时显示温度值,通过左边的曲线查看温度变化趋势。

  用手捏了一下热敏电阻,可以看到温度反应还是比较灵敏的。到此这个简易的温度巡检仪就算搞定了。

  还可以使用软件中的其他控件来显示温度。   这些控件都可以在软件左侧的空间工具栏中找到。

关于这个上位机软件的使用,可以看 串口示波器—伏特加 彻底的爱了 这篇文章。

本文中的这个工程也打包上传了,下载地址: STM8单片机自制简易温度巡检仪

标签: 电阻由温度变化而变化4线制热电阻温度变送器1812电阻一盘1812j电阻25l0电阻外接5k电阻到5v

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台