准备
Proteus
Keil
Proteus原理图绘制
芯片:STM32F103R6
LCD:LM016L
运算放大器:LM358
PT100
芯片设置这里,选择你在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,,可能存在很多不完善的地方,欢迎各位交流指正!
本文介绍了使用STM32F103R6微控制器通过ADC采集PT100信号,经过插值法计算温度,并在LCD1602显示屏上显示的过程。涉及到的工具包括Proteus进行电路仿真,Keil进行程序开发,以及相应的GPIO配置、LCD驱动程序和AD转换函数。代码示例展示了从ADC获取数据到转换为温度值并在LCD上显示的完整流程。



862

被折叠的 条评论
为什么被折叠?



