基于STM32的PT100测温系统仿真

本文介绍了使用STM32F103R6微控制器通过ADC采集PT100信号,经过插值法计算温度,并在LCD1602显示屏上显示的过程。涉及到的工具包括Proteus进行电路仿真,Keil进行程序开发,以及相应的GPIO配置、LCD驱动程序和AD转换函数。代码示例展示了从ADC获取数据到转换为温度值并在LCD上显示的完整流程。

准备

Proteus

Keil

Proteus原理图绘制

芯片:STM32F103R6

LCD:LM016L

运算放大器:LM358

PT100

运放电路
运放电路
系统电路
芯片设置
Keil设置

  芯片设置这里,选择你在keil里面编译的程序,注意在Keil里要勾选一下Create HEX File,频率那里要写50k,不然仿真的时候时间跳的很慢。

Keil程序编写

LCD部分的函数借鉴自LCD1602单片机(STC51/STM32)驱动程序详解,具体信息可移步至此观看。

LCD1602.h

#ifndef __LCD1602_H
#define __LCD1602_H 

/***************************根据自己的硬件引脚做修改*****************************/
#define LCD_RS_Set()	GPIO_SetBits( GPIOB, GPIO_Pin_12 )//1602的数据/指令选择控制线
#define LCD_RS_Clr()	GPIO_ResetBits( GPIOB, GPIO_Pin_12 )

#define LCD_RW_Set()	GPIO_SetBits( GPIOB, GPIO_Pin_13 )//1602的读写控制线
#define LCD_RW_Clr()	GPIO_ResetBits( GPIOB, GPIO_Pin_13 )

#define LCD_EN_Set()	GPIO_SetBits( GPIOB, GPIO_Pin_14 )//1602的使能控制线
#define LCD_EN_Clr()	GPIO_ResetBits( GPIOB, GPIO_Pin_14 )

#define DATAOUT( x ) GPIO_Write( GPIOA, x )	//1602的8条数据控制线

void GPIO_Configuration(void);

void LCD1602_Init(void);

void LCD1602_Wait_Ready(void);

void LCD1602_Write_Cmd( u8 cmd );

void LCD1602_Write_Dat( u8 data );

void LCD1602_ClearScreen(void);

void LCD1602_Set_Cursor( u8 x, u8 y );

void LCD1602_Show_Str( u8 x, u8 y, u8 *str );

#endif

LCD1602.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LCD1602.h"
/******************************************************************************
 * 函数名称:void GPIO_Configuration()				      		*
 * 函数功能:LCD1602引脚初始化						 					      		*
 * 输入参数:无									      			*
 * 返回值  :无														          *
 * 其他说明:	 				 				     			  				*
 ******************************************************************************/
/*******************根据自己的硬件引脚做修改*****************************************/
void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE );
	GPIO_InitStructure.GPIO_Pin	= GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14;
	GPIO_InitStructure.GPIO_Speed	= GPIO_Speed_50MHz;//选择工作频率
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_Out_PP;//设置工作模式
	GPIO_Init( GPIOB, &GPIO_InitStructure );

	GPIO_InitStructure.GPIO_Pin	= GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | 						
	GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_Out_PP;//设置工作模式
	GPIO_InitStructure.GPIO_Speed	= GPIO_Speed_50MHz;//选择工作频率
	GPIO_Init( GPIOA, &GPIO_InitStructure );
}

/******************************************************************************
 * 函数名称:void LCD1602_Init()				      		*
 * 函数功能:LCD1602初始化						 					      		*
 * 输入参数:无									      			*
 * 返回值  :无														          *
 * 其他说明:	 				 				     			  				*
 ******************************************************************************/
void LCD1602_Init(void)
{
	GPIO_Configuration();			//初始化引脚

	LCD1602_Write_Cmd( 0x38 );      //显示模式设置
	Delay_ms( 5 );
	LCD1602_Write_Cmd( 0x0c );      //显示开及光标设置
	Delay_ms( 5 );
	LCD1602_Write_Cmd( 0x06 );      //显示光标移动位置
	Delay_ms( 5 );
	LCD1602_Write_Cmd( 0x01 );      //显示清屏
	Delay_ms( 5 );	
}

/******************************************************************************
 * 函数名称:void LCD1602_Write_Cmd(u8 cmd)				      		*
 * 函数功能:写命令函数							 					      		*
 * 输入参数:	cmd 命令										      			*
 * 返回值  :无														          *
 * 其他说明:	 				 				     			  				*
 ******************************************************************************/
void LCD1602_Write_Cmd( u8 cmd )
{
	LCD_RS_Clr();
	LCD_RW_Clr();
	LCD_EN_Set();

	GPIO_Write( GPIOA, (GPIO_ReadOutputData( GPIOA ) & 0xff00) | cmd );//对电平的读取

	DATAOUT( cmd );
	Delay_ms( 5 );
	LCD_EN_Clr();
}

/******************************************************************************
 * 函数名称:void LCD1602_Write_Dat(u8 date)				      		*
 * 函数功能:写数据函数							 					      		*
 * 输入参数:	date 数据										      			*
 * 返回值  :无														          *
 * 其他说明:	 				 				     			  				*
 ******************************************************************************/
void LCD1602_Write_Dat( u8 data )
{
	LCD_RS_Set();
	LCD_RW_Clr();
	LCD_EN_Set();

	GPIO_Write( GPIOA, (GPIO_ReadOutputData( GPIOA ) & 0xff00) | data );//对电平的读取

	Delay_ms( 5 );
	LCD_EN_Clr();
}

/******************************************************************************
 * 函数名称:void LCD1602_ClearScreen()				      		*
 * 函数功能:1602清屏函数							 					      		*
 * 输入参数:无										      			*
 * 返回值  :无														          *
 * 其他说明:	 				 				     			  				*
 ******************************************************************************/
void LCD1602_ClearScreen(void)
{
	LCD1602_Write_Cmd( 0x01 );
}

/******************************************************************************
 * 函数名称:void LCD1602_Set_Cursor(u8 x, u8 y)				      		*
 * 函数功能:设置1602位置函数							 					      *
 * 输入参数:x 横坐标 y 纵坐标									      				*
 * 返回值  :无														          *
 * 其他说明:	 				 				     			  				*
 ******************************************************************************/
void LCD1602_Set_Cursor( u8 x, u8 y )
{
	u8 addr;

	if ( y == 0 )
		addr = 0x00 + x;
	else
		addr = 0x40 + x;
	LCD1602_Write_Cmd( addr | 0x80 );
}

/******************************************************************************
 * 函数名称:void LCD1602_Show_Str( u8 x, u8 y, u8 *str )				      		*
 * 函数功能:指定位置显示字符串函数							 					      *
 * 输入参数:x 横坐标 y 纵坐标		*str 字符串							      *
 * 返回值  :	无													          *
 * 其他说明:	 				 				     			  				*
 ******************************************************************************/
void LCD1602_Show_Str( u8 x, u8 y, u8 *str )
{
	LCD1602_Set_Cursor( x, y );
	while ( *str != '\0' )
	{
		LCD1602_Write_Dat( *str++ );
	}
}

AD处理模块搬运江科大自化协的教程,但是这里把校准函数屏蔽了,校准的第一个指令不返回RESET,一直没找到原因,屏蔽了好像也没什么影响

AD.h

#ifndef __AD_H
#define __AD_H

void AD_Init(void);
uint16_t AD_GetValue(void);

#endif

AD.c

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);		//72MHz/6
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_55Cycles5);
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1,&ADC_InitStructure);
	
	ADC_Cmd(ADC1,ENABLE);
	
	//ADC_ResetCalibration(ADC2);	
	//while (ADC_GetResetCalibrationStatus(ADC2));
	//ADC_StartCalibration(ADC2);
	//while (ADC_GetCalibrationStatus(ADC2));
	
	
	
}

uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
	while (ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}

因为PT100电阻随温度并非线性变化,这里采用插值法计算温度,本芯片ADC转换精度12位,即ADC输入端口0-5V电压转换为0-4095(2^12),程序中给出温度与0-4095的对应关系,本例只模拟0-100℃。

Interpolation.h

#ifndef INTERPOLATION__H
#define INTERPOLATION__H

float calculateTemperature(float measuredVoltage);

#endif

Interpolation.c


// 定义温度-电压查表
const float temperatureTable[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 
									10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
//const float voltageTable[] = {0.0656, 0.0686, 0.0717, 0.0751, 0.0788, 0.0828, 0.0871, 0.0918,
//								0.0968, 0.1022, 0.1079, 0.1792, 0.2574, 0.3356, 0.4132, 0.4903,
//								0.5668, 0.6427, 0.7181, 0.793};
const float voltageTable[] = {54, 56, 59, 62, 65, 68, 71, 75, 79, 84, 88, 147, 211, 275, 338, 402, 464, 526, 588, 650};
									
float calculateTemperature(float measuredVoltage) 
{
    int i;
    for (i = 0; i < sizeof(voltageTable)/sizeof(float); i++) {
        if (measuredVoltage <= voltageTable[i]) {
            break;
        }
    }

    if (i == 0) {
        return temperatureTable[0];
    } else if (i == sizeof(temperatureTable)/sizeof(float)) {
        return temperatureTable[sizeof(temperatureTable)/sizeof(float) - 1];
    } else {
        float voltage1 = voltageTable[i-1];
        float voltage2 = voltageTable[i];
        float temperature1 = temperatureTable[i-1];
        float temperature2 = temperatureTable[i];
        return temperature1 + (temperature2 - temperature1) * (measuredVoltage - voltage1) / (voltage2 - voltage1);
    }
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LCD1602.h"
#include "AD.h"
#include "stdio.h"
#include "Interpolation.h"

u8 str[] = "Temp test!";





int	main(void)
{	
	char buf[16];
	uint16_t ADValue = 0;
	//float voltage = 0;
	float Temp;
	
	LCD1602_Init();
	AD_Init();
	
	
	while(1)
	{
		LCD1602_Show_Str(0,0,str);	//(列,行)
		ADValue = AD_GetValue();
		Temp = (int16_t) calculateTemperature((float)ADValue);
		//voltage = (float) ADValue* (5.0/4096);
		//Temp =  (350.0 /(2049.0 - 54.0)) *(float) ADValue - 9.47;
		sprintf((char *)buf,(const char *)"Temp:%5.1f%cC",Temp,0xdf);
		//sprintf(buf,"ADValue: %u",ADValue);
		LCD1602_Show_Str(0,1,(u8 *)buf);

	}

}

结语

本文是我在学习STM32阶段写的一个小Demo,,可能存在很多不完善的地方,欢迎各位交流指正!

本资源库提供了使用STM32单片机制作的PT100温度测量项目,详细涵盖了从理论到实践的全过程。PT100作为常用的工业温度传感器,因其稳定性强、精度高而被广泛应用。此项目通过STM32单片机的AD转换功能,实现了对PT100传感器信号的精确采集,并通过Proteus进行仿真验证,确保软硬件设计的准确性。 内容包含: 理论基础:解释了PT100传感器的原理及其与温度的关系,以及STM32如何通过AD转换读取传感器信号。 硬件设计: STM32单片机为核心控制器。 PT100传感器负责温度采集。 LM324运算放大器用于信号调理,增强AD转换的准确性。 1602液晶显示器用于直观展示温度读数。 软件部分: 程序源码:包含STM32的初始化、AD转换、温度计算及结果显示的完整代码。 ADC配置,保证准确读取PT100的电阻变化,进而转换为温度。 温度计算公式和数据显示逻辑。 仿真与测试: Proteus仿真文件,帮助开发者在虚拟环境中测试整个系统。 文档资料: 完整的操作指南和设计思路说明。 技术规格: 测温范围:-55°C至110°C。 误差范围:≤1°C。 显示方式:1602 LCD显示屏。 开发环境:STM32CubeMX配置、Keil MDK编程。 仿真工具:Proteus 8.11或更高版本。 如何使用 下载资源:从指定链接下载源码和仿真所需文件。 环境搭建:安装STM32开发环境和Proteus仿真软件。 编译与上传:在Keil MDK中编译程序,通过编程器将固件烧录至STM32。 Proteus仿真:载入仿真文件,检查硬件连接正确后开始仿真。 实际测试:将程序部署到真实硬件上,测试温度测量的准确性。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值