最近在测试设备的时候需要监测设备的温度,平常测试时都是通过红外热成像仪测试,然后手动记录数据。这样测试的话工作量比较大,需要几分钟就记录一次数据。于是想着能不能用单片机做一个测试温度的装置,用电脑自动记录数据。手头刚好有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,%drn", 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单片机中自己实现 printf()函数功能
下一篇:如何通过map文件优化代码
推荐阅读最新更新时间:2024-11-17 09:08
推荐帖子
- 当年做的课程设计《综合课程设计简易计算器》
- 所说简单点,但是还是蛮可以的,不足之处求大家指正!当年做的课程设计《综合课程设计简易计算器》想了解一下是用什么编的哦!回复楼主冷枫yj的帖子是用C语言编写的回复沙发gaoxiao的帖子十分感谢~~~~~~同7楼!!!!!!下来看看先!!感谢分享!!顺便回10楼回帖就有芯币啦!!多多回帖吧!!!是用C语言编写的有用到栈吗收藏喽,,:)
- 冷枫yj 单片机
- WinCE系统自带的数据库备份问题
- 各位大侠好,最近在WINCE上开发一个项目,数据量不是很大,在数据库方面,我就采用了系统自带的数据库CEDB,由于项目要求,现在要对数据库的备份文件进行基本的操作,比如说查询之类的,如果是在WINCE上操作还好说,但是要移植到PC机上面,这个问题一直不知道该怎么解决,希望高人基于指点!WinCE系统自带的数据库备份问题自己顶一下!
- pengwr WindowsCE
- 我在学cadence软件,但是无从下手,大神们都是怎么学的呢?
- 同标题,学习cadence,不知道如何入手,主要是想学习第三方导入网表,用cadence进行布局布线。是不是需要从cadence的原理图设计开始呢?这个软件看起来比较复杂,大神们有没有什么推荐的视频以及书籍呢?谢谢啦我在学cadence软件,但是无从下手,大神们都是怎么学的呢?搜索于博士Cadence教程PCB制板设计要从原理图学起教程可以到下载中心找找https://download.eeworld.com.cn/eewsearcher?kw=cadence教程1910
- 651076842 PCB设计
- vc2005开发的智能设备ocx,如何改造能在pc(x86)下的智能设备应用中开发使用?高手帮忙
- vc2005开发的智能设备ocx,如何改造能在pc(x86)下的智能设备应用中开发使用?vc2005开发的智能设备ocx,如何改造能在pc(x86)下的智能设备应用中开发使用?高手帮忙拿源代码,重编译具体说,能指点以下吗?我的qq412925762楼主:给出详细的做法,本人刚入门
- laoqiao 嵌入式系统
- 关于DE1-SOC上的USB部分
- 最近由于工作需要在DE1-SOC上移植UCOS,目前需要实现USB通信,但是官方的硬件库没有USB驱动,想问下关于上面这个USB的裸机驱动有没有什么参考或者指点关于DE1-SOC上的USB部分目前也需要这方面的资料,不知道哪里有我现在也碰到了这个问题,楼主能给点建议吗?谢谢!
- 柯哀LV王道 Altera SoC
- 【TI讨论】修整引脚在哪里?
- 某天,Bruce和他的朋友讨论了我们用于“修整”或者调整放大器补偿电压至极低值所使用的各种技术。这让他想到了补偿电压修整引脚——它们到哪里去了呢?工程师朋友们,如果不看文章,你们能回答得上来吗?【TI讨论】修整引脚在哪里?OPA系列的调零管脚很多还是有的。我固执的避免用加减法电路来实现调零,感到这样会引入噪声和温漂现在每个厂商都有零失调系列的运放把“调整”改为了“修整”,我咋说不知道是怎么回事呢!
- 德州仪器 模拟与混合信号
设计资源 培训 开发板 精华推荐
- ADR445BR 2.048 Vout 超低噪声、LDO XFET 电压基准的典型应用,具有电流吸收器和电流源
- TCR5SB43、200mA、4.3V 输出电压 CMOS 低压降稳压器的典型应用
- LTC2376-16、16 位、250ksps、低功率 SAR ADC 的典型应用电路
- 一款用于手机的 LED 白光 LED 驱动器
- ArduinoSimpleFOC
- ADA4062-2ARMZ-RL微功率仪表放大器典型应用电路
- AD8330-EVAL,评估套件是一种易于使用的附件,可用于对 AD8330 可变增益放大器 (VGA) 进行动手评估
- 使用 Cypress Semiconductor 的 CY8C26443 的参考设计
- LTC3634MPFE 降压型稳压器的设计示例电路
- STEVAL-IDB006V1M,基于 SPBTLE-RF 模块的低功耗蓝牙 USB 加密狗评估板