有没tm1650的硬件写的驱动
用I2C的硬件和tm1650通讯,搞不好,到底是哪的问题需要定义io位开漏模式吗oid main()
{
P1M0 = 0xc0; P1M1 = 0xc0;
P_SW2 = 0x80;
I2CCFG = 0xff; //使能I2C主机模式
I2CMSST = 0x00;
while (1)
在处理TM1650与I2C硬件的通讯问题时,首先需要确保硬件连接和配置正确。您提到的代码片段中,P1M0和P1M1的配置用于设置IO口的模式,但具体是否设置为开漏模式需要根据实际情况判断。对于I2C通讯,通常SDA(数据线)和SCL(时钟线)需要设置为开漏模式,以便实现双向通讯和总线仲裁。<br><br>以下是一些可能的问题排查步骤:<br><br>1. IO口模式设置:确保SDA和SCL引脚设置为开漏模式。对于8051系列单片机,可以通过PxM0和PxM1寄存器配置。例如,P1M0 = 0xC0; P1M1 = 0xC0; 将P1.6和P1.7设置为开漏模式。<br><br>2. I2C配置:检查I2C配置寄存器是否正确设置。I2CCFG = 0xFF; 可能配置了I2C主机模式,但具体寄存器定义需参考芯片手册。<br><br>3. TM1650初始化:TM1650需要初始化命令来设置显示模式和亮度。确保在通讯前发送正确的初始化命令。<br><br>4. 时序和信号完整性:检查I2C通讯的时序是否符合TM1650的要求,确保信号没有干扰或衰减。<br><br>5. 硬件连接:检查SDA和SCL的硬件连接是否正确,包括上拉电阻的阻值是否合适(通常为4.7kΩ)。<br><br>建议参考TM1650和单片机的手册,确保所有配置和连接正确。如果问题仍然存在,可以使用逻辑分析仪或示波器检查I2C信号,进一步排查问题。<br><br>[本文内容由国芯人工智能辅助生成,仅供参考] 怎样有进展了没有? 我也一直想尝试用硬件IIC驱动tm01650苦于一直没有成功
在本坛搜索如下关键字
我这里有个ET6226的硬件I2C驱动代码,和TM1650、AIP650这些应该都是兼容的。
#include "intrins.h"
#include "main.h"
#include "ET6226.h"
#define ET6226_DISPLAY_BASE1 0x68 // 数码管0的地址
#define ET6226_DISPLAY_BASE2 0x6A // 数码管1的地址
#define ET6226_DISPLAY_BASE3 0x6C // 数码管2的地址
#define ET6226_DISPLAY_BASE4 0x6E // 数码管3的地址
#define ET6226_DCTRL_BASE 0x48 // 控制寄存器地址
#define ET6226_KEYBOARD_BASE 0x4F // 键盘编码地址
#define ET6226_DISPLAY_ON 0x09
#define ET6226_DISPLAY_OFF0x00
#define ET6226_CHIP_SLEEP 0x04
//code ET6226_BRIGHT_LEVEL = {0x11,0x21,0x31,0x41,0x51,0x61,0x71,0x01}; //输出亮度从低到高
code ET6226_BRIGHT_LEVEL = {0x19,0x29,0x39,0x49,0x59,0x69,0x79,0x09}; //输出亮度从低到高
unsigned char key_value;
unsigned char key_flag;
bitbusy;
unsigned char key_scan(void);
void Wait()
{
while (!(I2CMSST & 0x40));
I2CMSST &= ~0x40;
}
void Start()
{
I2CMSCR = 0x01; //发送START命令
Wait();
}
void SendData(char dat)
{
I2CTXD = dat; //写数据到数据缓冲区
I2CMSCR = 0x02; //发送SEND命令
Wait();
}
void RecvACK()
{
I2CMSCR = 0x03; //发送读ACK命令
Wait();
}
char RecvData()
{
I2CMSCR = 0x04; //发送RECV命令
Wait();
return I2CRXD;
}
void SendACK()
{
I2CMSST = 0x00; //设置ACK信号
I2CMSCR = 0x05; //发送ACK命令
Wait();
}
void SendNAK()
{
I2CMSST = 0x01; //设置NAK信号
I2CMSCR = 0x05; //发送ACK命令
Wait();
}
void Stop()
{
I2CMSCR = 0x06; //发送STOP命令
Wait();
}
void I2C_Init(void)
{
P_SW2|= 0x80;
I2CCFG= 0xe0; //使能I2C主机模式
I2CMSST = 0x00;
SDA = 1;
SCL = 1;
// P_SW2|= 0x00; //SCL/P1.5, SDA/P1.4
P_SW2|= 0x10; //SCL_2/P2.5, SDA_2/P2.4
//P_SW2|= 0x30; //SCL_4/P3.2, SDA_4/P3.3
}
void ET6226_sendbyte(unsigned char add,unsigned char dat)
{
char sfr_temp = P_SW2;
P_SW2 |= 0x80;
Start(); //发送起始命令
SendData(add); //发送控制地址
RecvACK();
SendData(dat); //发送开显示指令
RecvACK();
Stop();
P_SW2 = sfr_temp;
delay_ms(20);
}
void INT3_Isr() interrupt 11
{
unsigned char key_code;
char sfr_temp = P_SW2;
LED_COMM = 0;
P_SW2 |= 0x80;
Start(); //发送起始命令
SendData(ET6226_KEYBOARD_BASE); //发送设备地址+写命令
RecvACK();
key_code =RecvData();
SendNAK();
//RecvACK();
Stop();
P_SW2 = sfr_temp;
if (key_code&0x40)
{
key_value =key_code;
key_flag = 2;
}
LED_COMM = 1;
}
unsigned char key_scan(void)
{
unsigned char key_code;
char sfr_temp = P_SW2;
P_SW2 |= 0x80;
if(KEY_INT == 0)
{
Start(); //发送起始命令
SendData(ET6226_KEYBOARD_BASE); //发送设备地址+写命令
RecvACK();
key_code =RecvData();
SendNAK();
Stop();
P_SW2 = sfr_temp;
if (key_code&0x40){
//key_code <<= 1;
//key_code &=0x7F;
}
}
return key_code;
}
extern void ET6226_Init(void)
{
I2C_Init();
delay_ms(5);
ET6226_sendbyte(ET6226_DCTRL_BASE,ET6226_BRIGHT_LEVEL); //显示亮度最亮
ET6226_sendbyte(ET6226_DISPLAY_BASE1,0xFF); //小7键背光
ET6226_sendbyte(ET6226_DISPLAY_BASE2,0xFF); //启停键背光
Start(); //发送起始命令
SendData(ET6226_KEYBOARD_BASE); //发送设备地址+写命令
RecvACK();
RecvData();
SendNAK();
Stop();
P_SW2 |= 0x80;
INTCLKO |= 0x20; //使能INT3中断
}
硬件I2C驱动TM1650成功了吗 给你个我实验成功的代码,不过用的是89C52.
//功能:按TM1650四按键四LED数码管模块第二个键,个位闪烁,第三个键数值减小,第四个键数值增大
//按第一个按键时,4位LED总显示数值递减计数,再按一次,暂停。
#include<reg52.h>
//#include<intrins.h>
#include"tm1650.h"
#define uchar unsigned char
#define uintunsigned int
// 新增全局变量声明
bit flash_flag; // 闪烁标志
uchar flash_counter; // 闪烁计时器
uchar adjust_mode = 0;// 新增调整模式状态
uchar digits = {0,0,0,0}; // 新增数值存储数组
uint combined_value; // 4位LED显示总数值
bit counting_down = 0;// 倒计时标志
bit pause_flag = 0; // 暂停标志
// 显示编码表(带小数点控制位)
uchar CODE = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
// 声明 Scan_Key 函数
uchar Scan_Key();
// 定时器0初始化(原代码功能不变)
void Timer0_Init() {
TMOD |= 0x01; // 模式1
TL0 = 0x18; // 1ms定时
TH0 = 0xFC;
ET0 = 1; // 中断使能
TR0 = 1;
EA = 1;
}
// 显示更新函数(优化小数点处理)
void Update_Display()
{
uchar seg_data;
// 千位(地址0x68)
seg_data = (adjust_mode==4 && flash_flag) ? 0x00 : CODE];
TM1650_Set(0x68, seg_data | (adjust_mode==4 ? 0x80 : 0x00));
// 百位(地址0x6A)
seg_data = (adjust_mode==3 && flash_flag) ? 0x00 : CODE];
TM1650_Set(0x6A, seg_data | (adjust_mode==3 ? 0x80 : 0x00));
// 十位(地址0x6C)
seg_data = (adjust_mode==2 && flash_flag) ? 0x00 : CODE];
TM1650_Set(0x6C, seg_data | (adjust_mode==2 ? 0x80 : 0x00));
// 个位(地址0x6E)
seg_data = (adjust_mode==1 && flash_flag) ? 0x00 : CODE];
TM1650_Set(0x6E, seg_data | (adjust_mode==1 ? 0x80 : 0x00));
// 计算总数值
combined_value = digits * 1000 + digits * 100 + digits * 10 + digits;
}
// 定时器0中断服务(原代码功能不变)
void Timer0_ISR() interrupt 1
{
static uint counter = 0;
TH0 = 0xFC; // 重装初值
TL0 = 0x18;
if(++counter >= 500) { // 500ms周期
flash_flag = !flash_flag;
counter = 0;
}
}
// 定时器1初始化
void Timer1_Init() {
TMOD |= 0x10; // 定时器1,模式1
TH1 = 0xFC; // 1ms定时
TL1 = 0x18;
ET1 = 1; // 定时器1中断使能
TR1 = 0; // 先不启动定时器1
EA = 1;
}
// 定时器1中断服务
void Timer1_ISR() interrupt 3
{
static uint counter = 0;
TH1 = 0xFC; // 重装初值
TL1 = 0x18;
if (++counter >= 1000) { // 1000ms = 1s
counter = 0;
if (counting_down &&!pause_flag && combined_value > 0) {
combined_value--;
// 将总数值拆分为各个数位
digits = combined_value / 1000;
digits = (combined_value / 100) % 10;
digits = (combined_value / 10) % 10;
digits = combined_value % 10;
Update_Display();
}
}
}
// 按键处理(增加边界保护)
void Process_Key(uchar key)
{
static uchar last_key = 0;
if(key == last_key) return;
// 模式切换键处理
if(key == 0x54) // 0x54是TM1650的按键代码之一
{
adjust_mode = (adjust_mode < 4) ? adjust_mode+1 : 0;
flash_flag = 0; // 强制显示稳定
}
if(key == 0x5c) // 0x5c是TM1650的按键代码之一
{
if(combined_value > 0) {
if (!counting_down) {
counting_down = 1;// 开始倒计时
TR1 = 1; // 启动定时器1
pause_flag = 0; // 开始时不暂停
} else {
pause_flag =!pause_flag; // 切换暂停状态
}
}
}
// 数值调整(带范围限制)
if(adjust_mode > 0)
{
uchar *p = &digits;
if(key == 0x4C) *p = (*p - 1 + 10) % 10; // 循环减,0x4c是TM1650的按键代码之一
if(key == 0x44) *p = (*p + 1) % 10; // 循环加,0x44是TM1650的按键代码之一
}
last_key = key;
}
// 主函数(修正初始化逻辑)
void main()
{
Timer0_Init();
Timer1_Init();
TM1650_Set(0x48, 0x51); // 显示控制:5级亮度
Update_Display(); // 初始化显示
while(1)
{
Process_Key(Scan_Key());
Update_Display();
}
}
//TM1650 C文件
#include<reg52.h>
#include"tm1650.h"
void Delay_us(uint i) //us延时
{
for(;i>0;i--)
{
_nop_();
// _nop_();
// _nop_();
// _nop_();
// _nop_();
}
}
void I2CStart(void) //开始信号
{
CLK_H;
DIO_H;
Delay_us(5);
DIO_L;
}
void I2Cask(void) //ACK信号
{
uchar timeout = 1;
CLK_H;
Delay_us(5);
CLK_L;
while((DIO)&&(timeout<=100))
{
timeout++;
}
Delay_us(5);
CLK_L;
}
void I2CStop(void) //停止信号
{
CLK_H;
DIO_L;
Delay_us(5);
DIO_H;
}
void I2CWrByte(uchar oneByte) //写一个字节高位在前,低位在后
{
uchar i;
CLK_L;
Delay_us(1);
for(i=0;i<8;i++)
{
oneByte = oneByte<<1;
DIO = CY;
CLK_L;
Delay_us(5);
CLK_H;
Delay_us(5);
CLK_L;
}
}
uchar Scan_Key(void) // 按键扫描
{
uchar i;
uchar rekey;
I2CStart();
I2CWrByte(0x49);//读按键命令
I2Cask();
//DIO_H;
for(i=0;i<8;i++)
{
CLK_H;
rekey = rekey<<1;
if(DIO)
{
rekey++;
}
Delay_us(5);
CLK_L;
}
I2Cask();
I2CStop();
return(rekey);
}
void TM1650_Set(uchar add,uchar dat) //数码管显示
{
//写显存必须从高地址开始写
I2CStart();
I2CWrByte(add); //第一个显存地址
I2Cask();
I2CWrByte(dat);
I2Cask();
I2CStop();
}
//TM1650 H文件
#ifndef __TM1650_H__
#define __TM1650_H__
#include<intrins.h>
#define uchar unsigned char
#define uintunsigned int
sbit CLK = P1^0;
sbit DIO = P1^1;
#include<reg52.h>
#define CLK_HCLK = 1
#define CLK_LCLK = 0
#define DIO_HDIO = 1
#define DIO_LDIO = 0
void TM1650_Set(uchar add,uchar dat);
uchar Scan_Key(void);
#endif
zhaoyun189911 发表于 2025-4-10 22:11
怎样有进展了没有? 我也一直想尝试用硬件IIC驱动tm01650苦于一直没有成功
...
好像1637之类的硬件iic有点问题。。之前在哪里看到过 vb2002 发表于 2025-5-26 14:48
好像1637之类的硬件iic有点问题。。之前在哪里看到过
是么 我试验几次一直没有成功 也不知道是不是无能力不行 zhaoyun189911 发表于 2025-5-26 15:09
是么 我试验几次一直没有成功 也不知道是不是无能力不行
用io口的没问题。但是用iic硬件的就有点问题。
有人强行弄好过。但是现实有bug
页:
[1]
2