在普中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
原文件见下一篇。