综合1:stm32F4,ATKESP8266wifi,DS1302,AT24C02,KEY状态机,LCD屏幕320*240

目录

1、完成了ATK8266wifi的使用。包括,stm32和wifi的通信,通过wifi发送数据到TCP通信,发送数据到原子云上面,接收原子云的数据命令;
2、完成DS1302的时钟芯片控制,包括读取时间,电子时钟的按键调整功能;
3、完成了AT24C02的EEPROM数据存储,以及读出。主要是设置好数据之后,存储到24C02中,开机读取数据,不用每次都通过按键更新。
4、通过状态机按键key0,key1,key2,key3,key4五个按键进行调节。按键0和按键1用来调节时间,按键2、3和按键4调节温度、湿度等阈值,以及保存设置,撤销设置等。

下面分4个方面进行讲解。

1、wifi的使用。
买的是正点原子的wifi模块,学习步骤:
一、用USB转TTL模块,和WIFi模块进行连接,用网络串口助手,进行AT指令的学习,包括调节参数,设置AP,STA模式等。

参考资料:1、正点原子的wifi说明;/2、青柚视频的AT指令的讲解视频。包括配套视频和pdf文件,同时学习熟悉WIFI模块的基本知识,TCP,IP,UDP,等。
https://www.bilibili.com/video/BV1YW411C7tC?from=search&seid=8263631381031500092
二、用USB转TTL模块,和wifi模块进行连接,用网络串口助手,和原子云端进行通信。
参考资料:正点原子的WIFI说明的原子云部分内容;

三、用wifi的smartconfig功能,不用每次自动设置wifi等参数,开机自动连接。

四、将青柚的工程的wifi部分,内容进行修改和移植,移植到stm32F4。

说明,上面都有别人做好的视频、文档,所以不再做具体的视频和文档了。
移植到F4板子,用的是串口2,PD5和PD6这两个接口。
PD5(TXD)----wifi的RXD;
PD6(RXD)—wifi的TXD;
接线一定要对。

用的是串口2的空闲中断。

具体代码:

network.h

/******************************************************************
 * 文件:NetWork.c
 * 功能:声明TCP、UDP通信相关函数
 * 日期:2018-04-06
 * 作者:zx
 * 版本:Ver.1.0 | 最初版本
 * 
 * Copyright (C) 2018 zx. All rights reserved.
*******************************************************************/
#ifndef __NETWORK_H
#define __NETWORK_H

#include "sys.h"
#include "usart.h"
#include "Lcd_Driver.h"

/*连接AP宏定义*/
#define SSID "WIFI_SSID"
#define PWD  "WIFI_PWD"

/*连接服务器宏定义*/
#define TCP "TCP"
#define UDP "UDP"
#define IP  "192.168.xx.xx"
#define PORT 22958

/*定义原子云的设备地址和密码,在原子云中设置设备的时候,连接原子云的时候需要*/
#define YZYDevAddr "24858907199923482471"
#define YZYDevPassWord "12345678"

/*发送接收缓冲区长度宏定义*/
#define TXBUFFER_LEN 100
#define RXBUFFER_LEN 100

u8 checkESP8266(void);
u8 initESP8266(void);
void restoreESP8266(void);

u8 connectAP(u8* ssid,u8* pwd);

u8 connectServer(u8* mode,u8* ip,u16 port);

extern uint32_t flashtime;
extern u8 TXBuffer[TXBUFFER_LEN];  //网络通信数据发送缓冲
extern u8 RXBuffer[RXBUFFER_LEN];  //网络通信数据接收缓冲

void sendBuffertoServer(u8* buffer);
void processServerBuffer(void);
u8 disconnectServer(void);
u8 initESP8266(void);
u8 connectYZY(char* yzyDevNumtemp,char* yzyDevPassWordtemp);
u8 disconnectYZY(void);
#endif

network.c

/******************************************************************
*******************************************************************/
#include "stdio.h"
#include "string.h"
#include "NetWork.h"


u8 TXBuffer[TXBUFFER_LEN] = {0};  //网络通信数据发送缓冲
u8 RXBuffer[RXBUFFER_LEN] = {0};  //网络通信数据接收缓冲

/**
 * 功能:查找字符串中是否包含另一个字符串
 * 参数:
 *       dest:待查找目标字符串
 *       src:待查找内容
 *       retry_cn:查询超时时间
 * 返回值:查找结果,非0为查找成功,0为失败
 * 说明:
 *       当发出一个AT指令后,需要一段时间等待ESP8266回复,因此就需要等待一段时间,
 *       这个时间通常是几百ms(除了连接服务器和AP指令),本程序一般指令通常等待
 *       2S,耗时的连接AP和服务器的设置等待为8S,其实花不了那么多时间,但如果发生超时
 *       就一定可以判断是通信问题
 */
static u8 findStr(u8* dest,u8* src,u16 retry_cn)
{
    u16 retry = retry_cn;                   //超时时间
    u8 result_flag = 0;                     //查找结果

    while(strstr(dest,src)==0 && --retry!=0)//等待串口接收完毕或超时退出
    {
        delay_ms(10);
    }

   if(retry==0)                            //如果超时则有问题,此时返回0
   {
       return 0;
   }
   result_flag = 1;                        //执行到这里说明一切正常, 表示查找成功

    if(result_flag)
    {
        return 1;
    }else 
    {
        return 0;
    }
}

/**
 * 功能:初始化ESP8266
 * 参数:None
 * 返回值:初始化结果,非0为初始化成功,0为失败
 */
u8 initESP8266(void)
{				
	LCD_ShowStringAsc160(0,10,RED, WHITE,"init8266inY");
	sendString(USART2,"+++");          //退出透传 
  LCD_ShowStringAsc160(0,10,RED, WHITE,"init8266in0");

  delay_ms(500);
	sendString(USART2,"AT+RST\r\n");   //重启ESP8266 
	LCD_ShowStringAsc160(0,10,RED, WHITE,"init8266in1");

	delay_ms(500);
    if(checkESP8266()==0)              //使用AT指令检查ESP8266是否存在
    {
        return 0;
    }

    memset(RXBuffer,0,RXBUFFER_LEN);   //清空接收缓冲
    sendString(USART2,"ATE0\r\n");     //关闭回显  
		LCD_ShowStringAsc160(0,10,RED, WHITE,"init8266in2");

    if(findStr(RXBuffer,"OK",200)==0)  //设置不成功
    {
        return 0;      
    }

    return 1;                         //设置成功

}

/**
 * 功能:恢复出厂设置
 * 参数:None
 * 返回值:None
 * 说明:此时ESP8266中的用户设置将全部丢失回复成出厂状态
 */
void restoreESP8266(void)
{
	sendString(USART2,"+++");           //退出透传
  delay_ms(500);
	sendString(USART2,"AT+RESTORE\r\n");//恢复出厂 
   NVIC_SystemReset();                 //同时重启单片机   
}

/**
 * 功能:检查ESP8266是否正常
 * 参数:None
 * 返回值:ESP8266返回状态
 *        非0 ESP8266正常
 *        0 ESP8266有问题  
 */
u8 checkESP8266(void)
{
    memset(RXBuffer,0,RXBUFFER_LEN); //清空接收缓冲

    sendString(USART2,"AT\r\n");     //发送AT握手指令

    if(findStr(RXBuffer,"OK",200)!=0)//ESP8266正常
    {
        return 1;  
    }else                            //ESP8266不正常 
    {
        return 0;
    }
}

/**
 * 功能:连接热点
 * 参数:
 *         ssid:热点名
 *         pwd:热点密码
 * 返回值:
 *         连接结果,非0连接成功,0连接失败
 * 说明: 
 *         失败的原因有以下几种(UART通信和ESP8266正常情况下)
 *         1. WIFI名和密码不正确
 *         2. 路由器连接设备太多,未能给ESP8266分配IP
 */
u8 connectAP(u8* ssid,u8* pwd)
{
    memset(RXBuffer,0,RXBUFFER_LEN);                       
    sendString(USART2,"AT+CWMODE?\r\n");                       //查询此时WIFI工作模式
    if(findStr(RXBuffer,"CWMODE:1",200)==0)                    //如果此时不是MODE1模式,即不是STATION模式
    {
        memset(RXBuffer,0,RXBUFFER_LEN);     
        sendString(USART2,"AT+CWMODE_CUR=1\r\n");              //设置为STATION模式
        if(findStr(RXBuffer,"OK",200)==0)
        {
            return 0;
        }             
    }

    memset(TXBuffer,0,RXBUFFER_LEN);                            //清空发送缓冲
    memset(RXBuffer,0,RXBUFFER_LEN);                            //清空接收缓冲
    sprintf(TXBuffer,"AT+CWJAP_CUR=\"%s\",\"%s\"\r\n",ssid,pwd);//连接目标AP
    sendString(USART2,TXBuffer);
    if(findStr(RXBuffer,"OK",800)!=0)                           //连接成功且分配到IP
    {
        return 1;
    }
}

/**
 * 功能:使用指定协议(TCP/UDP)连接到服务器
 * 参数:
 *         mode:协议类型 "TCP","UDP"
 *         ip:目标服务器IP
 *         port:目标是服务器端口号
 * 返回值:
 *         连接结果,非0连接成功,0连接失败
 * 说明: 
 *         失败的原因有以下几种(UART通信和ESP8266正常情况下)
 *         1. 远程服务器IP和端口号有误
 *         2. 未连接AP
 *         3. 服务器端禁止添加(一般不会发生)
 */
u8 connectServer(u8* mode,u8* ip,u16 port)
{
    memset(RXBuffer,0,RXBUFFER_LEN);      
    memset(TXBuffer,0,RXBUFFER_LEN);   
   
    sendString(USART2,"+++");                   //多次连接需退出透传
    delay_ms(500);
    /*格式化待发送AT指令*/    
    sprintf(TXBuffer,"AT+CIPSTART=\"%s\",\"%s\",%d\r\n",mode,ip,port);
    sendString(USART2,TXBuffer);
    if(findStr(RXBuffer,"CONNECT",800)!=0)
    {
        memset(RXBuffer,0,RXBUFFER_LEN);    
        sendString(USART2,"AT+CIPMODE=1\r\n");  //设置为透传模式
        if(findStr(RXBuffer,"OK",200)!=0)
        {
            memset(RXBuffer,0,RXBUFFER_LEN); 
            sendString(USART2,"AT+CIPSEND\r\n");//开始处于透传发送状态
            if(findStr(RXBuffer,">",200)!=0)
            {
                return 1;
            }else 
            {
                return 0;
            }    
        }else 
        {
            return 0;
        }
        
    }else 
    {
        return 0;
    }
}

/**
 * 功能:主动和服务器断开连接
 * 参数:None
 * 返回值:
 *         连接结果,非0断开成功,0断开失败
 */
u8 disconnectServer(void)
{
    sendString(USART2,"+++");            //退出透传
    delay_ms(500);
    memset(RXBuffer,0,RXBUFFER_LEN);  
    sendString(USART2,"AT+CIPCLOSE\r\n");//关闭链接

    if(findStr(RXBuffer,"CLOSED",200)!=0)//操作成功,和服务器成功断开
    {
        return 1;
    }else 
    {
        return 0;
    }
}

/**
 * 功能:透传模式下的数据发送函数
 * 参数:
 *      buffer:待发送数据
 * 返回值:None
 */
void sendBuffertoServer(u8* buffer)
{
    memset(RXBuffer,0,RXBUFFER_LEN);
    sendString(USART2,buffer); 
}



/**
 * 功能:连接原子云https://cloud.alientek.com
 * 参数:
 *         mode:协议类型 "TCP","UDP"
 *         ip:目标服务器IP
 *         port:目标是服务器端口号
 * 返回值:
 *         连接结果,非0连接成功,0连接失败
 * 说明: 
 *        
 */
u8 connectYZY(char* yzyDevNumtemp,char* yzyDevPassWordtemp)
{
    memset(RXBuffer,0,RXBUFFER_LEN);      
    memset(TXBuffer,0,RXBUFFER_LEN);   
   	delay_ms(3000);

    /*格式化待发送AT指令连接原子云//	sendString(USART2,"AT+RST\r\n");   //重启ESP8266 */    
    sendString(USART2,"AT+ATKCLDSTA=\"24858907199923482471\",\"12345678\"\r\n");
//	    sendString(USART2,"AT+ATKCLDSTA=");
//   sendString(USART2,"\"24858907199923482471\",");
//	 sendString(USART2,"\"12345678\"\r\n");
	delay_ms(8000);

	//连接成功,会返回CLOUD CONNECTED
    if(findStr(RXBuffer,"OK",800)!=0)
    {			
			LCD_ShowStringAsc160(0,5,RED, WHITE,"ok");
      return 1;
        
    }else 
    {			
			LCD_ShowStringAsc160(0,5,RED, WHITE,"NG");
      return 0;
    }
}

/**
 * 功能:断开原子云
 * 参数:None
 * 返回值:
 *         连接结果,非0断开成功,0断开失败
 */
u8 disconnectYZY(void)
{
    sendString(USART2,"+++");            //退出透传
    delay_ms(500);
    memset(RXBuffer,0,RXBUFFER_LEN);  
    sendString(USART2,"AT+ATKCLDCLS\r\n");//关闭链接

    if(findStr(RXBuffer,"CLOUD DISCONNECT",200)!=0)//操作成功,和服务器成功断开
    {
        return 1;
    }else 
    {
        return 0;
    }
}

/**
 * 功能:处理服务器发回来的控制指令
 * 参数:None
 * 返回值:None
 */
void processServerBuffer(void)
{ 
    u8 i = 0;
    u8 numbuftemp0[9]={0};
		unsigned long numtemp0=0;
    /*LED状态控制*/
    if(strstr(RXBuffer,"LED_ON"))
    {
       //提取亮度数值格式:LED_ON=50#,将等号和#中间的数提取出来
			//第一步,找到RXBuffer中的等号的位置,#号的下标,然后将数据复制出来到另外一个字符串
			//将字符串转为
			memset(numbuftemp0,0,9);
			 numtemp0=FindNumInStr(RXBuffer,numbuftemp0);
      delay_ms(5);
    LCD_ShowNumAsc160(0,5,RED, BLUE,numtemp0,5);
	  flashtime=numtemp0;
			
      //  openLED();
    }else if(strstr(RXBuffer,"LED_OFF"))
    {
        ++i;
							LCD_ShowStringAsc160(0,6,RED, WHITE,"LED_OFF");

      //  closeLED();
    }else 
    {

    }
    
    /*继电器1状态控制*/
    if(strstr(RXBuffer,"RELAY1_CLOSE"))
    {
        ++i;
			LCD_ShowStringAsc160(0,7,RED, WHITE,"RELAY1_CLOSE");
       // setRelay(RELAY1,RELAY_CLOSE);
    }else if(strstr(RXBuffer,"RELAY1_OPEN"))
    {
        ++i;
			LCD_ShowStringAsc160(0,7,RED, WHITE,"RELAY1_OPEN");

      //  setRelay(RELAY1,RELAY_OPEN);
    }else 
    {

    }

    /*继电器2状态控制*/
    if(strstr(RXBuffer,"RELAY2_CLOSE"))
    {
        ++i;
       // setRelay(RELAY2,RELAY_CLOSE);
    }else if(strstr(RXBuffer,"RELAY2_OPEN"))
    {
        ++i;
      //  setRelay(RELAY2,RELAY_OPEN);
    }else 
    {
        
    }  

    /*只在接收控制指令时才清空,这样可避免接收AT指令时导致失败*/
    if(i!=0)
    {
        memset(RXBuffer,0,RXBUFFER_LEN);
    }          
}

第二个DS1302的使用。
主要参考资料
金沙滩的DS1302资料。
用的是burst模式;
初始化之后,读取时间就行了。需要修改时间的话,记得是DS1302是BCD编码。
什么是BCD编码?
DS1302中,看寄存器手册。用8Ch或者是8D年份寄存器。
比如2015年,这个寄存器只放的是后面两个15,将15的1分离出来,放在高四位,5分离出来,放在第四位,就可以设置了。
在这里插入图片描述
怎么分离?
十进制的23,,怎么转变成===0x23呢,?
(23/10)=2,用16进制是0x02,左移4位,23%10=3
则(23/10)<<4+(23%10)=0x23.

0x23如何转成十进制的23呢?
(0x23>>4)*10+(0x23&0x0F)=23.

另外注意,DS1302的数据IO口,有时候做输入口,有时候做输出口, 需跟进实际情况设置

DS1302.h

#ifndef __DS1302_H
#define __DS1302_H
#include "sys.h"
#include "delay.h"

#define DS1302_CE PFout(3)	// 
#define DS1302_CK PFout(5)	// 
#define DS1302_IOin PFin(6)	// 
#define DS1302_IOout PFout(6)	// 

#define DS1302_CE_PORT 	  GPIOF	//需要根据实际修改:端口
#define DS1302_CE_PIN       GPIO_Pin_3//需要根据修改:引脚号
#define DS1302_CE_CLK_ENA() {RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);}
//根据实际修改:时钟线,时钟使能

#define DS1302_CK_PORT 	  GPIOF	//需要根据实际修改:端口
#define DS1302_CK_PIN       GPIO_Pin_5//需要根据修改:引脚号
#define DS1302_CK_CLK_ENA() {RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);}
//根据实际修改:时钟线,时钟使能


#define DS1302_IO_PORT 	  GPIOF	//需要根据实际修改:端口
#define DS1302_IO_PIN       GPIO_Pin_6//需要根据修改:引脚号
#define DS1302_IO_CLK_ENA() {RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);}
//根据实际修改:时钟线,时钟使能

struct sTime {  //日期时间结构体定义
    unsigned int  year;  //年0x13===2013年。前面的20是默认的。不用书写
    unsigned char mon;   //月0x10
    unsigned char day;   //日0x08
    unsigned char hour;  //时0x12
    unsigned char min;   //分0x30
    unsigned char sec;   //秒0x00
    unsigned char week;  //星期
};



void DS1302_IOIN();
void DS1302_IOOUT();

/* 发送一个字节到DS1302通信总线上 */
void DS1302ByteWrite(unsigned char dat);
/* 由DS1302通信总线上读取一个字节 */
unsigned char DS1302ByteRead();
/* 用单次写操作向某一寄存器写入一个字节,reg-寄存器地址,dat-待写入字节 */
void DS1302SingleWrite(unsigned char reg, unsigned char dat);
/* 用单次读操作从某一寄存器读取一个字节,reg-寄存器地址,返回值-读到的字节 */
unsigned char DS1302SingleRead(unsigned char reg);
/* 用突发模式连续写入8个寄存器数据,dat-待写入数据指针 */
void DS1302BurstWrite(unsigned char *dat);
/* 用突发模式连续读取8个寄存器的数据,dat-读取数据的接收指针 */
void DS1302BurstRead(unsigned char *dat);
/* 获取实时时间,即读取DS1302当前时间并转换为时间结构体格式 */
void GetRealTime(struct sTime *time);
/* 设定实时时间,时间结构体格式的设定时间转换为数组并写入DS1302 */
void SetRealTime(struct sTime *time);
/* DS1302初始化,如发生掉电则重新设置初始时间 */
void InitDS1302();

#endif

DS1302.c

/*
*******************************************************************************
*                     《手把手教你学51单片机(C语言版)》
*                    配套 KST-51 单片机开发板 示例源代码
*
*         (c) 版权所有 2014 金沙滩工作室/清华大学出版社 保留所有权利
*                 获取更多资料请访问:http://www.kingst.org
*
* 文件名:DS1302.c
* 描  述:实时时钟芯片DS1302驱动模块
* 版本号:v1.0.0
* 备  注:
*******************************************************************************
*/

#include "DS1302.h"

/* 发送一个字节到DS1302通信总线上 */
void DS1302ByteWrite(unsigned char dat)
{
   // unsigned char mask;
	u8 i=0;
    DS1302_IOOUT();
		delay_ms(1);
	
			for(i = 0; i < 8; i ++)
			{
				DS1302_IOout	 = dat & 0x01;
				DS1302_CK = 1;
				DS1302_CK = 0;
				dat	>>= 1;
			}
    
    DS1302_IOout = 1;           //最后确保释放IO引脚
}
/* 由DS1302通信总线上读取一个字节 */
unsigned char DS1302ByteRead()
{
    unsigned char mask;
    unsigned char dat = 0;
    DS1302_IOIN();
				delay_ms(1);

    for (mask=0x01; mask!=0; mask<<=1)  //低位在前,逐位读取
    {
        if (DS1302_IOin != 0)  //首先读取此时的IO引脚,并设置dat中的对应位
        {
            dat |= mask;
        }
        DS1302_CK = 1;       //然后拉高时钟
				delay_us(5);
        DS1302_CK = 0;       //再拉低时钟,完成一个位的操作
    }
    return dat;              //最后返回读到的字节数据
}
/* 用单次写操作向某一寄存器写入一个字节,reg-寄存器地址,dat-待写入字节 */
void DS1302SingleWrite(unsigned char reg, unsigned char dat)
{
    DS1302_CE = 1;                   //使能片选信号
				delay_us(5);
    DS1302ByteWrite((reg<<1)|0x80);  //发送写寄存器指令
				delay_us(5);

    DS1302ByteWrite(dat);            //写入字节数据
				delay_us(5);

    DS1302_CE = 0;                   //除能片选信号
}
/* 用单次读操作从某一寄存器读取一个字节,reg-寄存器地址,返回值-读到的字节 */
unsigned char DS1302SingleRead(unsigned char reg)
{
    unsigned char dat;
    
    DS1302_CE = 1;                   //使能片选信号
				delay_us(5);
    DS1302ByteWrite((reg<<1)|0x81);  //发送读寄存器指令
				delay_us(5);

    dat = DS1302ByteRead();          //读取字节数据
				delay_us(5);

    DS1302_CE = 0;                   //除能片选信号
    
    return dat;
}
/* 用突发模式连续写入8个寄存器数据,dat-待写入数据指针 */
void DS1302BurstWrite(unsigned char *dat)
{
    unsigned char i;
    DS1302_CE = 1;

    DS1302ByteWrite(0xBE);  //发送突发写寄存器指令

    for (i=0; i<8; i++)     //连续写入8字节数据
    {
        DS1302ByteWrite(dat[i]);

    }
    DS1302_CE = 0;
}
/* 用突发模式连续读取8个寄存器的数据,dat-读取数据的接收指针 */
void DS1302BurstRead(unsigned char *dat)
{
    unsigned char i;
    
    DS1302_CE = 1;
				delay_us(5);
    DS1302ByteWrite(0xBF);  //发送突发读寄存器指令
    for (i=0; i<8; i++)     //连续读取8个字节
    {
        dat[i] = DS1302ByteRead();
				delay_us(5);

    }
    DS1302_CE = 0;
}
/* 获取实时时间,即读取DS1302当前时间并转换为时间结构体格式 */
void GetRealTime(struct sTime *time)
{
    unsigned char buf[8];
    
    DS1302BurstRead(buf);
    time->year = buf[6]+ 0x2000 ;
    time->mon  = buf[4];
    time->day  = buf[3];
    time->hour = buf[2];
    time->min  = buf[1];
    time->sec  = buf[0];
    time->week = buf[5];
}
/* 设定实时时间,时间结构体格式的设定时间转换为数组并写入DS1302 */
void SetRealTime(struct sTime *time)
{
    unsigned char buf[8];
    
    buf[7] = 0;
    buf[6] = time->year;//0x2021
    buf[5] = time->week;
    buf[4] = time->mon;
    buf[3] = time->day;
    buf[2] = time->hour;
    buf[1] = time->min;
    buf[0] = time->sec;
    DS1302BurstWrite(buf);//数组
}
/* DS1302初始化,如发生掉电则重新设置初始时间 */
void InitDS1302()
{
    unsigned char dat;
    struct sTime InitTime = {  //2013年10月8日 12:30:00 星期二
        0x2021,0x01,0x01, 0x23,0x56,0x00, 0x02
    };
  //  u8 temp=45;
		
		GPIO_InitTypeDef GPIO_InitStructure;
				//InitTime.min=((temp/10)<<4)+(temp%10);

    DS1302_CE_CLK_ENA();
	 GPIO_InitStructure.GPIO_Pin = DS1302_CE_PIN;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT ;   //推挽输出
	  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

	 GPIO_Init(DS1302_CE_PORT, &GPIO_InitStructure);

		
			
    DS1302_CK_CLK_ENA();
	 GPIO_InitStructure.GPIO_Pin = DS1302_CK_PIN;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT ;   //推挽输出
	  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

	 GPIO_Init(DS1302_CK_PORT, &GPIO_InitStructure);
	 
	  DS1302_IO_CLK_ENA();
	 GPIO_InitStructure.GPIO_Pin = DS1302_IO_PIN;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT ;   //推挽输出
	  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

	  GPIO_Init(DS1302_IO_PORT, &GPIO_InitStructure);
	 
	 
    DS1302_CE = 0;  //初始化DS1302通信引脚
    DS1302_CK = 0;
		
    dat = DS1302SingleRead(0);  //读取秒寄存器
    if ((dat & 0x80) != 0) //不等于0,进入判断,没有备用电池   
			//由秒寄存器最高位CH的值判断DS1302是否已停止
		//CH的作用:判断掉电后是否正常时钟
		//CH0:有备用电源
		//CH1:没有备用电池
    {
        DS1302SingleWrite(7, 0x00);  //撤销写保护以允许写入数据
	  	  delay_ms(1);
        SetRealTime(&InitTime);      //设置DS1302为默认的初始时间
    }
		//回复默认的时间
//		 SetRealTime(&InitTime);      //设置DS1302为默认的初始时间

}
//设置输入模式
void DS1302_IOIN()
{
	GPIO_InitTypeDef GPIO_InitStructure;
  DS1302_IO_CLK_ENA();
	GPIO_InitStructure.GPIO_Pin =DS1302_IO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN ;   //推挽
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(DS1302_IO_PORT, &GPIO_InitStructure);
}
//设置输出模式
void DS1302_IOOUT()
{
  GPIO_InitTypeDef GPIO_InitStructure;
  DS1302_IO_CLK_ENA();
	GPIO_InitStructure.GPIO_Pin =DS1302_IO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT ;   //推挽
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(DS1302_IO_PORT, &GPIO_InitStructure);
}

第三个,AT24C02,用的是正点原子的例子。
AT2402,可以放252个字节,主要是IIC的使用。
使用的时候,
初始化,
检测初始化是不是OK。
读取24c02的数据,
写入数据。
这里一个一字节songoing,接收。
包括额IIC的代码和24C02的代码。

myiic.h

#ifndef __MYIIC_H
#define __MYIIC_H
#include "sys.h" 
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK STM32F407开发板
//IIC 驱动代码	   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2014/5/6
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2014-2024
//All rights reserved									  
// 	
//IO操作函数	 
#define IIC_SCL    PBout(6) //SCL

#define IIC_SDA    PBout(7) //SDA	 
#define READ_SDA   PBin(7)  //输入SDA 
   	   		   
//IO方向设置
//#define SDA_IN()  {GPIOF->MODER&=~(3<<(9*2));GPIOF->MODER|=0<<9*2;}	//PB9输入模式
//#define SDA_OUT() {GPIOF->MODER&=~(3<<(9*2));GPIOF->MODER|=1<<9*2;} //PB9输出模式
void SDA_IN();
void SDA_OUT();

//IIC所有操作函数
void IIC_Init(void);                //初始化IIC的IO口				 
void IIC_Start(void);				//发送IIC开始信号
void IIC_Stop(void);	  			//发送IIC停止信号
void IIC_Send_Byte(u8 txd);			//IIC发送一个字节
u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
u8 IIC_Wait_Ack(void); 				//IIC等待ACK信号
void IIC_Ack(void);					//IIC发送ACK信号
void IIC_NAck(void);				//IIC不发送ACK信号

void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
u8 IIC_Read_One_Byte(u8 daddr,u8 addr);	  
#endif

myiic.c

#include "myiic.h"
#include "delay.h"
//	 
//初始化IIC
void IIC_Init(void)
{					     
	GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT ;   //推挽输出
	  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

	GPIO_Init(GPIOB, &GPIO_InitStructure);
	//GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); 	//PB6,PB7 输出高
	IIC_SCL=1;
	IIC_SDA=1;

}
void SDA_IN()
{
	GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟

	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN ;   //推挽
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
}
void SDA_OUT()
{
	GPIO_InitTypeDef GPIO_InitStructure;
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟

	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT ;   //推挽
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉

	GPIO_Init(GPIOB, &GPIO_InitStructure);
}

//产生IIC起始信号
void IIC_Start(void)
{
	SDA_OUT();     //sda线输出
	IIC_SDA=1;	  	  
	IIC_SCL=1;
	delay_us(4);
 	IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
	delay_us(4);
	IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}	  
//产生IIC停止信号
void IIC_Stop(void)
{
	SDA_OUT();//sda线输出
	IIC_SCL=0;
	IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
 	delay_us(4);
	IIC_SCL=1; 
	IIC_SDA=1;//发送I2C总线结束信号
	delay_us(4);							   	
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
	u8 ucErrTime=0;
	SDA_IN();      //SDA设置为输入  
	IIC_SDA=1;delay_us(1);	   
	IIC_SCL=1;delay_us(1);	 
	while(READ_SDA)
	{
		ucErrTime++;
		if(ucErrTime>250)
		{
			IIC_Stop();
			return 1;
		}
	}
	IIC_SCL=0;//时钟输出0 	   
	return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=0;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}
//不产生ACK应答		    
void IIC_NAck(void)
{
	IIC_SCL=0;
	SDA_OUT();
	IIC_SDA=1;
	delay_us(2);
	IIC_SCL=1;
	delay_us(2);
	IIC_SCL=0;
}					 				     
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答			  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        //IIC_SDA=(txd&0x80)>>7;
		if((txd&0x80)>>7)
			IIC_SDA=1;
		else
			IIC_SDA=0;
		txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
    }	 
} 	    
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        IIC_SCL=0; 
        delay_us(2);
		IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}


24cxx.h

#ifndef __24CXX_H
#define __24CXX_H
#include "myiic.h"   
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//24CXX驱动 代码(适合24C01~24C16,24C32~256未经过测试!有待验证!)		   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/9
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved									  
//

#define AT24C01		127
#define AT24C02		255
#define AT24C04		511
#define AT24C08		1023
#define AT24C16		2047
#define AT24C32		4095
#define AT24C64	    8191
#define AT24C128	16383
#define AT24C256	32767  
//Mini STM32开发板使用的是24c02,所以定义EE_TYPE为AT24C02
#define EE_TYPE AT24C02
					  
u8 AT24CXX_ReadOneByte(u16 ReadAddr);							//指定地址读取一个字节
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite);		//指定地址写入一个字节
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);//指定地址开始写入指定长度的数据
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);					//指定地址开始读取指定长度数据
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);	//从指定地址开始写入指定长度的数据
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);   	//从指定地址开始读出指定长度的数据

u8 AT24CXX_Check(void);  //检查器件
void AT24CXX_Init(void); //初始化IIC
#endif


24cxx.c

#include "24cxx.h" 
#include "delay.h"
//	 
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//24CXX驱动 代码(适合24C01~24C16,24C32~256未经过测试!有待验证!)		   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/9
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved									  
//



//初始化IIC接口
void AT24CXX_Init(void)
{
	IIC_Init();
}
//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址  
//返回值  :读到的数据
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{				  
	u8 temp=0;		  	    																 
    IIC_Start();  
	if(EE_TYPE>AT24C16)
	{
		IIC_Send_Byte(0XA0);	   //发送写命令
		IIC_Wait_Ack();
		IIC_Send_Byte(ReadAddr>>8);//发送高地址
		IIC_Wait_Ack();		 
	}else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1));   //发送器件地址0XA0,写数据 	 

	IIC_Wait_Ack(); 
    IIC_Send_Byte(ReadAddr%256);   //发送低地址
	IIC_Wait_Ack();	    
	IIC_Start();  	 	   
	IIC_Send_Byte(0XA1);           //进入接收模式			   
	IIC_Wait_Ack();	 
    temp=IIC_Read_Byte(0);		   
    IIC_Stop();//产生一个停止条件	    
	return temp;
}
//在AT24CXX指定地址写入一个数据
//WriteAddr  :写入数据的目的地址    
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{				   	  	    																 
    IIC_Start();  
	if(EE_TYPE>AT24C16)
	{
		IIC_Send_Byte(0XA0);	    //发送写命令
		IIC_Wait_Ack();
		IIC_Send_Byte(WriteAddr>>8);//发送高地址
 	}else
	{
		IIC_Send_Byte(0XA0+((WriteAddr/256)<<1));   //发送器件地址0XA0,写数据 
	}	 
	IIC_Wait_Ack();	   
    IIC_Send_Byte(WriteAddr%256);   //发送低地址
	IIC_Wait_Ack(); 	 										  		   
	IIC_Send_Byte(DataToWrite);     //发送字节							   
	IIC_Wait_Ack();  		    	   
    IIC_Stop();//产生一个停止条件 
	delay_ms(10);	 
}
//在AT24CXX里面的指定地址开始写入长度为Len的数据
//该函数用于写入16bit或者32bit的数据.
//WriteAddr  :开始写入的地址  
//DataToWrite:数据数组首地址
//Len        :要写入数据的长度2,4
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
{  	
	u8 t;
	for(t=0;t<Len;t++)
	{
		AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
	}												    
}

//在AT24CXX里面的指定地址开始读出长度为Len的数据
//该函数用于读出16bit或者32bit的数据.
//ReadAddr   :开始读出的地址 
//返回值     :数据
//Len        :要读出数据的长度2,4
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
{  	
	u8 t;
	u32 temp=0;
	for(t=0;t<Len;t++)
	{
		temp<<=8;
		temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); 	 				   
	}
	return temp;												    
}
//检查AT24CXX是否正常
//这里用了24XX的最后一个地址(255)来存储标志字.
//如果用其他24C系列,这个地址要修改
//返回1:检测失败
//返回0:检测成功
u8 AT24CXX_Check(void)
{
	u8 temp;
	temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX			   
	if(temp==0X55)return 0;		   
	else//排除第一次初始化的情况
	{
		AT24CXX_WriteOneByte(255,0X55);
	    temp=AT24CXX_ReadOneByte(255);	  
		if(temp==0X55)return 0;
	}
	return 1;											  
}

//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer  :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
	while(NumToRead)
	{
		*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);	
		NumToRead--;
	}
}  
//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
	while(NumToWrite--)
	{
		AT24CXX_WriteOneByte(WriteAddr,*pBuffer);
		WriteAddr++;
		pBuffer++;
	}
}
 

第四个,key状态机,用了5个按键,定时器3做定时扫描。

key.h

#ifndef __KeyStatusMachineTimer3_H
#define __KeyStatusMachineTimer3_H
#include "sys.h"
#include "Lcd_Driver.h"

//KEY端口定义
#define KEY0 PGin(3)	// DS0
#define KEY1 PGin(2)	// DS0
#define KEY2 PGin(4)	// DS0
#define KEY3 PGin(0)	// DS0
#define KEY4 PGin(1)	// DS0


#define KEY0_PORT 	  GPIOG	//需要根据实际修改:端口
#define KEY0_PIN       GPIO_Pin_3//需要根据修改:引脚号
#define KEY0_CLK_ENA() {RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);}//根据实际修改:时钟线,时钟使能


#define KEY1_PORT 	  GPIOG	//需要根据实际修改:端口
#define KEY1_PIN       GPIO_Pin_2//需要根据修改:引脚号
#define KEY1_CLK_ENA() {RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);}//根据实际修改:时钟线,时钟使能

#define KEY2_PORT 	  GPIOG	//需要根据实际修改:端口
#define KEY2_PIN       GPIO_Pin_4//需要根据修改:引脚号
#define KEY2_CLK_ENA() {RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);}//根据实际修改:时钟线,时钟使能

#define KEY3_PORT 	  GPIOG	//需要根据实际修改:端口
#define KEY3_PIN       GPIO_Pin_0//需要根据修改:引脚号
#define KEY3_CLK_ENA() {RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);}//根据实际修改:时钟线,时钟使能

#define KEY4_PORT 	  GPIOG	//需要根据实际修改:端口
#define KEY4_PIN       GPIO_Pin_1//需要根据修改:引脚号
#define KEY4_CLK_ENA() {RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);}//根据实际修改:时钟线,时钟使能

//定义枚举类型
typedef enum
{
	STA1_KEY_Up					=(unsigned char)0x01,
	STA2_KEY_DownShake	=(unsigned char)0x02,
	STA3_KEY_Down				=(unsigned char)0x03,
	STA4_KEY_UpShake		=(unsigned char)0x04,
}STA_Machine_Status_t;

//定义按键结构体的类型
typedef struct
{
	uint8_t volatile Key_Flag;
	uint8_t Click;
	uint8_t DoubleClick;
	uint8_t LongPress;
	void (*KEY_IOInit)(void);
	void (*KEY_Press)(void);//按键检测
	
}KEY_t;
//定义状态机的结构体类型
typedef struct
{
	STA_Machine_Status_t				ucSTA_Machine_Status;//状态机状态
	uint16_t volatile	ucSTA_Machine_Scan_Timer;//状态机扫描定时器
	uint16_t volatile	ucKey_DoubleClick_Timer;//按键双击定时器
	uint16_t volatile	ucKey_LongPress_Timer;//按键长按扫描定时器
}STA_Machine_t;

//定时器Time3的设置,定时器5ms进行扫描
typedef enum
{
		Timer3_10ms=(uint16_t)2,
		Timer3_50ms=(uint16_t)10,
		Timer3_100ms=(uint16_t)20,
		Timer3_200ms=(uint16_t)40,
		Timer3_500ms=(uint16_t)100,
		Timer3_1s=(uint16_t)200,
		Timer3_2s=(uint16_t)400,		
}TIMER3_Value_t;

typedef struct
{
	uint16_t volatile usMCU_RUN_Timer;
	void (*Timer3_Init)(uint16_t arr,uint16_t psc);	
}Timer3_t;

/*extern valueable---*/
extern KEY_t Keyii,Keyi1,Keyi2,Keyi3,Keyi4;
extern u8 setIndex;
extern u8 setParaIndex;
extern Timer3_t timer3;

extern void	IncSetTime();
extern void LeftShiftTimeSet();
extern void RightShiftTimeSet();
extern void EnterTimeSet();
extern void ExitTimeSet(u8 save);
extern void DecSetTime();
extern void IncSetTime();

extern void AddPar();
extern void SubPar();
extern void RightShiftParaSet();
extern void LeftShiftParaSet();
extern void EnterParaSet();
extern void ExitParaSet(u8 save);
extern void RefreshYZShow();
extern void RefreshSetParaShow();/* 刷新当前设置位的光标指示 */
extern void RefreshDataShow();
extern void DataBackUp();//备份数据到24C02中


//================按键的函数
void KeyGpioInit(void);//初始化
void KeyTimer3Init(uint16_t arr,uint16_t psc);
void KeyConfig(void);


//static void KEY_Detect(void);
#endif

key.c

#include "KeyStatusMachineTimer3.h"

static void KEY_Detect(void);

#define SetLongPressTime Timer3_2s	//设定长按的时间
#define SetDoubleClickTime Timer3_200ms	//设定双击时间

static uint8_t ClickBuf=0;//单击状态缓存
static uint8_t ClickBuf1=0;//单击状态缓存
static uint8_t ClickBuf2=0;//单击状态缓存
static uint8_t ClickBuf3=0;//单击状态缓存
static uint8_t ClickBuf4=0;//单击状态缓存

static uint8_t ClickCount=0;//按键次数
static uint8_t ClickCount1=0;

static uint8_t DoubleClickCount=0;//按键次数
static uint8_t DoubleClickCount1=0;
static uint8_t LongClickCount=0;//按键次数
static uint8_t LongClickCount1=0;

static uint8_t T1HourSet=8;//早上八点
static uint8_t T1MinSet=30;//早上三十分钟

static uint8_t T2HourSet=11;//早上八点
static uint8_t T2MinSet=30;//早上三十分钟

static uint8_t T3HourSet=17;//早上八点
static uint8_t T3MinSet=30;//早上三十分钟
//1浇水,0不浇水
uint8_t T1Flag=1;//1,一个时间点,早上浇水,=2,中午浇水,=3,晚上浇水,=4三个都可以浇水
uint8_t T2Flag=1;//1,一个时间点,早上浇水,=2,中午浇水,=3,晚上浇水,=4三个都可以浇水
uint8_t T3Flag=1;//1,一个时间点,早上浇水,=2,中午浇水,=3,晚上浇水,=4三个都可以浇水



KEY_t Keyii={0,0,0,0,KeyGpioInit,KEY_Detect};
KEY_t Keyi1={0,0,0,0,KeyGpioInit,KEY_Detect};
KEY_t Keyi2={0,0,0,0,KeyGpioInit,KEY_Detect};
KEY_t Keyi3={0,0,0,0,KeyGpioInit,KEY_Detect};
KEY_t Keyi4={0,0,0,0,KeyGpioInit,KEY_Detect};

Timer3_t timer3={0,KeyTimer3Init};
STA_Machine_t STA_Machine={STA1_KEY_Up,0,0,0};
STA_Machine_t STA_Machine1={STA1_KEY_Up,0,0,0};
STA_Machine_t STA_Machine2={STA1_KEY_Up,0,0,0};
STA_Machine_t STA_Machine3={STA1_KEY_Up,0,0,0};
STA_Machine_t STA_Machine4={STA1_KEY_Up,0,0,0};



void KeyGpioInit(void)//初始化
{
	GPIO_InitTypeDef  GPIO_InitStructure;      

	KEY0_CLK_ENA();
  GPIO_InitStructure.GPIO_Pin = KEY0_PIN;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;   //输出模式
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;	//上拉
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度选择	
	GPIO_Init(KEY0_PORT, &GPIO_InitStructure);
	
	KEY1_CLK_ENA();
  GPIO_InitStructure.GPIO_Pin = KEY1_PIN;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;   //输出模式
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;	//上拉
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度选择	
	GPIO_Init(KEY1_PORT, &GPIO_InitStructure);
	
	KEY2_CLK_ENA();
  GPIO_InitStructure.GPIO_Pin = KEY2_PIN;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;   //输出模式
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;	//上拉
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度选择	
	GPIO_Init(KEY2_PORT, &GPIO_InitStructure);	
	
	KEY3_CLK_ENA();
  GPIO_InitStructure.GPIO_Pin = KEY3_PIN;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;   //输出模式
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;	//上拉
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度选择	
	GPIO_Init(KEY3_PORT, &GPIO_InitStructure);
	
	KEY4_CLK_ENA();
  GPIO_InitStructure.GPIO_Pin = KEY4_PIN;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN;   //输出模式
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;	//上拉
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度选择	
	GPIO_Init(KEY4_PORT, &GPIO_InitStructure);
	
}

//-------------------------//定时5ms
void KeyTimer3Init(uint16_t arr,uint16_t psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;	
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);  	//=====TIM8时钟使能 	

  TIM_TimeBaseInitStructure.TIM_Period = arr; 	//自动重装载值
	TIM_TimeBaseInitStructure.TIM_Prescaler=psc;  //定时器分频
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;// 重复计数器的值,没用到不用管
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM8
	
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器8更新中断  
  TIM_ClearFlag(TIM3,TIM_FLAG_Update);
	TIM_Cmd(TIM3,ENABLE); //定时器8
	
  //确定定时器8的中断优先级,
  //		//定时器8中断配置
	NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器8更新中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00; //抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x01; //子优先级01
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}


void TIM3_IRQHandler(void)
{
	static int count00=0;
  if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    {  
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
        
				STA_Machine.ucKey_DoubleClick_Timer++;
				STA_Machine.ucKey_LongPress_Timer++;
				STA_Machine.ucSTA_Machine_Scan_Timer++;
			
				STA_Machine1.ucKey_DoubleClick_Timer++;
				STA_Machine1.ucKey_LongPress_Timer++;
				STA_Machine1.ucSTA_Machine_Scan_Timer++;
			
				STA_Machine2.ucKey_DoubleClick_Timer++;
				STA_Machine2.ucKey_LongPress_Timer++;
				STA_Machine2.ucSTA_Machine_Scan_Timer++;
			
				STA_Machine3.ucKey_DoubleClick_Timer++;
				STA_Machine3.ucKey_LongPress_Timer++;
				STA_Machine3.ucSTA_Machine_Scan_Timer++;
			
				STA_Machine4.ucKey_DoubleClick_Timer++;
				STA_Machine4.ucKey_LongPress_Timer++;
				STA_Machine4.ucSTA_Machine_Scan_Timer++;
				
				count00++;
				if(count00>=Timer3_1s)//125/5=25
				{
					count00=0;
				}
    } 
		  
}



static void KEY_Detect(void)
{
//定时时间到10ms,进行一次状态监测
	if(STA_Machine.ucSTA_Machine_Scan_Timer>Timer3_10ms)
	{
		//LED0=!LED0;
		//判断第一个个按键
		switch(STA_Machine.ucSTA_Machine_Status)
		{
			case STA1_KEY_Up://如果当前是弹起状态
				{
					//LED0=0;
					if(KEY0==1)//没有按下按键
					{
						if(ClickBuf==1)//之前有一次按下
						{
							if(STA_Machine.ucKey_DoubleClick_Timer>=SetDoubleClickTime)//超过双击时间
							{
								Keyii.Key_Flag=1;//有按键按下
								Keyii.Click=1;//
								ClickBuf=0;//清除单击缓存
							}
						}
					}
					else //之前没有按键按下来,现在按键暗下来,那么进入下一个状态
					{
						STA_Machine.ucSTA_Machine_Status=STA2_KEY_DownShake;
					}
				
				break;
				}
			case STA2_KEY_DownShake://如果当前是抖动状态,10ms到现在这里,检测到有按键暗下来
				{
					if(KEY0==0)//如果有按键按下,跳转到按键按下状态,否则是弹起状态
						{
							STA_Machine.ucSTA_Machine_Status=STA3_KEY_Down;
							STA_Machine.ucKey_LongPress_Timer=0;//长按定时器清0,开始计时
						}
//					else
//						{STA_Machine.ucSTA_Machine_Status=STA1_KEY_Up;}	
				
				break;
				}
			case STA3_KEY_Down:
				{
					if(KEY0==0)
					{
					//长按检测
						if(Keyii.LongPress==0)//检测长按是不是执行,不然会重复判断,没有长按
						{
							if(STA_Machine.ucKey_LongPress_Timer>=SetLongPressTime)
							{
								STA_Machine.ucSTA_Machine_Status=STA4_KEY_UpShake;
								Keyii.Key_Flag=1;
								Keyii.LongPress=1;//超过两秒,说明是长按的状态

											//LED0=!LED0;
								 if (setIndex == 0)  //不处于设置状态时,进入设置状态
									{
											EnterTimeSet();
									}
									else                //已处于设置状态时,保存时间并退出设置状态
									{
											ExitTimeSet(1);
									}
									
									
								if(ClickBuf==1)
									ClickBuf=0;//检测到长按,清除上一次的按键单击缓存
							}
						}
					}
					else
					{
						STA_Machine.ucSTA_Machine_Status=STA4_KEY_UpShake;
						if(Keyii.LongPress==0)
							{
							//双击检查
								if(ClickBuf==1)
									{
										Keyii.Key_Flag=1;
										Keyii.DoubleClick=1;
										ClickBuf=0;
									}
								else
								{
									ClickBuf=1;
									STA_Machine.ucKey_DoubleClick_Timer=0;
									
								}
							}
					}
				
				break;
				}
			case STA4_KEY_UpShake:
				{
					
					if(KEY0==1)//如果有按键按下,跳转到按键抖动状态,否则的确是弹起状态
 					{STA_Machine.ucSTA_Machine_Status=STA1_KEY_Up;}
				
				break;
				}
			default:STA_Machine.ucSTA_Machine_Status=STA1_KEY_Up;

		}
//======================================================
		//判断第2个个按键
		switch(STA_Machine1.ucSTA_Machine_Status)
		{
			case STA1_KEY_Up://如果当前是弹起状态
				{
					if(KEY1==1)//没有按下按键
					{
						if(ClickBuf1==1)//之前有一次按下
						{
							if(STA_Machine1.ucKey_DoubleClick_Timer>=SetDoubleClickTime)//超过双击时间
							{
								Keyi1.Key_Flag=1;//有按键按下
								Keyi1.Click=1;//
								ClickBuf1=0;//清除单击缓存
							}
						}
					}
					else //之前没有按键按下来,现在按键暗下来,那么进入下一个状态
					{
						STA_Machine1.ucSTA_Machine_Status=STA2_KEY_DownShake;
					}
				
				break;
				}
			case STA2_KEY_DownShake://如果当前是抖动状态,10ms到现在这里,检测到有按键暗下来
				{
					if(KEY1==0)//如果有按键按下,跳转到按键按下状态,否则是弹起状态
						{
							STA_Machine1.ucSTA_Machine_Status=STA3_KEY_Down;
							STA_Machine1.ucKey_LongPress_Timer=0;//长按定时器清0,开始计时
						}
//					else
//						{STA_Machine.ucSTA_Machine_Status=STA1_KEY_Up;}	
				
				break;
				}
			case STA3_KEY_Down:
				{
					if(KEY1==0)
					{
					//长按检测
						if(Keyi1.LongPress==0)//检测长按是不是执行,不然会重复判断,没有长按
						{
							if(STA_Machine1.ucKey_LongPress_Timer>=SetLongPressTime)
							{
								STA_Machine1.ucSTA_Machine_Status=STA4_KEY_UpShake;
								Keyi1.Key_Flag=1;
								Keyi1.LongPress=1;//超过两秒,说明是长按的状态
								
										//	LED0=!LED0;
		//	 ExitTimeSet(0);
								

								if(ClickBuf1==1)
									ClickBuf1=0;//检测到长按,清除上一次的按键单击缓存
							}
						}
					}
					else
					{
						STA_Machine1.ucSTA_Machine_Status=STA4_KEY_UpShake;
						if(Keyi1.LongPress==0)
							{
							//双击检查
								if(ClickBuf1==1)
									{
										Keyi1.Key_Flag=1;
										Keyi1.DoubleClick=1;
										ClickBuf1=0;
									}
								else
								{
									ClickBuf1=1;
									STA_Machine1.ucKey_DoubleClick_Timer=0;
									
								}
							}
					}
				
				break;
				}
			case STA4_KEY_UpShake:
				{
					
					if(KEY1==1)//如果有按键按下,跳转到按键抖动状态,否则的确是弹起状态
 					{STA_Machine1.ucSTA_Machine_Status=STA1_KEY_Up;}
				
				break;
				}
			default:STA_Machine1.ucSTA_Machine_Status=STA1_KEY_Up;

		}

		//KEY2========================================================
			switch(STA_Machine2.ucSTA_Machine_Status)
		{
			case STA1_KEY_Up://如果当前是弹起状态
				{
					//LED0=0;
					if(KEY2==1)//没有按下按键
					{
						if(ClickBuf2==1)//之前有一次按下
						{
							if(STA_Machine2.ucKey_DoubleClick_Timer>=SetDoubleClickTime)//超过双击时间
							{
								Keyi2.Key_Flag=1;//有按键按下
								Keyi2.Click=1;//
								ClickBuf2=0;//清除单击缓存
							}
						}
					}
					else //之前没有按键按下来,现在按键暗下来,那么进入下一个状态
					{
						STA_Machine2.ucSTA_Machine_Status=STA2_KEY_DownShake;
					}
				
				break;
				}
			case STA2_KEY_DownShake://如果当前是抖动状态,10ms到现在这里,检测到有按键暗下来
				{
					if(KEY2==0)//如果有按键按下,跳转到按键按下状态,否则是弹起状态
						{
							STA_Machine2.ucSTA_Machine_Status=STA3_KEY_Down;
							STA_Machine2.ucKey_LongPress_Timer=0;//长按定时器清0,开始计时
						}
//					else
//						{STA_Machine.ucSTA_Machine_Status=STA1_KEY_Up;}	
				
				break;
				}
			case STA3_KEY_Down:
				{
					if(KEY2==0)
					{
					//长按检测
						if(Keyi2.LongPress==0)//检测长按是不是执行,不然会重复判断,没有长按
						{
							if(STA_Machine2.ucKey_LongPress_Timer>=SetLongPressTime)
							{
								STA_Machine2.ucSTA_Machine_Status=STA4_KEY_UpShake;
								Keyi2.Key_Flag=1;
								Keyi2.LongPress=1;//超过两秒,说明是长按的状态
//长按,不断增加
								while(KEY2==0)
								{
									AddPar();
									delay_ms(10);
									
								}

								
								if(ClickBuf2==1)
									ClickBuf2=0;//检测到长按,清除上一次的按键单击缓存
							}
						}
					}
					else
					{
						STA_Machine2.ucSTA_Machine_Status=STA4_KEY_UpShake;
						if(Keyi2.LongPress==0)
							{
							//双击检查
								if(ClickBuf2==1)
									{
										Keyi2.Key_Flag=1;
										Keyi2.DoubleClick=1;
										ClickBuf2=0;
									}
								else
								{
									ClickBuf2=1;
									STA_Machine2.ucKey_DoubleClick_Timer=0;
									
								}
							}
					}
				
				break;
				}
			case STA4_KEY_UpShake:
				{
					
					if(KEY2==1)//如果有按键按下,跳转到按键抖动状态,否则的确是弹起状态
 					{STA_Machine2.ucSTA_Machine_Status=STA1_KEY_Up;}
				
				break;
				}
			default:STA_Machine2.ucSTA_Machine_Status=STA1_KEY_Up;

		}
		
		
		//KEY3===============================
			switch(STA_Machine3.ucSTA_Machine_Status)
		{
			case STA1_KEY_Up://如果当前是弹起状态
				{
					//LED0=0;
					if(KEY3==1)//没有按下按键
					{
						if(ClickBuf3==1)//之前有一次按下
						{
							if(STA_Machine3.ucKey_DoubleClick_Timer>=SetDoubleClickTime)//超过双击时间
							{
								Keyi3.Key_Flag=1;//有按键按下
								Keyi3.Click=1;//
								ClickBuf3=0;//清除单击缓存
							}
						}
					}
					else //之前没有按键按下来,现在按键暗下来,那么进入下一个状态
					{
						STA_Machine3.ucSTA_Machine_Status=STA2_KEY_DownShake;
					}
				
				break;
				}
			case STA2_KEY_DownShake://如果当前是抖动状态,10ms到现在这里,检测到有按键暗下来
				{
					if(KEY3==0)//如果有按键按下,跳转到按键按下状态,否则是弹起状态
						{
							STA_Machine3.ucSTA_Machine_Status=STA3_KEY_Down;
							STA_Machine3.ucKey_LongPress_Timer=0;//长按定时器清0,开始计时
						}
//					else
//						{STA_Machine.ucSTA_Machine_Status=STA1_KEY_Up;}	
				
				break;
				}
			case STA3_KEY_Down:
				{
					if(KEY3==0)
					{
					//长按检测
						if(Keyi3.LongPress==0)//检测长按是不是执行,不然会重复判断,没有长按
						{
							if(STA_Machine3.ucKey_LongPress_Timer>=SetLongPressTime)
							{
								STA_Machine3.ucSTA_Machine_Status=STA4_KEY_UpShake;
								Keyi3.Key_Flag=1;
								Keyi3.LongPress=1;//超过两秒,说明是长按的状态

								while(KEY3==0)
								{
									SubPar();
									delay_ms(10);
								}
									
								if(ClickBuf3==1)
									ClickBuf3=0;//检测到长按,清除上一次的按键单击缓存
							}
						}
					}
					else
					{
						STA_Machine3.ucSTA_Machine_Status=STA4_KEY_UpShake;
						if(Keyi3.LongPress==0)
							{
							//双击检查
								if(ClickBuf3==1)
									{
										Keyi3.Key_Flag=1;
										Keyi3.DoubleClick=1;
										ClickBuf3=0;
									}
								else
								{
									ClickBuf3=1;
									STA_Machine3.ucKey_DoubleClick_Timer=0;
									
								}
							}
					}
				
				break;
				}
			case STA4_KEY_UpShake:
				{
					
					if(KEY3==1)//如果有按键按下,跳转到按键抖动状态,否则的确是弹起状态
 					{STA_Machine3.ucSTA_Machine_Status=STA1_KEY_Up;}
				
				break;
				}
			default:STA_Machine3.ucSTA_Machine_Status=STA1_KEY_Up;

		}
//KEY4==========KEY4==========key4
			switch(STA_Machine4.ucSTA_Machine_Status)
		{
			case STA1_KEY_Up://如果当前是弹起状态
				{
					//LED0=0;
					if(KEY4==1)//没有按下按键
					{
						if(ClickBuf4==1)//之前有一次按下
						{
							if(STA_Machine4.ucKey_DoubleClick_Timer>=SetDoubleClickTime)//超过双击时间
							{
								Keyi4.Key_Flag=1;//有按键按下
								Keyi4.Click=1;//
								ClickBuf4=0;//清除单击缓存
							}
						}
					}
					else //之前没有按键按下来,现在按键暗下来,那么进入下一个状态
					{
						STA_Machine4.ucSTA_Machine_Status=STA2_KEY_DownShake;
					}
				
				break;
				}
			case STA2_KEY_DownShake://如果当前是抖动状态,10ms到现在这里,检测到有按键暗下来
				{
					if(KEY4==0)//如果有按键按下,跳转到按键按下状态,否则是弹起状态
						{
							STA_Machine4.ucSTA_Machine_Status=STA3_KEY_Down;
							STA_Machine4.ucKey_LongPress_Timer=0;//长按定时器清0,开始计时
						}
//					else
//						{STA_Machine.ucSTA_Machine_Status=STA1_KEY_Up;}	
				
				break;
				}
			case STA3_KEY_Down:
				{
					if(KEY4==0)
					{
					//长按检测
						if(Keyi4.LongPress==0)//检测长按是不是执行,不然会重复判断,没有长按
						{
							if(STA_Machine4.ucKey_LongPress_Timer>=SetLongPressTime)
							{
								STA_Machine4.ucSTA_Machine_Status=STA4_KEY_UpShake;
								Keyi4.Key_Flag=1;
								Keyi4.LongPress=1;//超过两秒,说明是长按的状态

									
								if(ClickBuf4==1)
									ClickBuf4=0;//检测到长按,清除上一次的按键单击缓存
							}
						}
					}
					else
					{
						STA_Machine4.ucSTA_Machine_Status=STA4_KEY_UpShake;
						if(Keyi4.LongPress==0)
							{
							//双击检查
								if(ClickBuf4==1)
									{
										Keyi4.Key_Flag=1;
										Keyi4.DoubleClick=1;
										ClickBuf4=0;
									}
								else
								{
									ClickBuf4=1;
									STA_Machine4.ucKey_DoubleClick_Timer=0;
									
								}
							}
					}
				
				break;
				}
			case STA4_KEY_UpShake:
				{
					
					if(KEY4==1)//如果有按键按下,跳转到按键抖动状态,否则的确是弹起状态
 					{STA_Machine4.ucSTA_Machine_Status=STA1_KEY_Up;}
				
				break;
				}
			default:STA_Machine4.ucSTA_Machine_Status=STA1_KEY_Up;

		}

//===================================================================
//执行按键1程序
	if(Keyii.Key_Flag==1)
	{
		Keyii.Key_Flag=0;

		if(Keyii.Click==1)
		{
					LED0=!LED0;
			        IncSetTime();

		}

		if(Keyii.DoubleClick==1)
		{
	
		 LED0=!LED0;
		 LeftShiftTimeSet();


		}

		if(Keyii.LongPress==1)
		{
	   LED0=!LED0;
    if (setIndex == 0)  //不处于设置状态时,进入设置状态
        {
            EnterTimeSet();
        }
        else                //已处于设置状态时,保存时间并退出设置状态
        {
            ExitTimeSet(1);
        }
		}

		Keyii.Click=0;
		Keyii.DoubleClick=0;
		Keyii.LongPress=0;
		
	}
	
	//执行按键2
	if(Keyi1.Key_Flag==1)
	{
		Keyi1.Key_Flag=0;

		if(Keyi1.Click==1)
		{
		
		 LED0=!LED0;
      DecSetTime();

		}

		if(Keyi1.DoubleClick==1)
		{
	   LED0=!LED0;
		 RightShiftTimeSet();

		}

		if(Keyi1.LongPress==1)
		{

				   LED0=!LED0;

			ExitTimeSet(0);
		}

		Keyi1.Click=0;
		Keyi1.DoubleClick=0;
		Keyi1.LongPress=0;
		
	}
//===按键3
  if(Keyi2.Key_Flag==1)
	{
		Keyi2.Key_Flag=0;

		if(Keyi2.Click==1)
		{
		
		 LED0=!LED0;
			AddPar();//加参数
		}

		if(Keyi2.DoubleClick==1)
		{
	   LED0=!LED0;
//切换参数
			 RightShiftParaSet();
		}

		if(Keyi2.LongPress==1)
		{

				   LED0=!LED0;
  //在状态机中实现,实现长+
			
		}

		Keyi2.Click=0;
		Keyi2.DoubleClick=0;
		Keyi2.LongPress=0;
		
	}
	//按键4

		if(Keyi3.Key_Flag==1)
	{
		Keyi3.Key_Flag=0;

		if(Keyi3.Click==1)
		{
		//减参数
		 LED0=!LED0;
     SubPar();
		}

		if(Keyi3.DoubleClick==1)
		{
	   LED0=!LED0;
			LeftShiftParaSet();
		}

		if(Keyi3.LongPress==1)
		{

				   LED0=!LED0;
//长减,在状态机中实现
			
		}

		Keyi3.Click=0;
		Keyi3.DoubleClick=0;
		Keyi3.LongPress=0;
		
	}	
	//按键5
		if(Keyi4.Key_Flag==1)
	{
		Keyi4.Key_Flag=0;

		if(Keyi4.Click==1)
		{
		
			//切换wifi和自制模式
			//开机的时候选择了,这里不用执行

		}

		if(Keyi4.DoubleClick==1)
		{
	   LED0=!LED0;
			//退出设置模式
				ExitParaSet(0);
			
				LCD_ShowCharAsc160(0,3,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(7,3,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(14,3,BLUE,WHITE,'?'); 
					
					LCD_ShowCharAsc160(0,5,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(7,5,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(14,5,BLUE,WHITE,'?'); 
			
					LCD_ShowCharAsc160(1,7,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(4,7,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(7,7,BLUE,WHITE,'?'); 
					
					LCD_ShowCharAsc160(10,7,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(13,7,BLUE,WHITE,'?'); 
		
					LCD_ShowCharAsc160(16,7,BLUE,WHITE,'?'); 
			//显示数据
			  RefreshDataShow();
		}

		if(Keyi4.LongPress==1)
		{

				   LED0=!LED0;
      if (setParaIndex == 0)  //不处于设置状态时,进入设置状态
        {

					EnterParaSet();
        }
        else                //已处于设置状态时,保存时间并退出设置状态
        {
						LCD_ShowCharAsc160(0,3,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(7,3,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(14,3,BLUE,WHITE,'?'); 
					
					LCD_ShowCharAsc160(0,5,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(7,5,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(14,5,BLUE,WHITE,'?'); 
			
					LCD_ShowCharAsc160(1,7,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(4,7,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(7,7,BLUE,WHITE,'?'); 
					
					LCD_ShowCharAsc160(10,7,BLUE,WHITE,'?'); 
					LCD_ShowCharAsc160(13,7,BLUE,WHITE,'?'); 
		
					LCD_ShowCharAsc160(16,7,BLUE,WHITE,'?'); 
					//显示设置的数据
            ExitParaSet(1);
						RefreshDataShow();//显示当前的数据阈值
					
        }
			
		}

		Keyi4.Click=0;
		Keyi4.DoubleClick=0;
		Keyi4.LongPress=0;
		
	}
	//===
   STA_Machine.ucSTA_Machine_Scan_Timer=0;
	 STA_Machine1.ucSTA_Machine_Scan_Timer=0;
	 STA_Machine2.ucSTA_Machine_Scan_Timer=0;
	 STA_Machine3.ucSTA_Machine_Scan_Timer=0;
	 STA_Machine4.ucSTA_Machine_Scan_Timer=0;


	}
	
}





LCD屏幕,用SPI,320*240

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值