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

x33g5p2x  于2021-11-25 转载在 其他  
字(4.9k)|赞(0)|评价(0)|浏览(709)

最近在测试设备的时候需要监测设备的温度,平常测试时都是通过红外热成像仪测试,然后手动记录数据。这样测试的话工作量比较大,需要几分钟就记录一次数据。于是想着能不能用单片机做一个测试温度的装置,用电脑自动记录数据。手头刚好有STM8S003单片机和 5K的NTC热敏电阻,于是就做了一个简易的温度测试装置,并使用伏特加上位机软件将温度波形显示出来。

最终测试效果如图所示:

下面将制作步骤分享出来。

首先设计NTC热敏电阻的采样电路。

  这里使用最简答电阻分压电路,将热敏电阻和一个10K电阻串联分压,然后将电压值直接送到单片机的AD采样口,由于热敏电阻的阻值会随着温度变化,所以送入单片机口的电压值也会随着温度变化,这样就可以通过单片机AD口采样的电压值推算出当前的温度值。

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

  硬件电路很简单,连接完成图如下:

  将两路温度采样电路焊接在一个小板上,然后连接到STM8S003单片机最小系统上,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,那么根据分压公式可以算出,两个电阻分压后的电压值为 Vo = 5V / (10K + R) * R ,,将热敏电阻的阻值和温度对照表复制到Excel表格中,然后根据分压公式计算出每个温度对应的分压电压值。

由于单片机采样的AD值并不是电压值,所以还需要将计算出来的电压值转换为单片机的采样值,这里使用的单片机AD精度为10位,所以最大的采样值为2^10=1024,单片机位5V供电,使用公式 采样ADC值 = 温度电压值 / 5V * 1024,计算采样值和分压值的对应关系。可以直接在表格中使用公式计算。

  这样就将单片机的采样值和温度值对应起来了,为了程序编写的方便,这里温度选择直接从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单片机自制简易温度巡检仪

相关文章