第一次接触AIP650这颗驱动芯片是在去年开发智能烤箱项目的时候。当时需要给烤箱面板添加温度显示功能,老板扔给我一个四位数码管模块和这颗国产驱动芯片的文档。说实话,刚开始看到全英文的数据手册时有点发怵,但实际用下来发现它的设计非常人性化。
AIP650本质上是一个通过I2C接口控制的数码管驱动芯片,最大支持4位共阴数码管。和传统的TM1650这类驱动芯片相比,它有三大优势:一是内置了数字0-9的段码表,省去了我们自己建表的麻烦;二是支持8级亮度调节;三是价格只有进口芯片的一半。我在热水器、温控器等多个项目里都用过它,稳定性确实不错。
芯片的工作电压是3.3V-5V,正好适配常见的STM32和ESP32开发板。最让我惊喜的是它的抗干扰能力——有次在电磁炉旁边测试,显示居然完全没有闪烁。不过要注意的是,它的I2C时序比较特殊,需要严格按照文档里的时序图来操作。
先说说硬件连接。AIP650只需要两个IO口——SCL和SDA,典型的I2C接口配置。但在实际布线时有个小技巧:一定要在SCL和SDA线上各加一个4.7K的上拉电阻。我刚开始偷懒没加,结果调试时数据经常出错,折腾了一下午才发现问题。
接线示意图如下:
code复制VCC ----[4.7K]---- SDA
[4.7K]---- SCL
[数码管]
对于四位数码管,需要将段选线(a-g,dp)接到AIP650的SEG引脚,位选线(COM0-COM3)接到对应的COM引脚。如果像我的烤箱项目只需要显示三位温度值,COM3可以空着不用。
初始化代码主要完成三件事:配置GPIO、设置工作模式、清空显示缓存。下面是我在STM32上验证过的初始化函数:
c复制void aip650e_init(struct _650e_drv_ *drv) {
// 配置SDA为推挽输出
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(SDA_PORT, &GPIO_InitStruct);
// 配置SCL同理
GPIO_InitStruct.Pin = CLK_PIN;
HAL_GPIO_Init(CLK_PORT, &GPIO_InitStruct);
// 清空显示缓存
memset(drv->_buf, 0, AIP650E_SIZE);
// 发送系统命令:开启显示,8级亮度
writeCMD(0x4801);
}
这里有个坑要注意:AIP650的I2C地址是固定的0x68,不需要像其他I2C设备那样发送设备地址。我第一次用的时候按照常规I2C流程操作,怎么都通讯不上,后来仔细看手册才发现这个特殊点。
AIP650最方便的地方就是内置了段码表,我们只需要发送数字值就能正确显示。芯片内部的段码表对应关系如下:
| 数字 | 段码值 | 显示效果 |
|---|---|---|
| 0 | 0x3F | "0" |
| 1 | 0x06 | "1" |
| ... | ... | ... |
| 9 | 0x6F | "9" |
| 空 | 0x00 | 不显示 |
| 负号 | 0x40 | "-" |
在温控设备中,我们通常需要显示60℃、90℃这样的温度值。以显示"90"为例,需要将十位数的"9"和个位数的"0"分别转换为对应的段码值0x6F和0x3F。
下面这个函数实现了温度值到数码管显示的完整转换:
c复制void show_temperature(uint8_t temp) {
struct _650e_drv_ *drv = GET_650E();
// 百位数(通常不显示)
drv->_buf[0] = leddata[10]; // 空
// 十位数
uint8_t ten = temp / 10;
drv->_buf[1] = leddata[ten];
// 个位数
uint8_t one = temp % 10;
drv->_buf[2] = leddata[one];
// 更新显示
aip650e_update(drv);
}
我在热水器项目中发现个有趣的现象:当温度低于10℃时,如果直接显示"5"会让人误以为是50℃。后来改进的方案是当温度<10℃时显示" 5"(前面加空格),这样用户体验就好多了。
AIP650的刷新是通过aip650e_update函数实现的,这个函数主要做了以下几件事:
实际测试中发现,刷新频率最好控制在50-100Hz之间。频率太低会有闪烁感,太高则浪费MCU资源。我的做法是在主循环里每20ms调用一次刷新函数:
c复制while(1) {
if(HAL_GetTick() - last_refresh > 20) {
aip650e_update(drv);
last_refresh = HAL_GetTick();
}
// 其他任务...
}
AIP650支持8级亮度调节,通过修改系统命令的低3位实现。比如要设置亮度为5级:
c复制writeCMD(0x4805); // 最后一位5表示亮度等级
实际项目中,我发现在不同环境下最佳亮度不同:白天需要最亮(7级),晚上3级就够了。后来加了个光敏电阻自动调节亮度,代码大致如下:
c复制void auto_adjust_brightness() {
uint16_t light = read_light_sensor();
uint8_t level = light > 500 ? 7 :
light > 200 ? 5 : 3;
writeCMD(0x4800 | level);
}
第一次使用AIP650时最容易遇到显示乱码的问题,通常有以下几种原因:
I2C时序不符合要求:AIP650的SCL高电平时间至少要500ns,我用逻辑分析仪抓波形发现很多开发库的I2C时序不满足这个要求。后来改用GPIO模拟I2C就稳定了。
电源干扰:遇到过数码管某些段位微微发亮的情况,在VCC和GND之间加个100uF电容就解决了。
段码数据错误:特别注意发送的数据格式是0x6X00 | 段码值,我曾经漏掉了|操作导致显示异常。
分享几个调试时很有用的方法:
使用测试模式:在aip650.h中打开AIP650_TEST_MODE宏定义,芯片会循环显示0-9数字,方便检查硬件连接是否正确。
简化测试代码:可以先屏蔽所有业务逻辑,只测试最基本的显示功能:
c复制drv->_buf[0] = leddata[1]; // 显示"1"
drv->_buf[1] = leddata[2]; // 显示"2"
aip650e_update(drv);