项目:6路温度显示+实时时钟
- 1、6路温度显示
- ①TempMenu.c文件的代码
- ②TempMenu.h文件的代码
- ③main.c文件的代码
- ④Timer.c文件的代码
- ⑤Delay.c文件的代码
- ⑥Key.c文件的代码
- 2、实时时钟显示
- ①BeiJingTime.c文件的代码
- ②BeiJingTime.h文件的代码
- ③main.c文件的代码如下
- ④Timer.c文件的代码
1、6路温度显示
项目描述:
①单片机启动时,LCD1602显示启动界面 “TEMP MENU”
②显示1s后,自动跳转到显示温度数据。一次显示界面显示2路温度数据
③LCD1602显示温度分为自动模式和手动模式,在自动模式下:每隔1s跳转显示。
④使用按键KEY2切换自动模式和手动模式,切换时显示为“Automa”表示切换为自动模式,显示为“Manual”表示手动模式
⑤在手动模式下:按键KEY1用于切换温度显示
⑥按键KEY4用于切换为设置不同通道温度阈值模式,进入设置模式后,按键KEY1为增加温度阈值,KEY2为减小温度阈值,KEY3确定阈值并且退出设置模式
项目演示:
QQ2025415-112215
①TempMenu.c文件的代码
#include "TempMenu.h"
/* 定义6路 CH1~CH6 温度缓存区 */
float Temp[] = {15.23, 21.55, 25.41, 22.77, 27.14, 22.34};
/* 定义CH1~CH6通道温度阈值 */
unsigned char ThreTemp[] = {11, 12, 13, 14, 15, 16};
unsigned char Waring_CHNum = 0;
/**
* 温度菜单开机显示
*/
void Temp_StartMenu(void)
{
LCD_ShowString(1,1," TEMP MENU ");
LCD_ShowString(2,1," V1.0 ");
}
/**
* 显示℃字符函数
*/
void SHOW_C(unsigned char Hang, unsigned char Lie)
{
LCD_ShowChar(Hang, Lie, 0xdf);
LCD_ShowChar(Hang, Lie + 1, 0x43);
}
/**
* 显示CH1 CH2通道的温度
*/
void SHOW_CH1_CH2(void)
{
/* 显示CH1通道的温度 */
LCD_ShowString(1,1,"CH1:");
LCD_ShowFloat(1,5,Temp[0],2,2);
SHOW_C(1,11);
LCD_ShowString(1,14," ");//清除上一次显示的残留字符
/* 显示CH2通道的温度 */
LCD_ShowString(2,1,"CH2:");
LCD_ShowFloat(2,5,Temp[1],2,2);
SHOW_C(2,11);
LCD_ShowString(2,13," ");
}
/**
* 显示CH3 CH4通道的温度
*/
void SHOW_CH3_CH4(void)
{
/* 显示CH3通道的温度 */
LCD_ShowString(1,1,"CH3:");
LCD_ShowFloat(1,5,Temp[2],2,2);
SHOW_C(1,11);
/* 显示CH4通道的温度 */
LCD_ShowString(2,1,"CH4:");
LCD_ShowFloat(2,5,Temp[3],2,2);
SHOW_C(2,11);
}
/**
* 显示CH5 CH6通道的温度
*/
void SHOW_CH5_CH6(void)
{
/* 显示CH5通道的温度 */
LCD_ShowString(1,1,"CH5:");
LCD_ShowFloat(1,5,Temp[4],2,2);
SHOW_C(1,11);
/* 显示CH6通道的温度 */
LCD_ShowString(2,1,"CH6:");
LCD_ShowFloat(2,5,Temp[5],2,2);
SHOW_C(2,11);
}
/**
* 显示设置CH1通道阈值界面
*/
void SHOW_SetCH1Temp(void)
{
LCD_ShowString(1,1," SETING ");
/* 显示被设置CH1通道的温度 */
LCD_ShowString(2,1,"CH1:");
LCD_ShowFloat(2,5,ThreTemp[0],2,2);
SHOW_C(2,11);
LCD_ShowString(2,13," ");
}
/**
* 显示设置CH2通道阈值界面
*/
void SHOW_SetCH2Temp(void)
{
LCD_ShowString(1,1," SETING ");
/* 显示被设置CH2通道的温度 */
LCD_ShowString(2,1,"CH2:");
LCD_ShowFloat(2,5,ThreTemp[1],2,2);
SHOW_C(2,11);
LCD_ShowString(2,13," ");
}
/**
* 显示设置CH3通道阈值界面
*/
void SHOW_SetCH3Temp(void)
{
LCD_ShowString(1,1," SETING ");
/* 显示被设置CH3通道的温度 */
LCD_ShowString(2,1,"CH3:");
LCD_ShowFloat(2,5,ThreTemp[2],2,2);
SHOW_C(2,11);
LCD_ShowString(2,13," ");
}
/**
* 显示设置CH4通道阈值界面
*/
void SHOW_SetCH4Temp(void)
{
LCD_ShowString(1,1," SETING ");
/* 显示被设置CH4通道的温度 */
LCD_ShowString(2,1,"CH4:");
LCD_ShowFloat(2,5,ThreTemp[3],2,2);
SHOW_C(2,11);
LCD_ShowString(2,13," ");
}
/**
* 显示设置CH5通道阈值界面
*/
void SHOW_SetCH5Temp(void)
{
LCD_ShowString(1,1," SETING ");
/* 显示被设置CH5通道的温度 */
LCD_ShowString(2,1,"CH5:");
LCD_ShowFloat(2,5,ThreTemp[4],2,2);
SHOW_C(2,11);
LCD_ShowString(2,13," ");
}
/**
* 显示设置CH6通道阈值界面
*/
void SHOW_SetCH6Temp(void)
{
LCD_ShowString(1,1," SETING ");
/* 显示被设置CH6通道的温度 */
LCD_ShowString(2,1,"CH6:");
LCD_ShowFloat(2,5,ThreTemp[5],2,2);
SHOW_C(2,11);
LCD_ShowString(2,13," ");
}
/**
* 显示报警界面
*/
void SHOW_Waring(void)
{
LCD_ShowString(1,1," WARING ");
/* 显示被设置CH6通道的温度 */
LCD_ShowString(2,1,"WaR CH Num:");
LCD_ShowNum(2, 12, Waring_CHNum,2);
}
②TempMenu.h文件的代码
#ifndef __TempMen_H
#define __TempMen_H
#include "LCD1602.h"
void Temp_StartMenu(void);
void SHOW_C(unsigned char Hang, unsigned char Lie);
void SHOW_CH1_CH2(void);
void SHOW_CH3_CH4(void);
void SHOW_CH5_CH6(void);
void SHOW_SetCH1Temp(void);
void SHOW_SetCH2Temp(void);
void SHOW_SetCH3Temp(void);
void SHOW_SetCH4Temp(void);
void SHOW_SetCH5Temp(void);
void SHOW_SetCH6Temp(void);
void SHOW_Waring(void);
#endif
③main.c文件的代码
#include "LCD1602.h"
#include "TempMenu.h"
#include "Key.h"
#include "Delay.h"
#include "Timer.h"
extern char ThreTemp[]; //CH1~CH6通道温度阈值
static char SET_Channel = 0; //设置模式下通道切换变量
static char Seting_Flag = 0; //进入设置模式标志位
char Menu_Status = 0; //状态变量
bit Mode = 0; //0表示自动模式,1表示手动模式
void KEY_ChangeMenu(void);
void SHOW_CHange(void);
void main(void)
{
LCD_Init();
Time0_Intrrupt_Init();
Temp_StartMenu(); //开机显示1s
Delay_s(1);
LCD_WriteCommand(0x01); //清屏
while(1)
{
KEY_ChangeMenu();
SHOW_CHange();
}
}
/**
* 按键切换菜单函数
*/
void KEY_ChangeMenu(void)
{
switch(Key_Scanf())
{
case 1: //按键1按下
if(!Seting_Flag) //没有进入设置模式
{
Menu_Status++; //按下KEY1改变Menu_Status
if(Menu_Status >= 4)
Menu_Status = 0;
}
else //在设置模式下
{
switch(SET_Channel) //按下KEY1增加温度阈值
{
case 1:ThreTemp[0]++;break; //增加CH1的温度阈值
case 2:ThreTemp[1]++;break; //增加CH2的温度阈值
case 3:ThreTemp[2]++;break; //增加CH3的温度阈值
case 4:ThreTemp[3]++;break; //增加CH4的温度阈值
case 5:ThreTemp[4]++;break; //增加CH5的温度阈值
case 6:ThreTemp[5]++;break; //增加CH6的温度阈值
default:break;
}
}
break;
case 2: //按键2按下
if(!Seting_Flag) //没有进入设置模式
{
Mode = !Mode; //切换模式
if(Mode == 0) //表示自动模式
{
LCD_ShowString(1,1," Automa ");
LCD_ShowString(2,1," Automa ");
}
else //手动模式
{
LCD_ShowString(1,1," Manual ");
LCD_ShowString(2,1," Manual ");
}
Delay_s(1);
}
else //在设置模式下
{
switch(SET_Channel) //按下KEY1减小温度阈值
{
case 1:ThreTemp[0]--;break; //减小CH1的温度阈值
case 2:ThreTemp[1]--;break; //减小CH2的温度阈值
case 3:ThreTemp[2]--;break; //减小CH3的温度阈值
case 4:ThreTemp[3]--;break; //减小CH4的温度阈值
case 5:ThreTemp[4]--;break; //减小CH5的温度阈值
case 6:ThreTemp[5]--;break; //减小CH6的温度阈值
default:break;
}
}
break;
case 3: //按键3按下,切换到初始界面
if(!Seting_Flag) //没有进入设置模式
{
Menu_Status = 0; //复位显示
}
else //在设置模式下
{
Seting_Flag = 0; //退出设置模式
Mode = 0; //退出手动模式
LCD_ShowString(1,1," SET OK ");
LCD_ShowString(2,1," SET OK ");
Delay_s(1);
}
break;
case 4: //按键4按下,切换到设置界面
Seting_Flag = 1; //进入设置模式
Mode = 1; //进入手动模式,关闭定时器改变Menu_Status
Menu_Status = 4;
SET_Channel++; //切换设置通道
if(SET_Channel == 7)
{
SET_Channel = 1;
}
break;
default:break;
}
}
/**
* 在不同的Menu_Status下的显示不同的界面
*/
void SHOW_CHange(void)
{
switch(Menu_Status)
{
case 0:SHOW_CH1_CH2();break; //显示CH1-CH2通道的温度
case 1:SHOW_CH3_CH4();break; //显示CH3-CH4通道的温度
case 2:SHOW_CH5_CH6();break; //显示CH5-CH6通道的温度
case 3:SHOW_Waring(); break; //显示报警界面
case 4: //显示设置温度阈值界面
switch(SET_Channel)
{
case 1:SHOW_SetCH1Temp();break; //显示设置CH1通道的界面
case 2:SHOW_SetCH2Temp();break; //显示设置CH2通道的界面
case 3:SHOW_SetCH3Temp();break; //显示设置CH3通道的界面
case 4:SHOW_SetCH4Temp();break; //显示设置CH4通道的界面
case 5:SHOW_SetCH5Temp();break; //显示设置CH5通道的界面
case 6:SHOW_SetCH6Temp();break; //显示设置CH6通道的界面
}
break;
default:break;
}
}
④Timer.c文件的代码
#include "Timer.h"
/**
* 定时器T0的初始化
*/
void Time0_Intrrupt_Init(void)
{
/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */
TMOD &= 0xF0; //将低4位置0
TMOD |= 0x01; //最低位置1
/* 设置定时计数器的初始值,定时1ms */
TH0 = ((65535 - (1000 - 1)) >> 8);
TL0 = (65535 - (1000 - 1)) & 0x00FF;
/* 启动T0 */
TF0 = 0; //清除标志位
TR0 = 1; //启动定时器0
/* 开启中断 */
PT0 = 1; //优先级较高
ET0 = 1; //使能定时器溢出中断
EA = 1; //开启总开关
}
/********中断服务函数*******/
/**
* T0的中断服务函数(每隔1ms对TimeCount加1)
*/
static unsigned long TimeCount = 0;
static unsigned char StatusFlag = 0;
static unsigned long GetTimeCon = 0;
extern char Menu_Status;
extern bit Mode;
void Time0_Rountine(void) interrupt 1
{
//这里不用清除标志位,硬件会自动清除
/* 设置定时计数器的初始值,定时1ms */
TH0 = ((65535 - (1000 - 1)) >> 8);
TL0 = (65535 - (1000 - 1)) & 0x00FF;
TimeCount++;
/* 每隔2s改变一次Menu_Status */
switch(StatusFlag)
{
case 0:
GetTimeCon = TimeCount;
StatusFlag = 1;
case 1:
if(TimeCount - GetTimeCon == 2000)
{
GetTimeCon = TimeCount;
if(!Mode) //自动模式下
{
Menu_Status++;
if(Menu_Status >= 4)
{
Menu_Status = 0;
}
}
}
break;
}
}
/**
* 对外暴露TimeCount的值
*/
unsigned long Get_TimeCount(void)
{
return TimeCount;
}
⑤Delay.c文件的代码
#include "Delay.h"
#include "Timer.h"
/**
* 使用T0构造延时函数ms
*/
void Delay_ms(unsigned int nms)
{
unsigned long time = Get_TimeCount();//获取此时的TimeCount值
while((Get_TimeCount() - time) < nms);
}
/**
* 使用T0构造延时函数s
*/
void Delay_s(unsigned char s)
{
while(s--)
{
Delay_ms(1000);
}
}
⑥Key.c文件的代码
#include "Key.h"
#include "Delay.h"
/**
* 按键检测函数(按下按下,引脚输入低电平)
* Position:需要检测那个按键
* 返回值:不同的按键按下,返回值不同
*/
unsigned char Key_Scanf(void)
{
unsigned char Key_Number = 0;
if(!GPIO3_0 || !GPIO3_1 || !GPIO3_2|| !GPIO3_3)
{
Delay_ms(10);//延时消抖
if(!GPIO3_0)
Key_Number = 1;
if(!GPIO3_1)
Key_Number = 2;
if(!GPIO3_2)
Key_Number = 3;
if(!GPIO3_3)
Key_Number = 4;
while(!GPIO3_0 || !GPIO3_1 || !GPIO3_2|| !GPIO3_3);//按键松手,跳出此循环
Delay_ms(10);//延时消抖
}
return Key_Number;//返回键值
}
2、实时时钟显示
项目描述:
①单片机启动时,LCD1602显示启动界面 “BeiJing Time”
②按键KEY4用于切换为设置时钟秒/分/时模式,进入设置模式后,按键KEY1为增加时钟,KEY1为减小时钟,KEY3确定时钟并且退出设置模式
项目演示:
QQ2025415-115636
①BeiJingTime.c文件的代码
#include "BeijingTime.h"
/* 定义存储时分秒的缓存区 */
char Current_Time[] = {10, 10 ,10};//时分秒
/**
* 北京时间开机显示界面
*/
void Beijing_Start(void)
{
LCD_ShowString(1,1," BeiJing Time ");
LCD_ShowString(2,1," V1.0 ");
}
/**
* 显示当前时间
*/
void SHOW_Current_Time(void)
{
LCD_ShowString(1,1," Current Time ");
LCD_ShowNum(2, 5, Current_Time[0],2);
LCD_ShowChar(2,7,':');
LCD_ShowNum(2, 8, Current_Time[1],2);
LCD_ShowChar(2,10,':');
LCD_ShowNum(2, 11, Current_Time[2],2);
}
/**
* 显示设置小时
*/
void Set_Hour(void)
{
LCD_ShowString(1,1," SET Hour ");
LCD_ShowNum(2, 5, Current_Time[0],2);
LCD_ShowChar(2,7,':');
LCD_ShowNum(2, 8, Current_Time[1],2);
LCD_ShowChar(2,10,':');
LCD_ShowNum(2, 11, Current_Time[2],2);
}
/**
* 显示设置分钟
*/
void Set_Min(void)
{
LCD_ShowString(1,1," SET Min ");
LCD_ShowNum(2, 5, Current_Time[0],2);
LCD_ShowChar(2,7,':');
LCD_ShowNum(2, 8, Current_Time[1],2);
LCD_ShowChar(2,10,':');
LCD_ShowNum(2, 11, Current_Time[2],2);
}
/**
* 显示设置秒
*/
void Set_Second(void)
{
LCD_ShowString(1,1," SET Second ");
LCD_ShowNum(2, 5, Current_Time[0],2);
LCD_ShowChar(2,7,':');
LCD_ShowNum(2, 8, Current_Time[1],2);
LCD_ShowChar(2,10,':');
LCD_ShowNum(2, 11, Current_Time[2],2);
}
②BeiJingTime.h文件的代码
#ifndef __BeijingTime_H
#define __BeijingTime_H
#include "LCD1602.h"
void Beijing_Start(void);
void SHOW_Current_Time(void);
void Set_Hour(void);
void Set_Min(void);
void Set_Second(void);
#endif
③main.c文件的代码如下
#include "LCD1602.h"
#include "BeijingTime.h"
#include "Key.h"
#include "Delay.h"
#include "Timer.h"
extern char Current_Time[];
static unsigned char SET = 0;
unsigned char Seting_Flag = 0; //进入设置模式标志位
void KEY_ChangeStatues(void);
void SHOW_TIME(void);
void main(void)
{
LCD_Init();
Time0_Intrrupt_Init();
Beijing_Start(); //开机显示1s
Delay_s(1);
LCD_WriteCommand(0x01); //清屏
while(1)
{
KEY_ChangeStatues();
SHOW_TIME();
}
}
/**
* KEY4改变状态
*/
void KEY_ChangeStatues(void)
{
switch(Key_Scanf())
{
case 1:
if(Seting_Flag) //在设置模式下
{
switch(SET)
{
case 1:Current_Time[2]++; //KEY1按键按下增加秒
if(Current_Time[2] > 60)
Current_Time[2] = 0;
break;
case 2:Current_Time[1]++; //KEY1按键按下增加分
if(Current_Time[1] > 60)
Current_Time[1] = 0;
break;
case 3:Current_Time[0]++; //KEY1按键按下增加时
if(Current_Time[0] > 24)
Current_Time[0] = 0;
break;
default:break;
}
}
break;
case 2:
if(Seting_Flag) //在设置模式下
{
switch(SET)
{
case 1:Current_Time[2]--; //KEY2按键按下减少秒
if(Current_Time[2] < 0)
Current_Time[2] = 59;
break;
case 2: Current_Time[1]++; //KEY2按键按下减少分
if(Current_Time[1] < 0)
Current_Time[1] = 59;
break;
case 3:Current_Time[0]++; //KEY2按键按下减少时
if(Current_Time[0] < 24)
Current_Time[0] = 0;
break;
default:break;
}
}
break;
case 3: //按键KEY3按键按下
if(Seting_Flag) //在设置模式下
{
LCD_ShowString(1,1," SET OK ");
LCD_ShowString(2,1," SET OK ");
Delay_s(1);
LCD_WriteCommand(0x01); //清屏
Seting_Flag = 0; //退出设置模式
}
break;
case 4: //按键KEY4按键按下
Seting_Flag = 1; //进入设置模式
SET++;
if(SET >= 4)
{
SET = 1;
}
break;
}
}
void SHOW_TIME(void)
{
if(Seting_Flag)
{
switch(SET)
{
case 1:Set_Second();break;
case 2:Set_Min();break;
case 3:Set_Hour();break;
}
}
else
{
SHOW_Current_Time();//显示当前时间
}
}
④Timer.c文件的代码
#include "Timer.h"
/**
* 定时器T0的初始化
*/
void Time0_Intrrupt_Init(void)
{
/* 设置T0的计数器为16,且时钟来源为晶振 TMOD = xxxx 0001 */
TMOD &= 0xF0; //将低4位置0
TMOD |= 0x01; //最低位置1
/* 设置定时计数器的初始值,定时1ms */
TH0 = ((65535 - (1000 - 1)) >> 8);
TL0 = (65535 - (1000 - 1)) & 0x00FF;
/* 启动T0 */
TF0 = 0; //清除标志位
TR0 = 1; //启动定时器0
/* 开启中断 */
PT0 = 1; //优先级较高
ET0 = 1; //使能定时器溢出中断
EA = 1; //开启总开关
}
/********中断服务函数*******/
/**
* T0的中断服务函数(每隔1ms对TimeCount加1)
*/
static unsigned long TimeCount = 0;
static unsigned char StatusFlag = 0;
static unsigned long GetTimeCon = 0;
extern unsigned char Seting_Flag;
extern char Current_Time[];
void Time0_Rountine(void) interrupt 1
{
//这里不用清除标志位,硬件会自动清除
/* 设置定时计数器的初始值,定时1ms */
TH0 = ((65535 - (1000 - 1)) >> 8);
TL0 = (65535 - (1000 - 1)) & 0x00FF;
TimeCount++;
/* 每隔1s秒变量增加1 */
switch(StatusFlag)
{
case 0:
GetTimeCon = TimeCount;
StatusFlag = 1;
case 1:
if(TimeCount - GetTimeCon == 1000)
{
GetTimeCon = TimeCount;
if(!Seting_Flag) //没有进入设置模式
{
Current_Time[2]++; //每隔1s秒变量增加
if(Current_Time[2] >= 60)
{
Current_Time[2] = 0;
Current_Time[1]++; //每隔60s分变量增加
if(Current_Time[1] >= 60)
{
Current_Time[1] = 0;
Current_Time[0]++; //每隔60min时变量增加
if(Current_Time[0] >= 24)
{
Current_Time[0] = 0;
}
}
}
}
}
break;
}
}
/**
* 对外暴露TimeCount的值
*/
unsigned long Get_TimeCount(void)
{
return TimeCount;
}