这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'sDo第2期任务+《贪吃蛇》成果帖

共1条 1/1 1 跳转至

Let'sDo第2期任务+《贪吃蛇》成果帖

菜鸟
2024-10-07 16:51:11     打赏

前言:利用RP2040_Raspberry Pi Pico驱动 Pico-Lcd-1.14的屏幕,在驱动之前我们要确定LCD屏幕的驱动方式。

这里我查了下资料使用的是 Serial Peripheral Interface接口,即SPI接口;

下面和大家分享一下开发的过程经历。

1:知识准备

LCD屏幕连接:

SPI引脚接口介绍:

SCLK(时钟线)

MOSI(主机输出从机输入)

MISO(主机输入从机输出,对于该项目来说不需要该引脚)

CS(片选)引脚

DC/RS (数据/命令引脚)

供电VCC和GND:一般屏幕都支持3.3V和5V的电源电源

如果需要背光的话,只需要将屏幕的背光引脚接到RP2040的GPIO口就可以(拉高或者置低)

下图是LCD屏幕的安装好后的图片:

微信图片_20241007160945.jpg

软件代码介绍:

按键部分代码:

static void (*key_pressed_cb[KEY_NUM])(void) = {NULL};

void key_scan(void)
{
    static int key_stat[KEY_NUM] = {0};
    for(char i=0; i<KEY_NUM; i++){
        if(gpio_get(get_key_pin(i))==0){
            key_stat[i]++;
        }
        else key_stat[i]=0;
    }
    for(char i=0; i<KEY_NUM; i++){
        //连续检测到10ms都按下则认为是按下
        if(key_stat[i]==10){
            if(NULL != key_pressed_cb[i])(*key_pressed_cb[i])();
        }
    }
}


void key_pressed_cb_register(uint8_t key, void(* cb)(void))
{
    if(key<0 || key>KEY_NUM){
        //printf("key_pressed_cb_register argument error!!!");
        return;
    }
    key_pressed_cb[key] = cb;
}

/**
 * @brief 按键按下回调函数清除
 * @param void 无入口参数
 * @return 无返回
*/
void key_pressed_cb_clear(void)
{
    for(char i=0; i<KEY_NUM; i++){
        key_pressed_cb[i] = NULL;
    }
}

开发过程经验

我们在开始接触的工程代码的时候,首先要对官方给的代码的基本代码进行一些学习和了解,其实里面大部分的内容在课程中都有涉及,这里就不做过多的介绍乐,主要对贪吃蛇的结构体和循环执行的位置进行判断。

对于项目中已经实现的功能,这里就不作介绍,我们秩序加入4个功能按键的控制器及其上下左右移动的控制即可。

我们在调试的代码的过程中,只需要对按键的扫描做好判断就好。

主界面的显示函数:

static uint8_t zh_string_gamestart[4]={0,1,2,3};
static uint8_t zh_string_setting[2] = {4,5};
static uint8_t zh_string_maps[3] = {21,22,23};

static uint8_t index_select = 0;
static uint8_t map_select = 0;

//左箭头 24*24
const unsigned char gImage_arrow_left[78] = {0X00,0X01,0X18,0X00,0X18,0X00,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X7F,0XFF,
0XFC,0X3F,0XFF,0XF8,0X3F,0XFF,0XF0,0X7F,0XFF,0XE0,0XFF,0XFF,0XC1,0XFF,0XFF,0X83,
0XFF,0XFF,0X07,0XFF,0XFE,0X0F,0XFF,0XFF,0X07,0XFF,0XFF,0X83,0XFF,0XFF,0XC1,0XFF,
0XFF,0XE0,0XFF,0XFF,0XF0,0X7F,0XFF,0XF8,0X3F,0XFF,0XFC,0X3F,0XFF,0XFE,0X7F,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,};

//右箭头 24*24
const unsigned char gImage_arrow_right[78] = {0X00,0X01,0X18,0X00,0X18,0X00,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XBF,0XFF,0XFF,
0X1F,0XFF,0XFE,0X0F,0XFF,0XFF,0X07,0XFF,0XFF,0X83,0XFF,0XFF,0XC1,0XFF,0XFF,0XE0,
0XFF,0XFF,0XF0,0X7F,0XFF,0XF8,0X3F,0XFF,0XF8,0X3F,0XFF,0XF0,0X7F,0XFF,0XE0,0XFF,
0XFF,0XC1,0XFF,0XFF,0X83,0XFF,0XFF,0X07,0XFF,0XFE,0X0F,0XFF,0XFF,0X1F,0XFF,0XFF,
0XBF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,};

static void show_menu(uint8_t index)
{
    zh_string_maps[2] = get_mapselect() + 23;
    LCD_ShowZh24(72,50,zh_string_maps,3,index==0?LBBLUE:LGRAYBLUE,index==0?LGRAY:BLACK);
    LCD_ShowZh24(72,74,zh_string_gamestart,4,index==1?LBBLUE:LGRAYBLUE,index==1?LGRAY:BLACK);
    LCD_ShowZh24(72,98,zh_string_setting,2,index==2?LBBLUE:LGRAYBLUE,index==2?LGRAY:BLACK);
}

static void key_a_pressed(void)
{
    if(index_select==0){
        
    }
    else if(index_select==1){
        //change ui to gamestart
        change_ui_to_snake();
    }
    else if(index_select==2){
        //change ui to setting
        change_ui_to_setting();
    }
}

static void key_up_pressed(void)
{
    if(index_select==0)index_select=2;
    else index_select--;
    show_menu(index_select);
}

static void key_down_pressed(void)
{
    index_select++;
    if(index_select==3)index_select=0;
    show_menu(index_select);
}

static void key_left_pressed(void)
{
    if(index_select==0){
        if(map_select==0)map_select=5;
        map_select--;
        set_mapselect(map_select);
        show_menu(index_select);
    }
}

static void key_right_pressed(void)
{
    if(index_select==0){
        map_select++;
        if(map_select==5)map_select=0;
        set_mapselect(map_select);
        show_menu(index_select);
    }
}

static void ui_main_init(void)
{
    index_select = 0;
    LCD_ShowZh32(24,0,0,RED,BLACK);
    LCD_ShowZh32(56,0,1,YELLOW,BLACK);
    LCD_ShowZh32(88,0,2,GREEN,BLACK);
    LCD_ShowZh32(120,0,3,BLUE,BLACK);
    LCD_ShowZh32(152,0,4,GBLUE,BLACK);
    LCD_ShowZh32(184,0,5,MAGENTA,BLACK);
    LCD_ShowBMP(24,50,LGRAY,BLACK,gImage_arrow_left);
    LCD_ShowBMP(192,50,LGRAY,BLACK,gImage_arrow_right);
    LCD_ShowZh24(72,50,zh_string_maps,3,LBBLUE,LGRAY);
    LCD_ShowZh24(72,74,zh_string_gamestart,4,LGRAYBLUE,BLACK);
    LCD_ShowZh24(72,98,zh_string_setting,2,LGRAYBLUE,BLACK);
}


void change_ui_to_mainmenu(void)
{
    LCD_Fill(0,0,LCD_W,LCD_H,BLACK);
    key_pressed_cb_clear();
    ui_main_init();
    key_pressed_cb_register(KEY_A,key_a_pressed);
    key_pressed_cb_register(KEY_UP,key_up_pressed);
    key_pressed_cb_register(KEY_DOWN,key_down_pressed);
    key_pressed_cb_register(KEY_LEFT,key_left_pressed);
    key_pressed_cb_register(KEY_RIGHT,key_right_pressed);
}

snake控制器主函数控制

#include "snake.h"
#include "pic.h"

//0:无 1:正常运行 2:赢得游戏 3:输掉游戏
static uint8_t game_stat = 0;
static uint8_t map_select = 0;
static uint8_t game_level = 0;

static uint8_t zh_string_scores[2] = {9,10};
static uint8_t zh_string_level[2] = {11,12};
static uint8_t zh_string_gamefailed[3] = {13,16,15};
static uint8_t zh_string_gamewin[3] = {13,14,15};

static uint16_t speed_table[10] = {800,700,600,500,400,350,300,250,200,150};

const uint8_t game_map1[15][21] = {
	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
};

const uint8_t game_map2[15][21] = {
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};

const uint8_t game_map3[15][21] = {
	1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1
};

const uint8_t game_map4[15][21] = {
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
	0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
	0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
	1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
};

typedef enum {
	SNAKE_DIR_UP,
	SNAKE_DIR_RIGHT,
	SNAKE_DIR_DOWN,
	SNAKE_DIR_LEFT
}_snake_dir_enum;


typedef struct {
	uint8_t x;
	uint8_t y;
	uint8_t dir;
}snake_body_t;

static struct {
	snake_body_t head;
	snake_body_t body[313];
	snake_body_t tail;
	uint16_t body_num;
	uint8_t level;
	uint16_t color_head;
	uint16_t color_body;
	uint16_t color_tail;
	uint8_t dir_next;
}snake;

uint8_t food_x = 0;
uint8_t food_y = 0;

char snake_map[15][21] = { 0 };

uint8_t get_gamestat(void){return game_stat;}
uint8_t get_mapselect(void){return map_select;}
void set_mapselect(uint8_t select){map_select = select;}

void game_refresh(void)
{
	LCD_ShowSnake(snake.head.x*9,snake.head.y*9,get_snake_head_color(),gImage_snake_head[snake.head.dir]);
	if (snake.body_num > 0) {
		for(int i=0;i<snake.body_num;i++){
			LCD_ShowSnake(snake.body[i].x*9,snake.body[i].y*9,get_snake_body_color(),gImage_snake_body);
		}
	}
	LCD_ShowSnake(snake.tail.x*9,snake.tail.y*9,get_snake_tail_color(),gImage_snake_tail[snake.tail.dir]);
}

void show_scores_update(void)
{
	if(snake.body_num<200)
		game_level = snake.body_num/20;
	else game_level=9;
	LCD_ShowIntNum(192,30,snake.body_num,3,RED,BLACK,24);
	LCD_ShowIntNum(192,95,game_level,3,RED,BLACK,24);
}

//stat 0赢得游戏 1输掉游戏
void show_ganeover(uint8_t stat)
{
	LCD_Fill(24,24,216,111,BLACK);
	LCD_DrawRectangle(24,24,216,111,WHITE);
	if(stat==0)LCD_ShowZh24(84,56,zh_string_gamewin,3,WHITE,BLACK);
	else if(stat==1)LCD_ShowZh24(84,56,zh_string_gamefailed,3,WHITE,BLACK);
}

void snake_init(void)
{
	game_level = 0;
	memset(&snake,0,sizeof(snake));
	if(map_select==0)
		memset(snake_map, 0, sizeof(snake_map));
	else if (map_select==1)
		memcpy(snake_map, game_map1, sizeof(snake_map));
	else if (map_select==2)
		memcpy(snake_map, game_map2, sizeof(snake_map));
	else if (map_select==3)
		memcpy(snake_map, game_map3, sizeof(snake_map));
	else if (map_select==4)
		memcpy(snake_map, game_map4, sizeof(snake_map));
	snake.tail.x = 1;
	snake.tail.y = 1;
	snake.head.x = 2;
	snake.head.y = 1;
	snake.head.dir = SNAKE_DIR_RIGHT;
	snake.dir_next = SNAKE_DIR_RIGHT;
	snake.tail.dir = SNAKE_DIR_RIGHT;
	for (int i = 0; i < 15; i++) {
		for (int j = 0; j < 21; j++) {
			if (snake_map[i][j] == 1)LCD_ShowSnake(9*j,9*i,WHITE,gImage_snake_body);//LCD_Fill(9*j,9*i,9*j+9,9*i+9,WHITE);
		}
	}
}

void snake_to_map(void)
{
	if(map_select==0)
		memset(snake_map, 0, sizeof(snake_map));
	else if (map_select==1)
		memcpy(snake_map, game_map1, sizeof(snake_map));
	else if (map_select==2)
		memcpy(snake_map, game_map2, sizeof(snake_map));
	else if (map_select==3)
		memcpy(snake_map, game_map3, sizeof(snake_map));
	else if (map_select==4)
		memcpy(snake_map, game_map4, sizeof(snake_map));
	snake_map[snake.head.y][snake.head.x] = 1;
	if (snake.body_num > 0) {
		for (int i = 0; i < snake.body_num; i++) {
			snake_map[snake.body[i].y][snake.body[i].x] = 1;
		}
	}
	snake_map[snake.tail.y][snake.tail.x] = 1;
}

int generate_food(void)
{
	uint8_t array[15] = { 0 };
	uint8_t num = 0;
	uint8_t x = time_us_64() % 21;
	uint8_t full_times = 0;
food:
	for (int i = 0; i < 15; i++) {
		if (snake_map[i][x] == 0) {
			array[num] = i;
			num++;
		}
	}
	if (num == 0) {
		x++;
		if (x == 21)x = 0;
		full_times++;
		if (full_times == 21)return 1;
		else goto food;
	}
	else if (num == 1) {
		food_x = x;
		food_y = array[0];
	}
	else {
		food_x = x;
		food_y = array[time_us_64() % num];
	}
	
	LCD_ShowSnake(food_x*9,food_y*9,YELLOW,gImage_snake_body);
	return 0;
}

void snake_head_move(snake_body_t* body)
{
	switch (body->dir) {
	case SNAKE_DIR_UP:
		if (body->y == 0)body->y = 15;
		body->y--;
		break;

	case SNAKE_DIR_RIGHT:
		body->x++;
		if (body->x == 21)body->x = 0;
		break;

	case SNAKE_DIR_DOWN:
		body->y++;
		if (body->y == 15)body->y = 0;
		break;

	case SNAKE_DIR_LEFT:
		if (body->x == 0)body->x = 21;
		body->x--;
		break;
	}
}

//将src的数值传递给dst,也即是蛇身dst移动到src
void snake_body_move(snake_body_t* dst, snake_body_t* src)
{
	dst->x = src->x;
	dst->y = src->y;
	dst->dir = src->dir;
}

//获取蛇头下次是否能吃到食物,此处需要使用形参传递数值,不能传地址,因为此时蛇头还不能移动
int next_is_food(snake_body_t body)
{
	snake_head_move(&body);
	if (body.x == food_x && body.y == food_y)return 0;
	else return -1;
}

//判断下次蛇头是否会撞到身体或者墙体,此处需要使用形参传递数值,不能传地址,因为此时蛇头还不能移动
int next_is_body(snake_body_t body)
{
	snake_head_move(&body);
	if (snake_map[body.y][body.x] == 1)return 0;
	else return -1;
}

/**
 * @brief 蛇运行函数
 * @retval 1:你赢了 
 *         0:正常运行
 *        -1:你输了
*/
int snake_run(void)
{
	uint8_t flag_is_eat_food = 0;
	//需要移动了,将dir_next复制到蛇头的移动方向中
	snake.head.dir = snake.dir_next;
	if (next_is_food(snake.head) == 0) {
		snake_body_move(&snake.body[snake.body_num],&snake.head);
		snake.body_num++;
		flag_is_eat_food = 1;
	}
	else {
		//没吃到食物,需要移动,先消除蛇尾显示
		LCD_Fill(snake.tail.x*9,snake.tail.y*9,snake.tail.x*9+9,snake.tail.y*9+9,BLACK);
		if (snake.body_num > 0) {
			snake_body_move(&snake.tail, &snake.body[0]);
			for (int i = 0; i < snake.body_num-1; i++) {
				snake_body_move(&snake.body[i], &snake.body[i + 1]);
			}
			snake_body_move(&snake.body[snake.body_num - 1], &snake.head);
		}
		else {
			snake_body_move(&snake.tail, &snake.head);
		}
	}
	snake_to_map();
	if (next_is_body(snake.head) == 0) {
		return -1;
	}
	snake_head_move(&snake.head);
	if(flag_is_eat_food==1){
		show_scores_update();
		return generate_food();
	}
	return 0;
}

static void key_b_pressed(void)
{
	game_stat = 0;
	show_ganeover(1);
	sleep_ms(2000);
	change_ui_to_mainmenu();
}

static void key_left_pressed(void)
{
    snake.dir_next = (snake.head.dir == SNAKE_DIR_UP || snake.head.dir == SNAKE_DIR_DOWN) ? SNAKE_DIR_LEFT : snake.head.dir;
}

static void key_right_pressed(void)
{
    snake.dir_next = (snake.head.dir == SNAKE_DIR_UP || snake.head.dir == SNAKE_DIR_DOWN) ? SNAKE_DIR_RIGHT : snake.head.dir;
}

static void key_up_pressed(void)
{
    snake.dir_next = (snake.head.dir == SNAKE_DIR_LEFT || snake.head.dir == SNAKE_DIR_RIGHT) ? SNAKE_DIR_UP : snake.head.dir;
}

static void key_down_pressed(void)
{
    snake.dir_next = (snake.head.dir == SNAKE_DIR_LEFT || snake.head.dir == SNAKE_DIR_RIGHT) ? SNAKE_DIR_DOWN : snake.head.dir;
}

void change_ui_to_snake(void)
{
    LCD_Fill(0,0,LCD_W,LCD_H,BLACK);
	LCD_DrawLine(189,0,189,135,WHITE);
	LCD_ShowZh24(190,0,zh_string_scores,2,WHITE,BLACK);
	LCD_ShowZh24(190,69,zh_string_level,2,WHITE,BLACK);
    key_pressed_cb_clear();
	snake_init();
	snake_to_map();
	generate_food();
	game_refresh();
	show_scores_update();
    key_pressed_cb_register(KEY_B,key_b_pressed);
    key_pressed_cb_register(KEY_UP,key_up_pressed);
    key_pressed_cb_register(KEY_DOWN,key_down_pressed);
    key_pressed_cb_register(KEY_LEFT,key_left_pressed);
    key_pressed_cb_register(KEY_RIGHT,key_right_pressed);
	game_stat = 1;
}

void game_run(void)
{
	uint8_t flag_game_faileed = 0;
	int ret = 0;
    static uint64_t time_to_wait_game = 0;   
	if(game_stat==1){
		if(try_to_wait(&time_to_wait_game,speed_table[game_level]*1000)==0){
			time_to_wait_game = 0; 
			ret = snake_run();
			if(ret==1){
				game_stat = 0;
				show_ganeover(0);
				sleep_ms(2000);
				change_ui_to_mainmenu();
				return;
			}
			else if(ret==-1){
				game_stat = 0;
				show_ganeover(1);
				sleep_ms(2000);
				change_ui_to_mainmenu();
				return;
			}
			snake_to_map();
			game_refresh();
		}
	}
}


番外篇:陀机的控制

舵机也叫也叫 RC 伺服器,通常用于机器人项目,也可以在遥控汽车,飞机等航模中找到它们。类似舵机这样的伺服系统通常由小型电动机,电位计,嵌入式控制系统和变速箱组成。机输出轴的位置由内部电位计不断采样测量,并与微控制器(例如STM32,Arduino)设置的目标位置进行比较;

根据相应的偏差,控制设备会调整电机输出轴的实际位置,使其与目标位置匹配。这样就形成了闭环控制系统。

微信图片_20241007163501.jpg

控制原理

通过向舵机的信号信号线发送PWM信号来控制舵机的输出量;

一般来说,PWM的周期以及占空比,我们是可控的,所以PWM脉冲的占空比直接决定了输出轴的位置。

下面举个例子;

当我们向舵机发送脉冲宽度为1.5毫秒(ms)的信号时,舵机的输出轴将移至中间位置(90度);

脉冲宽度为1ms时,舵机的输出轴将移至最小的位置(0度);

脉冲宽度为2ms时,舵机的输出轴将移至最小的位置(180度);

注意:不同类型和品牌的伺服电机之间最大位置和最小位置的角度可能会不同。许多伺服器仅旋转约170度(或者只有90度),但宽度为1.5 ms的伺服脉冲通常会将伺服设置为中间位置(通常是指定全范围的一半);


项目总结:

根据项目的提供的源码开发起来还是比较方便的,毕竟很多底层已经打通好了,在学习树莓派的开发过程,利用mdk开发还是比较方便的。整个项目开发从开始的硬件设计,为了方便调试,绘制了拓展板,调试起来方便乐很多,利用RP2040驱动LCD屏幕,完成了贪吃蛇的控制,再到利用定时器控制器陀机的工作,从中体会到了MDK开发树莓派额乐趣,后期有时间在对树莓派的其他功能进行开发学习。。

B站视频连接:

https://www.bilibili.com/video/BV1gh1yY8EEb/vd_source=fb5a6d1a3332aab1989e0f3e24f2afc1



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]