创建日期结构体
#ifndef __DRIVER_DATE_H
#define __DRIVER_DATE_H
#include <stdint.h>
#include <stdbool.h>
typedef struct{
uint8_t x;
uint8_t y;
uint8_t font;
uint8_t w;
uint8_t h;
uint8_t offset;
uint8_t val;
uint8_t maxval;
bool moving;
}tickerData_t;
typedef struct{
uint8_t secs;
uint8_t mins;
uint8_t hour;
char ampm;
}time_s;
typedef enum{
DAY_MON = 0,
DAY_TUE = 1,
DAY_WED = 2,
DAY_THU = 3,
DAY_FRI = 4,
DAY_SAT = 5,
DAY_SUN = 6,
}day_t;
typedef enum{
MONTH_JAN = 0,
MONTH_FEB = 1,
MONTH_MAR = 2,
MONTH_APR = 3,
MONTH_MAY = 4,
MONTH_JUN = 5,
MONTH_JUL = 6,
MONTH_AUG = 7,
MONTH_SEP = 8,
MONTH_OCT = 9,
MONTH_NOV = 10,
MONTH_DEC = 11
}month_t;
typedef struct{
day_t day;
uint8_t date;
month_t month;
uint8_t year;
}date_s;
typedef struct{
time_s time;
date_s date;
}timeDate_s;
void drawDate(void);
void ticker(void);
#endif
初始化并通过定时器中断来更新secs
timeDate_s timeDate = {{30,20,15},{2,23,1,24}};
void Timer2Callback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2){
mills++;
if(mills%1000 == 0){
timeDate.time.secs = (timeDate.time.secs+1)%60;
}
}
}
当secs发生改变,让相应改变的时间进行改变
向上滚动
#include "drivers.h"
#include "watch.h"
#include "oleddata.h"
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
timeDate_s timeDate = {{30,20,15},{1,14,2,23}};
static void drawTickerNum(tickerData_t *data);
void drawDate(){
char day[BUFFSIZE_STR_DAYS];
strcpy(day,days[timeDate.date.day]);
char month[BUFFSIZE_STR_MONTHS];
strcpy(month,months[timeDate.date.month]);
char buff[BUFFSIZE_DATE_FORMAT];
sprintf(buff,PSTR(DATE_FORMAT),day,timeDate.date.date,month,timeDate.date.year);
OledPrintf(0, 0, OLED_16X8, buff);
}
void ticker(void){
static uint8_t yPos;
static uint8_t yPos_secs;
static bool moving = false;
static bool moving2[5] = {0};
static uint8_t secs = 30;
static uint8_t mins = 20;
static uint8_t hour = 15;
if(timeDate.time.secs != secs){
yPos = 0;
yPos_secs = 0;
moving = true;
moving2[0] = (timeDate.time.secs/10)!=(secs/10);
if(moving2[0] && (secs/10==5)){
timeDate.time.mins = (timeDate.time.mins + 1)%60;
}
moving2[1] = (timeDate.time.mins%10)!=(mins%10);
moving2[2] = (timeDate.time.mins/10)!=(mins/10);
if(moving2[2] && (mins/10==5)){
timeDate.time.hour = (timeDate.time.hour + 1)%24;
}
moving2[3] = (timeDate.time.hour%10)!=(hour%10);
moving2[4] = (timeDate.time.hour/10)!=(hour/10);
if(moving2[4] && (hour/10==2)){
//
}
secs = timeDate.time.secs;
mins = timeDate.time.mins;
hour = timeDate.time.hour;
}
if(moving){
if(yPos <= 3){
yPos++;
}else if(yPos <= 6){
yPos+=3;
}else if(yPos <= 16){
yPos+=5;
}else if(yPos <= 22){
yPos+=3;
}else if(yPos <= MIDFONT_HEIGHT){
yPos++;
}
if(yPos >= MIDFONT_HEIGHT){
yPos = 255;
}
if(yPos_secs <= 1){
yPos_secs++;
}else if(yPos_secs <= 13){
yPos_secs+=3;
}else if(yPos_secs <= SMLFONT_HEIGHT){
yPos_secs++;
}
if(yPos_secs > SMLFONT_HEIGHT){
yPos_secs = 255;
}
if( (yPos > MIDFONT_HEIGHT) && (yPos_secs > SMLFONT_HEIGHT) ){
yPos = 0;
yPos_secs = 0;
moving = false;
memset(moving2,0,sizeof(moving2));
}
}
tickerData_t data;
//秒
data.y = 24;
data.w = SMLFONT_WIDTH;
data.h = SMLFONT_HEIGHT;
data.x = 80;
data.val = timeDate.time.secs/10;
data.maxval = 5;
data.moving = moving2[0];
data.offset = yPos_secs;
data.font = OLED_24X16;
drawTickerNum(&data);
data.x = 96;
data.val = timeDate.time.secs%10;
data.maxval = 9;
data.moving = moving;
data.offset = yPos_secs;
drawTickerNum(&data);
data.y = 16;
data.w = MIDFONT_WIDTH;
data.h = MIDFONT_HEIGHT;
//分
data.x = 64;
data.val = timeDate.time.mins%10;
data.maxval = 9;
data.moving = moving2[1];
data.offset = yPos;
data.font = OLED_32X16;
drawTickerNum(&data);
data.x = 48;
data.val = timeDate.time.mins/10;
data.maxval = 5;
data.moving = moving2[2];
data.offset = yPos;
drawTickerNum(&data);
//时
data.x = 16;
data.val = timeDate.time.hour%10;
data.maxval = 9;
data.moving = moving2[3];
data.offset = yPos;
drawTickerNum(&data);
data.x = 0;
data.val = timeDate.time.hour/10;
data.maxval = 5;
data.moving = moving2[4];
data.offset = yPos;
drawTickerNum(&data);
if(timeDate.time.secs%2 == 0){
OledShowImage(32, 16,MIDFONT_WIDTH,MIDFONT_HEIGHT,OLED_F32X16[10*4],0);
}else{
OledShowImage(32, 16,MIDFONT_WIDTH,MIDFONT_HEIGHT,OLED_F32X16[11*4],0);
}
}
static void drawTickerNum(tickerData_t *data){
if(!data->moving || data->offset == 0 || data->offset == 255 ){
if(data->font == OLED_24X16){
OledShowChar(data->x, data->y, data->val*3, OLED_24X16);
}else{
OledShowChar(data->x, data->y, data->val*4, OLED_32X16);
}
}else{
uint8_t prev = data->val - 1;
if(prev == 255){
prev = data ->maxval;
}
if(data->font == OLED_24X16){
OledShowImage(data->x, data->y,data->w,data->h,OLED_F24X16[data->val*3],data->offset-SMLFONT_HEIGHT);
OledShowImage(data->x, data->y,data->w,data->h,OLED_F24X16[prev*3],data->offset);
}else{
OledShowImage(data->x, data->y,data->w,data->h,OLED_F32X16[data->val*4],data->offset-MIDFONT_HEIGHT);
OledShowImage(data->x, data->y,data->w,data->h,OLED_F32X16[prev*4 ],data->offset);
}
}
}
主函数中循环调用
该程序是在FreeRTOS下编写 在裸机中也可以正常使用在主函数中使用while()循环即可
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
DataInit();
unsigned int count = 10;
OledInit();
TimerInit(&htim2);
for(;;)
{
drawwatch();
OledUpdate();
OledClear();
}
/* USER CODE END StartDefaultTask */
}
效果展示
手表主界面