基于STM32的PT100温度测量目录一、前言 (1)二、系统描述 (1)2.1 综述 (1)2.2 系统框图 (1)2.3 功能实现 (1)三、硬件设计 (2)3.1 STM32 微控制器 (2)3.2 PT100温度传感器电路 (3)3.3 1602液晶屏 (4)四、软件设计 (4)4.1 ADC程序 (4)4.2 1602LCD显示程序 (5)4.3 主程序 (5)五、性能测试 (5)六、课程设计心得 (6)参考文献 (6)附录1:系统实物图 (7)附录2:系统主要程序 (7)一、前言Cortex-M3 是ARM 公司为要求高性(1.25DhrystoneMIPS/MHz)、低成本、低功耗的嵌入式应用专门设计的核。
STM32 系列产品得益于Cortex-M3 在架构上进行的多项改进,包括提升性能的同时又提高了代码密度的Thumb-2 指令集和大幅度提高中断响应的紧耦合嵌套向量中断控制器,所有新功能都同时具有业界最优的功耗水平。
本系统是基于Cortex-M3 核的STM32 微控制器与PT100温度传感器的温度测量,在硬件方面主要有最小系统板、1602LCD 液晶屏以及PT100温度传感电路,在软件方面主要有1602LCD液晶屏的驱动,ADC功能的驱动,及滤波算法设计。
整个设计过程包括电子系统的设计技术及调试技术,包括需求分析,原理图的绘制,器件采购,安装,焊接,硬件调试,软件模块编写,软件模块测试,系统整体测试等整个开发调试过程。
二、系统描述2.1综述本系统是基于STM32微控制器所设计的多功能画板,该画板具有基本的绘画功能及画布颜色的选择,触摸屏校正等功能。
整个系统模块分为三个模块:ALIENTEK MiniSTM32开发板、液晶显示。
MiniSTM32开发板是ALIENTEK开发的是一款迷你型的开发板,小巧而不小气,简约而不简单。
上面有芯片工作需要的资源,时钟控制电路、复位电路、JTAG 控制口以及与外围电路相连的接口。
液晶屏采用的是1602LCD液晶屏。
2.2 系统框图本设计采用STM32F103RBT6 作为微控制器,其外围硬件模块主要包括电源模块﹑微处理器模块﹑按键及JAIG等。
电源采用USB 供电,在设计过程中用PC 供电。
其系统框图如图2-1所示。
2.3 功能实现PI100温度传感器是利用其电阻和温度成一定函数关系而制成的温度传感器,温度变化导致它的电阻变化,在电路中它的电阻变化会导致电压变化,STM32 微控制器的ADC将电压换成数字信号,通过处理运算以及PT100温度与电阻的函数关系,得到一个温度值,并将温度值输入1602液晶屏显示。
三、硬件设计3.1 STM32 微控制器STM32 微控制器最小系统包括晶振电路,电源模块,JTAG接口模块,串口ISP下载模块,系统复位模块。
本次课程设计采用的是ALIENTEK MiniSTM32开发板。
STM32F103RBT6 管脚图STM32 微控制器的部分工作电路图3.2 PT100温度传感器电路铂电阻温度传感器是利用其电阻和温度成一定函数关系而制成的温度传感器,由于其测量准确度高、测量围大、复现性和稳定性好等,被广泛用于中温围的温度测量中。
PT100 是一种广泛应用的测温元件,在-50 ~600 ℃围具有其他任何温度传感器无可比拟的优势,包括高精度、稳定性好、抗干扰能力强等。
由于铂电阻的电阻值与温度成非线性关系,所以需要进行非线性校正。
校正分为模拟电路校正和微处理器数字化校正,模拟校正有很多现成的电路,其精度不高且易受温漂等干扰因素影响,数字化校正则需要在微处理系统中使用,将PT电阻的电阻值和温度对应起来后存入EEPROM中,根据电路中实测的AD值以查表方式计算相应温度值。
常用的PT电阻接法有三线制和两线制,其中三线制接法的优点是将PT100 的两侧相等的的导线长度分别加在两侧的桥臂上,使得导线电阻得以消除。
常用的采样电路有两种:一为桥式测温电路,一为恒流源式测温电路。
本设计采用的是三线制桥式测温电路,电路如图所示测温原理:电路采用TL31和电位器VR1调节产生4.096V的参考电源;采用R1、R2、VR2、RPT构成测量电桥(其中R1=R2,VR2为100Ω精密电阻),当RPT的电阻值和VR2的电阻值不相等时,电桥输出一个mV级的压差信号,这个压差信号经过运放LM3放大后输出期望大小的电压信号,该信号可直接连AD转换芯片。
差动放大电路中R3=R4、R5=R6、放大倍数=R5/R3,运放采用单一5V 供电。
设计及调试注意点:1. 同幅度调整R1和R2的电阻值可以改变电桥输出的压差大小;2. 改变R5/R3的比值即可改变电压信号的放大倍数,以便满足设计者对温度围的要求4. VR2为电位器,调节电位器阻值大小可以改变温度的零点设定,测量电位器的阻值时须在没有接入电路时调节,这是因为接入电路后测量的电阻值发生了改变。
5. 理论上,运放输出的电压为输入压差信号×放大倍数,但实际在电路工作时测量输出电压与输入压差信号并非这样的关系,压差信号比理论值小很多,实际输出信号为V O =4.096*(RPT /(R1+RPT)- VR2 /(R1+VR2 ))式中电阻值以电路工作时量取的为准。
4.096为基于源电压。
6. 电桥的正电源必须接稳定的参考基准,因为如果直接VCC的话,当网压波动造成VCC发生波动时,运放输出的信号也会发生改变,此时再到以VCC未发生波动时建立的温度-电阻表中去查表求值时就不正确了,这可以根据式进行计算得知。
3.3 1602LCD液晶屏1602字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式LCD。
引脚功能说明1602LCD采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如下表所示:1602与STM32连接说明:四、软件设计4.1 ADC程序STM32F103RBT6部有3个ADC,实际上我们只需要软件设置就可以正常工作,不过我们需要在外部连接其端口到被测电压上面。
本系统通过ADC1的通道0(PA0)来读取外部电压值。
测量电压不能超过3.3V。
程序步骤1)启开启PA口和ADC1时钟,设置PA0为模拟输入。
2)复位ADC1,同时设置ADC1分频因子。
开启ADC1 时钟之后,我们要复位ADC1,将ADC1的全部寄存器重设为缺省值之后我们就可以通过RCC_CFGR 设置ADC1的分频因子。
分频因子要确保ADC1 的时钟(ADCCLK)不要超过14Mhz。
这个我们设置分频因子位6,时钟为72/6=12MHz。
3)初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息。
设置单次转换模式、触发方式选择、数据对齐方式等都在这一步实现。
同时,我们还要设置ADC1 规则序列的相关信息,我们这里只有一个通道,并且是单次转换的,所以设置规则序列道数为1。
5)使能ADC并校准。
在设置完了以上信息后,我们就使能AD转换器,执行复位校准和AD校准,注意这两步是必须的!不校准将导致结果很不准确。
每次进行校准之后要等待校准结束。
这里是通过获取校准状态来判断是否校准是否结束。
6)读取ADC在上面的校准完成之后,ADC 就算准备好了。
接下来我们要做的就是设置规则序列1 里面的通道,采样顺序,以及通道的采样周期,然后启动ADC转换。
在转换结束后,读取ADC转换结果值就是了。
7)多次读取ADC值,求平均求平均使获得的ADC值稳定。
4.2 1602LCD显示程序程序步骤必要的声明定义等;写入指令数据到LCD;写入字符显示数据到LCD;写字符串函数;写数字函数;GPIO配置;LCD初始化设定;4.3 主程序各子函数初始化(SystemInit();delay_init(72);NVIC_Configuration();uart_init(9600);LED_Init();LCD_Init();Adc_Init();)while循环(获取ADC值,转换成电压值,写字符串,写数据值,LED闪烁)。
五、性能测试硬件调试比较简单,主要是调试PT100温度传感器电路,首先检查电路的焊接是否正确,然后用万用表测试,首先检测PT100传感器的电阻值是否随温度变化,并测量其在0°C和100°C的电阻值;然后在测量基准电压,将其调试到合适值(4.960V);然后测量电桥输出的最大电压差Umax,并确定运算放大器的放大倍数(放大器的输出电压不能大于3.3V,倍数A=R5/R3=3.3/Uma x,调试过程中可改变R5电阻值);最后测量运算放大器实际的输出电压,与电桥输出电压,计算实际放大倍数与理论放大倍数比较;调试完后可连接STM3 2进行软件编写。
软件调试可以先编写1602显示程序并进行硬件的正确性检验,然后分别进行ADC程序和主程序的编写和调试。
最后进行整体系统测试六、课程设计心得经过将近一段时间的设计、焊接、编程、调试,我们终于完成了温度测量的设计,基本能够达到设计要求,此次的设计使我从中学到了一些很重要的东西,那就是如何从理论到实践的转化,怎样将我们所学到的知识运用到实践中去。
在大学课堂的学习只是给我们灌输专业知识,而我们应把所学的知识应用到我们现实的生活中去。
这次的设计不仅使我们将课堂上学到的理论知识与实际应用结合了起来,而且使我们对电子电路、电子元器件等方面的知识有了更进一步的认识,同时在软件编程、焊板调试、相关调试仪器的使用等方面得到较全面的锻炼和提高,为今后能够独立进行某些单片机应用系统的开发设计工作打下一定的基础。
此次单片机设计也为我们以后进行更复杂的单片机系统设计提供了宝贵的经验。
通过此次的综合设计,我们初步掌握了单片机系统设计的基本原理。
充分认识到理论学习与实践相结合的重要性,对于书本上的很多知识,不但要学会,更重要的是会运用到实践中去。
在以后的学习中,我们会更加注重实践方面的锻炼,多提高自己的动手实践能力。
参考文献1、STM32F103RBT6 数据开发手册;2、ALIENTEK miniSTM32 开发板资料3、1602中文资料4、戴蓉,波峰。
传感器原理与工程应用,电子工业.2013.1附录1:系统实物图附录2:系统主要程序一、ADC程序,文件名(adc.c)#include "adc.h"#include "delay.h"void Adc_Init(void){ADC_InitTypeDef ADC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE ); //使能ADC1通道时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12,ADC最大时间不能超过14MGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚GPIO_Init(GPIOA, &GPIO_InitStructure);ADC_DeInit(ADC1); //将外设ADC1 的全部寄存器重设为缺省值ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//模数转换工作在单次转换模式ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1ADC_ResetCalibration(ADC1); //重置指定的ADC1的校准寄存器while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1重置校准寄存器的状态,设置状态则等待ADC_StartCalibration(ADC1); //开始指定ADC1的校准状态while(ADC_GetCalibrationStatus(ADC1));//获取指定ADC1的校准程序,设置状态则等待ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能}//获得ADC值//ch:通道值0-3u16 Get_Adc(u8 ch){//设置指定ADC的规则组通道,设置它们的转化顺序和采样时间ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );//ADC1,,规则采样顺序值为1,采样时间为239.5周期ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能ADC的软件转换启动功能ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果}//获取通道ch的转换值,取times次,然后平均//ch:通道编号//times:获取次数//返回值:通道ch的times次转换结果平均值u16 Get_Adc_Average(u8 ch,u8 times){u32 temp_val=0;u8 t;for(t=0;t<times;t++){ temp_val+=Get_Adc(ch);delay_ms(5);}return temp_val/times;}二、LCD程序,文件名(lcd.c)#include "lcd.h"#include "stdlib.h"#include "delay.h"unsigned char digit[ ]={"0123456789 "}; void LCD_Writecmd(uchar cmd){LCD_RS=0; delay_us(1);LCD_RW=0; delay_us(1);DATAOUT(cmd);delay_us(300);LCD_EN=1;delay_us(300);//必要的延时LCD_EN=0; //下降沿,LCD1602开始工作}void LCD_Writedata(uchar dat){LCD_RS=1;delay_us(1);LCD_RW=0;delay_us(1);DATAOUT(dat);delay_us(300);LCD_EN=1; delay_us(300); //很重要的延时,经调试,延时300us以上才可以LCD_EN=0; //下降沿,开始写入有效数据}void LCD_DispString(char str[]){uchar i=0;for(i=0;str[i] != '\0';i++){LCD_Writedata(str[i]);}}void LCD_Dispnum(uint32_t num){ u16 R1=5000; u16 R2=5000;u16 R3=300;u16 Vin=40960; float x,y,z,rx;float t,VB; u16 T,RX,i;unsigned char B1,B2,B3,B4,B5;unsigned char C1,C2,C3,C4,C5;unsigned char D1,D2,D3,D4,D5;VB=(float)num/30;x=(float)VB/(float)Vin; //Rx = (R3*R2 + R2* (R1+R3)VB/Vin )/ (R1- (R1+R3)*VB/ Vin)y=R3*R2+(float)R2*(R1+R3)*x;z=R1- (R1+R3)*x;rx=y/z;RX=rx*1000/10;t=1.000/0.77*rx-300.000/0.77; //(0C,300)(100,377)T=t*1000/10;B5=num/10000;B4=num%10000/1000;B3=num%1000/100;B2=num%100/10;B1=num%10;C5=RX/10000;C4=RX%10000/1000;C3=RX%1000/100;C2=RX%100/10;C1=RX%10; if(C5==0){C5=11;if(C4==0){C4=11; }}D5=T/10000; D4=T%10000/1000;D3=T%1000/100;D2=T%100/10;D1=T%10;if(D5==0){ D5=12;if(D4==0){D4=12; }}LCD_Writecmd(0x80+0x06);LCD_Writedata(digit[B5]);LCD_Writedata('.');LCD_Writedata(digit[B4]);LCD_Writedata(digit[B3]);LCD_Writedata(digit[B2]);LCD_Writedata(digit[B1]);LCD_Writecmd(0x80+0x41);LCD_Writedata(digit[C5]);LCD_Writedata(digit[C4]);LCD_Writedata(digit[C3]);LCD_Writedata('.');LCD_Writedata(digit[C2]);LCD_Writedata(digit[C1]);LCD_Writecmd(0x80+0x48);LCD_Writedata(digit[D5]);LCD_Writedata(digit[D4]);LCD_Writedata(digit[D3]);LCD_Writedata('.');LCD_Writedata(digit[D2]);LCD_Writedata(digit[D1]);for(i=0;i<4;i++) //每1s采集一次数据)delay_ms(25);}void GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE );GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE); //JTAG-DP 失能+ SW-DP使能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(GPIOB, &GPIO_InitStructure);GPIO_Write(GPIOB,0XFFFF); //PB口OD输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_SetBits(GPIOC, GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_8|GPIO_Pin_3);//如果每一位决定一个GPIO_Pin,则可以通过或的形式来初始化多个IO}void LCD_Init(void){ GPIO_Configuration();delay_ms(200); //延时200ms LCD_EN=0;LCD_Writecmd(0x38); delay_ms(5); LCD_Writecmd(0x38); delay_ms(5); LCD_Writecmd(0x38); delay_ms(5); LCD_Writecmd(0x08); delay_ms(5); LCD_Writecmd(0x06); delay_ms(5); LCD_Writecmd(0x01); delay_ms(5); LCD_Writecmd(0x0c); delay_ms(5); }三、主程序,文件名(main.c)#include "led.h"#include "delay.h"#include "sys.h"#include "usart.h"#include "lcd.h"#include "adc.h"int main(void){ u16 adcx;float V;u16 voltage;SystemInit();delay_init(72); //延时初始化NVIC_Configuration();uart_init(9600);LED_Init();LCD_Init();Adc_Init();while(1){adcx=Get_Adc_Average(ADC_CH1 ,200);V=(float)adcx*(3.3/4096);LCD_Writecmd(0x80);LCD_DispString("PA0 V: v");LCD_Writecmd(0x80+0x40);LCD_DispString("R T C");voltage=V*100000/10;LCD_Dispnum(voltage);LED0=!LED0;delay_ms(250);}}。