数码之家

 找回密码
 立即注册
搜索
查看: 1697|回复: 8

[ARM] SDL1.2 多表盘模拟时钟

[复制链接]
发表于 2022-3-16 16:30:30 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
SDL 是跨平台的,各种Linux平台、包括ARM-Linux、Os、Windows、WindowsCE等等,都可以。并且支持多种显示驱动。还有各种多媒体功能。关于怎么编译,这就不多说。
(先前用过MiniGUI,应该是有些坑)
(话说这分类,虽然ARM-LINUX也是ARM,但好像和论坛的ARM不是同一类)

下边是源码,后附编译参数

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <SDL/SDL.h>
#include <SDL/SDL_draw.h>
#include <SDL/SDL_ttf.h>
#include <SDL/SDL_thread.h>

struct POINT{
    int x;
    int y;
};
//==========================================================
SDL_Color colorWhite = {0xff, 0xff, 0xff};    //文字颜色
//画线用的几个颜色
Uint32 c_black,            //底色,
    c_white,            
    c_green,
    c_red,                 //秒之色
    c_cyan;                //表盘上点的颜色

#define _UIx    0        //mainwindow left x
#define _UIy    0        //mainwindow topp y
#define _UIw    240        //width
#define _UIh    320        //height

#define _ClockX    81        //离左边
#define _ClockY 60        //离顶端,33刚好在双线下边

#define _R        40        //圆的直径
#define CNT        2        //表盘数
static int rx=_ClockX+_R, ry=_ClockY+_R,    //表盘的中心
           yO[]={0, 120},                    //各表盘的偏移,这只偏移Y
           oldHx[CNT]={0}, oldHy[CNT]={0},    //上次的坐标
           oldMx[CNT]={0}, oldMy[CNT]={0},
           oldSx[CNT]={0}, oldSy[CNT]={0};

#define _Text1_X  50    //第1行文字
#define _Text2_X  85    //第2行文字

//字体路径。个人用,字体就是windows\fonts目录拷贝过来
#ifdef __ARM_EABI__        //ARM
const char fntPath[]  = "/mnt/sd/font/msyh.ttf";
#else                    //PC
const char fntPath[]  = "/opt/msyh.ttf";
#endif
SDL_Surface *screen;    //主界面
TTF_Font    *font14;    //显示文字的字体
SDL_TimerID tmr1;        //定时器id

time_t      tNow;        //即时时间
struct tm  *mytime;
const char *WK[]={"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};

//==========================================================
void applySurface(int x, int y, SDL_Surface* source, SDL_Surface* destination){
    SDL_Rect offset;            //Temporary rectangle to hold the offsets
    offset.x = x;  offset.y = y;//Get the offsets
    SDL_BlitSurface(source, NULL, destination, &offset);//Blit the surface
}
void fillRectColor(SDL_Surface* destination, Uint32 color, int x, int y, int w, int h){
    SDL_Rect rect;rect.x=x;rect.y=y;rect.w=w; rect.h=h;
    // Uint32 color = SDL_MapRGB(destination->format, r, g, b);    //蓝色
    SDL_FillRect(screen, &rect, color);    //整个屏幕填充颜色
}
void textOut(const char*text, TTF_Font *font1, int x, int y){
    SDL_Surface * surface1 = TTF_RenderText_Solid(font1, text, colorWhite);
    applySurface(x,y,surface1, screen);
    SDL_FreeSurface(surface1);
}
//==========================================================
//模拟时钟的算法,来自网络,在这做了简化。
//==========================================================
//round's radius is 40 ,twelve point of it's 30 degree 表盘各字
const struct POINT PD_R40D30[]={ {40,0},{34,19},{20,34},{0,39},
  {-19,34},{-34,20},{-40,0},{-34,-20},
  {-19,-34},{0,-39},{20,-34},{34,-19}
};
const struct POINT PD_R30D6[]={
{30,0},{29,3},{29,6},{28,9},{27,12},{25,14},{24,17},{22,20},{20,22},{17,24},
{15,25},{12,27},{9,28},{6,29},{3,29},{0,29},{-3,29},{-6,29},{-9,28},{-12,27},
{-14,25},{-17,24},{-20,22},{-22,20},{-27,17},{-25,15},{-27,12},{-28,9},{-29,6},{-29,3},
{-29,0},{-29,-3},{-29,-6},{-28,-9},{-27,-12},{-25,-14},{-24,-17},{-22,-20},{-20,-22},{-17,-24},
{-15,-25},{-12,-27},{-9,-28},{-6,-29},{-3,-29},{0,-29},{3,-29},{6,-29},{9,-28},{12,-27},
{14,-25},{17,-24},{20,-22},{22,-20},{24,-17},{25,-15},{27,-12},{28,-9},{29,-6},{29,-3}
};
const struct POINT PD_R20D5[]={
{20,0},{19,1},{19,3},{19,5},{18,6},{18,8},{17,9},{16,11},{15,12},{14,14},
{12,15},{11,16},{10,17},{8,18},{6,18},{5,19},{3,19},{1,19},{0,19},{-1,19},
{-3,19},{-5,19},{-6,18},{-8,18},{-9,17},{-11,16},{-12,15},{-14,14},{-15,12},{-16,11},
{-17,10},{-18,8},{-18,6},{-19,5},{-19,3},{-19,1},{-19,0},{-19,-1},{-19,-3},{-19,-5},
{-18,-6},{-18,-8},{-17,-9},{-16,-11},{-15,-12},{-14,-14},{-12,-15},{-11,-16},{-10,-17},{-8,-18},
{-6,-18},{-5,-19},{-3,-19},{-1,-19},{0,-19},{1,-19},{3,-19},{5,-19},{6,-18},{8,-18},
{9,-17},{11,-16},{12,-15},{14,-14},{15,-12},{16,-11},{17,-10},{18,-8},{18,-6},{19,-5},
{19,-3},{19,-1}
};

//draw point(x,y) and four point side of it
void DispTimeSub(int x, int y, int r){
    x=_ClockX+r+x;
    y=_ClockY+r+y;
    Draw_Pixel(screen, x,y,  c_cyan);
    Draw_Pixel(screen, x+1,y,c_cyan);
    Draw_Pixel(screen, x-1,y,c_cyan);
    Draw_Pixel(screen, x,y+1,c_cyan);
    Draw_Pixel(screen, x,y-1,c_cyan);
}
//draw point(x,y)'s top and under line
void DispTimeSubHL(int x, int y, int r){
    x=_ClockX+r+x;
    y=_ClockY+r+y;
    Draw_Line(screen, x, y-1, x-3, y-1, c_cyan);
    Draw_Line(screen, x, y+1, x-3, y+1, c_cyan);
}
//draw point(x,y)'s top and under line
void DispTimeSubHR(int x, int y, int r){
    x=_ClockX+r+x;
    y=_ClockY+r+y;
    Draw_Line(screen, x, y-1, x+3, y-1, c_cyan);
    Draw_Line(screen, x, y+1, x+3, y+1, c_cyan);
}
void DispTimeSubLT(int x, int y, int r){
    x=_ClockX+r+x;
    y=_ClockY+r+y;
    Draw_Line(screen, x-1, y, x-1, y-4, c_cyan);
    Draw_Line(screen, x+1, y, x+1, y-4, c_cyan);
}
void DispTimeSubLB(int x, int y, int r){
    x=_ClockX+r+x;
    y=_ClockY+r+y;
    Draw_Line(screen, x-1, y, x-1, y+4, c_cyan);
    Draw_Line(screen, x+1, y, x+1, y+4, c_cyan);
}

void DrawTimeFrame(int y){    //画表盘
    Draw_Line(screen, 0, y,   240, y,   c_green);
    Draw_Line(screen, 0, y+2, 240, y+2, c_cyan);
   
    int i, j;
    for(j=0; j<CNT; j++){
        for(i=0; i<12; i++){
            switch(i){
            case 0: DispTimeSubHL(PD_R40D30.x,PD_R40D30.y+yO[j],40);break; //Right
            case 3: DispTimeSubLT(PD_R40D30.x,PD_R40D30.y+yO[j],40);break; //Bottom
            case 6: DispTimeSubHR(PD_R40D30.x,PD_R40D30.y+yO[j],40);break; //Left
            case 9: DispTimeSubLB(PD_R40D30.x,PD_R40D30.y+yO[j],40);break; //TOP
            default:
                    DispTimeSub(PD_R40D30.x,  PD_R40D30.y+yO[j],40);
            }
        }
    }
}

void DrawClock(int i){    //画时钟针
    int x, y, n, m;
   
    if((oldSx+oldSy) != 0){
        Draw_Line(screen, rx,ry+yO,oldSx,oldSy, c_black);
        Draw_Line(screen, rx,ry+yO,oldMx,oldMy, c_black);
        Draw_Line(screen, rx,ry+yO,oldHx,oldHy, c_black);
    }
   
    n=(mytime->tm_sec+45)%60;
    x=_ClockX+_R+PD_R30D6[n].x;
    y=_ClockY+_R+PD_R30D6[n].y+yO;
    //show second hand
    Draw_Line(screen, rx, ry+yO,x,y, c_red);
    oldSx=x; oldSy=y;

    //calculate min whether or not move
    //note:  the array of PD_R30D6 begin at right place,that the place of 3 hour.
    //mytime->tm_min/60  is percent  the first 60 is clock divide up 60 part
    //see above note,when n is 0,it must add 45 from 3 hour place.
    n=(mytime->tm_min+45)%60;
    x=_ClockX+_R+PD_R30D6[n].x;
    y=_ClockY+_R+PD_R30D6[n].y+yO;
    Draw_Line(screen, rx, ry+yO,x,y, c_green);
    oldMx=x; oldMy=y;
   
    //calculate hour*60+minute.
    //the 72 is clock divide up 72 part. the same as minute disposal
    m=mytime->tm_min+(mytime->tm_hour%12)*60;
    n=(m/10+54)%72;
    x=_ClockX+_R+PD_R20D5[n].x;
    y=_ClockY+_R+PD_R20D5[n].y+yO;
    Draw_Line(screen, rx, ry+yO,x,y, c_white);
    oldHx=x; oldHy=y;
}

void DrawTimeText(int i){    //文字
    char buf[21];
    sprintf(buf, "%d-%02d-%02d %s",
        mytime->tm_year+1900, mytime->tm_mon+1,mytime->tm_mday, WK[mytime->tm_wday]);
    if(0==i)
    fillRectColor(screen, c_black, _Text1_X,  1+yO[0], 200, 20);        //清除旧字
    fillRectColor(screen, c_black, _Text2_X, 30+yO, 200, 20);
    if(0==i)
    textOut(buf, font14, _Text1_X, 1+yO[0]);                            //年月日
   
    memset(buf, 0, 21);
    sprintf(buf, "%02d:%02d:%02d",mytime->tm_hour,mytime->tm_min,mytime->tm_sec);
    textOut(buf, font14, _Text2_X, 30+yO);                            //时分秒
    SDL_UpdateRect(screen, _Text1_X, 1, _UIw-_Text1_X, 50+yO);        //局部更新屏幕
}
//==========================================================
static Uint32 SDLCALL timerProc(Uint32 interval, void *param){            // SDL_AddTimer()
    // printf("timerProc:%d, %d\n", interval, (int)(uintptr_t)param);
    time(&tNow);
    mytime=localtime(&tNow);

    DrawClock(0);
    DrawTimeText(0);
   
    tNow=tNow-8*3600;
    mytime=localtime(&tNow);
    DrawClock(1);
    DrawTimeText(1);
    SDL_UpdateRect(screen, _ClockX, _ClockY, _UIw-_ClockX, _UIh-_ClockY); //局部更新屏幕

    return interval;
}
//==========================================================
int main(int argc, char *argv[]){
    int bStop = 0;
    SDL_Event event;

    if ( SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTTHREAD) < 0 ) {
        fprintf(stderr, "SDL_Init(): %s", SDL_GetError());
        exit(1);
    }
    atexit(SDL_Quit);        //退出"事件"
   
    screen = SDL_SetVideoMode(_UIw, _UIh, 16, SDL_SWSURFACE);    //Video mode activation
    if (!screen) {
        fprintf(stderr, "Video mode: %dx%d %s\n",_UIw,_UIh,SDL_GetError());
        exit(2);
    }
    c_black = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
    c_white = SDL_MapRGB(screen->format, 0xFF, 0xFF, 0xFF);
    c_green = SDL_MapRGB(screen->format, 0x00, 0xFF, 0x00);
    c_cyan  = SDL_MapRGB(screen->format, 0x00, 0xFF, 0xFF);
    c_red   = SDL_MapRGB(screen->format, 0xFF, 0x00, 0x00);
   
    if(TTF_Init()==-1){
        printf("TTF_Init: %s\n", TTF_GetError());
    }
    font14  = TTF_OpenFont((const char *)fntPath, 18);            //字体大小,随要求改变
    if(!font14){
        printf("TTF_OpenFont: Open .ttf %s\n", TTF_GetError());
        TTF_Quit();
        return 1;
    }   

    fillRectColor(screen, c_black, 0, 0, _UIw, _UIh);   
    DrawTimeFrame(27);                    //上2行
    SDL_UpdateRect(screen,0,0,0,0);        //更新整个屏幕

    tmr1=SDL_AddTimer(995, timerProc, (void*)1);
    /* 事件处理,鼠标点击、任意按键、点击X,或控制台CTRL+C,都退出程序 */
    while( ! bStop ){
        if(SDL_PollEvent(&event) ){
            switch (event.type) {
            case SDL_MOUSEBUTTONDOWN:    /*break;*/
            case SDL_KEYDOWN:            /*break;*/
            case SDL_QUIT:
                bStop = 1;
                break;
            default:
                break;
            }
        }
        if(bStop)break;
        SDL_Delay(20);
    }
   
    if(tmr1)SDL_RemoveTimer(tmr1);
    if(font14 )TTF_CloseFont(font14);
    TTF_Quit();
   
    return 0;
}
/*
编译、执行
假设 SDL 1.2 默认安装
OPT_xib=-lpthread\ -lm\ -O3\ -Wall\ -ldl\ -liconv\ -lz\ -lfreetype
OPT_xib=${OPT_xib}\ -lSDL\ -lSDL_image\ -lSDL_net\ -lSDL_ttf\ -lSDL_mixer\ -lSDL_draw
gcc ${OPT_xib} sdl_clock.c -o sdl_clock && ./sdl_clock
SDL是跨平台的。如,arm就是引用不同的include和lib。
*/



 楼主| 发表于 2022-3-16 16:31:41 | 显示全部楼层


图片参考


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复 支持 反对

使用道具 举报

发表于 2022-3-17 11:28:43 | 显示全部楼层
厉害了,顶楼主
回复 支持 反对

使用道具 举报

发表于 2022-3-17 11:35:09 | 显示全部楼层
最近也在学习GUI,向楼主学习

打赏

参与人数 1家元 +10 收起 理由
devcang + 10 歡迎探討

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2022-3-18 14:30:23 | 显示全部楼层

打赏

参与人数 1家元 +10 收起 理由
devcang + 10 歡迎探討

查看全部打赏

回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-3-30 12:41:56 | 显示全部楼层
qq1329491328 发表于 2022-3-18 14:30
我用LVGL做的比你好看多了,芯片S5PV210(cortex A8内核):
视频地址ARM裸机_基于LVGL的模拟时钟项目《蒲公英 ...

漂亮

但,硬件不在一个级别层次,玩不起太高的。

其实,时钟不是目标,要做一些数据文字,在时钟周边。
回复 支持 反对

使用道具 举报

发表于 2022-3-30 14:50:27 | 显示全部楼层
是一个keil这种编辑器吗
回复 支持 反对

使用道具 举报

发表于 2022-3-30 15:43:05 | 显示全部楼层
devcang 发表于 2022-3-30 12:41
漂亮

但,硬件不在一个级别层次,玩不起太高的。

哦!{字数补丁-能做自己喜欢的事情,会是最大的幸福}
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-3-31 17:04:41 | 显示全部楼层
本帖最后由 devcang 于 2022-3-31 17:08 编辑
beiling 发表于 2022-3-30 14:50
是一个keil这种编辑器吗

嵌入系统的界面框架,如用在arm-linux中。

SDL包括在界面(窗口、文字<支持TTF字体>、几何绘画)、多媒体(视频、音频)、网络等等,自消耗不多、依赖也少。

LVGL呢,因为没有更好的硬件,暂时未玩。不过看LVGL可以用在STM32F103 上,以后有时间可以试试。开源https://github.com/lvgl/lvgl  

LVGL is completely platform independent and can be used with any MCU that fulfills the requirements.Just to mention some platforms:
LVGL is also available as:
(有中文说明的)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-5-14 07:23 , Processed in 0.312001 second(s), 10 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

快速回复 返回顶部 返回列表