单片机第七周重制版

AD/DA 与外设控制

1. 硬件地址与控制字速查表

以下地址/控制字用于函数调用参数或外设控制:

设备名称 类型 控制字/指令 (Hex) 说明
光敏电阻 AD输入 0x41 PCF8591 通道 1 (AIN1)
滑动变阻器 AD输入 0x43 PCF8591 通道 3 (AIN3)
继电器 数字输出 0x10 需配合锁存器/译码器使用
蜂鸣器 数字输出 0x40 需配合锁存器/译码器使用

2. I2C 驱动代码 (PCF8591)

AD 读取函数 (模数转换)

用于读取传感器(如光敏电阻、滑动变阻器)的电压值。

  • 输入参数 addr: 对应上方表格中的 0x41 (光敏) 或 0x43 (变阻器)。

  • 返回值: 读取到的 8位 数据 (0-255)。

C

unsigned char Ad_Read(unsigned char addr)
{
    unsigned char temp;
    IIC_Start();
    IIC_SendByte(0x90);   // 发送设备写地址 (PCF8591)
    IIC_WaitAck();
    IIC_SendByte(addr);   // 发送控制字节 (如 0x41 或 0x43)
    IIC_WaitAck();
    
    IIC_Start();          // 重启 I2C 总线
    IIC_SendByte(0x91);   // 发送设备读地址
    IIC_WaitAck();
    temp = IIC_RecByte(); // 读取数据
    IIC_SendAck(1);       // 发送非应答 (NACK),结束读取
    IIC_Stop();
    
    return temp;
}

DA 写入函数 (数模转换)

用于输出模拟电压(例如控制 LED 亮度或波形输出)。

  • 注意: 此处函数参数名为 addr,但实际逻辑中它代表要写入的数据值 (Data/Voltage),而非地址。

  • 固定配置: 代码中硬编码了 0x41,表示开启 DAC 输出并允许模拟输入通道 1。

C

void Da_Write(unsigned char addr) // 注意:此处的 addr 实为要输出的电压数据
{
    IIC_Start();
    IIC_SendByte(0x90);   // 发送设备写地址 (PCF8591)
    IIC_WaitAck();
    IIC_SendByte(0x41);   // 发送控制字节 (开启 DAC 输出)
    IIC_WaitAck();
    IIC_SendByte(addr);   // 发送 DAC 数据值 (0-255)
    IIC_WaitAck();
    IIC_Stop();
}

3. 关键逻辑说明

  1. I2C 时序:

    • 读取流程:StartWrite Addr(0x90)Control ByteRestartRead Addr(0x91)Read DataStop

    • IIC_SendAck(1):在读取最后一个字节后,主机通常发送非应答(NACK,通常逻辑为1)来通知从机释放总线。

  2. PCF8591 控制字:

    • 0x41: 二进制 0100 0001

      • Bit 6 = 1 (允许模拟电压输出/DAC Enable)。

      • Bit 0-1 = 01 (选择通道 1/光敏电阻)。

    • 0x43: 二进制 0100 0011

      • Bit 6 = 1 (允许模拟电压输出)。

      • Bit 0-1 = 11 (选择通道 3/滑动变阻器)。

  3. 继电器与蜂鸣器:

    • 0x100x40 通常不是 I2C 地址,而是用于控制板载外设(如 74HC573 锁存器或 ULN2003 驱动)的位掩码。

    • 继电器: 0x10 (对应 P0.4)。

    • 蜂鸣器: 0x40 (对应 P0.6)。

没问题!这是包含完整代码的更新版笔记。我把代码直接嵌入到了对应的操作说明中,方便你直接复制使用。:memo::laptop:


:books: EEPROM (AT24C02) 读写操作笔记

1. 核心概念:AT24C02 芯片特性 :light_bulb:

(基于中间说明图)

  • 芯片类型:I2C 接口的 EEPROM 芯片。

  • 寻址方式:每个字节都有唯一地址,其中一个地址对应一个字节。

  • :warning: 关键约束(页写入限制)

    • 该芯片具有 8个字节 的页长(Page Size)。

    • 地址对齐:在示例代码中,要求读写地址 必须是8的倍数

    • 写入限制:一次写入操作最多只能写入8个字节。如果不按8的倍数对齐或超过页长,可能导致写入错误数据丢失


2. 写操作 (EEPROM_Write) :writing_hand:

(基于第一张代码图)

该函数用于向EEPROM的特定地址写入指定数量的字符。

  • 关键流程:Start → 发送器件地址(写) → 发送数据地址 → 循环写入数据 (需延时) → Stop

C

//函数名:写EEPROM函数
//入口参数:需要写入的字符串,写入的地址(务必为8的倍数),写入数量
//返回值:无
//函数功能:向EERPOM的某个地址写入字符串中特定数量的字符。
void EEPROM_Write(unsigned char* EEPROM_String, unsigned char addr, unsigned char num)
{
    IIC_Start();       //发送开启信号
    IIC_SendByte(0xA0);//选择EEPROM芯片,确定写的模式
    IIC_WaitAck();     //等待EEPROM反馈
​
    IIC_SendByte(addr);//写入要存储的数据地址
    IIC_WaitAck();     //等待EEPROM反馈
​
    while(num--)
    {
        IIC_SendByte(*EEPROM_String++); //将要写入的信息写入
        IIC_WaitAck();                  //等待EEPROM反馈
        IIC_Delay(200);                 //重要:等待内部写入完成
    }
    IIC_Stop(); //停止发送
}

3. 读操作 (EEPROM_Read) :open_book:

(基于第三张代码图)

该函数用于从EEPROM的特定地址读取数据并存入数组。

  • 关键流程:Start → 发送器件地址(写) → 发送数据地址 → Restart → 发送器件地址(读) → 循环读取 (注意ACK/NACK) → Stop

C

//函数名:读EEPROM函数
//入口参数:读到的数据需要存储的字符串,读取的地址(务必为8的倍数),读取的数量
//返回值:无
//函数功能:读取EERPOM的某个地址中的数据,并存放在字符串数组中。
void EEPROM_Read(unsigned char* EEPROM_String, unsigned char addr, unsigned char num)
{
    IIC_Start();       //发送开启信号
    IIC_SendByte(0xA0);//选择EEPROM芯片,确定写的模式
    IIC_WaitAck();     //等待EEPROM反馈
​
    IIC_SendByte(addr);//写入要读取的数据地址
    IIC_WaitAck();     //等待EEPROM反馈
​
    IIC_Start();       //发送开启信号
    IIC_SendByte(0xA1);//选择EEPROM芯片,确定读的模式
    IIC_WaitAck();     //等待EEPROM反馈
​
    while(num--)
    {
        *EEPROM_String++ = IIC_RecByte(); //接收数据
        if(num) IIC_SendAck(0);           //发送应答 (继续读)
        else    IIC_SendAck(1);           //不应答 (最后一位,准备停止)
    }
​
    IIC_Stop(); //停止发送
}

:pushpin: 重点对比记忆

  1. 延时:写操作在循环中每写一个字节都需要 IIC_Delay(200),而读操作不需要。

  2. 模式切换:读操作中间多了一次 IIC_Start()0xA1(读模式指令)的发送。

  3. 应答信号

    • :主机只负责接收从机的 ACK。

    • :主机读取数据后,需要主动发送 ACK(继续)或 NACK(结束)。