zoukankan      html  css  js  c++  java
  • 2017-2018-1 20155301-2015539实验二 固件程序设计实验报告

    实验二 固件程序设计

    1.MDK

    实验要求

    0. 注意不经老师允许不准烧写自己修改的代码
    1. 两人(个别三人)一组
    2. 参考云班课资源中“信息安全系统实验箱指导书.pdf “第一章,1.1-1.5安装MDK,JLink驱动,注意,要用系统管理员身分运行uVision4,破解MDK(破解程序中target一定选ARM)
    3. 提交破解程序中产生LIC的截图
    4. 提交破解成功的截图

    实验步骤

    • 按照“信息安全系统实验箱指导书.pdf “第一章,1.1-1.5安装即可,注意勾选如下选项

    实验中遇到的问题

    • 问题一:出现如下异常

    • 解决:没有以管理员身份运行,注意要以管理员身份运行,否则会出现如是错误。

    • 问题二:CID破解失败。

    • 解决:将MDK安装在keil目录下,问题解决,破解成功

    实验结果

    2.LED

    实验要求

    0. 注意不经老师允许不准烧写自己修改的代码
    1. 参考云班课资源中“信息安全系统实验箱指导书.pdf “第一章,1.4” KEIL-MDK 中添加 Z32 SC-000 芯片库,提交安装截图
    2. 参考云班课资源中“信息安全系统实验箱指导书.pdf “第一章,1.9”完成LED实验,注意“打开Z32的电源开关前,按住Reboot按键不放,两次打开电源开关,Z32即可被电脑识别,进行下载调试。提交运行结果截图
    3. 实验报告中分析代码

    实验步骤

    • 按照信息安全系统实验箱指导书.pdf “第一章,1.4” 的步骤在KEIL-MDK 中添加 Z32 SC-000 芯片库。
    • 按照信息安全系统实验箱指导书.pdf “第一章,1.9“完成该实验。

    代码分析

    1.这段代码不能修改,否则会使芯片局受损

    SystemInit ();//中断向量设置,使能所有中断
    if(0 == GPIO_GetVal(0))//判断按键状态,返回boot值,以确定是否连接以及是否下载程序。
    {
    BtApiBack(0x55555555, 0xAAAAAAAA);
    }
    

    2.设置GPIO0为上拉输出
    GPIO_PuPdSel(0,0); // 设置 GPIO0 为上拉
    GPIO_InOutSet(0,0); // //设置 GPIO0为输出
    3.进入循环程序,LED 灯间隔 100ms 闪烁,得到该实验所要求的现象:LED闪烁。

    while(1)
    {
    delay(100);
    GPIO_SetVal(0,0); //输出低电平,点亮 LED
    delay(100);
    GPIO_SetVal(0,1); //输出高电平,熄灭 LED
    }
    

    实验结果

    由于闪烁无法拍出,故呈现了其闪烁过程中亮、暗两种状态

    3.UART

    实验要求

    0. 注意不经老师允许不准烧写自己修改的代码
    1. 参考云班课资源中“信息安全系统实验箱指导书.pdf “第一章,1.4” KEIL-MDK 中添加 Z32 SC-000 芯片库,提交安装截图
    2. 参考云班课资源中“信息安全系统实验箱指导书.pdf “第一章,1.0”完成UART发送与中断接收实验,注意“打开Z32的电源开关前,按住Reboot按键不放,两次打开电源开关,Z32即可被电脑识别,进行下载调试。提交运行结果截图
    3. 实验报告中分析代码

    实验步骤

    • 按照信息安全系统实验箱指导书.pdf “第一章,1.4” 的步骤在KEIL-MDK 中添加 Z32 SC-000 芯片库。
    • 按照信息安全系统实验箱指导书.pdf “第一章,1.0”完成UART发送与中断接收实验

    实验中遇到的问题

    • 问题一:一直提示无法连接。
    • 解决方案:电脑重启,再次尝试即可。

    代码分析

    一、串口相关函数:
    1.void UART_IrqService(void)是一个串口中断服务函数,在本实验中可以实现串口中
    断执行子程序,从 PC 端串口调试助手发送数据至 Z32,Z32 再经串口发送至 PC 机;

    void UART_IrqService(void)
    {
    //*****your code*****/
    UARTCR &= ~TRS_EN;
    {
    do
     {
     shuju[uart_rx_num] = UARTDR;
    if(shuju[uart_rx_num]=='
    '||shuju[uart_rx_num]=='
    ')
    {
    shuju_lens = uart_rx_num;
    uart_rx_num=0;
    uart_rx_end=1;
    }
    else uart_rx_num++;
     }
     while(FIFO_NE & UARTISR);
    }
    UARTCR |= TRS_EN;
    }
    

    2.void UART_BrpSet(UINT16 set)波特率设置函数,默认波特率 115200,需根据时钟源和分频计算出 set = 时钟(hz)/波特率,无返回值。

    void UART_BrpSet(UINT16 set)
    {
    UINT16 brp=0;
     UINT8 fd=0; 
     if(0 == set)
     {
     //uartband@115200bps
     fd = SCU->UARTCLKCR & 0x80; 
     switch(fd)
     {
     case 0x80: /*外部时钟 12M 晶振*/
     brp = 0x0068;
     break;
     case 0x00: /*内部时钟*/
    brp = 0x00AD; 
     break; 
     default:
     brp = 0x00AD;
     break;
     }
    fd = SCU->UARTCLKCR & 0x7f ; 
     brp = brp/(fd+1);
     }
     else
     {
     brp = set;
     }
    UARTBRPH = (UINT8)((brp >> 8) & 0xFF);
     UARTBRPL = (UINT8)((brp) & 0xFF);
    }
    

    3.void UART_Init(void)初始化串口,实现配置串口时钟、使能中断,无返回值。

    void UART_Init(void)
    {
    IOM->CRA |= (1<<0); //使能 Uart 接口
    SCU->MCGR2 |= (1<<3); //使能 Uart 总线时钟
    /******配置 Uart 时钟(建议使用外部晶振)******/
    SCU->SCFGOR |= (1<<6);// 使能外部晶振
    SCU->UARTCLKCR |= (1<<7);//使用外部时钟
    // SCU->UARTCLKCR &= ~(1<<7);//使用内部 OSC 时钟
    UART_BrpSet(0); //设置波特率为默认 115200
    UARTISR = 0xFF; //状态寄存器全部清除
    UARTCR |= FLUSH; //清除接收 fifo
    UARTCR = 0; //偶校验
    - 78 -
    /******配置中断使能******/
    UARTIER |= FIFO_NE;
    ModuleIrqRegister(Uart_Exception, UART_IrqService);//挂载中断号
    }
    
    1. void UART_SendByte(UINT8 dat)Uart发送单字节函数,dat为要发送的字节,使用此函数一次发送一个字节数据,无返回值。
    void UART_SendByte(UINT8 dat)
    { 
    UARTCR |= TRS_EN;
    UARTDR = dat;
     do
     {
     if(UARTISR & TXEND)
     { 
     UARTISR |= TXEND;//清除发送完成标志,写 1 清除
     break;
     }
     }
     while (1);
     UARTCR &= (~TRS_EN);
    }
    

    5.void UART_SendString(UINT8 * str)Uart发送一个字符串,使用此函数发送
    字符串数据,str为要发送的字符串,无返回值。

    void UART_SendString(UINT8 * str)
    {
    UINT8 *p ;
    p=str;
    while(*p!=0)
    {
    UART_SendByte(*p++);
    }
    }
    

    6.void uart_SendString(UINT8 buf[],UINT8 length)Uart 发送某一长度的字符串,实现发送一定长度的字符串数据
    ,buf: 要发送的字符串,length: 要发送的长度,无返回值。

    void uart_SendString(UINT8 buf[],UINT8 length)
    {
    UINT8 i=0;
    while(length>i)
    {
    UART_SendByte(buf[i]);
    i=i+1;
    }
    }
    

    7.void UART_SendNum(INT32 num)使用此
    函数发送一个十进制整数;Uart 发送一个十进制整数,num: 要发送的整数,无返回值。

    void UART_SendNum(INT32 num)
    {
    INT32 cnt = num,k;
    UINT8 i,j;
    if(num<0) {UART_SendByte('-');num=-num;}
    //计算出 i 为所发数据的位数
    for(i=1;;i++)
    {
    cnt = cnt/10;
    if(cnt == 0) break;
    }
    //算出最大被除数从高位分离
    k = 1;
    for(j=0;j<i-1;j++)
    {
    k = k*10;
    }
    //分离并发送各个位
    cnt = num;
    for(j=0;j<i;j++)
    {
    cnt = num/k;
    num = num%k;
    UART_SendByte(0x30+cnt);
    k /= 10;
    }
    }  
    

    8.void UART_SendHex(UINT8 dat)是发送单个十六进制整数函数,使用此
    函数发送一个十六进制整数,dat为要发送的 16 进制数,无返回值。

    void UART_SendHex(UINT8 dat)
    {
    UINT8 ge,shi;
    UART_SendByte('0');
    UART_SendByte('x');
    ge = dat%16;
    shi = dat/16;
    if(ge>9) ge+=7; //转换成大写字母
    if(shi>9) shi+=7;
    UART_SendByte(0x30+shi);
    UART_SendByte(0x30+ge);
    UART_SendByte(' ');
    }
    

    9.UINT8 UART_GetByte(UINT8 *data)是接收单字节函数,使用此函数接
    收单字节数据,返回flag。

    UINT8 UART_GetByte(UINT8 *data)
    {
     UINT8 ret= 0; 
     if(0 != (UARTISR & FIFO_NE))
     {
     *data = UARTDR;
     ret = 1;
     } 
     return ret;
    }
    

    10.void UART_Receive(UINT8 *receive, UINT8 len)Uart 是接收多字节函数,使
    用此函数接收多个字节数据,len:长度。

    void UART_Receive(UINT8 *receive, UINT8 len)
    { 
    while(len != 0)
    {
    if(len >= 4)
    {
    while (!(UARTISR & FIFO_FU));
    *receive++ = UARTDR;
     *receive++ = UARTDR;
    *receive++ = UARTDR;
     *receive++ = UARTDR;
     len -= 4;
     
    }
    else if(len >= 2)
    {
    while (!(UARTISR & FIFO_HF)); 
    *receive++ = UARTDR;
     *receive++ = UARTDR;
     len -= 2;
    } 
    else
    {
    while (!(UARTISR & FIFO_NE));
     *receive++ = UARTDR;
    len--;
    }
    }
    }
    

    二、主函数

    1. 同样需要进行系统初始化,中断设置,使能所有中断;
      2.同样需要判断按键,返回 boot 条件,确认是否进行程序下载;
      3.初始化 Uart,使能 Uart 接口,配置 Uart 中断并使能;
      UART_Init();
    2. 先发送单个字符“A”,换行,再发送字符串“Welcome to Z32HUA!",
      5.换行,发送数字串“1234567890”,换行,再发送 16 位数“0xAA”,换行。
    UART_SendByte('A'); //Uart 发送一个字符 A
    UART_SendByte('
    ');UART_SendByte('
    ');//换行
    UART_SendString("Welcome to Z32HUA!"); //Uart 发送字符串
    UART_SendByte('
    ');UART_SendByte('
    ');//换行
    UART_SendNum(1234567890); //Uart 发送一个十进制数
    UART_SendByte('
    ');UART_SendByte('
    ');//换行
    UART_SendHex(0xAA); //Uart 发送一个十六进制数
    UART_SendByte('
    ');UART_SendByte('
    ');//换行
    
    1. 进入 while 循环程序,等待串口中断到来并判断数据是否接收完毕,若中断到来,转入执行串口中断服务程序,待接收数据完毕,Z32 将数据发回串口助手。
    while(1)
    {
    if(uart_rx_end)
    {
    uart_rx_end=0;
    uart_SendString(shuju,shuju_lens);
    }
    } 
    

    实验结果

    4.国密算法

    实验任务

    0. 网上搜集国密算法标准SM1,SM2,SM3,SM4
    1. 网上找一下相应的代码和标准测试代码,在Ubuntu中分别用gcc和gcc-arm编译
    2.四个算法的用途?
    3.《密码学》课程中分别有哪些对应的算法?
    4.提交2,3两个问题的答案
    5.提交在Ubuntu中运行国密算法测试程序的截图

    用途

    • SM1:采用该算法已经研制了系列芯片、智能 IC 卡、智能密码钥匙、加密卡、加 密
      机等安全产品,广泛应用于电子政务、电子商务及国民经济的各个应用领域(包括国家政 务
      通、警务通等重要领域)。
    • SM2算法和RSA算法都是公钥密码算法SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。随着密码技术和计算机技术的发展,目前常用的1024位RSA算法面临严重的安全威胁,我们国家密码管理部门经过研究,决定采用SM2椭圆曲线算法替换RSA算法。SM2在PBOC认证中签名和验签的使用。
    • SM3:摘要函数在密码学中具有重要的地位,被广泛应用在数字签名,消息认证,数据完整性检测等领域。
    • SM4分组密码算法是用于无线局域网和可信计算系统的专用分组密码算法,该算法的分组长度为128比特,密钥长度为128比特。SM4算法是我国制定WAPI标准的组成部分,同时也可以用于其它环境下的数据加密保护。

    《密码学》课程中分别对应的算法

    SM1:SHA-1
    SM2:ECC
    SM3:MD5
    SM4:DES

    国密算法测试程序的截图

    • SM2

    • SM3

    • SM4

    5. SM1

    实验要求

    0.注意不经老师允许不准烧写自己修改的代码
    1.参考云班课资源中“信息安全系统实验箱指导书.pdf “第一章,1.4” KEIL-MDK 中添加 Z32 SC-000 芯片库,提交安装截图
    2.参考云班课资源中“信息安全系统实验箱指导书.pdf “第一章,1.16”完成SM1加密实验,注意“打开Z32的电源开关前,按住Reboot按键不放,两次打开电源开关,Z32即可被电脑识别,进行下载调试。提交运行结果截图
    3.实验报告中分析代码

    实验步骤

    • 按照信息安全系统实验箱指导书.pdf “第一章,1.4” 的步骤在KEIL-MDK 中添加 Z32 SC-000 芯片库。
    • 按照信息安全系统实验箱指导书.pdf “第一章,1.16”完成SM1加密实验。

    代码分析

    主函数代码的执行过程为:

    1. 系统初始化,中断设置,使能所有中断;SystemInit ();
    2. 判断按键,返回 boot 条件,确认是否进行程序下载;
    if(0 == GPIO_GetVal(0))
    {
    BtApiBack(0x55555555, 0xAAAAAAAA);
    }
    
    1. 初始化 IC 卡插入检测端口 GPIO6;
    GPIO_Config(6);
    GPIO_PuPdSel(6,0); //上拉
    GPIO_InOutSet(6,1);//输入
    
    1. 串口初始化;UART_Init();
    2. LCD12864 初始化;lcd_init();
    3. 矩阵键盘初始化;KEY_Init();
    4. 液晶屏第一行显示字符串“SLE4428 实验!”。
    lcd_pos(0,0);//定位第一行
    lcd_string("SLE4428 实验!");
    

    A 段程序:
    8) 第二行显示“请插入 IC 卡”,等待卡片插入;

    lcd_pos(1,0);//定位第二行
    lcd_string("请插入 IC 卡. ");
    delay(1000);
    if(GPIO_GetVal(6)==0) break;
    lcd_pos(1,0);//定位第二行
    lcd_string("请插入 IC 卡.. ");
    delay(1000);
    if(GPIO_GetVal(6)==0) break;
    lcd_pos(1,0);//定位第二行
    lcd_string("请插入 IC 卡...");
    delay(1000);
    if(GPIO_GetVal(6)==0) break;
    
    1. SLE4428 IC 卡正确插入,第二行显示“已插入 SLE4428”,卡片插入错
      误则第二行显示“卡不正确 ”;
    if(SLE4428_InitAndRST(2)!=0xFFFFFFFF) //收到 ATR
    {
    lcd_pos(1,0);//定位第二行
    lcd_string("已插入 SLE4428");
    }
    else
    {
    lcd_pos(1,0);//定位第二行
    lcd_string("卡不正确 ");
    SLE4428_Deactivation(); //下电,去激活
    delay(1000);
    goto A;
    }
    
    1. IC 卡正确插入,则显示“用户代码为:XXXXXXXXXX”(XXXXXXXXXX 代表
      用户的代码),等待按下键盘的“A”键;
    lcd_pos(2,0);//定位第三行
    lcd_string("用户代码为:");
    SLE4428_ReadData(0x15,UserCode,6); //读取用户代码
    lcd_pos(3,0);//定位第四行
    for(UINT8 i=0;i<6;i++)
    lcd_Hex(UserCode[i]) ;
    while(KEY_ReadValue()!='A'); //等待 A 键按下
    lcd_wcmd(0x01);//清屏
    
    1. 按下“A”键,显示屏第一行显示“按-A 键校验密码”,第二行显示“校
      验 0xFF,0xFF”,等待“A”键按下。
    lcd_pos(0,0);//定位第一行
    lcd_string("按-A 键校验密码");
    lcd_pos(1,0);//定位第二行
    lcd_string("校验 0xFF,0xFF");
    while(KEY_ReadValue()!='A'); //等待 A 键按下
    
    1. 按下“A”键,若校验密码正确,显示屏第三行显示“校验成功”,否则
      显示“校验失败”,第四行显示剩余密码验证机会次数“剩余机会: X
      次”(X 初始最大为 8,最小 0,当校验密码错误验证一次后,X 减 1),
      等待“A”键按下;
    lcd_pos(2,0);//定位第三行
    if(SLE4428_PassWord(0xFF,0xFF)==1) 
    lcd_string("校验成功");
    else
    {lcd_string("校验失败"); return 0;}
    lcd_pos(3,0);//定位第四行
    switch(SLE4428_ReadByte(0x03fd)) //查看剩余密码验证机会
    ...
    while(KEY_ReadValue()!='A'); //等待 A 键按下
    

    B 段程序:
    13) 按下“A”键,显示屏第一行显示“加密解密试验”,第二、三行分别显
    示“1.加密”、“2.解密”两个选项。等待按键按下:如果“1”按下,
    跳转至加密程序段,如果“2”按下,跳转至解密程序段;
    加密程序段:

    lcd_pos(0,0);//定位第一行
    lcd_string("加密解密实验");
    lcd_pos(1,0);//定位第二行
    lcd_string("1.加密");
    lcd_pos(2,0);//定位第三行
    lcd_string("2.解密")
    do
    {
    C=KEY_ReadValue();
    }
    while(C!='1'&&C!='2'); //等待 1 或 2 键按下
    lcd_wcmd(0x01);//清屏
    if(C=='1') goto jiami;
    else if(C=='2') goto jiemi;
    else ;
    
    1. 第一行显示“观看串口调试助手”,第二行显示“A 键确认加密”,通过
      串口发送字符串“将加密以下数据:”并将加密前的数据发送至 PC 机,
      发送换行,串口继续发送“加密密钥:”并将加密密钥数组发送至 PC 机,
      发送完毕等待“A”键按下;
    lcd_pos(0,0);//定位第一行
    lcd_string("观看串口调试助手");
    lcd_pos(1,0);//定位第二行
    lcd_string("A 键确认加密");
    UART_SendString("将加密以下数据:
    ");
    for(UINT8 i=0;i<16;i++)
    {
    UART_SendHex(jiamiqian[i]);
    }
    UART_SendString("
    ");
    UART_SendString("加密密钥:
    ");
    for(UINT8 i=0;i<16;i++)
    {
    UART_SendHex(jiamimiyue[i]);
    }
    UART_SendString("
    ");
    while(KEY_ReadValue()!='A'); //等待 A 键按下
    
    1. 按下“A”键后,SM1 初始化;
      SM1_Init(jiamimiyue); //SM1 初始化
    2. 进行 SM1 加密;
      SM1_Crypto(jiamiqian, 16, 0, 0, 0,jiamihou); //进行加密
    3. 关闭 SM1 加密安全模块;
      SM1_Close(); //关闭安全模块
    4. 通过串口发送字符串“加密后的数据:”并将加密后的数据发送至 PC 机,
      换行,在液晶屏第三行显示“加密完成”,第四行显示“A 键存入 IC 卡”,
      等待“A”键按下。当“A”键按下后,向 SLE4428 IC 卡加密后的数据,
      通过串口向 PC 发送“已将数据写入 IC 卡。”跳转至 B 段程序。
      解密程序段:
    UART_SendString("加密后的数据:
    ");
    for(UINT8 i=0;i<16;i++)
    {
    UART_SendHex(jiamihou[i]);
    }
    UART_SendString("
    ");
    lcd_pos(2,0);//定位第三行
    lcd_string("加密完成");
    lcd_pos(3,0);//定位第四行
    lcd_string("A 键存入 IC 卡");
    while(KEY_ReadValue()!='A'); //等待 A 键按下
    for(UINT8 i=0;i<16;i++)
    {
    SLE4428_Write_Byte(0x20+i,jiamihou[i]);//设置 IC 卡 0x20 地址为存储
    加密数据的地址
    }
    UART_SendString("已将数据写入 IC 卡。
    ");
    UART_SendString("
    ");
    goto B;
    
    1. 屏幕第一行显示“观看串口调试助手”,第二行显示“A 键读取 IC 卡数
      据”,当“A”键按下,读取 SLE4428 IC 卡解密前数据,通过串口发送
      “读取的数据为:”至 PC 机并发送解密前的数据至 PC 机。在显示屏的
      四行分别显示“读取成功”,“选择密钥解密”,“1.正确密钥”,“错误密
      钥”,等待按键“1”或“2”按下。如果“1”按下,解密密钥为正确的
      密钥,“2”按下,解密密钥为错误的密钥,然后通过串口发送“将使用
      以下密钥进行解密:”并将相应的解密密钥数据发送至 PC 机。发送完毕,
      第一行显示“A 键确认解密”,等待“A”键按下。
    lcd_pos(0,0);//定位第一行
    lcd_string("观看串口调试助手");
    lcd_pos(1,0);//定位第二行
    lcd_string(" A 键读取 IC 卡数据");
    while(KEY_ReadValue()!='A'); //等待 A 键按下
    SLE4428_ReadData(0x20,jiemiqian,16);
    UART_SendString("读取的数据为:
    ");
    for(UINT8 i=0;i<16;i++)
    {
    UART_SendHex(jiemiqian[i]);
    }
    UART_SendString("
    ");
    lcd_wcmd(0x01);//清屏
    lcd_pos(0,0);//定位第一行
    lcd_string("读取成功");
    lcd_pos(1,0);//定位第二行
    lcd_string("选择密钥解密:");
    lcd_pos(2,0);//定位第三行
    lcd_string("1.正确密钥");
    lcd_pos(3,0);//定位第四行
    lcd_string("2.错误密钥");
    do
    {
    C=KEY_ReadValue();
    }
    while(C!='1'&&C!='2'); //等待 1 或 2 键按下
    lcd_wcmd(0x01);//清屏
    if(C=='1')
    {
    for(UINT8 i=0;i<16;i++)
    jiemimiyue[i] = jiamimiyue[i];
    }
    else if(C=='2')
    {
    for(UINT8 i=0;i<16;i++)
    jiemimiyue[i] = cuowumiyue[i];
    }
    else ;
    UART_SendString("将使用以下密钥进行解密:
    ");
    for(UINT8 i=0;i<16;i++)
    {
    UART_SendHex(jiemimiyue[i]);
    }
    UART_SendString("
    ");
    lcd_pos(0,0);//定位第一行
    lcd_string("A 键确认解密");
    while(KEY_ReadValue()!='A'); //等待 A 键按下
    
    1. 按下“A”键后,SM1 初始化;
      SM1_Init(jiemimiyue); //SM1 初始化
    2. 进行 SM1 解密;
      SM1_Crypto(jiemiqian, 16, 1, 0, 0,jiemihou); //进行解密
    3. 关闭 SM1 解密安全模块;
      SM1_Close(); //关闭安全模块
    4. 显示屏第二行显示“解密完成”,第三行显示“A 键返回”,通过串口将
      “解密后的数据为:”和解密后的数据发送至 PC 机,发送完毕等待“A”
      键按下,若“A”键按下,跳转至 B 段程序。
    lcd_pos(1,0);//定位第二行
    lcd_string("解密完成");
    lcd_pos(2,0);//定位第三行
    lcd_string("A 键返回");
    UART_SendString("解密后的数据为:
    ");
    for(UINT8 i=0;i<16;i++)
    {
    UART_SendHex(jiemihou[i]);
    }
    UART_SendString("
    ");
    UART_SendString("
    ");
    while(KEY_ReadValue()!='A'); //等待 A 键按下
    goto B;
    
    1. 断电,去除 IC 卡激活,实验结束。
      SLE4428_Deactivation(); //下电,去激活,实验结束

    实验结果

  • 相关阅读:
    Django_jinja2
    css画太极
    python 自己实现map
    python 比赛 组合问题
    python 找素数
    如何快速掌握一门新技术/语言/框架
    jQuery常用事件-思维导图
    jQuery常用函数-思维导图
    jQuery选择器汇总-思维导图
    3.git版本控制-管理修改、撤销、删除
  • 原文地址:https://www.cnblogs.com/pingcpingcuo/p/7787450.html
Copyright © 2011-2022 走看看