• 51单片机入门_江协科技_27~28_OB记录的自学笔记_AT24C02数据存储&秒表


    27. AT24C02(I2C总线)

    • 27.1. 存储器介绍
      在这里插入图片描述

    • 27.2. 存储器简化模型介绍,存储原理
      在这里插入图片描述

    • 27.3. AT24C02介绍
      •AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息
      •存储介质:E2PROM
      •通讯接口:I2C总线
      •容量:256字节

    在这里插入图片描述

    • 27.4. AT24C02引脚及应用电路,VCC接电源,A0~A2和GND接地,WP写保护接地,上拉电阻在单片机接口位置已经接好,开发板原理图中就不需要接了
      在这里插入图片描述

    • 27.5. AT24C02内部结构框图,EEPROM为存储单元网格,DEC译码器,RECOVERY数据擦除,
      在这里插入图片描述

    • 27.6. I2C总线介绍
      •I2C总线(Inter IC BUS)是由Philips公司开发的一种通用数据总线(通信协议,实现多设备通信,并标准规范化数据通信)
      •两根通信线:SCL(Serial Clock)、SDA(Serial Data)
      •同步、半双工,带数据应答
      •通用的I2C总线,可以使各种设备的通信标准统一,对于厂家来说,使用成熟的方案可以缩短芯片设计周期、提高稳定性,对于应用者来说,使用通用的通信协议可以避免学习各种各样的自定义协议,降低了学习和应用的难度。(标准和专利付费),下面是I2C相关的附件设备,左边第一个12864的小屏幕,中间是DS3231的时钟芯片,精度更高,右侧是陀螺仪。

    在这里插入图片描述

    • 27.7. I2C电路规范
      •所有I2C设备的SCL连在一起,SDA连在一起
      •设备的SCL和SDA均要配置成开漏输出模式(单片机IO口为弱上拉模式,可以想象成输出口带上拉电阻,输出电流受限,开漏模式则是在上述基础上取消上拉电阻,无输出的时候IO口容易受外界干扰,电压不稳定)
      •SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右(有标准规定,什么速率接什么电阻)
      •开漏输出和上拉电阻的共同作用实现了“线与”的功能,此设计主要是为了解决多机通信互相干扰的问题(可以实现与一个设备通信的时候,其他设备处于“断开”的状态,防止通信干扰)
      在这里插入图片描述

    • 27.8. I2C时序结构(六块拼图)
      •起始条件:SCL高电平期间,SDA从高电平切换到低电平(S蓝色开始)
      •终止条件:SCL高电平期间,SDA从低电平切换到高电平(P红色结束)
      在这里插入图片描述

    • 27.9. I2C时序结构_发送一个字节_绿色S byte
      •发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节(下面SDA是连根线麻花的状态的意思是SDA初始情况不确定是0还是1,在SCL高电平(固定SDA的0或1状态),红色框是基本结构,SDA的最终状态看数据发送完毕后的状态,如果是0就是低电平,1就是高电平)
      在这里插入图片描述

    • 27.10. I2C时序结构_接收一个字节_紫色byte
      •接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
      在这里插入图片描述

    • 27.11. I2C时序结构
      •发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
      •接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
      在这里插入图片描述

    • 27.12. I2C数据帧
      •发送一帧数据(S为开始)(S:SLAVE+ADDRESS+W写,1读0写,地址前4位固定,24C02为1010,24C02芯片引脚A2,A1,A0接地0)(RA接收应答,从机应该发0)(S byte数据)(结束)
      在这里插入图片描述

      •完成任务:(上述完成)向谁发什么

    • 27.13. I2C数据帧
      •接收一帧数据:(S开始)(发送地址+R读)(RA应答0)(数据读)(主机发送应答)。。。(最后可发应答或非应答)(结束)
      在这里插入图片描述

      •完成任务:(上述完成)向谁收什么

    • 27.14. I2C数据帧
      •先发送再接收数据帧(复合格式)上述两个拼接,取消了一个P
      在这里插入图片描述

      •完成任务:向谁收指定的什么

    • 27.15. AT24C02数据帧
      •字节写:在WORD ADDRESS处写入数据DATA(发送一帧数据的变形)
      在这里插入图片描述

      •随机读:读出在WORD ADDRESS处的数据DATA(复合格式)
      在这里插入图片描述

      •AT24C02的固定地址为1010,可配置地址本开发板上为000
      所以SLAVE ADDRESS+W写为0xA0(1010 0000),SLAVE ADDRESS+R读为0xA1(1010 0001)

    • 27.16. AT24C02数据帧
      •字节写:在“字地址”处写入“数据”
      在这里插入图片描述

      •随机读:读出在“字地址”处的“数据”
      在这里插入图片描述

      27.17. 24C02手册介绍24C04地址8位不够(8位256)

    28. AT24C02数据存储&秒表

    • 28.1. 程序设计思路

      • 分为2个模块I2C.c 和AT24C02.c
      • I2C.c模块包括6个模块,开始,结束,发送字节,接受字节,发送应答,接受应答
      • AT24C02写2个数据帧,第一个数据帧在地址下写入数据,第二个在某个地址下读出;
      • main中只需要调用AT24C02函数即可;
    • 28.2. Proteus测试环境搭建
      在Proteus中搜索 24C02找到24C02C并插入;
      在这里插入图片描述

      • 笔者的例子中的接线方式如图
        在这里插入图片描述
    • 28.3. 按照编程思路,先做好I2C.c模块程序如下:

    #include 
    
    sbit I2C_SCL=P2^1;
    sbit I2C_SDA=P2^0;
    
    /**
      * @brief I2C开始	
      * @param 无
      * @retval 无
      */
    
    
    
    void I2C_Start(void)	
    {
    	I2C_SDA=1; //不清楚SDA 的初始状态,所以都置1
    	I2C_SCL=1;
    	I2C_SDA=0;
    	I2C_SCL=0;
    }
    
    /**
      * @brief I2C停止
      * @param 
      * @retval 
      */
    
    
    
    void I2C_Stop(void)	
    {
    	I2C_SDA=0; //不清楚SDA 的初始状态,所以都置1
    	I2C_SCL=1;
    	I2C_SDA=1;
    }
    
    /**
      * @brief I2C发送一个字节
      * @param Byte要发送的字节
      * @retval 无
      */
    
    
    
    void I2C_SendByte(unsigned char Byte)
    {
    	unsigned char i;
    	for(i=0;i<8;i++)
    	{
    		I2C_SDA=Byte&(0x80>>i);
    		I2C_SCL=1;				//复核芯片手册关于高低切换时间的限制;
    		I2C_SCL=0;				//所以此处无需delay;
    	} 
    }
    
    /**
      * @brief I2C接收一个字节
      * @param 无
      * @retval 接收到的一个字节数据
      */
    
    
    
    unsigned char I2C_ReceiveByte()
    {
    	unsigned char i,Byte;
    	I2C_SDA=1;
    	for(i=0;i<8;i++)
    	{
    		I2C_SCL=1;
    		if(I2C_SDA){Byte|=(0x80>>i);}
    		I2C_SCL=0;
    	}
    	return Byte;
    }
    
    /**
      * @brief I2C发送应答
      * @param AckBit应答位,0为应答,1为非应答
      * @retval 无
      */
    
    
    
    void I2C_SendAck(unsigned char AckBit)
    {
    	I2C_SDA=AckBit;
    	I2C_SCL=1;
    	I2C_SCL=0;
    }
    
    /**
      * @brief I2C接收应答位
      * @param 无	
      * @retval 接收到的应答位,0为应答,1为非应答
      */
    
    
    
    unsigned char I2C_ReceiveAck(void)
    {
    	unsigned char AckBit;
    	I2C_SDA=1;
    	I2C_SCL=1;
    	AckBit=I2C_SDA;
    	I2C_SCL=0;
    	return AckBit;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 28.4. I2C.h程序如下:
    #ifndef _I2C_H_  
    #define _I2C_H_  
    
    	void I2C_Start(void);
    	void I2C_Stop(void);
    	void I2C_SendByte(unsigned char Byte);
    	unsigned char I2C_ReceiveByte();
    	void I2C_SendAck(unsigned char AckBit);
    	unsigned char I2C_ReceiveAck(void);
    		
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 28.5. AT24C02.c的程序如下:
    #include 
    #include "I2C.h"
    
    
    #define AT24C02_ADDRESS 0xa0
    
    /**
      * @brief AT24C02 写入一个字节
      * @param WordAddress字节要写入的地址0~255,Data要写入的数据
      * @retval 无
      */
    
    
    
    void AT24C02_WriteByte(unsigned char WordAddress, Data)
    {
    
    	I2C_Start();
    	I2C_SendByte(AT24C02_ADDRESS);
    	I2C_ReceiveAck();
    	I2C_SendByte(WordAddress);
    	I2C_ReceiveAck();
    	I2C_SendByte(Data);
    	I2C_ReceiveAck();
    	I2C_Stop();
    }
    
    /**
      * @brief AT24C02读取一个字节
      * @param WordAddress 要读出的字节的地址
      * @retval 读出的数据
      */
    
    
    
    unsigned char AT24C02_ReadByte(unsigned char WordAddress)
    {
    	unsigned char Data;
    	I2C_Start();
    	I2C_SendByte(AT24C02_ADDRESS);
    	I2C_ReceiveAck();
    	I2C_SendByte(WordAddress);
    	I2C_ReceiveAck();
    	I2C_Start();
    	I2C_SendByte(AT24C02_ADDRESS|0x01);
    	I2C_ReceiveAck();
    	Data=I2C_ReceiveByte();	
    	I2C_SendAck(1);
    	I2C_Stop();	
    	
    	return Data;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 28.6. AT24C02.h的程序如下:
    #ifndef _AT24C02_H_  
    #define _AT24C02_H_  
    
    void AT24C02_WriteByte(unsigned char WordAddress, Data);
    unsigned char AT24C02_ReadByte(unsigned char WordAddress);
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 28.7. 主程序如下,在独立按键1按下的时候增加数字(最大65535),独立按键2按下的时候减小数字(最小0),按键3按下的时候,将对应的数字写入AT24C02,按键4按下的时候读出并显示之前写入的数字;
    #include 
    #include "Four_Key.h"
    #include "LCD1602.h"
    #include "AT24C02.h"
    #include "delay_xms.h"
    
    unsigned char KeyNum;
    unsigned int Num;
    
    void main()
    {
    	LCD_Init();					//LCD1602初始化
    	LCD_ShowString(1,1,"Hello");//不按按键显示Hello
    //	AT24C02_WriteByte(0,123);
    //	delay_xms(5);
    //	AT24C02_WriteByte(1,234);
    //	delay_xms(5);
    //	AT24C02_WriteByte(2,345);
    //	delay_xms(5);
    //	Data=AT24C02_ReadByte(1);
    //	LCD_ShowNum(2,1,Data,3);
    	while(1)
    	{
    		KeyNum=Four_Key();
    		if(KeyNum==1)
    		{
    			Num++;
    			LCD_ShowNum(1,1,Num,5);//数字随按键1按下释放后增加
    		}
    		if(KeyNum==2)
    		{
    			Num--;
    			LCD_ShowNum(1,1,Num,5);//数字随按键2按下释放后减小
    		}
    		if(KeyNum==3)
    		{
    			AT24C02_WriteByte(0,Num%256);
    			delay_xms(5);
    			AT24C02_WriteByte(1,Num/256);
    			delay_xms(5);
    			LCD_ShowString(2,1,"Write OK");
    			delay_xms(1000);
    			LCD_ShowString(2,1,"        ");//将数字拆分高低8位写入,写入后延时5ms
    		}	
    		if(KeyNum==4)
    		{
    			Num=AT24C02_ReadByte(0);
    			Num|=AT24C02_ReadByte(1)<<8;
    			LCD_ShowNum(1,1,Num,5);
    			LCD_ShowString(2,1,"Read OK");
    			delay_xms(1000);				//读出并显示之前写入的数字
    
    		}			
    			
    	}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 28.8. Proteus仿真和开发板测试无误
      在这里插入图片描述

    • 28.9. 新建工程AT24C02数据存储&秒表-定时器扫描按键数码管

      • 工程的编程思路:
      • 主函数main直接引用三个模块:定时器模块,独立按键模块和数码管模块
      • 但是数码管和按键扫描需用用到定时器中断,如果独立按键模块和数码管模块直接一起调用定时器模块会出错;
      • 所以需要改变写法;
      • main中写定时器中断,按键模块中写一个函数是中断函数的调用,数码管一样的思路(称为驱动函数或调用函数,让主函数每隔一段时间调用一下)
      • 反之,如果将独立按键模块与数码管显示都放在定时器模块中,则程序耦合性较高,太混乱,不利于代码管理;
      • 之前的独立按键模块是用延时函数,为了消抖在按键按下后延时20ms,松开后依旧延时20ms,如果按键不松手,按键模块在while(1)中一直循环等待,之后考虑修改为每隔20ms对按键进行扫描(同时过滤了抖动),看按键的状态,同时设立一个标志位对比按键按下前后的状态,每隔20ms进行前后标志位对比,如果标志位没有变化说明按键没有按下,否则为按下,按键不卡程序;
    • 28.10. 新建工程,程序需要实现的功能为,按下按键1,松开后秒表开始计时,再按一下1松开,秒表计时停止,按下按键2,计数清零,按下按键3,存储数据到AT24C02,按下按键4,将之前存储的数据显示在数码管上面,新建的工程中的数码管显示的模块程序为:

    • nixietube.c

    #include 			
    #include "delay_xms.h"		
    
    unsigned char Nixie_Buf[9]={0,10,10,10,10,10,10,10,10,};
    
    unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};
    
    void Nixie_SetBuf(unsigned char Location,Number)
    {
    	Nixie_Buf[Location]=Number;
    }
    
    void Nixie_Scan(unsigned char Location,Number)
    {
    	P0=0x00;//清零;
    	switch(Location)
    	{
    		case 1:P2_4=1;P2_3=1;P2_2=1;break;
    		case 2:P2_4=1;P2_3=1;P2_2=0;break;
    		case 3:P2_4=1;P2_3=0;P2_2=1;break;
    		case 4:P2_4=1;P2_3=0;P2_2=0;break;
    		case 5:P2_4=0;P2_3=1;P2_2=1;break;
    		case 6:P2_4=0;P2_3=1;P2_2=0;break;
    		case 7:P2_4=0;P2_3=0;P2_2=1;break;
    		case 8:P2_4=0;P2_3=0;P2_2=0;break;
    	}
    	P0=NixieTable[Number];//数码管消影,因为位选-段选-位选-段选,段选数据与位选穿位导致
    }
    
    void Nixie_Loop(void)
    {
    	static unsigned char i;//计次
    	Nixie_Scan(i,Nixie_Buf[i]);
    	i++;
    	if(i>=9){i=1;}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • nixietube.h的程序为:
    #ifndef _NIXIETUBE_H_
    #define _NIXIETUBE_H_
    
    void Nixie_SetBuf(unsigned char Location,Number);
    void Nixie_Scan(unsigned char Location,Number);
    void Nixie_Loop(void);
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 独立按键的模块程序Key.c程序为:
    #include 
    #include "delay_xms.h"
    
    unsigned char Key_KeyNumber;
    
    unsigned char Key(void)
    {
    	unsigned char Temp=0;  //加入中间变量,对Key_KeyNumber进行清0
    	Temp=Key_KeyNumber;
    	Key_KeyNumber=0;
    	return Temp;		
    }
    
    
    unsigned char Key_GetStatus()
    {
    	unsigned char KeyNum=0;
    	
    		if(P3_1==0){KeyNum=1;}
    		if(P3_0==0){KeyNum=2;}
    		if(P3_2==0){KeyNum=3;}
    		if(P3_3==0){KeyNum=4;}
    	
    	return KeyNum;
    }
    
    void Key_Loop(void)
    {
    	static unsigned char Now_Status,Last_Status;
    	Last_Status=Now_Status;
    	Now_Status=Key_GetStatus();
    	if(Last_Status==1 && Now_Status==0){Key_KeyNumber=1;}
    	if(Last_Status==2 && Now_Status==0){Key_KeyNumber=2;}
    	if(Last_Status==3 && Now_Status==0){Key_KeyNumber=3;}
    	if(Last_Status==4 && Now_Status==0){Key_KeyNumber=4;}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • Key.h的程序为:
    #ifndef _KEY_H_ 
    #define _KEY_H_  
    
    	 unsigned char Key();
    	 void Key_Loop();
    	 
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • main.c主函数程序为:
    #include 
    #include "TimeR0.h"
    #include "Key.h"
    #include "nixietube.h"
    #include "delay_xms.h"
    #include "AT24C02.h"
    
    unsigned char KeyNum;
    unsigned char Min,Sec,mSec;
    unsigned char RunFlag;
    
    void main()
    {
    	TimeR0_Init();
    	while(1)
    	{
    		KeyNum=Key();
    		if(KeyNum==1)
    		{
    			RunFlag=!RunFlag;
    		}
    		if(KeyNum==2)
    		{
    			Min=0;
    			Sec=0;
    			mSec=0;
    		}	
    		if(KeyNum==3)
    		{
    			AT24C02_WriteByte(0,Min);
    			delay_xms(5);
    			AT24C02_WriteByte(1,Sec);
    			delay_xms(5);
    			AT24C02_WriteByte(2,mSec);
    			delay_xms(5);			
    		}
    		if(KeyNum==4)
    		{
    		Min=AT24C02_ReadByte(0);
    		Sec=AT24C02_ReadByte(1);
    		mSec=AT24C02_ReadByte(2);			
    		}
    		
    			Nixie_SetBuf(1,Min/10);
    			Nixie_SetBuf(2,Min%10);
    			Nixie_SetBuf(3,11);
    			Nixie_SetBuf(4,Sec/10);
    			Nixie_SetBuf(5,Sec%10);
    			Nixie_SetBuf(6,11);
    			Nixie_SetBuf(7,mSec/10);
    			Nixie_SetBuf(8,mSec%10);
    	}
    }
    
    void Sec_Loop(void)
    {
    	mSec++;
    	if(mSec>=100)
    	{
    		mSec=0;
    		Sec++;
    		if(Sec>=60)
    		{
    			Sec=0;
    			Min++;
    			if(Min>=60)
    			{
    				Min=0;
    			}
    		}
    	}
    }
    
    
    void TimeR0_Routine() interrupt 1 //中断子函数
    {
    	static unsigned int T0Count1,T0Count2,T0Count3; //设置静态子函数用T0Count,防止T0Count丢失
    	TL0=0x18;					 //设置定时初始值
    	TH0=0xFC;					 //设置定时初始值
    	T0Count1++;
    	if(T0Count1>=1000)
    	{
    		T0Count1=0;
    		Key_Loop();
    	}
    	T0Count2++;
    	if(T0Count2>=2)
    	{
    		T0Count2=0;
    		Nixie_Loop();
    	}
    	T0Count3++;
    	if(T0Count3>=10)
    	{
    		T0Count3=0;
    		Sec_Loop();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • Proteus仿真
      在这里插入图片描述
  • 相关阅读:
    Vue-Router学习记录
    大学阶段总结
    【UE】UMG通信的三种方法
    MyISAM和innoDB两种引擎的对比
    UniApp 中 nvue 盒模型入门
    Linux 命令:PS(进程状态)
    [Python]语音识别媒体中的音频到文本
    redis 数据结构(二)
    壳聚糖-聚乙二醇-羟基|羟基-PEG-壳聚糖|Chitosan-PEG-OH
    从handle得到GraphicBuffer
  • 原文地址:https://blog.csdn.net/BRUCE201902/article/details/137678405