2254 views|1 replies

1662

Posts

0

Resources
The OP
 

【Share】 RV-STAR development board transplants Chrome's offline game Little Dinosaur [Copy link]

 This post was last edited by Hot Ximixiu on 2021-7-20 09:12

There happened to be a button on the RV-STAR development board, and it would be a shame not to make a small game with it, so I bought an OLED screen, modified the game code of a big guy on the Internet, and ported Chrome's offline small game Dino the dinosaur.

The OLED I bought has 7 pins and supports I2C and SPI protocols. The protocol can be modified by soldering resistors. I did not modify it and used the default SPI protocol. The wiring is as follows:

Originally GD32VF103 supports hardware SPI, but it has not been successful, so I used software SPI (using ordinary GPIO to simulate SPI protocol transmission signals).

OLED manufacturers will provide corresponding drivers, which can be easily found on the Internet. They include not only OLED initialization code (but the initialization code of different manufacturers seems to be different), but also software SPI communication implementation, OLED graphic GUI library, etc. It is still very convenient to develop.

The game code is modified from the code of cr4fun on the Internet. I modified the code from MicroPython to C language, and the basic game logic has not changed much.

Thanks to Coreline Technology for providing the RISC-V course and experience opportunity. The RV-STAR development board has an onboard debugger, which is very convenient for debugging. It is now driver-free and has a good IDE, which makes it very convenient to build a project and download code. The library functions of GD32VF103 also seem to be very rich, but there are not many materials and routines on the Internet, so it is a bit confusing to learn.

I hope that Corelai Technology and domestic chips will develop better and better!

The code is as follows.

Entrance:

#include "gd32vf103.h"
#include "gd32vf103v_rvstar.h"
#include "game.h"
#include "oled.h"
#include "gui.h"

/*!
  \brief   main function
  \param[in] none
  \param[out] none
  \retval   none
*/

int main(void)
{
 gd_rvstar_key_init(KEY_WAKEUP,KEY_MODE_EXTI);
 __enable_irq();
 OLED_Init();    //初始化OLED
 OLED_Clear(1);       //清屏(全黑)
 while(1)
 {
  game_loop();
 }
}
OLED初始化:

//-----------------Pin Def----------------
#define OLED_PORT GPIOA
#define OLED_CS //empty
#define OLED_DC GPIO_PIN_8
#define OLED_RST GPIO_PIN_6
#define OLED_SCK GPIO_PIN_5
#define OLED_MOSI GPIO_PIN_7
//-----------------OLED Reg Clr/Set function----------------
#define OLED_CS_Clr() //empty
#define OLED_CS_Set() //empty
#ifdef SPI_SW
#define OLED_MOSI_Clr() gpio_bit_reset(OLED_PORT, OLED_MOSI)
#define OLED_MOSI_Set() gpio_bit_set(OLED_PORT, OLED_MOSI)
#define OLED_CLK_Clr() gpio_bit_reset(OLED_PORT, OLED_SCK)
#define OLED_CLK_Set() gpio_bit_set(OLED_PORT, OLED_SCK)
#define OLED_DC_Clr() gpio_bit_reset(OLED_PORT, OLED_DC)
#define OLED_DC_Set() gpio_bit_set(OLED_PORT, OLED_DC)

#define OLED_RST_Clr() gpio_bit_reset(OLED_PORT, OLED_RST)
#define OLED_RST_Set() gpio_bit_set(OLED_PORT, OLED_RST)
void OLED_Init_GPIO(void)
{

  //  RCU config
  rcu_periph_clock_enable(RCU_GPIOA);

  // GPIO config
  /* SPI_SW GPIO config:SCK/PA5->D0, MOSI/PA7->D1 */
  gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, OLED_SCK | OLED_MOSI);
  /* GPIO config:PA6->RES, PA8->DC */
  gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, OLED_DC | OLED_RST);
  /* GND->CS */
}
void SPI_SW_WriteByte(uint8_t Data)
{
  uint8_t i = 0;
  for (i = 8; i > 0; i--) {
    if (Data & 0x80) {
      OLED_MOSI_Set(); //写数据1
    } else {
      OLED_MOSI_Clr(); //写数据0
    }
    OLED_CLK_Clr(); //将时钟拉低拉高
    OLED_CLK_Set(); //发送1bit数据
    Data <<= 1;
  }
}

void OLED_WR_Byte(uint8_t dat, uint8_t cmd)
{
  if (cmd) {
    OLED_DC_Set();
  } else {
    OLED_DC_Clr();
  }
  OLED_CS_Clr();
  SPI_SW_WriteByte(dat);
  OLED_CS_Set();
}

void OLED_Init(void)
{

  OLED_Init_GPIO(); //初始化GPIO
  delay_1ms(200);
  OLED_Reset(); //复位OLED
  /**************初始化SSD1306*****************/
  OLED_WR_Byte(0xAE, OLED_CMD); //--turn off oled panel
  OLED_WR_Byte(0x00, OLED_CMD); //---set low column address
  OLED_WR_Byte(0x10, OLED_CMD); //---set high column address
  OLED_WR_Byte(0x40, OLED_CMD); //--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
  OLED_WR_Byte(0x81, OLED_CMD); //--set contrast control register
  OLED_WR_Byte(0xCF, OLED_CMD); // Set SEG Output Current Brightness
  OLED_WR_Byte(0xA1, OLED_CMD); //--Set SEG/Column Mapping   0xa0左右反置 0xa1正常
  OLED_WR_Byte(0xC8, OLED_CMD); //Set COM/Row Scan Direction  0xc0上下反置 0xc8正常
  OLED_WR_Byte(0xA6, OLED_CMD); //--set normal display
  OLED_WR_Byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
  OLED_WR_Byte(0x3f, OLED_CMD); //--1/64 duty
  OLED_WR_Byte(0xD3, OLED_CMD); //-set display offset Shift Mapping RAM Counter (0x00~0x3F)
  OLED_WR_Byte(0x00, OLED_CMD); //-not offset
  OLED_WR_Byte(0xd5, OLED_CMD); //--set display clock divide ratio/oscillator frequency
  OLED_WR_Byte(0x80, OLED_CMD); //--set divide ratio, Set Clock as 100 Frames/Sec
  OLED_WR_Byte(0xD9, OLED_CMD); //--set pre-charge period
  OLED_WR_Byte(0xF1, OLED_CMD); //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
  OLED_WR_Byte(0xDA, OLED_CMD); //--set com pins hardware configuration
  OLED_WR_Byte(0x12, OLED_CMD);

  OLED_WR_Byte(0xDB, OLED_CMD); //--set vcomh
  OLED_WR_Byte(0x40, OLED_CMD); //Set VCOM Deselect Level
  OLED_WR_Byte(0x20, OLED_CMD); //-Set Page Addressing Mode (0x00/0x01/0x02)
  OLED_WR_Byte(0x02, OLED_CMD); //
  OLED_WR_Byte(0x8D, OLED_CMD); //--set Charge Pump enable/disable
  OLED_WR_Byte(0x14, OLED_CMD); //--set(0x10) disable
  OLED_WR_Byte(0xA4, OLED_CMD); // Disable Entire Display On (0xa4/0xa5)
  OLED_WR_Byte(0xA6, OLED_CMD); // Disable Inverse Display On (0xa6/a7)
  OLED_WR_Byte(0xAF, OLED_CMD);
  OLED_Clear(0);
}

OLED initialization:

//-----------------Pin Def----------------
#define OLED_PORT GPIOA
#define OLED_CS //empty
#define OLED_DC GPIO_PIN_8
#define OLED_RST GPIO_PIN_6
#define OLED_SCK GPIO_PIN_5
#define OLED_MOSI GPIO_PIN_7
//-----------------OLED Reg Clr/Set function----------------
#define OLED_CS_Clr() //empty
#define OLED_CS_Set() //empty
#ifdef SPI_SW
#define OLED_MOSI_Clr() gpio_bit_reset(OLED_PORT, OLED_MOSI)
#define OLED_MOSI_Set() gpio_bit_set(OLED_PORT, OLED_MOSI)
#define OLED_CLK_Clr() gpio_bit_reset(OLED_PORT, OLED_SCK)
#define OLED_CLK_Set() gpio_bit_set(OLED_PORT, OLED_SCK)
#define OLED_DC_Clr() gpio_bit_reset(OLED_PORT, OLED_DC)
#define OLED_DC_Set() gpio_bit_set(OLED_PORT, OLED_DC)

#define OLED_RST_Clr() gpio_bit_reset(OLED_PORT, OLED_RST)
#define OLED_RST_Set() gpio_bit_set(OLED_PORT, OLED_RST)
void OLED_Init_GPIO(void)
{

    // 	RCU config
    rcu_periph_clock_enable(RCU_GPIOA);

    //  GPIO config
    /* SPI_SW GPIO config:SCK/PA5->D0, MOSI/PA7->D1 */
    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, OLED_SCK | OLED_MOSI);
    /* GPIO config:PA6->RES, PA8->DC */
    gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, OLED_DC | OLED_RST);
    /* GND->CS */
}
void SPI_SW_WriteByte(uint8_t Data)
{
    uint8_t i = 0;
    for (i = 8; i > 0; i--) {
        if (Data & 0x80) {
            OLED_MOSI_Set(); //写数据1
        } else {
            OLED_MOSI_Clr(); //写数据0
        }
        OLED_CLK_Clr(); //将时钟拉低拉高
        OLED_CLK_Set(); //发送1bit数据
        Data <<= 1;
    }
}

void OLED_WR_Byte(uint8_t dat, uint8_t cmd)
{
    if (cmd) {
        OLED_DC_Set();
    } else {
        OLED_DC_Clr();
    }
    OLED_CS_Clr();
    SPI_SW_WriteByte(dat);
    OLED_CS_Set();
}

void OLED_Init(void)
{

    OLED_Init_GPIO(); //初始化GPIO
    delay_1ms(200);
    OLED_Reset(); //复位OLED
    /**************初始化SSD1306*****************/
    OLED_WR_Byte(0xAE, OLED_CMD); //--turn off oled panel
    OLED_WR_Byte(0x00, OLED_CMD); //---set low column address
    OLED_WR_Byte(0x10, OLED_CMD); //---set high column address
    OLED_WR_Byte(0x40, OLED_CMD); //--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    OLED_WR_Byte(0x81, OLED_CMD); //--set contrast control register
    OLED_WR_Byte(0xCF, OLED_CMD); // Set SEG Output Current Brightness
    OLED_WR_Byte(0xA1, OLED_CMD); //--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
    OLED_WR_Byte(0xC8, OLED_CMD); //Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
    OLED_WR_Byte(0xA6, OLED_CMD); //--set normal display
    OLED_WR_Byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
    OLED_WR_Byte(0x3f, OLED_CMD); //--1/64 duty
    OLED_WR_Byte(0xD3, OLED_CMD); //-set display offset	Shift Mapping RAM Counter (0x00~0x3F)
    OLED_WR_Byte(0x00, OLED_CMD); //-not offset
    OLED_WR_Byte(0xd5, OLED_CMD); //--set display clock divide ratio/oscillator frequency
    OLED_WR_Byte(0x80, OLED_CMD); //--set divide ratio, Set Clock as 100 Frames/Sec
    OLED_WR_Byte(0xD9, OLED_CMD); //--set pre-charge period
    OLED_WR_Byte(0xF1, OLED_CMD); //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    OLED_WR_Byte(0xDA, OLED_CMD); //--set com pins hardware configuration
    OLED_WR_Byte(0x12, OLED_CMD);

    OLED_WR_Byte(0xDB, OLED_CMD); //--set vcomh
    OLED_WR_Byte(0x40, OLED_CMD); //Set VCOM Deselect Level
    OLED_WR_Byte(0x20, OLED_CMD); //-Set Page Addressing Mode (0x00/0x01/0x02)
    OLED_WR_Byte(0x02, OLED_CMD); //
    OLED_WR_Byte(0x8D, OLED_CMD); //--set Charge Pump enable/disable
    OLED_WR_Byte(0x14, OLED_CMD); //--set(0x10) disable
    OLED_WR_Byte(0xA4, OLED_CMD); // Disable Entire Display On (0xa4/0xa5)
    OLED_WR_Byte(0xA6, OLED_CMD); // Disable Inverse Display On (0xa6/a7)
    OLED_WR_Byte(0xAF, OLED_CMD);
    OLED_Clear(0);
}

Game content:

#include "game.h"
#include "gui.h"
#include "oled.h"
#include 
#include 
#define TRUE 1
#define FALSE 0
#define FONTSIZE 8
#define jump_button_click_handler EXTI0_IRQHandler
//===========================BMP===================================
uint8_t OBJ_BMP[] = {

    0x1C, 0x00, 0x1C, 0x00, 0x1D, 0x80, 0x1D, 0x80, 0x1D, 0x80, 0x1D, 0x80, 0x1D, 0x80, 0xDD, 0x80,
    0xDD, 0x80, 0xDF, 0x00, 0xDE, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0x7C, 0x00, 0x3C, 0x00,

    0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x1C, 0x00
};
uint8_t PLAYER_BMP[] = {
    0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x37, 0xF0, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xF0, 0x00,

    0x3E, 0x00, 0x80, 0x3F, 0xC0, 0x80, 0x78, 0x00, 0xC1, 0xF8, 0x00, 0xE7, 0xFE, 0x00, 0xFF, 0xFA,
    0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xE0, 0x00,

    0x06, 0x60, 0x00, 0x04, 0x20, 0x00, 0x04, 0x20, 0x00, 0x06, 0x30, 0x00
};
uint8_t PLAYER1_BMP[] = {
    0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x37, 0xF0, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xF0, 0x00,
    0x3E, 0x00, 0x80, 0x3F, 0xC0, 0x80, 0x78, 0x00, 0xC1, 0xF8, 0x00, 0xE7, 0xFE, 0x00, 0xFF, 0xFA,
    0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x0F, 0xA0, 0x00,

    0x06, 0x20, 0x00, 0x04, 0x30, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00
};
uint8_t PLAYER2_BMP[] = {
    0x00, 0x1F, 0xE0, 0x00, 0x3F, 0xF0, 0x00, 0x37, 0xF0, 0x00, 0x3F, 0xF0, 0x00, 0x3F, 0xF0, 0x00,

    0x3E, 0x00, 0x80, 0x3F, 0xC0, 0x80, 0x78, 0x00, 0xC1, 0xF8, 0x00, 0xE7, 0xFE, 0x00, 0xFF, 0xFA,
    0x00, 0xFF, 0xF8, 0x00, 0x7F, 0xF8, 0x00, 0x3F, 0xF8, 0x00, 0x1F, 0xF0, 0x00, 0x0C, 0xE0, 0x00,

    0x04, 0x60, 0x00, 0x06, 0x20, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x00
};
//===========================ENUM===================================
typedef enum BMPn_Enum {
    PLAYER_BMPN,
    PLAYER_LEG1_BMPN,
    PLAYER_LEG2_BMPN,
    OBJ_BMPN,
} BMPn_Enum;
typedef enum Game_State_Enum {
    READY,
    PLAYING,
    GAMEOVER
} Game_State_Enum;
//===========================Global variables===================================
Game_State_Enum Game_State = PLAYING;
int Status_is_jumpfinish = 0, Status_is_jumping = 0;


uint16_t Gametime = 0, Distance = 0;
char Distance_str[20] = { '\0' };
int X_obj = 130, Y_obj = 44;

int X_player = 10, Y_player = 44, Status_leg_player = 1;
const int X_bg = 0, Y_bg = 53;

//===========================Functions===================================
#define blit_text(str, x, y) (GUI_ShowString((x), (y), (str), (FONTSIZE), 1))
void blit_bmp(BMPn_Enum BMPn, uint8_t x, uint8_t y)
{
    switch (BMPn) {
    case PLAYER_BMPN:
        GUI_DrawBMP_TransparentBg(x, y, 20, 20, PLAYER_BMP, 1);
        break;
    case PLAYER_LEG1_BMPN:
        GUI_DrawBMP_TransparentBg(x, y, 20, 20, PLAYER1_BMP, 1);
        break;
    case PLAYER_LEG2_BMPN:
        GUI_DrawBMP_TransparentBg(x, y, 20, 20, PLAYER2_BMP, 1);
        break;
    case OBJ_BMPN:
        GUI_DrawBMP_TransparentBg(x, y, 10, 20, OBJ_BMP, 1);
        break;
    default:
        break;

    }
}

void game_init(void)
{
    Game_State = READY;
    Gametime = 0;
    Distance = 0;
    Status_is_jumping = FALSE;
    Status_is_jumpfinish = TRUE;
    X_obj = 130;
    Y_obj = 44;

    Y_player = 44;
}

void jump_button_click_handler(void)
{
    if (RESET != exti_interrupt_flag_get(WAKEUP_KEY_PIN)) {

        if (RESET == gd_rvstar_key_state_get(KEY_WAKEUP)) {
            if (Game_State == PLAYING) {
                if (Status_is_jumpfinish) {
                    Status_is_jumping = TRUE;
                    Status_is_jumpfinish = FALSE;
                }
            }
            if (Game_State == GAMEOVER) {
                Game_State = READY;
                game_init();
            } else {
                Game_State = PLAYING;

            }
        }
    }
    /* clear EXTI lines pending flag */
    exti_interrupt_flag_clear(WAKEUP_KEY_PIN);
}
void draw_player(void)
{
    static uint8_t player_pic = PLAYER_BMPN;
    if (Status_is_jumping) {
        Y_player -= 3;
        blit_bmp(player_pic, X_player, Y_player);
        if (Y_player < 15)
            Status_is_jumping = FALSE;
    } else {
        player_pic = PLAYER_LEG1_BMPN;
        Y_player += 3;
    }
    if (Y_player >= 43) {
        Y_player = 43;
        Status_is_jumpfinish = TRUE;
    }
    if (Status_leg_player == 1) {
        blit_bmp(PLAYER_LEG1_BMPN, X_player, Y_player);
        Status_leg_player = 2;
    }
    else if (Status_leg_player == 2) {
        blit_bmp(PLAYER_LEG2_BMPN, X_player, Y_player);

        Status_leg_player = 1;
    }
}

void draw_obj(void)
{
    X_obj -= 4;
    blit_bmp(OBJ_BMPN, X_obj, Y_obj);
    if (X_obj <= -10)
        X_obj = 130;
}
void draw_score(void)
{
    itoa(Distance, Distance_str, 10);
    strcat(Distance_str, " km");
    blit_text(Distance_str, 2, 0);
}
void check(void)
{
    if (X_obj - X_player < 15 && Y_obj - Y_player < 15)
        Game_State = GAMEOVER;
}

int game_loop(void)
{
    while (TRUE) {
        GUI_Fill(0, 0, 127, 63, 0); //Black
        if (Game_State == READY) {
            blit_text("> Click to play!", 10, 10);
            blit_text("by cr4fun", 10, 30);
            blit_text("   & Endless", 10, 40);
        } else if (Game_State == PLAYING) {
            Distance += 1;
            Gametime += 1;
            GUI_DrawLine(0, 63, 127, 63, 1); //draw the ground
            draw_score();
            draw_player();
            draw_obj();
            check();
        } else if (Game_State == GAMEOVER) {
            draw_score();
            GUI_ShowString(23, 20, "GAME OVER!", 16, 1);
        }
        OLED_Display();
        delay_1ms(100);
    }
}

1053.gif (3.86 MB, downloads: 0)

1053.gif
This post is from Domestic Chip Exchange

Latest reply

Good, the screen is refreshed smoothly   Details Published on 2021-7-20 09:52
 
 

650

Posts

8

Resources
2
 

Good, the screen is refreshed smoothly

This post is from Domestic Chip Exchange
 
 
 

Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list