STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)

智能温度计的设计

设计内容

1)一路温度检测,量程为-40℃~+125℃,误差≤±0.5℃;

2)温度3位数码显示(XX.X℃);

3)开机自检;

4)配简单键盘,如温度上、下限临界报警值设置;

5)配置通信接口,上位机显示温度曲线。

单片机(32、51)、温度传感器()、键盘、LCD、

我们的基本思路是DS180B20温度传感器采集温度信号,经内部ADC转换为数字信号,输出到MCU,通过按键设置温度传感器报警的上下限,并通过USART串口通讯将温度信号传入上位机中,然后温度显示通过0.96寸OLED显示,报警是通过STM32mini自带的LED灯显示报警。

STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第1张图片

STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第2张图片

1.OLED显示屏

首先做的是OLED显示屏的显示,具体可以参考基于stm32的OLED温湿度显示_stm32温湿度显示_IT23131的博客-CSDN博客

 完成基本的显示之后我采用了多级菜单显示具体效果如下图所示:

STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第3张图片STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第4张图片

STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第5张图片STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第6张图片

STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第7张图片  STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第8张图片

 多级菜单的实现主要通过构建一个结构体,然后通过按键的触发实现界面的转换,本项目中,使用到了3个按键:下一个(next),确定(enter),退出(back)。所以,接下首先定义一个结构体,结构体中一共有5个变量(3+2),分别为:当前索引序号(current),向下一个(next),确定(enter),退出(back),当前执行函数(void)。

duoji.h

#ifndef __MENU_H
#define __MENU_H
#include "stm32f10x.h" 
#define  u8 unsigned char
 

//#define KEY0 HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)		//KEY0
//#define KEY1 HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)		//
//#define WK_UP HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)		//
 #define KEY0  GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)//低电平有效
#define KEY1  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_15)//低电平有效
#define WK_UP   GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//高电平有效

#define KEY0_PRES	1		//KEY0  
#define KEY1_PRES	2		//KEY1 
#define WKUP_PRES	3		//WK_UP  
typedef struct
{
    u8 current;	//当前状态索引号
    u8 next; 		//向下一个
    u8 enter; 	//确定
		u8 back; 		//退出
    void (*current_operation)(void); //当前状态应该执行的操作
} Menu_table;
 
//界面UI
void home();
void Temperature();
void Maxtem();  //设置最大警告温度值
void Mintem(); //设置最低警告温度值

 
void KEY_Init(void);//IO??? 
void  Menu_key_set(void);
u8 KEY_Scan(u8 mode);
 

#endif

注意代码部分引入了很多头文件是和各个模块有关系的如果读者不需要自主删除就好。

duoji.c

#include "duoji.h"
#include "oled.h"
#include "ds18b20.h"
#include "gui.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "ds18b20.h" 
#include "Key.h"
#include "led.h"



//UI界面
//主页
/****************************************************/
//UI库
/****************************************************/
void KEY_Init(void)
{
	
	GPIO_InitTypeDef GPIO_InitStructure;

 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);

	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_15;//PA15
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 
 	GPIO_Init(GPIOA, &GPIO_InitStructure);//???GPIOA15
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;//PC5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; 
 	GPIO_Init(GPIOC, &GPIO_InitStructure);//???GPIOC5
 
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;//PA0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIOA, &GPIO_InitStructure);//GPIOA.0
	
}  
void (*current_operation_index)();	 
 
Menu_table  table[30]=
{
    {0,1,0,0,(*home)},	//一级界面(主页面)
		
    {1,2,1,0,(*Setting)},	//温度界面
    {2,3,2,0,(*Palygame)},	//上限温度设置界面
    {3,1,3,0,(*Temperature)},	//下限温度设置界面
};
 
uint8_t  func_index = 0;	//主程序此时所在的程序索引值

void  Menu_key_set(void)
{
  if((KEY_Scan(0) == KEY0_PRES) && (func_index != 4))
  { 
    func_index=table[func_index].next;	//按键next按下后的索引号
    printf("1");
		OLED_Clear(0); 
		delay_ms(10);
  }
  if((KEY_Scan(0) == KEY1_PRES) && (func_index != 4))
  {
    func_index=table[func_index].enter;	//按下enter后的索引号
    OLED_Clear(0);
		printf("2");
		delay_ms(10);
  }
 
	if(KEY_Scan(0) == WKUP_PRES)
  {
    func_index=table[func_index].back;	//按键back后的索引号
    OLED_Clear(0);
		printf("3");
		delay_ms(10);
  }
	//printf("{tem:%d\r\n}",func_index);
  current_operation_index=table[func_index].current_operation;	//执行当前索引号对应的功能函数
  (*current_operation_index)();//执行操作函数
}
 
//初始界面
void home()
{

	  GUI_ShowCHinese(10,0,16,"智能温度系统:",1);
	  GUI_ShowCHinese(20,20,16,"感谢使用",1);
	  GUI_ShowCHinese(15,40,16,"南理彭于晏",1);
}
 u8 data=0; //记录输入最大温度上限的数
 u8 data1=0; //记录输入最小温度上限的数
void Temperature()
{

	u8 t;
	float temperate;	
	float temperate1;
	float temperate2;
	float temperate3;
	while(1)
	{
		OLED_Clear(0);
		 	while(DS18B20_Init())	//DS18B20初始化	
	{
		GUI_ShowString(0,15,"DS18B20 Error",16,1);
		delay_ms(200);
	}		
	  OLED_Clear(0);
	  GUI_ShowString(15,0,"DS18B20 OK",16,1);
		GUI_ShowCHinese(20,20,16,"当前温度:",1);
	  while(!DS18B20_Init())
	{	  
		// 界面设计
    // OLED界面显示温度		
 		if(t%10==0)//每100ms读取一次
		{									  
			temperate=DS18B20_Get_Temp();	
			if(temperate<0)
			{
				GUI_ShowString(20,40,"-",16,1);			//显示负号
				temperate=-temperate;					//转为正数
			}else GUI_ShowString(20,40," ",16,1);			//去掉负号
			temperate=temperate/10;
			//温度补偿
			temperate2 = 0.9399*exp(0.0157*temperate); //该函数有标定数据得出
			temperate3 = temperate+temperate2;//进行补偿
			GUI_ShowNum(20,40,(u8)temperate3,3,16,1);	//显示正数部分	    
			temperate1=temperate3-(u8)temperate3;	  		
		  GUI_ShowString(50,40,".",16,1);
		  GUI_ShowNum(55,40,temperate1*10,1,16,1);
		  GUI_ShowString(65,40,"^C",16,1);
		}
		temperate=DS18B20_Get_Temp();
		if(temperate3>data)//温度过高,红灯亮
		{
		GPIO_ResetBits(GPIOA,GPIO_Pin_8); //LED0
		GPIO_SetBits(GPIOD,GPIO_Pin_2);//LED1
		}
		else if(temperate3

2.按键输出

我自己搭建了一个12键的3*4扫描法的键盘,基本原理可参照(48条消息) STM32单片机学习3--STM32控制键盘_stm32 键盘_贝勒里恩的博客-CSDN博客

比较简陋,也可以直接从网上买集成好的键盘,自己焊上杜邦线就可以,我是3+4一共需要7个I/O引脚,连接到stm32上,具体引脚图如下:

第一行

PB5

第二行 PB6
第三行 PB7
第四行 PB8
第一列 PA1
第二列 PA2
第三列 PA3

STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第9张图片

key.h

#ifndef __KEY_H
#define __KEY_H
#include "sys.h"
#include "stm32f10x.h"

void delay_us(uint32_t delay_us);
void delay_ms(uint16_t delay_ms);

void KEY_GPIO_Config(void);
int scan(void);
 
		    
#endif


key.c

#include "Key.h"
#include "delay.h"
void KEY_GPIO_Config(void)
{
	//定义一个GPIO_InitTypeDef类型的结构体
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//开启GPIOA、GPIOB外设时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB,ENABLE);
	
	///控制行  四行
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	///读取列 三列
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
}
int scan(void)
{
	uint8_t flag = 0;
	
	//扫描第一行
	GPIO_SetBits(GPIOB,GPIO_Pin_5);
	GPIO_ResetBits(GPIOB,GPIO_Pin_6);
	GPIO_ResetBits(GPIOB,GPIO_Pin_7);
	GPIO_ResetBits(GPIOB,GPIO_Pin_8);
	
	//扫描第一列
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
		if(flag == 1) {
			flag = 2;
			return 1;
		}
	}
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
		if(flag == 1) {
			flag = 0;
			return 4;
		}
	}
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
		if(flag == 1) {
			flag = 0;
			return 7;
		}
	}
	//扫描第二行
	GPIO_ResetBits(GPIOB,GPIO_Pin_5);
	GPIO_SetBits(GPIOB,GPIO_Pin_6);
	GPIO_ResetBits(GPIOB,GPIO_Pin_7);
	GPIO_ResetBits(GPIOB,GPIO_Pin_8);
	
	//?????
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
		if(flag == 1) {
			flag = 0;
			return 2;
		}
	}
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
		if(flag == 1) {
			flag = 0;
			return 5;
		}
	}
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
		if(flag == 1) {
			flag = 0;
			return 8;
		}
	}
	
	//扫描第三行
	GPIO_ResetBits(GPIOB,GPIO_Pin_5);
	GPIO_ResetBits(GPIOB,GPIO_Pin_6);
	GPIO_SetBits(GPIOB,GPIO_Pin_7);
	GPIO_ResetBits(GPIOB,GPIO_Pin_8);
	
	//?????
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
	if(flag == 1) {
		delay_ms(100);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
		if(flag == 1) {
			flag = 0;
			return 3;
		}
	}
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
	if(flag == 1) {
		delay_ms(100);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
		if(flag == 1) {
			flag = 0;
			return 6;
		}
	}
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
		if(flag == 1) {
			flag = 0;
			return 9;
		}
	}
	
	//扫描第四行
	GPIO_ResetBits(GPIOB,GPIO_Pin_5);
	GPIO_ResetBits(GPIOB,GPIO_Pin_6);
	GPIO_ResetBits(GPIOB,GPIO_Pin_7);
	GPIO_SetBits(GPIOB,GPIO_Pin_8);
	
	//?????
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1);
		if(flag == 1) {
			flag = 0;
			return 10;
		}
	}
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2);
		if(flag == 1) {
			flag = 0;
			return 0;
		}
	}
	flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
	if(flag == 1) {
		delay_ms(200);
		flag = GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3);
		if(flag == 1) {
			flag = 0;
			return 11;
		}
	}

	return -1;
}

 3. DS180B20温度传感器

STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第10张图片

这款温度传感器内部已经集成了ADC直接输出数字信号,不需要外接ADC,所以它只有三个口VCC、GND、DATA。

VCC 3.3V
GND GND
DATA PA5

 ds18b20.h

#ifndef __DS18B20_H
#define __DS18B20_H 
#include "sys.h"   

//IO方向设置
#define DS18B20_IO_IN()  {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=8<<20;}
#define DS18B20_IO_OUT() {GPIOA->CRL&=0XFF0FFFFF;GPIOA->CRL|=3<<20;}
IO操作函数											   
#define	DS18B20_DQ_OUT PAout(5) //数据端口	PA0
#define	DS18B20_DQ_IN  PAin(5)  //数据端口	PA0 
   	
u8 DS18B20_Init(void);			//初始化DS18B20
short DS18B20_Get_Temp(void);	//获取温度
void DS18B20_Start(void);		//开始温度转换
void DS18B20_Write_Byte(u8 dat);//写入一个字节
u8 DS18B20_Read_Byte(void);		//读出一个字节
u8 DS18B20_Read_Bit(void);		//读出一个位
u8 DS18B20_Check(void);			//检测是否存在DS18B20
void DS18B20_Rst(void);			//复位DS18B20    
#endif

 ds18b20.c

#include "ds18b20.h"
#include "delay.h"	

//复位DS18B20
void DS18B20_Rst(void)	   
{                 
	DS18B20_IO_OUT(); //SET PA0 OUTPUT
    DS18B20_DQ_OUT=0; //拉低DQ
    delay_us(750);    //拉低750us
    DS18B20_DQ_OUT=1; //DQ=1 
	delay_us(15);     //15US
}
//等待DS18B20的回应
//返回1:未检测到DS18B20的存在
//返回0:存在
u8 DS18B20_Check(void) 	   
{   
	u8 retry=0;
	DS18B20_IO_IN();//SET PA0 INPUT	 
    while (DS18B20_DQ_IN&&retry<200)
	{
		retry++;
		delay_us(1);
	};	 
	if(retry>=200)return 1;
	else retry=0;
    while (!DS18B20_DQ_IN&&retry<240)
	{
		retry++;
		delay_us(1);
	};
	if(retry>=240)return 1;	    
	return 0;
}
//从DS18B20读取一个位
//返回值:1/0
u8 DS18B20_Read_Bit(void) 			 // read one bit
{
    u8 data;
	DS18B20_IO_OUT();//SET PA0 OUTPUT
    DS18B20_DQ_OUT=0; 
	delay_us(2);
    DS18B20_DQ_OUT=1; 
	DS18B20_IO_IN();//SET PA0 INPUT
	delay_us(12);
	if(DS18B20_DQ_IN)data=1;
    else data=0;	 
    delay_us(50);           
    return data;
}
//从DS18B20读取一个字节
//返回值:读到的数据
u8 DS18B20_Read_Byte(void)    // read one byte
{        
    u8 i,j,dat;
    dat=0;
	for (i=1;i<=8;i++) 
	{
        j=DS18B20_Read_Bit();
        dat=(j<<7)|(dat>>1);
    }						    
    return dat;
}
//写一个字节到DS18B20
//dat:要写入的字节
void DS18B20_Write_Byte(u8 dat)     
 {             
    u8 j;
    u8 testb;
	DS18B20_IO_OUT();//SET PA0 OUTPUT;
    for (j=1;j<=8;j++) 
	{
        testb=dat&0x01;
        dat=dat>>1;
        if (testb) 
        {
            DS18B20_DQ_OUT=0;// Write 1
            delay_us(2);                            
            DS18B20_DQ_OUT=1;
            delay_us(60);             
        }
        else 
        {
            DS18B20_DQ_OUT=0;// Write 0
            delay_us(60);             
            DS18B20_DQ_OUT=1;
            delay_us(2);                          
        }
    }
}
//开始温度转换
void DS18B20_Start(void)// ds1820 start convert
{   						               
    DS18B20_Rst();	   
	DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);// skip rom
    DS18B20_Write_Byte(0x44);// convert
} 
//初始化DS18B20的IO口 DQ 同时检测DS的存在
//返回1:不存在
//返回0:存在    	 
u8 DS18B20_Init(void)
{
 	GPIO_InitTypeDef  GPIO_InitStructure;
 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	 //使能PORTA口时钟 
	
 	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				//PORTA0 推挽输出
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		  
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOA, &GPIO_InitStructure);

 	GPIO_SetBits(GPIOA,GPIO_Pin_5);    //输出1

	DS18B20_Rst();

	return DS18B20_Check();
}  
//从ds18b20得到温度值
//精度:0.1C
//返回值:温度值 (-550~1250) 
short DS18B20_Get_Temp(void)
{
    u8 temp;
    u8 TL,TH;
	short tem;
    DS18B20_Start ();                    // ds1820 start convert
    DS18B20_Rst();
    DS18B20_Check();	 
    DS18B20_Write_Byte(0xcc);// skip rom
    DS18B20_Write_Byte(0xbe);// convert	    
    TL=DS18B20_Read_Byte(); // LSB   
    TH=DS18B20_Read_Byte(); // MSB  
	    	  
    if(TH>7)
    {
        TH=~TH;
        TL=~TL; 
        temp=0;//温度为负  
    }else temp=1;//温度为正	  	  
    tem=TH; //获得高八位
    tem<<=8;    
    tem+=TL;//获得底八位
    tem=(float)tem*0.625;//转换     
	if(temp)return tem; //返回温度值
	else return -tem;    
} 
 

 4. 上位机显示

我直接采用的纸飞机调试助手软件,它可以直接通过usb串口接收数据,并且实时输出图像。

STM32设计实现智能温度计(OLED屏幕的使用,多级屏幕转换,扫描键盘法的搭建、DS180B20温度传感器的使用、实现上位机的可视化)_第11张图片

大家可以参照:(48条消息) STM32数据可视化显示——纸飞机串口调试助手的使用_stm32串口调试助手_拾柒#_17的博客-CSDN博客

 感谢大家的观看,希望大家点个关注多多支持,有不懂的可以私信或者评论。

你可能感兴趣的:(stm32,单片机)