STM32 F1普中开发板 TFT彩屏指针时间显示及闹钟。

本文介绍STM32微控制器RTC模块的配置与使用,包括时钟设置、闹钟功能及时间更新。同时,展示了如何利用GUI库在LCD屏上绘制时钟界面,实现时间的实时显示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在普中RTC时钟上更改,按KEY键可更改时间。指针圆盘显示时钟,可设置闹钟。

 

 

#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "system.h"
#include "usart.h"
#include "gui.h"
#include "flash.h"
#include "rtc.h"
#include "math.h"
#include "beep.h"
#include "systick.h"
RTC_TimeTypeDef time;
uint8_t showValue[5] = {0, 0, 0, 0, 0};
void GUI_DisplayTime(uint8_t num);
void TIME_Set(uint8_t num, uint8_t state);
#define PI 3.1415926 
void get_circle(int x,int y,int r,int col)
{
	int xc=0;
	int yc,p;
	yc=r;
	p=3-(r<<1);	
	while(xc <= yc)
	{
		GUI_Dot(x+xc,y+yc,col);
		GUI_Dot(x+xc,y-yc,col);	
		GUI_Dot(x-xc,y+yc,col);
		GUI_Dot(x-xc,y-yc,col);
		GUI_Dot(x+yc,y+xc,col);	
		GUI_Dot(x+yc,y-xc,col);
		GUI_Dot(x-yc,y+xc,col);
		GUI_Dot(x-yc,y-xc,col);
		if(p<0)
		{
			p += (xc++ << 2) + 6;	
		}
		else
			p += ((xc++ - yc--)<<2) + 10;
	}
}
void draw_circle()	 //画圆
{
	get_circle(100,200,100,YELLOW);
	get_circle(100,200,99,YELLOW);
	get_circle(100,200,98,YELLOW);
	get_circle(100,200,97,YELLOW);
	get_circle(100,200,5,YELLOW);			
}
void draw_dotline()  //画格点
{
	u8 i;
	u8 rome[][3]={"12","1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11" } ; //表盘数字 
	int x1,y1,x2,y2,x3,y3;
	for(i=0;i<60;i++)
	{
		x1 = (int)(100 + (sin(i * PI / 30) * 92)); 
		y1 = (int)(100 - (cos(i * PI / 30) * 92)); 
		x2 = (int)(100 + (sin(i * PI / 30) * 97)); 
		y2 = (int)(100 - (cos(i * PI / 30) * 97)); 
		GUI_Line(x1,y1+100,x2,y2+100,RED);

		if(i%5==0)
		{
			x1 = (int)(100 + (sin(i * PI / 30) * 85)); 
			y1 = (int)(100 - (cos(i * PI / 30) * 85)); 
			x2 = (int)(100 + (sin(i * PI / 30) * 97)); 
			y2 = (int)(100 - (cos(i * PI / 30) * 97)); 
			GUI_Line(x1,y1+100,x2,y2+100,RED);	

			x3 = (int)(92 + (sin((i ) * PI / 30) * 80)); 
			y3 = (int)(92 - (cos((i ) * PI / 30) * 80));

			GUI_Show12ASCII(x3,y3+100,rome[i/5],YELLOW,BLACK);
		}
		
	}		
}
void draw_hand(int hhour,int mmin,int ssec)  //画指针
{
	int xhour, yhour, xminute, yminute, xsecond, ysecond; //表心坐标系指针坐标
	xhour = (int)(60 * sin( hhour * PI / 6 + mmin * PI / 360 + ssec * PI / 1800)); 
	yhour = (int)(60 * cos( hhour * PI / 6 + mmin * PI / 360 + ssec * PI / 1800)); 
	xminute = (int)(90 * sin( mmin * PI / 30 + ssec * PI / 1800)); 
	yminute = (int)(90 * cos( mmin * PI / 30 + ssec * PI / 1800)); 
	xsecond = (int)(100 * sin( ssec * PI / 30)); 
	ysecond = (int)(100 * cos( ssec * PI / 30)); 

	
	GUI_Line(100 + xhour, 200 - yhour, 100 -xhour / 6, 200 + yhour / 6,RED);
	GUI_Line(100 + xminute, 200 - yminute, 100 -xminute / 4, 200 + yminute / 4,BLUE);
	GUI_Line(100 + xsecond, 200 - ysecond, 100 -xsecond / 3, 200 + ysecond / 3,GREEN);
	
}
void draw_hand_clear(int hhour,int mmin,int ssec)  //擦指针
{
	int xhour, yhour, xminute, yminute, xsecond, ysecond; //表心坐标系指针坐标
	xhour = (int)(60 * sin( hhour * PI / 6 + mmin * PI / 360 + ssec * PI / 1800)); 
	yhour = (int)(60 * cos( hhour * PI / 6 + mmin * PI / 360 + ssec * PI / 1800)); 
	xminute = (int)(90 * sin( mmin * PI / 30 + ssec * PI / 1800)); 
	yminute = (int)(90 * cos( mmin * PI / 30 + ssec * PI / 1800)); 
	xsecond = (int)(100 * sin( ssec * PI / 30)); 
	ysecond = (int)(100 * cos( ssec * PI / 30)); 

	
	GUI_Line(100 + xhour, 200 - yhour, 100 -xhour / 6, 200 + yhour / 6,BLACK);
	GUI_Line(100 + xminute, 200 - yminute, 100 -xminute / 4, 200 + yminute / 4,BLACK);
	GUI_Line(100 + xsecond, 200 - ysecond, 100 -xsecond / 3, 200 + ysecond / 3,BLACK);
	
}



int main(void)
{
    uint8_t ledState, setState, m;
    uint8_t keyValue;
	  uint16_t i;

    /* 初始化时钟值 */
    time.year = 2019;
    time.month = 12;
    time.day = 29;
    time.week = 4;
    time.hour = 12;
    time.minit = 03;
    time.second = 32;

    /* 初始化 */
    TFT_Init(); 
    FLASH_Init();
    RTC_Config(&time);
    LED_Config();
    KEY_Config();

/* 彩屏显示初始化 */
TFT_ClearScreen(BLACK);
GUI_Show12Char(120, 0,"xiaopeng", RED, BLACK);
GUI_Show12Char(120, 21, "内部时钟实验", RED, BLACK);
GUI_Show12Char(32, 42, "年  月  日", RED, BLACK);
GUI_Show12Char(128, 42, ":  :", RED, BLACK);

   setState = 0; //初始设置为普通模式,非设置模式
   m = 0;        //显示无高亮位置
	
	while(1)
	{
		
		
		u8 dat[9];
				if(timebz==0)
		{
			u16 hur=0,mn=0,sc=0;
			
			timebz=0;
			draw_hand_clear(hur,mn,sc);
			hur=RTC_Time.hour;
			mn = RTC_Time.minit ;
			sc =RTC_Time.second;
		
			dat[0]=hur/10+'0';
			dat[1]=hur%10+'0';
			dat[2]=' ';
			dat[3]=mn/10+'0';
			dat[4]=mn%10+'0';
			dat[5]=' ';
			dat[6]=sc/10+'0';
			dat[7]=sc%10+'0';
			dat[8]='\0';
			draw_hand(hur,mn,sc);
			delay_ms(700);
      draw_hand_clear(hur,mn,sc);
		}
		draw_circle();
		draw_dotline();
		//GUI_Show12ASCII(80,50,dat,YELLOW,BLACK);	
      /*  //LED灯闪烁 
       i++;       
        if(i > 0xFF)
        {   
            i = 0; 
            if(ledState == 0xFE)
            {
                ledState = 0xFF;
            }
            else
            {
                ledState = 0xFE;
            }
            LED_SetState(ledState);
        }*/

        /* 键盘扫描 */
        keyValue = KEY_Scan();

        /* 如果按键是右键,进入或者退出设置模式 */
        if(keyValue == KEY_RIGHT)
        {
            if(setState == 0)
            {
                setState = 1;
            }
            else
            {
                setState = 0;      
							//led_display();    
            }
            if(setState)  //退出设置模式则更新时间
            {
                m = 1;     
            }
            else
            {
                RTC_SetClock(&time);
                m = 0;
            }
        }

        /* 进入设置模式 */
        if(setState == 1)
        {
            switch(keyValue)
            {
                case(KEY_UP):      //上键高亮数字加1
                    TIME_Set(m, 1);
                    break;
                case(KEY_DOWN):    //下键高亮数字减1
                    TIME_Set(m, 0);
                    break;
                case(KEY_LEFT):    //左键高亮位置左移1位
                    if(m == 6)
                    {
                        m = 1;
                    }
                    else
                    {
                        m++;
                    }
                    break;
                default:
                    break;        
            }
        }
        /* 普通模式显示时钟 */
        else
        {
            /* 读取时钟 */
            time = RTC_Time;       //读取时钟
        }
        GUI_DisplayTime(m);    //显示时钟
				BEEP_Init();	//端口初始化  
				//if(RTC_Time.day==29 & RTC_Time.hour==11 & RTC_Time.minit==53 & RTC_Time.second==07)
	      if(RTC_Time.minit==53 & RTC_Time.second==07)   //     闹钟
				{
				sound2();
				}
				
	}

}


/****************************************************************************
* Function Name  : GUI_DisplayTime
* Description    : 在彩屏上面显示时钟
* Input          : num:进入设置模式时,高亮选择(0:普通模式,其他为设置模式)
* Output         : None
* Return         : None
****************************************************************************/

void GUI_DisplayTime(uint8_t num)
{
    
    /* 显示年 */
    showValue[0] = (time.year % 10000 /1000) + '0';
    showValue[1] = (time.year % 1000 / 100) + '0';
    showValue[2] = (time.year % 100 /10) + '0';
    showValue[3] = (time.year % 10) + '0';
    if(num == 6)
    {
        GUI_Show12Char(0, 42, showValue, GREEN, BLACK);
    }
    else
    {
        GUI_Show12Char(0, 42, showValue, RED, BLACK);
    }
    
    
    /* 显示月 */
    showValue[2] = 0;
    showValue[0] = (time.month % 100 /10) + '0';
    showValue[1] = (time.month % 10) + '0';
    if(num == 5)
    {
        GUI_Show12Char(48, 42, showValue, GREEN, BLACK);
    }
    else
    {
        GUI_Show12Char(48, 42, showValue, RED, BLACK);
    }
    
    /* 显示日 */
    showValue[0] = (time.day % 100 /10) + '0';
    showValue[1] = (time.day % 10) + '0';
    if(num == 4)
    {
        GUI_Show12Char(80, 42, showValue, GREEN, BLACK);
    }
    else
    {
    GUI_Show12Char(80, 42, showValue, RED, BLACK);
    }
    
    /* 显示时 */
    showValue[0] = (time.hour % 100 /10) + '0';
    showValue[1] = (time.hour % 10) + '0';
    if(num == 3)
    {
        GUI_Show12Char(112, 42, showValue, GREEN, BLACK);
    }
    else
    {
        GUI_Show12Char(112, 42, showValue, RED, BLACK);
    }
    
    /* 显示分钟 */
    showValue[0] = (time.minit % 100 /10) + '0';
    showValue[1] = (time.minit % 10) + '0';
    if(num == 2)
    {
        GUI_Show12Char(136, 42, showValue, GREEN, BLACK);
    }
    else
    {
        GUI_Show12Char(136, 42, showValue, RED, BLACK);
    }

    /* 显示秒 */
    showValue[0] = (time.second % 100 /10) + '0';
    showValue[1] = (time.second % 10) + '0';
    if(num == 1)
    {
        GUI_Show12Char(160, 42, showValue, GREEN, BLACK);
    }
    else
    {
        GUI_Show12Char(160, 42, showValue, RED, BLACK);        
    } 
}

/****************************************************************************
* Function Name  : TIME_Set
* Description    : 根据设置选择高亮数字部分加一或者减一,注意这里设置日期的时
*                * 候,日是到31号的,但是有些月份日是没有到31号的,自己设置的
*                * 时候要注意,否则日期时间会出错。
* Input          : num:高亮数字位置
*                * state:选择加一或者减一(非零加一,否则减一)
* Output         : None
* Return         : None
****************************************************************************/

void TIME_Set(uint8_t num, uint8_t state)
{
    switch(num)
    {   
        /* 高亮部分为秒 */
        case(1):          
            if(state)
            {
                if(time.second == 59)
                {
                    time.second = 0;
                }
                else
                {
                    time.second++;
                }    
            }
            else
            {
                if(time.second == 0)
                {
                    time.second = 59;
                }
                else
                {
                    time.second--;
                }    
            }
            break;
        /* 高亮部分为分钟 */
        case(2):        
            if(state)
            {
                if(time.minit == 59)
                {
                    time.minit = 0;
                }
                else
                {
                    time.minit++;
                }    
            }
            else
            {
                if(time.minit == 0)
                {
                    time.minit = 59;
                }
                else
                {
                    time.minit--;
                }    
            }
            break;
        /* 高亮部分为小时 */
        case(3):
            if(state)
            {
                if(time.hour == 23)
                {
                    time.hour = 0;
                }
                else
                {
                    time.hour++;
                }    
            }
            else
            {
                if(time.hour == 0)
                {
                    time.hour = 23;
                }
                else
                {
                    time.hour--;
                }    
            }
            break;
        /* 高亮部分为日 */
        case(4):
            if(state)
            {
                if(time.day == 31)
                {
                    time.day = 1;
                }
                else
                {
                    time.day++;
                }    
            }
            else
            {
                if(time.day == 1)
                {
                    time.day = 31;
                }
                else
                {
                    time.day--;
                }    
            }
            break;
        /* 高亮部分为月 */
        case(5):
            if(state)
            {
                if(time.month == 12)
                {
                    time.month = 1;
                }
                else
                {
                    time.month++;
                }    
            }
            else
            {
                if(time.month == 1)
                {
                    time.month = 12;
                }
                else
                {
                    time.month--;
                }    
            }
            break;
        /* 高亮部分为年 */
        case(6):
            if(state)
            {
                    time.year++;
            }
            else
            {
                    if(time.year > 1999)
                    {
                        time.year--;
                    }
                    
            }
            break;
        default:
            break;
    }
		
}



 GUI.C 有稍微改动。

#include "gui.h"

#ifdef USE_FONT_UPDATE
#include "ff.h"
#include "diskio.h"
#endif

#ifdef USE_FLASH_CHAR
#include "flash.h"
#else
#include "asciicode.h"
#endif
#include "asciicode.h"
#ifdef USE_FONT_UPDATE
#include "malloc.h"
#endif
/****************************************************************************
* Function Name  : GUI_Dot
* Description    : 在彩屏上面画一点
* Input          : x:点的X坐标
*                * y:点的Y坐标
*                * color:点的颜色
* Output         : None
* Return         : None
****************************************************************************/

void GUI_Dot(uint16_t x, uint16_t y, uint16_t color)
{  
	TFT_SetWindow(x, y, x, y);  //设置点的位置
	TFT_WriteData(color);       //画点	
}

/****************************************************************************
* Function Name  : GUI_Box
* Description    : 给一个区域涂上颜色
* Input          : sx:起始X坐标, sy:其实Y坐标, 
*                * ex:终止X坐标, ey:终止Y坐标,
*                * color:方框的颜色
* Output         : None
* Return         : None
****************************************************************************/

void GUI_Line(u16 xStart, u16 yStart, u16 xEnd, u16 yEnd, u16 color)
{
	u16 t;  
	int xerr = 0, yerr = 0, delta_x, delta_y, distance;  
	int incx, incy;  
	u16 row, col;  
	delta_x = xEnd - xStart;//计算坐标增量  
	delta_y = yEnd - yStart;  
	col = xStart;  
	row = yStart;  
	if (delta_x > 0)
	{
		incx=1;//设置单步方向
	} 	  
	else    
	{  
	    if (delta_x == 0)
		{
			incx = 0;//垂直线 
		} 		 
	    else 
			{
				incx = -1;
				delta_x = -delta_x;
			}  
	}  
	if (delta_y > 0)
	{
		incy = 1;
	}	  
	else  
	{  
	    if (delta_y == 0)
		{
			incy = 0;//水平线  
		} 
	    else 
		{
			incy = -1;
			delta_y = -delta_y;
		}  
	}  
	if (delta_x > delta_y)
	{ 
		distance = delta_x;//选取基本增量坐标轴  
	}
	else
	{
		distance = delta_y; 
	} 	
	for (t=0; t<=distance+1; t++)  
	{                                     //画线输出  
	    GUI_Dot(col, row, color);
	    xerr += delta_x;  
	    yerr += delta_y;  
	  	if(xerr > distance)  
	    {  
	        xerr -= distance;  
	        col += incx;  
	    }  
	    if(yerr > distance)  
	    {  
	        yerr -= distance;  
	        row += incy;  
	    }  
	}  
}

void GUI_Box(uint16_t xState, uint16_t yState, uint16_t xEnd, uint16_t yEnd, uint16_t color)
{ 
	uint16_t temp;

    if((xState > xEnd) || (yState > yEnd))
    {
        return;
    }   
	TFT_SetWindow(xState, yState, xEnd, yEnd); 
    xState = xEnd - xState + 1;
	yState = yEnd - yState + 1;

	while(xState--)
	{
	 	temp = yState;
		while (temp--)
	 	{	
			TFT_WriteData(color);
		}
	}
}



/****************************************************************************
* Function Name  : GUI_DrowSign
* Description    : 画一个十字的标记
* Input          : x:标记的X坐标;
*                * y:标记的Y坐标
*                * color:标记的颜色
* Output         : None
* Return         : None
****************************************************************************/

void GUI_DrowSign(uint16_t x, uint16_t y, uint16_t color)
{
    uint8_t i;

    /* 画点 */
    TFT_SetWindow(x-1, y-1, x+1, y+1);
    for(i=0; i<9; i++)
    {
        TFT_WriteData(color);    
    }

    /* 画竖 */
    TFT_SetWindow(x-4, y, x+4, y);
    for(i=0; i<9; i++)
    {
        TFT_WriteData(color);    
    }

    /* 画横 */
    TFT_SetWindow(x, y-4, x, y+4);
    for(i=0; i<9; i++)
    {
        TFT_WriteData(color);    
    }
}

/****************************************************************************
* Function Name  : GUI_Show12ASCII
* Description    : 写12号ASCII码
* Input          : x:起始X坐标
*                * y:起始Y坐标
*                * p:字符串首地址
*                * wordColor:字体颜色
*                * backColor:背景颜色
* Output         : None
* Return         : None
****************************************************************************/

void GUI_Show12ASCII(uint16_t x, uint16_t y, uint8_t *p, 
                     uint16_t wordColor, uint16_t backColor)
{
	uint8_t i, wordByte, wordNum;
	uint16_t color;

	while(*p != '\0')   //检测是否是最后一个字
	{
        /* 在字库中的ASCII码是从空格开始的也就是32开始的,所以减去32 */
		wordNum = *p - 32;
		
        TFT_SetWindow(x, y, x+7, y+15);           //字宽*高为:8*16
		for (wordByte=0; wordByte<16; wordByte++) //每个字模一共有16个字节
		{
			color = ASCII8x16[wordNum][wordByte];
			for (i=0; i<8; i++) 
			{
				if ((color&0x80) == 0x80)
				{
					TFT_WriteData(wordColor);
				} 						
				else
				{
					TFT_WriteData(backColor);
				} 	
				color <<= 1;
			}
		}

		p++;    //指针指向下一个字
		
        /* 屏幕坐标处理 */
        x += 8;
        if(x > 233)   //TFT_XMAX -8
        {
            x = 0;
            y += 16;    
        }
	}
}



/****************************************************************************
* Function Name  : GUI_Show12Char
* Description    : 通过FLASH字库显示12号字母和汉字(使用GBK)
* Input          : x:起始X坐标
*                * y:起始Y坐标
*                * ch:字符串首地址
*                * wordColor:字体颜色
*                * backColor:背景颜色
* Output         : None
* Return         : None
****************************************************************************/

void GUI_Show12Char(uint16_t x, uint16_t y, uint8_t *ch, 
                    uint16_t wordColor, uint16_t backColor)
{
    uint8_t i, j, color, buf[32];
    uint16_t asc;
    uint32_t wordAddr = 0;

    while(*ch != '\0')
    {
        /*显示字母,ASCII编码 */
        if(*ch < 0x80)  //ASCII码从0~127
        {
            /* 在字库中的ASCII码是从空格开始的也就是32开始的,所以减去32 */
    		wordAddr = *ch - 32;
            wordAddr *= 16;
            wordAddr += GUI_FLASH_ASCII_ADDR;
            
            /* 读取FLASH中该字的字模 */
            FLASH_ReadData(buf, wordAddr, 16);
            
            /* 显示该文字 */		
            TFT_SetWindow(x, y, x+7, y+15);           //字宽*高为:8*16
    		for (j=0; j<16; j++) //每个字模一共有16个字节
    		{
    			color = buf[j];
    			for (i=0; i<8; i++) 
    			{
    				if ((color&0x80) == 0x80)
    				{
    					TFT_WriteData(wordColor);
    				} 						
    				else
    				{
    					TFT_WriteData(backColor);
    				} 	
    				color <<= 1;
    			}
    		}
    
    		ch++;    //指针指向下一个字
    		
            /* 屏幕坐标处理 */
            x += 8;
            if(x > TFT_XMAX -8)   //TFT_XMAX -8
            {
                x = 0;
                y += 16;    
            }            
        }
        /* 显示汉字,GBK编码 */
        else
        {
            /* 将汉字编码转换成在FLASH中的地址 */
            asc = *ch - 0x81;     //高字节是表示分区,分区是从0x81到0xFE,所以转换成地址-0x80
            wordAddr = asc * 190; //每个分区一共有190个字
    
            asc = *(ch + 1); //低字节代表每个字在每个分区的位置,它是从0x40到0xFF
            if(asc < 0x7F)   //在0x7F位置有个空位,但是我们取模不留空,所以大于0x7F之后多减一
            {
                asc -= 0x40;
            }
            else
            {
                asc -= 0x41;
            }
            
            wordAddr += asc; //求出在GBK中是第几个字
            wordAddr *= 32;  //将字位置转换位FLASH地址
            wordAddr += GUI_FLASH_12CHAR_ADDR; //加上首地址
    
            /* 读取FLASH中该字的字模 */
            FLASH_ReadData(buf, wordAddr, 32);
    
            /* 在彩屏上面显示 */
            TFT_SetWindow(x, y, x+15, y+15);
            for(i=0; i<32; i++)
            {
                 
                color = buf[i];            
                for(j=0; j<8; j++) 
        		{
        			if((color & 0x80) == 0x80)
        			{
        				TFT_WriteData(wordColor);
        			} 						
        			else
        			{
        				TFT_WriteData(backColor);
        			} 
        			color <<= 1;
        		}//for(j=0;j<8;j++)结束
            }
    
            /* 屏幕坐标处理 */
            x += 16;
            if(x > TFT_XMAX -15)   //TFT_XMAX -15
            {
                x = 0;
                y += 16;    
            }
    
            /* 写下一个字,每个汉字占两个字节所以+2 */
            ch += 2;             
        }
    }    
}
/****************************************************************************
* Function Name  : GUI_Show12Chinese
* Description    : 通过FLASH字库显示12号汉字(使用GBK)
* Input          : x:起始X坐标
*                * y:起始Y坐标
*                * cn:字符串首地址
*                * wordColor:字体颜色
*                * backColor:背景颜色
* Output         : None
* Return         : None
****************************************************************************/

void GUI_Show16Chinese(uint16_t x, uint16_t y, uint8_t *cn, 
                       uint16_t wordColor, uint16_t backColor)
{   
    uint8_t i, j, color, buf[63];
    uint16_t asc;
    uint32_t wordAddr = 0;    
    while(*cn != '\0')
    {  
        /* 将汉字编码转换成在FLASH中的地址 */
        asc = *cn - 0x81;     //高字节是表示分区,分区是从0x81到0xFE,所以转换成地址-0x80
        wordAddr = asc * 190; //每个分区一共有190个字

        asc = *(cn + 1); //低字节代表每个字在每个分区的位置,它是从0x40到0xFF
        if(asc < 0x7F)   //在0x7F位置有个空位,但是我们取模不留空,所以大于0x7F之后多减一
        {
            asc -= 0x40;
        }
        else
        {
            asc -= 0x41;
        }
        
        wordAddr += asc; //求出在GBK中是第几个字
        wordAddr *= 63;  //将字位置转换位FLASH地址
        wordAddr += GUI_FLASH_16CHAR_ADDR; //加上首地址

        /* 读取FLASH中该字的字模 */
        FLASH_ReadData(buf, wordAddr, 63);

        /* 在彩屏上面显示 */
        TFT_SetWindow(x, y, x+23, y+20);
        for(i=0; i<63; i++)
        {
            color = buf[i];            
            for(j=0; j<8; j++) 
    		{
    			if((color & 0x80) == 0x80)
    			{
    				TFT_WriteData(wordColor);
    			} 						
    			else
    			{
    				TFT_WriteData(backColor);
    			} 
    			color <<= 1;
    		}//for(j=0;j<8;j++)结束
        }

        /* 屏幕坐标处理 */
        x += 21;
        if(x > 218)   //TFT_XMAX -21
        {
            x = 0;
            y += 21;    
        }

        /* 写下一个字,每个汉字占两个字节所以+2 */
        cn += 2;      
    }    
}




#ifdef USE_FONT_UPDATE

/****************************************************************************
* Function Name  : GUI_FontUpdate
* Description    : 更新字库
* Input          : updateState:选择更新的字库
* Output         : None
* Return         : None
****************************************************************************/

void GUI_FontUpdate(uint8_t updateState)
{
    FRESULT res;
	FIL fsrc;
	UINT  br;
    uint32_t wordAddr, i, j;

#ifdef __MALLOC_H	
    uint8_t *p;
    p = malloc(4096);                  //开辟一个内存块
    if(p == 0)
    {
        return;
    }
#else
	uint8_t buffer[512];
#endif    	

    /* 更新ASCII字库 */
    if((updateState & GUI_UPDATE_ASCII) == GUI_UPDATE_ASCII)
    {
        /* 设置写入起始地址 */
        wordAddr = GUI_FLASH_ASCII_ADDR;
        j = 0;

        /* 打开读取文件 */
        res = f_open(&fsrc, GUI_ASCII_FILE, FA_READ);	
    	if(res == FR_OK)  //打开成功
        { 
         	for (;;)      //开始读取数据
         	{       
#ifdef __MALLOC_H	
                res = f_read(&fsrc, p, 4096, &br);
    
                /* 将读取到的数据写入FLASH */
                FLASH_WriteData(p, wordAddr, br);
          	    wordAddr += br;   //写入地址增加

#else
                res = f_read(&fsrc, buffer, sizeof(buffer), &br);
    
                /* 将读取到的数据写入FLASH */
                FLASH_WriteData(buffer, wordAddr, br);
          	    wordAddr += br;   //写入地址增加
#endif
                j += br;
                i = j * 100 / 1456;
                GUI_Box(0, 80, i, 90, RED);    

                if (res || br == 0)
    			{
    				break;    // error or eof 
    			}
            } 
        }
    	 
        f_close(&fsrc);  //不论是打开,还是新建文件,一定记得关闭
    }

    /* 更新12号汉字库 */
    if((updateState & GUI_UPDATE_12CHAR) == GUI_UPDATE_12CHAR)
    {
        wordAddr = GUI_FLASH_12CHAR_ADDR;
        j = 0;

        res = f_open(&fsrc, GUI_12CHAR_FILE, FA_READ);
    	
    	if(res == FR_OK) 
        {  
         	for (;;)  
         	{      
#ifdef __MALLOC_H	
                res = f_read(&fsrc, p, 4096, &br);
    
                /* 将读取到的数据写入FLASH */
                FLASH_WriteData(p, wordAddr, br);
          	    wordAddr += br;   //写入地址增加
#else
                res = f_read(&fsrc, buffer, sizeof(buffer), &br);
    
                FLASH_WriteData(buffer, wordAddr, br);
          	    wordAddr += br;
#endif
                j += br;
                i = j * 100 / 766080;
                GUI_Box(0, 95, i, 105, RED);    

    
                if (res || br == 0)
    			{
    				break;    // error or eof 
    			}
            } 
        }
        f_close(&fsrc);  //不论是打开,还是新建文件,一定记得关闭
    }
    
    /* 更新16号汉字库 */
    if((updateState & GUI_UPDATE_16CHAR) == GUI_UPDATE_16CHAR)
    {
        
        wordAddr = GUI_FLASH_16CHAR_ADDR;
        j = 0;

        res = f_open(&fsrc, GUI_16CHAR_FILE, FA_READ);	
    	if(res == FR_OK) 
        { 
         	for (;;)  
         	{       
#ifdef __MALLOC_H	
                res = f_read(&fsrc, p, 4096, &br);
    
                /* 将读取到的数据写入FLASH */
                FLASH_WriteData(p, wordAddr, br);
          	    wordAddr += br;   //写入地址增加
#else
                res = f_read(&fsrc, buffer, sizeof(buffer), &br);
    
                FLASH_WriteData(buffer, wordAddr, br);
          	    wordAddr += br;
#endif
                j += br;
                i = j * 100 / 1508220;
                GUI_Box(0, 110, i, 120, RED);    

    
                if (res || br == 0)
    			{
    				break;    // error or eof 
    			}
            } 
        }
    	 
        f_close(&fsrc);  //不论是打开,还是新建文件,一定记得关闭
    }
#ifdef __MALLOC_H	
    free(p);
#endif
} 
 
#endif


GUI.H

#ifndef __GUI_H
#define __GUI_H

#include "stm32f10x.h"
#include "lcd_driver.h"

/* 编译选择 */
//#define USE_FONT_UPDATE                   //使用字库更新函数
#define USE_FLASH_CHAR                    //使用FLASH字库

/* 字库文件地址 */
#define GUI_ASCII_FILE  "系统/FONT/ASCII(8X16).DZK"
#define GUI_12CHAR_FILE "系统/FONT/12号字体(16X16).DZK"
#define GUI_16CHAR_FILE "系统/FONT/16号字体(24X21).DZK"

/* 设置字库地址 */
#define GUI_FLASH_ASCII_ADDR     6112846  //ASCII字库首地址(6114304 - 1456 - 2)
#define GUI_FLASH_12CHAR_ADDR    6114304  //12号字库首地址(6880386 - 766080 - 2)
#define GUI_FLASH_16CHAR_ADDR    6880386  //16号字库首地址(8388608 - 1508220 - 2)

/* 更新字库选择项 */
#define GUI_UPDATE_ASCII         0x01     
#define GUI_UPDATE_12CHAR        0x02
#define GUI_UPDATE_16CHAR        0x04
#define GUI_UPDATE_ALL           0x07

/* 声明全局变量 */
void GUI_Dot(uint16_t x, uint16_t y, uint16_t color);
void GUI_BigPoint(uint16_t x, uint16_t y, uint16_t color);
void GUI_Box(uint16_t xState, uint16_t yState, uint16_t xEnd, uint16_t yEnd, uint16_t color);
void GUI_DrowSign(uint16_t x, uint16_t y, uint16_t color);

void GUI_FontUpdate(uint8_t updateState);
void GUI_Show12ASCII(uint16_t x, uint16_t y, uint8_t *p, uint16_t wordColor, uint16_t backColor);
void GUI_Show12Char(uint16_t x, uint16_t y, uint8_t *ch, 
                    uint16_t wordColor, uint16_t backColor);
void GUI_Show16Chinese(uint16_t x, uint16_t y, uint8_t *cn, 
                       uint16_t  wordColor, uint16_t backColor);
void GUI_Dot(uint16_t x, uint16_t y, uint16_t color);
void GUI_Line(u16 xStart, u16 yStart, u16 xEnd, u16 yEnd, u16 color);


#endif

 

KEY.C

#include "key.h"
#include "usart.h"

/* 声明函数 */
static void KEY_Delay10ms(void);

/****************************************************************************
* Function Name  : KEY_Config
* Description    : 初始化按键是用的IO口
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/

void KEY_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    /* 开启GPIO时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    /*  配置GPIO的模式和IO口 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_KEY;        //选择你要设置的IO口
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //设置传输速率
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;      //设置输入上拉模式

    /* 初始化GPIO */
    GPIO_Init(GPIOE, &GPIO_InitStructure);
    	          
    /* PA0 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;          //选择你要设置的IO口
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;      //设置输入上拉模式

    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

#ifdef USE_EXTI
/****************************************************************************
* Function Name  : KEY_NVIC_Config
* Description    : 初始化外部中断
* Input          : key:选择使用外部中断的按键
* Output         : None
* Return         : None
****************************************************************************/

void KEY_NVIC_Config(uint8_t key)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;

    /* 打开时钟使能 */
    if(key & KEY_UP)
    {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    }
    if(key & (KEY_DOWN | KEY_LEFT | KEY_RIGHT))
    {
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);    
    }
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

    /* 设置GPIO参数 */    
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //设置传输速率
    if(key & KEY_UP)
    {
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;      //设置输入下拉模式
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;          //选择你要设置的IO口
    	/*初始化GPIO*/
    	GPIO_Init(GPIOA, &GPIO_InitStructure);
    }
    if(key & (KEY_DOWN | KEY_LEFT | KEY_RIGHT))
    {
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;      //设置输入上拉模式
        if(key & KEY_LEFT)
        {
            GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;          //选择你要设置的IO口
        }
        if(key & KEY_DOWN)
        {
            GPIO_InitStructure.GPIO_Pin |= GPIO_Pin_3;          //选择你要设置的IO口
        }
        if(key & KEY_RIGHT)
        {
            GPIO_InitStructure.GPIO_Pin |= GPIO_Pin_4;          //选择你要设置的IO口
        }
    	/*初始化GPIO*/
    	GPIO_Init(GPIOA, &GPIO_InitStructure);        
    }

/***************************************************************************/
/**************************** 中断设置 *************************************/
/***************************************************************************/

	/* 设置NVIC参数,注意一次只能开启一位,不能几位相或一起打开*/
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//设置抢占优先级为0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;       //设置从优先级为0;	
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		     //使能。
    
    if(key & KEY_UP)
    {
        NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;         //开启的外部中断0通道中断使能
        NVIC_Init(&NVIC_InitStructure);
    }
    if(key & KEY_LEFT)
    {
        NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;         //开启的外部中断0通道中断使能
        NVIC_Init(&NVIC_InitStructure); 
    }
    if(key & KEY_DOWN)
    {
        NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;         //开启的外部中断0通道中断使能
        NVIC_Init(&NVIC_InitStructure); 
    }
    if(key & KEY_RIGHT)
    {
        NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;         //开启的外部中断0通道中断使能
        NVIC_Init(&NVIC_InitStructure); 
    }

	/* 选择EXTI */
    if(key & KEY_UP)
    {
	    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //选择KEY_UP做外部中断
    }
    if(key & KEY_LEFT)
    {
	    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource2); //选择KEY_UP做外部中断
    }
    if(key & KEY_DOWN)
    {
	    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource3); //选择KEY_UP做外部中断
    }
    if(key & KEY_RIGHT)
    {
	    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE, GPIO_PinSource4); //选择KEY_UP做外部中断
    }

    /* 设置外部中断的模式 */    
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;			    //打开使能
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;     //中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  //上升沿触发

    if(key & KEY_UP)
    {
	    EXTI_InitStructure.EXTI_Line = EXTI_Line0;			    //设置打开外部中断通道
        /*初始化EXTI*/
	    EXTI_Init(&EXTI_InitStructure);
	}
    if(key & (KEY_DOWN | KEY_LEFT | KEY_RIGHT))
    {
        if(key & KEY_LEFT)
        {
            EXTI_InitStructure.EXTI_Line |= EXTI_Line2;
        }
        if(key & KEY_DOWN)
        {
            EXTI_InitStructure.EXTI_Line |= EXTI_Line3;
        }
        if(key & KEY_RIGHT)
        {
            EXTI_InitStructure.EXTI_Line |= EXTI_Line4;
        }
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;  //下降沿触发
        /*初始化EXTI*/
    	EXTI_Init(&EXTI_InitStructure);
    }
}

/****************************************************************************
* Function Name  : EXTI0_IRQHandler
* Description    : 外部中断0的中断函数
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/

void EXTI0_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line0))
	{
        printf(" KEY_UP发生中断!\n");
	}
	EXTI_ClearITPendingBit(EXTI_Line0);
}


/****************************************************************************
* Function Name  : EXTI2_IRQHandler
* Description    : 外部中断2的中断函数
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/

void EXTI2_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line2))
	{
        printf(" KEY_LEFT发生中断!\n");
	}
	EXTI_ClearITPendingBit(EXTI_Line2);
}

/****************************************************************************
* Function Name  : EXTI3_IRQHandler
* Description    : 外部中断3的中断函数
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/

void EXTI3_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line3))
	{
        printf(" KEY_DOWN发生中断!\n");
	}
	EXTI_ClearITPendingBit(EXTI_Line3);
}

/****************************************************************************
* Function Name  : EXTI4_IRQHandler
* Description    : 外部中断4的中断函数
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/

void EXTI4_IRQHandler(void)
{
	if (EXTI_GetITStatus(EXTI_Line4))
	{
        printf(" KEY_RIGHT发生中断!\n");
	}
	EXTI_ClearITPendingBit(EXTI_Line4);
}

#endif

/****************************************************************************
* Function Name  : KEY_Delay10ms
* Description    : 按键使用的消抖延时函数。注意:该延时函数具体延时时间是不确
*                * 定的,并非真的就延时10ms,要精确延时请使用定时器。
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/

static void KEY_Delay10ms(void)
{
    uint16_t i;
    for(i=0; i<0x5FFF; i++);
}

/****************************************************************************
* Function Name  : KEY_Scan
* Description    : 按键扫描,注意该按键扫描支持一次按1个键,不支持同时按多个键
* Input          : None
* Output         : None
* Return         : keyValue:按键的键值
****************************************************************************/

uint8_t KEY_Scan(void)
{
    uint8_t keyValue = 0, timeCount = 0;

    if((KEY0 == 1) || (KEY1 == 0) || (KEY2 == 0) || (KEY3 == 0)) //检测是否有按键按下
    {
        KEY_Delay10ms();                                      //延时消抖

        /* 检测是哪个按键按下 */
        if(KEY0 == 1)
        {
            keyValue = KEY_UP;
        }
        else if(KEY1 == 0)
        {
            keyValue = KEY_LEFT;
        }
        else if(KEY2 == 0)
        {
            keyValue = KEY_DOWN;
        }
        else if(KEY3 == 0)
        {
            keyValue = KEY_RIGHT;
        }
        else
        {
            keyValue = 0;
        }
        
        /* 有按键按下时,做松手检测 */
        if(keyValue != 0)
        {
            while(((KEY0 == 1) || (KEY1 == 0) || (KEY2 == 0) || (KEY3 == 0)) && (timeCount < 150))
            {
                KEY_Delay10ms();
                timeCount++;        
            }
//            KEY_Delay10ms();//由于主函数中程序较少,连续扫描的速度太快,加一个松手消抖减少误读   
        }        
    }

    return keyValue;
}

KEY.H

#ifndef __KEY_H
#define __KEY_H

#include "stm32f10x.h"

//#define USE_EXTI    //使用外部中断

/* 定义要设置的按键使用的PIN口 */
#define GPIO_Pin_KEY (GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4)

/* 按键读取 */
#define KEY0 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)
#define KEY1 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_2)
#define KEY2 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_3)
#define KEY3 GPIO_ReadInputDataBit(GPIOE, GPIO_Pin_4)

/* 定义按键的键值 */
#define KEY_UP    0x01
#define KEY_DOWN  0x02
#define KEY_LEFT  0x04
#define KEY_RIGHT 0x08
#define KEY_ALL   0x0F
/* 声明全局函数 */
void KEY_Config(void);
uint8_t KEY_Scan(void);
void KEY_NVIC_Config(uint8_t key);





#endif

RTC.C

#include "rtc.h"
u8 timebz;
/* 月份   1  2  3  4  5  6  7  8  9  10 11 12 */
/* 闰年   31 29 31 30 31 30 31 31 30 31 30 31 */
/* 非闰年 31 28 31 30 31 30 31 31 30 31 30 31 */
const uint8_t RtcLeapMonth[12]   = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const uint8_t RtcCommonMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

/* 定义一个全局变量保存时钟 */
RTC_TimeTypeDef RTC_Time;

/* 声明内部函数 */
static uint8_t RTC_CheckLeapYear(uint16_t year);
static uint8_t RTC_SetTime(RTC_TimeTypeDef *time);
static void RTC_NVIC_Config(void);
static void RTC_GetTime(void);

/****************************************************************************
* Function Name  : RTC_SetClock
* Description    : 设置时钟
* Input          : *time:要设置的时钟值
* Output         : None
* Return         : None
****************************************************************************/

void RTC_SetClock(RTC_TimeTypeDef *time)
{   
    RTC_EnterConfigMode();                    //允许配置	
    RTC_WaitForLastTask();	                  //等待最近一次对RTC寄存器的写操作完成
    RTC_SetTime(time);                        //设置时间	
    RTC_ExitConfigMode();                     //退出配置模式  
    RTC_GetTime();         //更新时间
}

/****************************************************************************
* Function Name  : RTC_Config
* Description    : 初始化时钟,并初始化内部的时钟信息
* Input          : time:要初始化的时钟
* Output         : None
* Return         : 0:初始化成功;0xFF:初始化失败
****************************************************************************/

int8_t RTC_Config(RTC_TimeTypeDef *time)
{
    uint32_t timeCount;

    if(BKP_ReadBackupRegister(BKP_DR1) != 0x5050)
    {
        /* 使能PWR电源时钟和BKP备份区域外设时钟 */   
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);

        PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问 
		BKP_DeInit();	                //复位备份区域 	
		RCC_LSEConfig(RCC_LSE_ON);	    //设置外部低速晶振(LSE),使用外设低速晶振

        /* 检查指定的RCC标志位设置与否,等待低速晶振(LSE)就绪 */
    	while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
		{
    		timeCount++;
            if(timeCount > 0x00FFFFF)
            {
                break;
            }
		}

        /* 外部晶振错误,返回设置失败 */
        if(timeCount > 0x00FFFFF)
        {
            return 0xFF;            
        }

        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);   //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
		RCC_RTCCLKCmd(ENABLE);	                  //使能RTC时钟
        RTC_WaitForLastTask();	                  //等待最近一次对RTC寄存器的写操作完成
		RTC_WaitForSynchro();		              //等待RTC寄存器同步  
		RTC_ITConfig(RTC_IT_SEC, ENABLE);		  //使能RTC秒中断
		RTC_WaitForLastTask();              	  //等待最近一次对RTC寄存器的写操作完成

		RTC_EnterConfigMode();                    //允许配置	
		RTC_SetPrescaler(32767);                  //设置RTC预分频的值
		RTC_WaitForLastTask();	                  //等待最近一次对RTC寄存器的写操作完成
		RTC_SetTime(time);                        //设置时间	
		RTC_ExitConfigMode();                     //退出配置模式  
		BKP_WriteBackupRegister(BKP_DR1, 0X5050); //向指定的后备寄存器中写入用户程序数据 
    }
    else
    {
        RTC_WaitForSynchro();	           //等待最近一次对RTC寄存器的写操作完成
		RTC_ITConfig(RTC_IT_SEC, ENABLE);  //使能RTC秒中断
		RTC_WaitForLastTask();	           //等待最近一次对RTC寄存器的写操作完成
    }

    RTC_NVIC_Config();     //RCT中断分组设置,开启中断		    				     
	RTC_GetTime();         //更新时间

    return 0;
}

/****************************************************************************
* Function Name  : RTC_IRQHandler
* Description    : RTC时钟的中断函数,用来跟新时间,或者闹钟
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/

void RTC_IRQHandler(void)
{		 
	if (RTC_GetITStatus(RTC_IT_SEC) != RESET)     //秒钟中断
	{							
		RTC_GetTime();                            //更新时间   
 	}

	if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)       //闹钟中断
	{
		RTC_ClearITPendingBit(RTC_IT_ALR);	      //清闹钟中断	  	   
  	}
     				  								 
	RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);  //清闹钟中断
	RTC_WaitForLastTask();	  	    			  //等待最近一次对RTC寄存器的写操作完成			 	   	 
}

/****************************************************************************
* Function Name  : RTC_NVIC_Config
* Description    : RTC中断的设置
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/

static void RTC_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

	NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;		        //RTC全局中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//抢占优先级设置
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	        //响应优先级设置
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		        //使能该通道中断

	NVIC_Init(&NVIC_InitStructure);   //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}

/****************************************************************************
* Function Name  : RTC_SetTime
* Description    : 设置RTC时钟的计数器初始值
* Input          : time:设置的初始值(注:年份设置从2000到2100年之间)
* Output         : None
* Return         : 0:设置成功;0xFF:设置失败
****************************************************************************/

static uint8_t RTC_SetTime(RTC_TimeTypeDef *time)
{
    uint8_t  leapYear = 0;
    uint16_t i;
    uint32_t secondCount = 0;
    
    /* 确定写入的时间不超过年限 */
    if((time->year < 2000) || (time->year > 2100)) //从2000年到2100年,一共100年
    {
        return 0xFF;             //超过时限返回失败
    }
   
    /* 将所有的年份秒数相加 */
    for(i = RTC_BASE_YEAR; i<time->year; i++)
    {
        if(RTC_CheckLeapYear(i) == 0)          //如果年份是闰年
        {
            secondCount += RTC_LEEP_YEAR_SECOND;     
        }
        else
        {
            secondCount += RTC_COMMON_YEAR_SECOND;    
        }    
    }
    
    
    /* 检测写入年份是闰年还是平年 */
    if(RTC_CheckLeapYear(time->year) == 0) //如果是闰年
    {
        leapYear = 1;                     //标记为闰年            
    }
    else
    {
        leapYear = 0;                     //标记为平年    
    }
    /* 所有月份秒数相加 */
    for(i=1; i<time->month; i++)
    {
        if(leapYear == 1)
        {
            secondCount += RtcLeapMonth[i - 1] * RTC_DAY_SECOND;     
        }
        else
        {
            secondCount += RtcCommonMonth[i - 1] * RTC_DAY_SECOND;
        }       
    }
    
    /* 所有的日期秒数相加 */
    for(i=1; i<time->day; i++)
    {
        secondCount += RTC_DAY_SECOND;
    }
    
    /* 小时的秒数 */
    secondCount += RTC_HOUR_SECOND * time->hour;
    
    /* 分钟的秒数 */
    secondCount += 60 * time->minit;
    
    /* 加上秒数 */
    secondCount += time->second; 

    /* 使能PWR电源时钟和BKP备份区域外设时钟 */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
	PWR_BackupAccessCmd(ENABLE);	  //使能RTC和后备寄存器访问 
	RTC_SetCounter(secondCount);	  //设置RTC计数器的值 
    
    RTC_WaitForLastTask();	          //等待最近一次对RTC寄存器的写操作完成  	

	return 0;                         //设置成功返回0
}

/****************************************************************************
* Function Name  : RTC_CheckLeapYear
* Description    : 检测年份是否是闰年
* Input          : year:检测的年份
* Output         : None
* Return         : 0:是闰年;0xFF:是平年
****************************************************************************/

static uint8_t RTC_CheckLeapYear(uint16_t year)
{
    /* 闰年有两种计算方式,第一种是能被四整除且不能被100整除, */
    /* 第二种是能被100整除且能被400整除 */

    if((year % 100) == 0) //能被100整除的,且能被400整除是闰年
    {
        if((year % 400) == 0)
        {
            return 0;     //是闰年 
        }
        else
        {
            return 0xFF;  //是平年
        }   
    }
    else                  //不能被100整除,但能被4整除是闰年
    {
        if((year % 4) == 0)
        {
            return 0;     //是闰年
        }
        else
        {
            return 0xFF;  //是平年
        }
    }
}

/****************************************************************************
* Function Name  : RTC_GetTime
* Description    : 读取RTC计数器的值,并将其转化为日期
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/
 
static void RTC_GetTime(void)
{
    uint8_t leapYear = 0, i = 0;
    uint32_t secondCount = 0;
    uint32_t day;

    /* 读取时钟计数器的值 */
    secondCount =  RTC->CNTH;
    secondCount <<= 16;
    secondCount |= RTC->CNTL;
    
    day = secondCount / RTC_DAY_SECOND;           //求出天数
    secondCount = secondCount % RTC_DAY_SECOND;   //求出剩余秒数

    RTC_Time.year = RTC_BASE_YEAR;

    /* 求出星期几 */
    RTC_Time.week = (day + 6) % 7;         //因为2000年1月1日是星期六所以加6

    /* 求出年份 */
    while(day >= 365)
    {
        if(RTC_CheckLeapYear(RTC_Time.year) == 0)   //是闰年
        {
            day -= 366;                    //闰年有366天    
        }
        else
        {
            day -= 365;                    //平年有365天
        }

        RTC_Time.year++;
    }

    /* 求出月份 */
    if(RTC_CheckLeapYear(RTC_Time.year) == 0)
    {
        leapYear = 1;                        //如果是闰年标记
    }

    i = 0;
    RTC_Time.month = 1;
    while(day >= 28)
    {        
        if(leapYear == 1)
        {
            if(day < RtcCommonMonth[i]) //天数不够一个月
            {
                break;
            }
            day -= RtcLeapMonth[i];     //减去闰年该月的天数
        }
        else
        {
            if(day < RtcCommonMonth[i]) //天数不够一个月
            {
                break;
            }
            day -= RtcCommonMonth[i];   //减去平年该月的天数 
        }
        RTC_Time.month++;               //月份加1
        i++;                            //月份数组加1
    }

    /* 求出天数 */
    RTC_Time.day = day + 1;             //月份剩下的天数就是日期(日期从1号开始)

    RTC_Time.hour = secondCount / RTC_HOUR_SECOND;       //求出小时
    RTC_Time.minit = secondCount % RTC_HOUR_SECOND / 60; //求出分钟
    RTC_Time.second = secondCount % RTC_HOUR_SECOND %60; //求出秒
 
}

RTC.H

#ifndef __RTC_H
#define __RTC_H

#include "stm32f10x.h"
extern u8 timebz;
/* 定义时钟的结构体 */
typedef struct{
uint8_t  second;
uint8_t  minit;
uint8_t  hour;
uint8_t  week;
uint8_t  day;
uint8_t  month;
uint16_t year;
}RTC_TimeTypeDef;

/* 保存时钟信息 */
extern RTC_TimeTypeDef RTC_Time;

/* 定义时钟设置 */
#define RTC_BASE_YEAR      (uint16_t)2000                  //年份最小设置为2000年

#define RTC_LEEP_YEAR_SECOND    (uint32_t)(366 * 24 * 60 * 60)  //闰年秒数
#define RTC_COMMON_YEAR_SECOND  (uint32_t)(365 * 24 * 60 * 60)  //平年秒数
#define RTC_DAY_SECOND          (uint32_t)(24 * 60 * 60)        //一天的秒数
#define RTC_HOUR_SECOND         (uint32_t)(60 * 60)             //一个小时的秒数



/* 声明全局函数 */
int8_t RTC_Config(RTC_TimeTypeDef *time);
void RTC_SetClock(RTC_TimeTypeDef *time);






LED.C 包含报警系统

#include "led.h"
#include "stm32f10x_rtc.h"

/****************************************************************************
* Function Name  : LED_Config
* Description    : 将LED使用的IO口设置为上拉输出
* Input          : None
* Output         : None
* Return         : None
****************************************************************************/

void delay(u32 i)
{
	while(i--);
}


void LED_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;               //声明一个结构体变量,用来初始化GPIO

    /* 开启GPIO时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);

    /*  配置GPIO的模式和IO口 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_LED;        //选择你要设置的IO口
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  //设置传输速率
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   //设置推挽输出模式

    /* 初始化GPIO */
    GPIO_Init(GPIOC, &GPIO_InitStructure);	           //初始化GPIO_LED

    /* 初始化GPIO */
    GPIO_SetBits(GPIOC, GPIO_Pin_LED);                 //将LED的IO口全部赋值为1,即熄灭LED灯
}

/****************************************************************************
* Function Name  : LED_SetState
* Description    : 设置LED的状态,0代表相应的LED点亮,1表示相应的LED熄灭
* Input          : stateValue:LED的状态
* Output         : None
* Return         : None
****************************************************************************/

void LED_SetState(uint8_t stateValue)
{    
    /* 设置LED灯的状态, GPIO一次设置16位,将其值强制转换位16位 */
    GPIO_SetBits(GPIOC, (uint16_t)stateValue & 0x00FF);         //将要熄灭的LED熄灭
    GPIO_ResetBits(GPIOC, (~(uint16_t)stateValue) & 0x00FF);    //将要点亮的LED点亮                  
}

void led_display()
{
	
	GPIO_ResetBits(GPIOC,GPIO_Pin_0);
	
}


void BEEP_Init()	  //端口初始化
{
	GPIO_InitTypeDef GPIO_InitStructure;

	SystemInit();
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure); 	
}

void sound1()  //救护车报警
{
	u32 i=8000;
	while(i--)
	{
		GPIO_SetBits(GPIOB,GPIO_Pin_5);
		delay(i);
		GPIO_ResetBits(GPIOB,GPIO_Pin_5);
		delay(i--);
	}	
}
void sound2()  //电动车报警
{
	u32 i=8000;
	while(i--)
	{
		GPIO_SetBits(GPIOB,GPIO_Pin_5);
		delay(i);
		GPIO_ResetBits(GPIOB,GPIO_Pin_5);
		delay(i--);
	}	
}


led.h

#ifndef __LED_H
#define __LED_H

#include "stm32f10x.h"

/* 定义要设置的LED使用的PIN口 */
#define GPIO_Pin_LED (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5\
| GPIO_Pin_6 | GPIO_Pin_7)
#define BZ GPIO_Pin_5 //PB5	 定义端口PB5

/* 声明全局函数 */
void LED_Config(void);
void LED_SetState(uint8_t stateValue);


void delay(u32 i);



void sound1(void);
void sound2(void);
void BEEP_Init(void);
void TIME(void);








#endif

 

原文件见下一篇。

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值