HT16C21 驱动模拟I2C实现

简介: HT16C21 是一款功能不错的LCD驱动控制器,通过I2C接口与微控制器通信,能够驱动最多20×4或16×8点的LCD显示。由于DSP28335可能没有硬件I2C资源,或者硬件I2C配置不够灵活,软件模拟I2C(Software I2C) 就成了一个实用的选择。

HT16C21 是一款功能不错的LCD驱动控制器,通过I2C接口与微控制器通信,能够驱动最多20×4或16×8点的LCD显示。由于DSP28335可能没有硬件I2C资源,或者硬件I2C配置不够灵活,软件模拟I2C(Software I2C) 就成了一个实用的选择。

HT16C21 驱动模拟I2C实现

软件I2C关键实现要点

软件模拟I2C的核心在于通过GPIO引脚精确模拟I2C协议的时序,包括起始条件、停止条件、数据读写和应答信号。

  1. 引脚定义与初始化:需要定义两个GPIO引脚分别作为SDA(数据线)和SCL(时钟线),并将它们初始化为输出模式,初始状态通常设置为高电平。
  2. 时序模拟:严格按照I2C协议的时序要求,通过控制GPIO引脚的高低电平时序来产生起始信号、停止信号、数据有效等。需要注意的是,I2C协议规定SCL为高电平时,SDA的数据必须稳定
  3. 数据收发:逐位读写数据,每个时钟脉冲传输一位数据。写数据时,先传输最高位(MSB);读数据时,同样先读取最高位。
  4. 应答处理:每传输完一个字节(8位)后,接收方(无论是主机还是从机)需要发送一个应答信号(ACK)或非应答信号(NACK)。

DSP28335 模拟I2C驱动HT16C21代码

1. 宏定义与引脚控制

首先定义SDA和SCL引脚,以及基本的引脚操作宏:

// 假设使用GPIO31作为SDA, GPIO32作为SCL
#define I2C_SDA_GPIOPIN   31
#define I2C_SCL_GPIOPIN   32

// 控制SDA和SCL引脚输出高电平
#define I2C_SDA_HIGH      GpioDataRegs.GPASET.bit.GPIO31 = 1
#define I2C_SCL_HIGH      GpioDataRegs.GPASET.bit.GPIO32 = 1

// 控制SDA和SCL引脚输出低电平
#define I2C_SDA_LOW       GpioDataRegs.GPACLEAR.bit.GPIO31 = 1
#define I2C_SCL_LOW       GpioDataRegs.GPACLEAR.bit.GPIO32 = 1

// 设置SDA引脚为输入方向(用于读取)或输出方向(用于写入)
#define I2C_SDA_INPUT     GpioCtrlRegs.GPADIR.bit.GPIO31 = 0
#define I2C_SDA_OUTPUT    GpioCtrlRegs.GPADIR.bit.GPIO31 = 1

// 读取SDA引脚的电平状态
#define I2C_READ_SDA      GpioDataRegs.GPADAT.bit.GPIO31

// 简单的延时函数,需要根据CPU时钟频率调整
void I2C_Delay(void)
{
   
    Uint16 i;
    for (i = 0; i < 100; i++);
}

2. I2C基本信号模拟

模拟I2C的起始信号、停止信号、应答信号等:

// I2C起始信号:SCL高电平期间,SDA从高变低
void I2C_Start(void)
{
   
    I2C_SDA_OUTPUT; // 设置SDA为输出
    I2C_SDA_HIGH;
    I2C_SCL_HIGH;
    I2C_Delay();
    I2C_SDA_LOW;
    I2C_Delay();
    I2C_SCL_LOW; // 保持SCL低电平,准备发送数据
    I2C_Delay();
}

// I2C停止信号:SCL高电平期间,SDA从低变高
void I2C_Stop(void)
{
   
    I2C_SDA_OUTPUT; // 设置SDA为输出
    I2C_SDA_LOW;
    I2C_Delay();
    I2C_SCL_HIGH;
    I2C_Delay();
    I2C_SDA_HIGH;
    I2C_Delay();
}

// 发送应答信号(ACK):SCL低电平期间,SDA拉低;SCL产生一个脉冲
void I2C_SendAck(void)
{
   
    I2C_SDA_OUTPUT;
    I2C_SDA_LOW;
    I2C_Delay();
    I2C_SCL_HIGH;
    I2C_Delay();
    I2C_SCL_LOW;
    I2C_Delay();
}

// 发送非应答信号(NACK):SCL低电平期间,SDA拉高;SCL产生一个脉冲
void I2C_SendNack(void)
{
   
    I2C_SDA_OUTPUT;
    I2C_SDA_HIGH;
    I2C_Delay();
    I2C_SCL_HIGH;
    I2C_Delay();
    I2C_SCL_LOW;
    I2C_Delay();
}

// 检查从机应答信号
// 返回值:0-应答成功,1-无应答
Uint16 I2C_CheckAck(void)
{
   
    Uint16 ack;

    I2C_SDA_INPUT; // 设置SDA为输入,准备读取从机应答
    I2C_Delay();
    I2C_SCL_HIGH;  // SCL拉高,在此期间读取SDA状态
    I2C_Delay();

    if (I2C_READ_SDA) {
   
        ack = 1;   // SDA为高,表示无应答(NACK)
    } else {
   
        ack = 0;   // SDA为低,表示应答(ACK)
    }

    I2C_SCL_LOW;
    I2C_Delay();
    I2C_SDA_OUTPUT; // 将SDA重新设置为输出,以便后续操作

    return ack;
}

3. I2C字节读写函数

实现通过I2C读写一个字节的数据:

// 通过I2C写入一个字节数据
void I2C_WriteByte(Uint8 data)
{
   
    Uint8 i;
    I2C_SDA_OUTPUT;

    for (i = 0; i < 8; i++) {
   
        if (data & 0x80) {
      // 先传输最高位(MSB)
            I2C_SDA_HIGH;
        } else {
   
            I2C_SDA_LOW;
        }
        I2C_Delay();
        I2C_SCL_HIGH; // SCL上升沿,数据有效
        I2C_Delay();
        I2C_SCL_LOW;
        I2C_Delay();
        data <<= 1;   // 左移,准备发送下一位
    }

    // 发送完8位数据后,读取从机应答
    I2C_CheckAck();
}

// 通过I2C读取一个字节数据
Uint8 I2C_ReadByte(void)
{
   
    Uint8 i, data = 0;
    I2C_SDA_INPUT; // 设置SDA为输入,准备读取数据

    for (i = 0; i < 8; i++) {
   
        data <<= 1;   // 左移,准备接收下一位
        I2C_Delay();
        I2C_SCL_HIGH; // SCL拉高,在此期间读取SDA状态
        I2C_Delay();
        if (I2C_READ_SDA) {
   
            data |= 0x01; // SDA为高,该位为1
        }
        I2C_SCL_LOW;
    }

    I2C_SDA_OUTPUT; // 将SDA重新设置为输出,以便后续发送应答

    return data;
}

4. HT16C21初始化与显示控制

HT16C21需要正确的初始化才能正常工作,以下是一个初始化示例:

// HT16C21初始化
void HT16C21_Init(void)
{
   
    // 发送起始信号
    I2C_Start();

    // 发送HT16C21的I2C地址(7位地址为0x70,左移一位后写操作为0xE0)
    I2C_WriteByte(0x70 << 1); // 假设最后一位为0,表示写操作

    // 发送配置命令
    // 设置系统振荡器开、显示开
    I2C_WriteByte(0x84); // 系统振荡器开、显示开 的命令字节
    // 具体配置值需参考数据手册,例如0x84可能表示:1000 0100,即开启振荡器和显示

    // 设置显示参数,如占空比(Duty)、偏置(Bias)
    I2C_WriteByte(0x82); // 假设0x82是设置Duty和Bias的命令
    I2C_WriteByte(0x00); // 具体的配置数据,例如1/4 Duty, 1/3 Bias

    // 设置帧频率
    I2C_WriteByte(0x86);
    I2C_WriteByte(0x01); // 例如设置帧频为160Hz

    // 关闭闪烁
    I2C_WriteByte(0x88);
    I2C_WriteByte(0x00); // 关闭闪烁

    // VLCD电压调整设置(如果需要)
    I2C_WriteByte(0x8A);
    I2C_WriteByte(0x10); // 具体的电压调整值,需参考数据手册

    // 发送停止信号
    I2C_Stop();
}

5. 向HT16C21写入显示数据

初始化完成后,可以向其显示RAM写入数据:

// 向HT16C21的指定地址写入显示数据
void HT16C21_WriteData(Uint8 address, Uint8 data)
{
   
    // 发送起始信号
    I2C_Start();

    // 发送HT16C21的I2C地址(写操作)
    I2C_WriteByte(0x70 << 1); // 7位器件地址为0x70,左移一位,最低位为0表示写

    // 发送写显示RAM的命令(0x80)和地址
    // HT16C21的显示RAM读写命令通常为0x80,与地址组合
    I2C_WriteByte(0x80 | address); // 组合命令和地址

    // 写入显示数据
    I2C_WriteByte(data);

    // 发送停止信号
    I2C_Stop();
}

使用示例

在主函数中,你可以这样使用:

void main(void)
{
   
    // 初始化系统控制、GPIO等
    InitSysCtrl();
    InitGpio(); // 确保初始化了用于I2C的GPIO引脚

    // 初始化软件I2C
    // (GPIO方向设置等已在宏定义中体现,可根据需要额外初始化)

    // 初始化HT16C21
    HT16C21_Init();

    // 向HT16C21的显示RAM地址0x00写入数据0xAB
    HT16C21_WriteData(0x00, 0xAB);

    while(1)
    {
   
        // 主循环,可以不断更新显示内容
    }
}

参考代码 HTC16C21 驱动模拟I2C www.youwenfan.com/contentalj/56960.html

重要参考:HT16C21常用命令字节

根据HT16C21的数据手册,以下是一些常用的命令字节概要:

命令字节 (Command Byte) 功能描述 典型数据字节 (Data Byte) 说明
0x82 设置Duty和Bias 0x00 例如:1/4 Duty, 1/3 Bias
0x84 系统振荡器与显示开关控制 0x03 开启系统振荡器和显示
0x86 设置帧频率 (Frame Frequency) 0x01 例如:160Hz
0x88 设置闪烁模式 (Blinking) 0x00 关闭闪烁
0x8A VLCD电压调整 (Voltage Adjust) 0x10 具体的电压调整值,需参考数据手册
0x80 显示RAM读写命令 (结合地址使用) - 与地址组合,如`0x80 \ address`
相关文章
|
2月前
|
人工智能 NoSQL Java
【Spring AI Alibaba 实战】大模型也有“金鱼记忆”?详解短时记忆(Chat Memory)核心原理与生产级实践
在使用 Spring AI Alibaba 开发大模型应用时,你是否发现模型总是“记不住”上一轮对话的内容?这并非模型智商问题,而是缺少了“短时记忆”机制。本文将深入剖析 Spring AI Alibaba 中 Chat Memory 的设计哲学,从内存存储到 Redis 持久化,手把手带你构建具备上下文感知能力的智能应用,并附上生产环境的避坑指南。
|
11月前
|
算法
三电平逆变器SVPWM控制(无解耦功能)与谐波分析
三电平逆变器的空间矢量脉宽调制(SVPWM)控制方法,重点分析在不使用解耦控制的情况下实现5%谐波含量的技术方案。我们将使用MATLAB/Simulink进行建模和仿真分析。
767 1
|
安全 数据安全/隐私保护
WEP
WEP
839 2
|
10月前
|
数据可视化
16QAM、32QAM和64QAM星座图的MATLAB实现
16QAM、32QAM和64QAM星座图的MATLAB实现
1091 4
|
敏捷开发 数据可视化 项目管理
2025年最值得选择的Jira替代方案(国产工具版)
2025国产Jira替代方案盘点:板栗看板、Worktile、Tower、禅道等工具成为敏捷开发新选择。Jira虽功能强大但存在价格高、本地化不足等问题,国产替代方案在功能完备性(支持Scrum/看板)、本地部署、钉钉/企业微信集成及性价比方面更具优势。对比显示:创业团队适合板栗看板/Tower,研发团队推荐禅道/Worktile,设计营销团队可选择Tower或钉钉项目+语雀组合。迁移建议从数据导出和团队培训着手,国产工具已能提供媲美Jira的协作体验,是企业项目管理数字化转型的更优解。
1031 0
|
9月前
|
并行计算 数据挖掘 5G
MATLAB R2024b 数据分析软件,安装详细步骤,附安装包
MATLAB R2024b 发布,聚焦性能提升与稳定性优化,支持GPU加速、5G/6G工具链及HDL代码生成,新增NPU硬件支持,配合深色界面与调试增强,助力高效科学计算与工程设计。
4586 5
|
程序员 编译器 C#
C#语言中使用"using"关键字的介绍
以上就是 C# 中 "using" 关键字的主要用法。了解并熟练应用这个关键字,对于提高代码质量、解决命名冲突、管理资源都有着重要的作用。它是 C# 编程中不可或缺的一部分,无论是对初学者还是有经验的开发者而言,掌握它都是提高编写高效、清晰、可维护代码的关键。
385 7
|
7月前
|
数据采集 人工智能 自然语言处理
寻找 AI 全能王——阿里云 Data+AI 工程师全球大奖赛正式开启
在AI迈向专业决策的关键节点,阿里云联合NVIDIA发起“寻找AI全能王”全球大奖赛,聚焦高质量数据构建与智能体开发两大挑战。赛事设高校与企业双赛道,覆盖万亿语料去重与DeepSearch智能体构建,提供工业级实战平台、专家指导与丰厚奖励,推动Data+AI融合创新,助力开发者实现“所想即所得”的技术突破。
1650 2
|
3月前
|
IDE 算法 安全
PS2手柄控制6轴机械臂程序设计与实现
使用PS2手柄作为输入设备,通过Arduino主控板(如Arduino Mega 2560或Uno)控制6轴舵机机械臂(如SMALLROBOTAM机械臂),实现无线遥控操作。系统核心是将PS2手柄的摇杆、按键信号转换为舵机角度指令,通过PWM信号驱动6个舵机(对应机械臂的6个自由度:底座旋转、大臂、小臂、手腕俯仰、手腕旋转、夹爪),适用于教育演示、工业抓取、娱乐互动等场景。
335 0
|
安全 数据安全/隐私保护
WiFi工作原理及WiFi接入过程
【9月更文挑战第17天】WiFi(Wireless Fidelity)是一种基于IEEE 802.11标准的无线局域网技术,使用2.4GHz和5GHz频段进行数据传输,并通过正交频分复用(OFDM)技术提高传输效率。WiFi网络通常由接入点和客户端组成,采用IEEE 802.11系列协议实现通信。接入WiFi网络需经历扫描、选择网络、身份验证和关联等步骤,最终实现数据传输。
3295 4

热门文章

最新文章