51单片机--AT24C02数据存储

简介: 51单片机--AT24C02数据存储

存储器的介绍

存储器是计算机系统中的一种重要设备,用于存储程序和数据,它可以通过电子、磁性介质等技术来记录和保持数据。在这里,主要介绍的是随机存储器(RAM)和只读存储器(ROM)。

随机存储器(Random Access Memory,RAM)是一种可以读取和写入数据的存储器。 它的特点是可以随机访问其中的任意位置,并且读写速度较快。RAM通常由电子芯片制成,用于临时存储计算机运行时所需的程序和数据。

RAM可以分为静态随机存储器(Static RAM,SRAM)和动态随机存储器(Dynamic RAM,DRAM)两种类型。

静态随机存储器(SRAM):SRAM使用了触发器电路来存储数据,每个存储单元由多个触发器组成,具有较高的稳定性和快速的读写速度。由于使用了更多的电子元件,SRAM的密度较低,成本相对较高。它常用于高速缓存(Cache)等需要快速访问的场景。

动态随机存储器(DRAM):DRAM使用了电容器和开关电路来存储数据,每个存储单元由一个电容器和一个访问开关组成。由于电容器的电荷会随时间衰减,DRAM需要周期性地进行刷新操作来保持数据的稳定。DRAM具有较高的存储密度和较低的成本,但相对而言读写速度较慢。它常用于主存储器(内存)等需要较大容量的场景。

只读存储器(Read-Only Memory,ROM)是一种只能读取数据而无法写入或修改数据的存储器。ROM中的数据在制造时被写入,通常用于存储固化的程序代码、系统设置、固件等不需要频繁修改的数据。ROM的数据在断电后依然可以保持,具有非易失性。

ROM根据存储数据的方式可以分为多种类型,如只读存储器(ROM)、可编程只读存储器(PROM)、可擦除可编程只读存储器(EPROM)和电可擦除可编程只读存储器(EEPROM)等。这些ROM的特点是在制造或编程后,其存储的数据无法修改或只能经过特定方式修改。对于我们这款单片机来说,AT24C02就是E2PROM,电可擦除可编程ROM,可以通过编程来进行存储数据,数据根据具体的地址存储;断电之后,他还会保存在地址中,当我们需要读取时,可以通过相对应的地址取出数据;


AT24C02

AT24C02是一种2K位(256字节)的串行EEPROM(Electrically Erasable Programmable Read-Only Memory),常用于51单片机系统中的数据存储。

AT24C02采用I2C总线协议进行通信,通过两根线路(SCL和SDA)与单片机进行连接。它具有8位的设备地址,可通过引脚A0、A1和A2进行编程设置,从而允许多个AT24C02共存在同一I2C总线上。

对于AT24C02,在读写速度上支持400kHz标准模式,数据保存能力可达10年之久,而且有写入保护,可以防止误操作;

在单片机系统中,可以使用AT24C02来存储各种数据,如配置参数、校准数据、历史记录等。单片机可以使用相应的I2C库函数来向AT24C02写入或读取数据,以实现对其存储空间的读写操作。


需要注意的是,AT24C02是一种非易失性存储器,即使在断电情况下也可以保持存储的数据。因此,它适用于需要长期保存数据的应用场景。

上图时AT24C02的内部结构框图,红色部分为它的存储位置;

I2C总线

I2C,全称为Inter-Integrated Circuit,是一种串行通信协议,用于在电子设备之间进行数字数据传输。它由飞利浦半导体(现在的NXP半导体)公司在1980年代开发,并于1982年发布。I2C采用了两根导线(一根用于传输数据,另一根用于传输时钟信号)来连接设备,这使得多个设备可以通过同一组导线进行通信。

I2C协议有两个重要的角色:主设备(Master)和从设备(Slave)。主设备负责控制通信的序列和时钟信号的生成,而从设备则被动响应主设备的指令。


I2C支持多主设备和多从设备的连接,每个设备都有一个唯一的地址标识。主设备可以向从设备发送数据或者接收从设备的数据。在传输数据时,数据被分为多个字节,每个字节都会被从设备确认。

在51单片机中,AT24C02通过I2C总线与单片机进行数据通信;

通过I2C总线,单片机可以发送读取或写入命令给AT24C02,然后AT24C02会响应相应的操作。例如,单片机可以向AT24C02发送写入命令,并指定要写入的地址和数据,AT24C02会将数据写入指定地址的存储单元。而当单片机需要读取AT24C02中的数据时,它可以向AT24C02发送读取命令和要读取的地址,然后AT24C02会返回相应的数据给单片机。


I2C时序结构

I2C总线的时序结构一般分为6部分:起始条件、终止条件、发送数据、接收数据、接收应答和发送应答;

起始条件主设备通过SCL(串行时钟线)保持高电平的同时,将SDA(串行数据线)由高电平转换为低电平,表示要启动一次通信

代码:

void I2C_Start()
{
  I2C_SDA=1;//表示SCL高电平之前SDA就是高电平了
  I2C_SCL=1;//SCL高电平期间
  I2C_SDA=0;//SDA降为低电平
  I2C_SCL=0;//SCL回到低电平
}


发送一个字节:SCL低电平期间,主设备将数据位依次放到SDA线上(高位在前),然后拉高SCL,在SCL上升沿时从设备将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节;

代码:

void I2C_SendByte(unsigned char byte)
{
  unsigned char i;
  for(i=0;i<8;i++)
  {
    I2C_SDA=byte&(0x80>>i);//先将数据放到SDA上
    I2C_SCL=1; //SCL为上升沿时,从设备读取数据
    I2C_SCL=0;
  }
}

接收一个字节:SCL低电平期间,从设备将数据位依次放到SDA线上(高位在前),然后拉高SCL,主设备将在SCL上升沿期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA

代码:

unsigned char I2C_ReceiveByte()
{
  unsigned char i,byte=0x00;
  I2C_SDA=1; //释放SDA,规定置于高电平
  for(i=0;i<8;i++)
  {
  //在SCL上升沿期间,主设备读取SDA的数据,
    I2C_SCL=1;
    if(I2C_SDA){byte|=(0x80>>i);
    //通过判断SDA位的数据是否为1,进行位赋值
    //为1执行条件内容,将位变为1,为0则不变,仍为0;
    I2C_SCL=0;
  }
  return byte;
}


发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答 ;

代码:

void I2C_SendAck(unsigned char AckBit)
{
  I2C_SDA=AckBit;
  //SDA发送应答,应答或者不应答
  I2C_SCL=1;
  //在SCL上升沿期间,从设备接收主设备发送应答
  I2C_SCL=0;
}

接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA);主设备发送一个高电平的SDA并保持SCL线为高电平,使得从设备可以拉低SDA线来应答。如果接收方正确收到数据,它会发一个低电平的SDA信号应答;

代码:

unsigned char I2C_ReceiveAck()
{
  unsigned char AckBit;
  I2C_SDA=1; //释放SDA
  I2C_SCL=1;  //在SCL高电平期间
  AckBit=I2C_SDA; //接收SDA的应答数据
  I2C_SCL=0; 
  return AckBit;
}

终止条件:将SCL线保持高电平的同时,将SDA线由低电平转换为高电平,表示通信结束;

代码:

void I2C_Stop()
{
  I2C_SDA=0;// 在SCL高电平之前SDA就为低电平
  I2C_SCL=1; //SCL处于高电平期间
  I2C_SDA=1;
}


AT24C02数据帧

数据帧是在通信中用于传输数据的基本单元

对于AT24C02,数据帧包括一个地址字节和一个或多个数据字节

上图为AT24C02数据帧的格式:


  1. 起始位(Start Bit):数据传输开始时,为低电平。
  2. 7位地址(Address):表示要访问的内存地址。AT24C02共有256个地址,即0x00到0xFF。
  3. R/W位(Read/Write Bit):用于选择读(高电平)或写(低电平)操作。
  4. 数据字节(Data Byte):在写操作中,数据字节表示要写入到指定地址的数据。在读操作中,数据字节表示从指定地址读取到的数据。
  5. 应答位(Acknowledge Bit):用于发送方向接收方确认数据传输的成功。

而这些数据帧的格式是遵循I2C总线的通信协议的;所以我们只需要运用I2O的时序结构,将它们对应进AT24C02的数据帧即可;


对于读操作,数据帧的格式如下:

起始位 + 7位地址 + R/W位(设置为高电平)+ 应答位 + 存储的地址标识 + 应答位 + 数据字节 + 应答位 + 起始位 +读取数据+ 应答位 + 停止位


对于写操作,数据帧的格式如下:

起始位 + 7位地址 + R/W位(设置为低电平)+ 应答位 + 存储的地址标识 + 应答位 + 数据字节 + 应答位 + 停止位


代码(利用到I2C总线时序写的代码):


写入字节:

#define AT24C02_ADDRESS 0xA0 //AT24C02的写操作地址
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
  I2C_Start(); //起始条件
  I2C_SendByte(AT24C02_ADDRESS); //主设备发送AT24C02的地址
  I2C_ReceiveAck(); //从设备接收应答(确认地址)
  I2C_SendByte(WordAddress); // 主设备向从设备发送地址
  I2C_ReceiveAck(); //从设备接收应答
  I2C_SendByte(Data); //主设备向从设备发送数据
  I2C_ReceiveAck(); //从设备接收应答
  I2C_Stop(); //终止条件
}


读取字节:

unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
  unsigned char Data;
  I2C_Start(); //起始条件
  I2C_SendByte(AT24C02_ADDRESS); //主设备发送AT24C02的地址
  I2C_ReceiveAck();//从设备接收应答(确认地址)
  I2C_SendByte(WordAddress);// 主设备向从设备发送要读取字节的地址
  I2C_ReceiveAck();//从设备接收应答
  //以上操作完成了主设备向从设备要读取字节的地址的操作,是主设备
  //告诉从设备的地址
  //下面操作是从设备向主设备发送对应的字节操作,主设备从写入变
  //为读取,所以要重新开始定起始条件
  I2C_Start(); //起始条件
  I2C_SendByte(AT24C02_ADDRESS|0x01); //主设备发送AT24C02的读取地址
  I2C_ReceiveAck(); //从设备接收应答(确认地址
  Data=I2C_ReceiveByte();//读取从设备对应地址的数据字节
  I2C_SendAck(1); //主设备发送应答(地址对应正确发送回应给从设备)
  I2C_Stop(); //终止条件
  return Data;
}


AT24C02数据存储实例

写一个能通过独立按键让数字逐渐增加或者减少的程序,并且让这个程序能记住某一个数字,断电或者置0的时候可以恢复到这个数字

代码:

Delay.h

#ifndef __DELAY_H__
#define __DELAY_H__
//获取一个毫秒为单位的延迟函数,填入对应数字表示延迟多少毫秒
void Delay(unsigned int xms);
#endif


Delay.c

void Delay(unsigned int xms)
{
  unsigned char i, j;
  while(xms--)
  {
    i = 2;
    j = 239;
    do
    {
      while (--j);
    } while (--i);
  }
}


Key.h

#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif


Key.c

#include <REGX52.H>
#include "Delay.h"
/**
  * @brief  获取独立按键键码
  * @param  无
  * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0
  */
unsigned char Key()
{
  unsigned char KeyNumber=0;
  if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
  if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
  if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
  if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
  return KeyNumber;
}


LCD1602.h

#ifndef __LCD1602_H__
#define __LCD1602_H__
//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
#endif

LCD1602.c

#include <REGX52.H>
//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
  unsigned char i, j;
  i = 2;
  j = 239;
  do
  {
    while (--j);
  } while (--i);
}
/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
  LCD_RS=0;
  LCD_RW=0;
  LCD_DataPort=Command;
  LCD_EN=1;
  LCD_Delay();
  LCD_EN=0;
  LCD_Delay();
}
/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
  LCD_RS=1;
  LCD_RW=0;
  LCD_DataPort=Data;
  LCD_EN=1;
  LCD_Delay();
  LCD_EN=0;
  LCD_Delay();
}
/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
  if(Line==1)
  {
    LCD_WriteCommand(0x80|(Column-1));
  }
  else if(Line==2)
  {
    LCD_WriteCommand(0x80|(Column-1+0x40));
  }
}
/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
  LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
  LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
  LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
  LCD_WriteCommand(0x01);//光标复位,清屏
}
/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
  LCD_SetCursor(Line,Column);
  LCD_WriteData(Char);
}
/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
  unsigned char i;
  LCD_SetCursor(Line,Column);
  for(i=0;String[i]!='\0';i++)
  {
    LCD_WriteData(String[i]);
  }
}
/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
  unsigned char i;
  int Result=1;
  for(i=0;i<Y;i++)
  {
    Result*=X;
  }
  return Result;
}
/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
  unsigned char i;
  LCD_SetCursor(Line,Column);
  for(i=Length;i>0;i--)
  {
    LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
  }
}
/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
  unsigned char i;
  unsigned int Number1;
  LCD_SetCursor(Line,Column);
  if(Number>=0)
  {
    LCD_WriteData('+');
    Number1=Number;
  }
  else
  {
    LCD_WriteData('-');
    Number1=-Number;
  }
  for(i=Length;i>0;i--)
  {
    LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
  }
}
/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
  unsigned char i,SingleNumber;
  LCD_SetCursor(Line,Column);
  for(i=Length;i>0;i--)
  {
    SingleNumber=Number/LCD_Pow(16,i-1)%16;
    if(SingleNumber<10)
    {
      LCD_WriteData(SingleNumber+'0');
    }
    else
    {
      LCD_WriteData(SingleNumber-10+'A');
    }
  }
}
/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
  unsigned char i;
  LCD_SetCursor(Line,Column);
  for(i=Length;i>0;i--)
  {
    LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
  }
}


AT24C02.h

#ifndef __KEY_H__
#define __KEY_H__
void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);
#endif


AT24C02.c

#include <REGX52.H>
#include"I2C.h"
#define AT24C02_ADDRESS 0xA0
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();
}
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;
}


I2C.h

#ifndef __KEY_H__
#define __KEY_H__
void I2C_Start();//¶ÔI2C³õʼ»¯
void I2C_Stop();//¶ÔI2CÄ©¶Ë
void I2C_SendByte(unsigned char byte);//I2CÖ÷»ú·¢ËÍÒ»¸ö×Ö½Ú
unsigned char I2C_ReceiveByte();  //½ÓÊÕÒ»¸ö×Ö½Ú
void I2C_SendAck(unsigned char AckBit);  //·¢ËÍÓ¦´ð
unsigned char I2C_ReceiveAck();   //½ÓÊÕÓ¦´ð
#endif


I2C.c

#include <REGX52.H>
sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;
void I2C_Start()
{
  I2C_SDA=1;
  I2C_SCL=1;
  I2C_SDA=0;
  I2C_SCL=0;
}
void I2C_Stop()
{
  I2C_SDA=0;
  I2C_SCL=1;
  I2C_SDA=1;
}
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;
  }
}
unsigned char I2C_ReceiveByte()
{
  unsigned char i,byte=0x00;
  I2C_SDA=1;
  for(i=0;i<8;i++)
  {
    I2C_SCL=1;
    if(I2C_SDA){byte|=(0x80>>i);}
    I2C_SCL=0;
  }
  return byte;
}
void I2C_SendAck(unsigned char AckBit)
{
  I2C_SDA=AckBit;
  I2C_SCL=1;
  I2C_SCL=0;
}
unsigned char I2C_ReceiveAck()
{
  unsigned char AckBit;
  I2C_SDA=1;
  I2C_SCL=1;
  AckBit=I2C_SDA;
  I2C_SCL=0;
  return AckBit;
}


main.c

#include <REGX52.H>
#include"AT24C02.h"
#include"I2C.h"
#include"LCD1602.h"
#include"Delay.h"
unsigned char KeyNum;
unsigned short Num;
void main()
{
  LCD_Init();
  LCD_ShowNum(1,1,Num,5);
  while(1)
  {
    KeyNum=Key();
    if(KeyNum==1)  //K1按键,Num自增
    {
      Num++;
      LCD_ShowNum(1,1,Num,5);
    }
    if(KeyNum==2)   //K2按键,Num自减
    {
      Num--;
      LCD_ShowNum(1,1,Num,5);
    }
    if(KeyNum==3)  //K3按键,向AT24C02写入数据
    {
      AT24C02_WriteByte(0,Num%256);
      Delay(5);
      AT24C02_WriteByte(1,Num/256);
      Delay(5);
      LCD_ShowString(2,1,"Write OK");
      Delay(1000);
      LCD_ShowString(2,1,"        ");
    }
    if(KeyNum==4)  //K4按键,从AT24C02读取数据
    {
      Num=AT24C02_ReadByte(0);
      Num|=AT24C02_ReadByte(1)<<8;
      LCD_ShowNum(1,1,Num,5);
      LCD_ShowString(2,1,"Read OK ");
      Delay(1000);
      LCD_ShowString(2,1,"        ");
    }
  }
}


对于无符号的short类型数字,范围是0~65535,对应的有两个字节,所以写入数据要分别两部分,前8位和后8位,存储的地址可由自己选取,但在写入多个数据之间要延迟5ms,否则将会报错

相关文章
|
1月前
|
存储 监控 芯片
单片机的扩展结构
单片机的扩展结构
72 2
|
1月前
|
物联网 芯片
STC51单片机-应用系统并行扩展电路设计(存储器扩展)-物联网应用系统设计
STC51单片机-应用系统并行扩展电路设计(存储器扩展)-物联网应用系统设计
49 0
|
Android开发 异构计算
nios ii FIFO读取FPGA数据交互实验1
nios ii FIFO读取FPGA数据交互实验1
214 0
nios ii FIFO读取FPGA数据交互实验1
|
9月前
|
存储 人工智能 安全
单片机特性
单片机特性
70 0
|
11月前
|
存储 算法 计算机视觉
m基于FPGA的各类存储器纯Verilog实现,包含testbench,包括RAM,SRAM等
m基于FPGA的各类存储器纯Verilog实现,包含testbench,包括RAM,SRAM等
344 2
|
存储 传感器 Linux
(9)存储和EEPROM管理
(9)存储和EEPROM管理
146 0
|
存储 芯片
STM32入门开发: 采用IIC硬件时序读写AT24C08(EEPROM)
STM32入门开发: 采用IIC硬件时序读写AT24C08(EEPROM)
403 0
STM32入门开发: 采用IIC硬件时序读写AT24C08(EEPROM)
|
传感器 存储 编解码
STM32入门开发: 编写DS18B20温度传感器驱动(读取环境温度、支持级联)
STM32入门开发: 编写DS18B20温度传感器驱动(读取环境温度、支持级联)
1198 0
STM32入门开发: 编写DS18B20温度传感器驱动(读取环境温度、支持级联)
RK3399平台开发系列讲解(高速设备驱动篇)6.54、PCIe对PCI配置空间的扩展
RK3399平台开发系列讲解(高速设备驱动篇)6.54、PCIe对PCI配置空间的扩展
302 0
RK3399平台开发系列讲解(高速设备驱动篇)6.54、PCIe对PCI配置空间的扩展
|
芯片
【全栈计划 —— 单片机】——Part_03 使用放大电路或拓展芯片解决GPIO的输出电流不足够支持驱动设备的问题(1)
【全栈计划 —— 单片机】——Part_03 使用放大电路或拓展芯片解决GPIO的输出电流不足够支持驱动设备的问题(1)
188 0
【全栈计划 —— 单片机】——Part_03 使用放大电路或拓展芯片解决GPIO的输出电流不足够支持驱动设备的问题(1)