uCOSIII实时操作系统 三 移植

目录

uCOSIII简介:

准备工作:

准备基础工程:

UCOSIII工程源码:

UCOSIII移植:

向基础工程中添加相应的文件夹

向工程中添加分组

常见问题:

下载验证:

uCOSIII简介:

UCOS-III 是UCOS系统的第三代内核。

  1. 可剥夺式任务管理:总是执行当前就绪任务中优先级最高的任务。
  2. 同优先级任务的时间片轮转调度:UCOS-III允许一个任务优先级被多个任务使用,当这个优先级处在最高就绪态的时候,操作系统会轮流的调度处在这个优先级级别里面的所有任务,让优先级里面的每一个任务运行由用户指定的一段时间长度,这个时间通常称为"时间片"。这个特性也是UCOS-III与UCOS-II的一个重要区别。(II中不支持一个优先级内多个任务)。
  3. 极短的中断时间:UCOS-III采用的是锁定内核调度的方式而不是关中断的方式来保护临界区代码段,这样就可以把关中断的时间降至最低,使得UCOS-III能够非常快速的响应中断请求。
  4. 任务数目不受限制:UCOS-III自己本身是没有任务数目的限制的。但是实际情况下,任务数目会受到硬件比如CPU的影响不可能是无限制的。(每个任务都占用数据结构内存)
  5. 优先级数目不受限制:UCOS-III本身支持无限大的任务优先级。
  6. 内核对象数目不受限制:UCOS-III允许定义任意数目的内核对象。内核对象常见的包括任务,互斥信号量,事件标志组,消息队列,定时器和存储块等等。
  7. 软件定时器:用户可以任意定义“单次”和“周期”型定时器,定时器是一个递减计数器,递减到零就会执行预先定义好的操作。每个定时器都可以指定所需操作,周期型定时器在递减到零时会执行指定操作,并自动重置计数器值。
  8. 同时等待多个内核对象:UCOSIII允许一个任务同时等待多个事件,也就是说,一个任务能够挂起多个信号量或者消息队列上,当其中任何一个等待的时间发生时,等待任务就会被唤醒。
  9. 直接向任务发送信号:UCOSIII允许中断或者任务直接给另一个任务发送信号,避免创建和使用诸如信号量,或者事件标志等内和对象作为向其他任务发送信号的中介,该特征有效的提高了系统的性能。
  10. 直接向任务发送信息:UCOSIII 允许中断或任务直接给另一个任务发送消息,避免创建和使用消息队列作为中介。
  11. 任务寄存器:每个任务都可以设定若干个“任务定时器”任务寄存器和 CPU 硬件寄存器是不同的,主要用来保存各个任务的错误信息,ID 识别信息,中断关闭时间的测量结果等。
  12. 任务级时间节拍处理:UCOSIII的时钟节是通过一个专门的任务完成的,定时中断仅触发该任务。将延时处理和超时判断放在任务级代码完成。极大的减少了中断延时时间。
  13. 防止锁死:所有UCOSIII的 "等待"功能都提供了一个超时检测机制,有效的避免了锁死。
  14. 时间戳:UCOSIII需要一个16位或者32位的自由运行的计数器(时基计数器)来实现时间测量,在系统运行时,可以通过读取该计数器来测量,某一个时间信息。

准备工作:

准备基础工程:

首先需要准备一个移植的基础工程,使用库函数版本的跑马灯实验。

UCOSIII工程源码:

在移植uCOS-III之前,首先要获取它的源码。其源码可以从Micrium 的官方网站:www.micrium.com得到。μC/OS-III 是一个操作系统,其实也可以理解成一个软件库,它可以移植到多种硬件平台,如 M3、M4、M7 内核的 STM32,或者 ARM9 等等其他芯片。核心代码肯定是一致的,但是针对不同的处理器肯定要不同的实现部分。若要从 0 开始移植 μC/OS-III 到目标硬件平台,需要极大的精力和软件水平。为了方便移植,我们建议直接下载官网上移植好的基于目标平台的例子。

打开UCOSIII源码的压缩包:

  • EvalBoards:

主要内容是基于评估板(厂商的板子)的应用实现,在我们移植中有部分文件是可以用来使用的,在路径红色方框中我们可以看到官方移植的评估板芯片是STM32F107,但是不影响我们在STM32F103开发板上进行移植

另一个红色方框中的八个文件就是我们所需要添加到工程中的文件

  • uC-CPU:

这是和 CPU 紧密相关的文件,里边的一些文件很重要,都是我们需要使用的,

  1. cpu_core.h文件中包含了适用于所有CPU架构的C代码,也就是常说的通用代码。这是一个很重要的文件,主要包含的函数都是通过CPU进行命名的,时间戳的计算等等,跟CPU底层的移植没有太大依靠硬件实现,这里采用C语言方式,以防止某些CPU不支持前导零指令,该文件还包含用来监测中断关闭事件的函数(中断关闭和打开分别由
    CPU_CRITICAL_ENTER()和 CPU_CRITICAL_EXIT()两个宏实现)。
  2. cpu_core.h 文件包含 cpu_core.c 中函数的原型声明以及其他的一些变量的定义。
  3. cpu_def.h 文件包含 uC/CPU 模块使用的各种#define 常量。
  • 在 ARM-Cortex-M3文件夹下,存在 cpu_c.c 一些对不同编译器移植相关的文件,有 GNU、IAR、RealView,里面都有一些很重要的文件,目前我们使用的开发环境是 MDK(keil),所以我们选择 RealView 文件夹。

点击ARM-cortex-M3文件夹中,常用MDK开发故选择Realview,可以看到如下所示

  1. cpu.h文件中包含了一些类型的定义,使用UCOSIII和其他的模块可以CPU架构和编译器子宽无关。
  2. cpu_a.asm 文件包含了一些用汇编语言编写的函数,可用来开中断和关中断,计算前导零(如果 CPU支持这条指令),以及其他一些只能用汇编语言编写的与 CPU 相关的函数,这个文件中的函数可以从 C 代码中调用。
  3. cpuc.c 文件包含了一些基于特定 CPU 架构但为了可移植而用 C 语言编写的函数 C 代
  • uC-LIB :

文件夹是Micrium 公司提供的官方库,诸如字符串操作、内存操作等接口,可用可不用。一般能用于代替标准库中的一些函数,使得在嵌入式中应用更加方便安全。

  • uCOS-III 

该文件夹是操作系统的内核文件夹,都是系统核心文件。这些文件是我们全部需要的。文件这个文件夹中有两个文件Ports 和 Sourece

μC/OS 是软件,我们的开发板是硬件,软硬件必须有桥梁来连接,这些与处理器架构相关的代码,可以称之为 RTOS 硬件接口层它们位于 μC/OS-III->Ports 文件夹下,在不同的编译器中选择的是不同的我们不需要去理会官方已经帮我们写好了。

Source :

文件夹里面为 UCOSIII 3.0.3的源码

各个文件的作用如下表所示在学习的过程中慢慢了解:

UCOSIII移植:

向基础工程中添加相应的文件夹

在基础工程文件夹中新建一个UCOSIII文件夹,然后将我们下载的官方移植工程中的uC-CPU、uC-LIB 和 UCOS-III 这三个文件复制到工程中

在UCOSIII文件中在建立两个文件夹:UCOS_BSP和UCOS_CONFIG

将下边路径下的八个文件放到UCOS_CINFIG中:

同样复制 Micrium 官方移植好的工程中的相关文件到 UCOS_BSP 文件下,需要复制的文件路径为Micrium\Software\EvalBoards\Micrium\uC-Eval-STM32F107\BSP将下边两个文件移植到自己的所建的UCOSIII_BSP的目录当中。

向工程中添加分组

根据个人习惯向目录中添加6个分组

工程中的分组建立完了之后,我们就要向新建的各个分组当中添加文件了

  • UCOSIII_BSP添加路径:UCOSIII\UCOS_BSP里的bsp.c添加进去
  • UCOSIII_CPU添加路径:UCOSIII\UCOS_CPU里的cpu_core.c添加进去,并继续进入目录ARM-Cortex-M4\RealView选择cpu_a.sam\cpu_c.c两个文件,添加进去
  • UCOSIII_LIB添加路径:UCOSIII\uC-LIB里的,继续点击Ports\ARM-Cortex-M4\RealView,选择All file,添加lib_mem_a.asm文件
  • UCOSIII_CORE添加路径:UCOSIII\uCOS-III\Source,添加所有文件
  • UCOSIII_PORT添加路径:UCOSIII\uCOS-III\Ports\ARM-Cortex-M4\Generic\RealView,选择All file,添加所有文件
  • UCOS_CONFIG添加路径:UCOSIII\UCOS_CONFIG选择All file,添加所有文件

注意:此时有的文件会带一把钥匙,表示不能修改,修改方法:返回工程文件,点击属性,把只读去掉即可进入工程对其修改

上面完成了对.c文件的添加,然后是.h头文件路径的添加

做完这一步我们编辑一下整个工程,结果显示很多错误

常见问题:

下边是正点原子对一些错误的解释:

这里我还要补充一个错误就是下边这个问题

这个问题我推荐看一下这篇博客:http://t.csdnimg.cn/E9VvQ

最后一步就是在注意在os_cpu_c.c中添加#include "includes.h" //添加头文件
移植完成后就需要编写测试软件测试我们移植是否正确,我们建立 3 个任务,其中两个任务分别用于 LED0 和 LED1 闪烁,另外一个任务用于测试浮点计算。

例程:main.c

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "includes.h"
//UCOSIII中以下优先级用户程序不能使用,ALIENTEK
//将这些优先级分配给了UCOSIII的5个系统内部任务
//优先级0:中断服务服务管理任务 OS_IntQTask()
//优先级1:时钟节拍任务 OS_TickTask()
//优先级2:定时任务 OS_TmrTask()
//优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
//优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()
//技术支持:www.openedv.com
//淘宝店铺:http://eboard.taobao.com  
//广州市星翼电子科技有限公司  
//作者:正点原子 @ALIENTEK//任务优先级
#define START_TASK_PRIO		3
//任务堆栈大小	
#define START_STK_SIZE 		512
//任务控制块
OS_TCB StartTaskTCB;
//任务堆栈	
CPU_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *p_arg);//任务优先级
#define LED0_TASK_PRIO		4
//任务堆栈大小	
#define LED0_STK_SIZE 		128
//任务控制块
OS_TCB Led0TaskTCB;
//任务堆栈	
CPU_STK LED0_TASK_STK[LED0_STK_SIZE];
void led0_task(void *p_arg);//任务优先级
#define LED1_TASK_PRIO		5
//任务堆栈大小	
#define LED1_STK_SIZE 		128
//任务控制块
OS_TCB Led1TaskTCB;
//任务堆栈	
CPU_STK LED1_TASK_STK[LED1_STK_SIZE];
//任务函数
void led1_task(void *p_arg);//任务优先级
#define FLOAT_TASK_PRIO		6
//任务堆栈大小
#define FLOAT_STK_SIZE		128
//任务控制块
OS_TCB	FloatTaskTCB;
//任务堆栈
__align(8) CPU_STK	FLOAT_TASK_STK[FLOAT_STK_SIZE];
//任务函数
void float_task(void *p_arg);int main(void)
{OS_ERR err;CPU_SR_ALLOC();delay_init();       //延时初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置uart_init(115200);    //串口波特率设置LED_Init();         //LED初始化OSInit(&err);		//初始化UCOSIIIOS_CRITICAL_ENTER();//进入临界区//创建开始任务OSTaskCreate((OS_TCB 	* )&StartTaskTCB,		//任务控制块(CPU_CHAR	* )"start task", 		//任务名字(OS_TASK_PTR )start_task, 			//任务函数(void		* )0,					//传递给任务函数的参数(OS_PRIO	  )START_TASK_PRIO,     //任务优先级(CPU_STK   * )&START_TASK_STK[0],	//任务堆栈基地址(CPU_STK_SIZE)START_STK_SIZE/10,	//任务堆栈深度限位(CPU_STK_SIZE)START_STK_SIZE,		//任务堆栈大小(OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息(OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,(void   	* )0,					//用户补充的存储区(OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项(OS_ERR 	* )&err);				//存放该函数错误时的返回值OS_CRITICAL_EXIT();	//退出临界区	 OSStart(&err);  //开启UCOSIIIwhile(1);
}//开始任务函数
void start_task(void *p_arg)
{OS_ERR err;CPU_SR_ALLOC();p_arg = p_arg;CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0uOSStatTaskCPUUsageInit(&err);  	//统计任务                
#endif#ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间CPU_IntDisMeasMaxCurReset();	
#endif#if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候//使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5msOSSchedRoundRobinCfg(DEF_ENABLED,1,&err);  
#endif		OS_CRITICAL_ENTER();	//进入临界区//创建LED0任务OSTaskCreate((OS_TCB 	* )&Led0TaskTCB,		(CPU_CHAR	* )"led0 task", 		(OS_TASK_PTR )led0_task, 			(void		* )0,					(OS_PRIO	  )LED0_TASK_PRIO,     (CPU_STK   * )&LED0_TASK_STK[0],	(CPU_STK_SIZE)LED0_STK_SIZE/10,	(CPU_STK_SIZE)LED0_STK_SIZE,		(OS_MSG_QTY  )0,					(OS_TICK	  )0,					(void   	* )0,					(OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,(OS_ERR 	* )&err);				//创建LED1任务OSTaskCreate((OS_TCB 	* )&Led1TaskTCB,		(CPU_CHAR	* )"led1 task", 		(OS_TASK_PTR )led1_task, 			(void		* )0,					(OS_PRIO	  )LED1_TASK_PRIO,     	(CPU_STK   * )&LED1_TASK_STK[0],	(CPU_STK_SIZE)LED1_STK_SIZE/10,	(CPU_STK_SIZE)LED1_STK_SIZE,		(OS_MSG_QTY  )0,					(OS_TICK	  )0,					(void   	* )0,				(OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR 	* )&err);	//创建浮点测试任务OSTaskCreate((OS_TCB 	* )&FloatTaskTCB,		(CPU_CHAR	* )"float test task", 		(OS_TASK_PTR )float_task, 			(void		* )0,					(OS_PRIO	  )FLOAT_TASK_PRIO,     	(CPU_STK   * )&FLOAT_TASK_STK[0],	(CPU_STK_SIZE)FLOAT_STK_SIZE/10,	(CPU_STK_SIZE)FLOAT_STK_SIZE,		(OS_MSG_QTY  )0,					(OS_TICK	  )0,					(void   	* )0,				(OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, (OS_ERR 	* )&err);								 OS_TaskSuspend((OS_TCB*)&StartTaskTCB,&err);		//挂起开始任务			 OS_CRITICAL_EXIT();	//进入临界区
}//led0任务函数
void led0_task(void *p_arg)
{OS_ERR err;p_arg = p_arg;while(1){LED0=0;OSTimeDlyHMSM(0,0,0,200,OS_OPT_TIME_HMSM_STRICT,&err); //延时200msLED0=1;OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_HMSM_STRICT,&err); //延时500ms}
}//led1任务函数
void led1_task(void *p_arg)
{OS_ERR err;p_arg = p_arg;while(1){LED1=~LED1;OSTimeDlyHMSM(0,0,0,500,OS_OPT_TIME_HMSM_STRICT,&err); //延时500ms}
}//浮点测试任务
void float_task(void *p_arg)
{CPU_SR_ALLOC();static float float_num=0.01;while(1){float_num+=0.01f;OS_CRITICAL_ENTER();	//进入临界区printf("float_num的值为: %.4f\r\n",float_num);OS_CRITICAL_EXIT();		//退出临界区delay_ms(500);			//延时500ms}
}


下载验证:

编译下载之后打开串口助手,我们可以看到LED1和led0按照设定好的时间闪烁,串口有信息输出以0.01递增

例程:

链接:https://pan.baidu.com/s/1x1foTZvqQjdjv3QAsGX5QQ 
提取码:k9jr

正点原子的UCOSIII开发手册

链接:https://pan.baidu.com/s/1Za1q0H8giaA-Xkjpcw7Wrg 
提取码:wt2f

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/97734.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot配置kafka

server:port: 8080 spring:kafka:bootstrap-servers: 192.168.79.104:9092producer: # 生产者retries: 3 # 设置大于 0 的值,则客户端会将发送失败的记录重新发送batch-size: 16384buffer-memory: 33554432acks: 1# 指定消息key和消息体的编解码方式key-serializer:…

【Nginx学习】—Nginx基本知识

【Nginx学习】—Nginx基本知识 一、什么是Nginx Nginx是一个高性能的HTTP和反向代理的web服务器,Nginx是一款轻量级的Web服务器/反向代理服务器处理高并发能力是十分强大的,并且支持热部署,启动简单,可以做到7*24不间断运行。 …

【ringbuff share mem】

ringbuff 和share mem 结合实现PV操作 参考链接 https://juejin.cn/post/7113550346835722276 https://zhuanlan.zhihu.com/p/147826545 代码如下: #include "rb.h"int g_shmid 0;shm_buff * create_shm(int *smid) {int id;shm_buff *share_mem NU…

SketchyCOCO数据集进行前景图像、背景图像和全景图像的分类

SketchyCOCO数据集进行前景图像、背景图像和全景图像的分类 import os import shutildef CopyFile(src, dst, filename):if not os.path.exists(dst):os.makedirs(dst)print(create dir: dst)try:shutil.copy(src\\filename, dst\\filename)except Exception as e:print(cop…

计算机网络-计算机网络体系结构-物理层

目录 一、通信基础 通信方式 传输方式 码元 传输率 *二 准则 2.1奈氏准则(奈奎斯特定理) 2.2香农定理 三、信号的编码和调制 *数字数据->数字信号 数字数据->模拟信号 模拟数据->数字信号 模拟数据->模拟信号 *四、数据交换方式 电路交换 报文交换…

算法练习(11):牛客在线编程07 动态规划

package jz.bm;import javax.crypto.MacSpi; import java.util.ArrayList; import java.util.Arrays;public class bm7 {/*** BM62 斐波那契数列*/public int Fibonacci(int n) {if (n < 2) {return 1;}int[] dp new int[n 1];dp[1] 1;dp[2] 1;for (int i 3; i < n;…

kafka客户端应用参数详解

一、基本客户端收发消息 Kafka提供了非常简单的客户端API。只需要引入一个Maven依赖即可&#xff1a; <dependency><groupId>org.apache.kafka</groupId><artifactId>kafka_2.13</artifactId><version>3.4.0</version></depend…

将python项目部署在一台服务器上

将python项目部署在一台服务器上 1.服务器2.部署方法2.1 手动部署2.2 容器化技术部署2.3 服务器less技术部署 1.服务器 服务器一般为&#xff1a;物理服务器和云服务器。 我的是物理服务器&#xff1a;这是将服务器硬件直接放置在您自己的数据中心或机房的传统方法。这种方法需…

力扣 -- 516. 最长回文子序列

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:int longestPalindromeSubseq(string s) {int ns.size();vector<vector<int>> dp(n,vector<int>(n));//记得从下往上填表for(int in-1;i>0;i--){//记得i是小于等于j的for(int ji;j&l…

山体滑坡监测系统——高效、便捷的新选择

在当今社会&#xff0c;科技的进步为我们的生活和工作带来了诸多便利。而在山体滑坡监测领域&#xff0c;全球导航卫星系统&#xff08;GNSS&#xff09;的引入更是增加了数据监测的高效性和便捷性。 一、山体滑坡监测系统的基本原理 山体滑坡监测系统是由监控平台和GNSS位移…

2.6 宽带接入技术

思维导图&#xff1a; 前言&#xff1a; 我的理解&#xff1a; 1. **早期互联网接入技术的局限性**&#xff1a; - 作者首先回顾了早期用户通过电话线和调制解调器连接到互联网服务提供商&#xff08;ISP&#xff09;的方式&#xff0c;指出这种方式的速度上限是56 kbit/…

my_print_defaults 及perror

参考文档&#xff1a; https://mysql.net.cn/doc/refman/8.0/en/my-print-defaults.html https://mysql.net.cn/doc/refman/8.0/en/perror.html -- my.cnf的内容 [rootredhat762100 mysql3306]# more my.cnf [mysqld] datadir/mysql/mysql3306/data #socket/tmp/mysql3306.so…

UE5.1编辑器拓展【三、脚本化资产行为,删除无引用资产】

目录 需要考虑的问题 重定向的修复函数 代码&#xff1a; 删除无引用资产 代码 需要添加的头文件和模块 在我们删除资产的时候&#xff0c;会发现&#xff0c;有些资产在删除的时候会出现有被什么什么引用&#xff0c;还有的是没有被引用。 而我们如果直接选择一片去进行…

FFmpeg横竖版视频互换背景模糊一键生成

视频处理是现代多媒体应用中常见的需求。其中横竖版视频互换和背景模糊是视频编辑中常见的操作。FFmpeg是一个功能强大的工具,适用于这些任务。 本文将详细介绍如何使用FFmpeg进行横竖版视频互换和背景模糊。 文章目录 操作命令与命令说明横版转竖版竖版转横版背景模糊处理横…

PHP 伪协议:使用 php://input 访问原始 POST 数据

文章目录 参考环境PHP 伪协议概念为什么需要 PHP 伪协议&#xff1f; php://input为什么需要 php://input&#xff1f;更灵活的数据处理减小性能压力 发送 POST 数据HackBarHackBar 插件的获取 $_POST打开 HackBar 插件通过 HackBar 插件发起 POST 请求 基操 enable_post_data_…

ROS机械臂开发-开发环境搭建【一】

目录 前言环境配置docker搭建Ubuntu环境安装ROS 基础ROS文件系统 bugs 前言 想系统学习ROS&#xff0c;做一些机器人开发。因为有些基础了&#xff0c;这里随便写写记录一下。 环境配置 docker搭建Ubuntu环境 Dockerfile # 基础镜像 FROM ubuntu:18.04 # 设置变量 ENV ETC…

Split index API

Split index API | Elasticsearch Guide [8.10] | Elastic 当您使用Elasticsearch集群出现索引分片设置不合理&#xff08;例如索引主分片设置不合理、每个分片存在大量数据等&#xff09;引发集群性能问题时&#xff0c;可通过_split API在线扩大主分片数&#xff0c;将现有索…

[开源]基于Vue的拖拽式数据报表设计器,为简化开发提高效率而生

一、开源项目简介 Cola-Designer 是一个 基于VUE&#xff0c;实现拖拽 配置方式生成数据大屏&#xff0c;为简化开发、提高效率而生。 二、开源协议 使用GPL-2.0开源协议 三、界面展示 概览 部分截图&#xff1a; 四、功能概述 特性 0 代码 实现完全拖拽 配置式生成…

SpringBoot中常用注解的含义

一、方法参数注解 1. PathVariable 通过RequestMapping注解中的 { } 占位符来标识URL中的变量部分 在控制器中的处理方法的形参中使用PathVariable注解去获取RequestMapping中 { } 中传进来的值&#xff0c;并绑定到处理方法定一的形参上。 //请求路径&#xff1a;http://3333…

【好玩】如何在github主页放一条贪吃蛇

前言 &#x1f34a;缘由 github放小蛇&#xff0c;就问你烧不烧 起因看到大佬github上有一条贪吃蛇扭来扭去&#xff0c;觉得好玩&#xff0c;遂给大家分享一下本狗的玩蛇历程 &#x1f95d;成果初展 贪吃蛇 &#x1f3af;主要目标 实现3大重点 1. github设置主页 2. git…