You are here

Fun with the TFT | サイプレス セミコンダクタ

Fun with the TFT

I have never used the TFT to do anything other than draw some shapes and print text. Of course, that’s not too surprising really... since that’s what they are designed to do! But I am going to make some simple animated applications now and that should force me to dig a little deeper into what the screen can do and how emWin works. Should be fun!

I am going to use the function void GUI_FillCircle( int x0, int y0, int r) to draw a ball and move it around the screen. I’ll be doing this from the TFT_Play project I created last time so I do not need to bother adding the libraries and setting the COMPONENT in the Makefile again. I’ll start by defining the screen dimensions and a box inside that. The idea is that the ball shall bounce around inside the box so the following allows me to define a box of any shape and position.



#define SCREEN_TO

/* Define the box in which to bounce */
#define BOX_LEFT
#define BOX_RIGHT
#define BOX_TOP
#define BOX_BOTTOM

The FillCircle function takes a radius as the third argument and so whenever the ball is drawn such that its edge touches a side, we should bounce. Here are some handy functions that figure out if the ball is touching

inline int isBallTouchingLeft(int x, int radius) { return ( x <= ( BOX_LEFT + radius ) ); }
inline int isBallTouchingRight(int x, int radius) { return ( x >= ( BOX_RIGHT - radius ) ); }
inline int isBallTouchingTop(int y, int radius) { return ( y <= ( BOX_TOP + radius ) ); }
inline int isBallTouchingBottom(int y, int radius) { return ( y >= ( BOX_BOTTOM - radius ) ); }


Next, here is a type for the ball. It may seem unnecessary to create this right now but, in my next blogs, I intend to create multiple balls and bounce them all at the same time.

typedef struct​
} ball_t;


The color and radius should be pretty self-explanatory. The speed is going to control the time between moves and has a range between 0 and 50 ( #define MAX_SPEED (50)). A speed of 0 is the slowest (boring) and a speed of 50 hurtles around the screen with wild abandon! The direction arguments indicate the number of pixels to move every time, which provides a lot of freedom to alter the angle of travel. Note that they are signed quantities so you can start the ball in either a left/right or north/south.

The meat of the program is going to be in the void bounce( ball_t* ball ) function, below. It takes a pointer to the ball as an argument. Again, this is a little overkill for a single ball, but it will be really useful in my next few blogs. It is good form to make local copies of the ball_t values because it is pointing to memory outside of the function. Making copies of the values helps avoid very bad results if you make the mistake of passing a pointer to local (non-static) data. You will see a little later that I explicitly define the ball in static memory but constrain its scope to the main() function. I could have just created a global but then I would be tempted to access it directly inside bounce(), which is lazy and would have to be re-written in my next blog anyway.

Once the color, speed, size and direction are set, the forever loop draws the ball (in red), delays a while based on the speed, then clears the ball (in black), changes the position, and repeats.  You can also see how those helper functions, above, are used to make the ball actually bounce of the edges.


void bounce( ball_t* ball )

    /* Set up local variables to control the ball */
        GUI_COLOR color = ball->color;
        uint32_t speed = ( MAX_SPEED < ball->speed ) ? 0 : MAX_SPEED - ball->speed;
        uint8_t radius = ball->radius;

    /* Extract the up/down and left/right increments */
         int8_t xDir = ball-> xDir;
         int8_t yDir = ball-> yDir;

    /* Start the ball at a fixed position */
        uint16_t xPos = BOX_LEFT + ( ( BOX_RIGHT - BOX_LEFT ) / 2 );​
        uint16_t yPos = BOX_TOP + ( ( BOX_BOTTOM - BOX_TOP ) / 2 );

    /* Draw - wait - clear - move */
           /* Draw the ball */
               GUI_SetColor( color );
               GUI_FillCircle( xPos, yPos, radius );

        /* Moderate the speed of the ball */
            Cy_SysLib_Delay( speed );

        /* Clear the previously drawn ball */
            GUI_SetColor( GUI_BLACK );
            GUI_FillCircle( xPos, yPos, radius );

        /* If the ball touches an edge, change direction */

            if( isBallTouchingLeft( xPos, radius ) || isBallTouchingRight( xPos, radius ) )
                { xDir = -xDir; }

            if( isBallTouchingTop( yPos, radius ) || isBallTouchingBottom( yPos, radius ) )
                { yDir = -yDir; }

        /* Move the ball in both axes */
            xPos += xDir;
            yPos += yDir;


All that is needed now is to show you the code in main() that sets everything up. I created a small, speedy red ball (in permanent memory) that moves one pixel left-right and 3 pixels up-down on every cycle, then I turned on the display with a gray background, and finally called my bounce() function (which never returns).


static ball_t b1 = { GUI_RED, 3, 45, +1 /*RIGHT*/, -3 /*UP*/ };

    GUI_SetBkColor( GUI_GRAY );
    bounce( &b1 );


I’ve attached a completed main.c file to this blog so, if you run into problems following my ramblings, you have a good reference. Try out a few different values in the ball_t struct and you’ll find out that making them too big and too fast creates display problems because you start pushing the limits of the OLED update rate. Or maybe it is my eyes???

Here is a picture of the screen after a few seconds. Notice how the background is gray and the ball is leaving a black trail behind it. I did that because I like the way it looks but you should be able to turn the effect off if you do not like it. Try out the program with a few different box sizes too – and let me know if you find a bug!!!


このサイトに掲示されているすべてのコンテンツと資料は、「そのままの状態」で提供されます。サイプレス セミコンダクタとその関連サプライヤは、これらの資料について、いかなる目的への適合性をも表明することはありません。また、これらの資料について、すべての保証や条件を放棄します。これには、暗示的な保証および条件、商用性、特定の目的への適合性、すべてのサードパーティの知的財産権に対する権利と非侵害などが含まれますが、これらに制限されることはありません。サイプレス セミコンダクタにより、明示または暗示にかかわらず、禁反言などによるライセンスは、付与されないものとします。このサイトに掲示されている情報の使用には、サードパーティまたはサイプレス セミコンダクタからのライセンスが必要となる場合があります。

このサイトのコンテンツには、特定のガイドラインや使用制限が含まれている場合があります。このサイトにおけるすべての掲示やコンテンツの使用は、サイトの利用規約に準じて行われるものとします。このコンテンツを使用するサードパーティは、制限やガイドラインに従い、このサイトの利用規約を遵守するものとします。サイプレス セミコンダクタとそのサプライヤは、コンテンツや資料、その製品、プログラム、サービスに対し、いつでも修正、削除、変更、改善、向上、その他の変更を加える権利を有します。また、いかなるコンテンツ、製品、プログラム、サービスを予告なく変更または閉鎖する権利を有します。