zhaojingbo111 发表于 2025-3-16 18:14:50

有没tm1650的硬件写的驱动

用I2C的硬件和tm1650通讯,搞不好,到底是哪的问题需要定义io位开漏模式吗


oid main()
{
      P1M0 = 0xc0; P1M1 = 0xc0;


    P_SW2 = 0x80;

    I2CCFG = 0xff;                              //使能I2C主机模式
    I2CMSST = 0x00;

   
    while (1)

国芯人工智能 发表于 2025-3-16 18:18:00

在处理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>[本文内容由国芯人工智能辅助生成,仅供参考]

zhaoyun189911 发表于 2025-4-10 22:11:16

怎样有进展了没有? 我也一直想尝试用硬件IIC驱动tm01650苦于一直没有成功

神农鼎 发表于 2025-4-10 22:14:21


在本坛搜索如下关键字

晓飛飛 发表于 2025-4-12 10:27:39

我这里有个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中断      
}




人在江南 发表于 2025-5-19 08:41:52

硬件I2C驱动TM1650成功了吗

cjtdz 发表于 2025-5-19 09:37:52

给你个我实验成功的代码,不过用的是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



vb2002 发表于 2025-5-26 14:48:27

zhaoyun189911 发表于 2025-4-10 22:11
怎样有进展了没有? 我也一直想尝试用硬件IIC驱动tm01650苦于一直没有成功
...

好像1637之类的硬件iic有点问题。。之前在哪里看到过

zhaoyun189911 发表于 2025-5-26 15:09:11

vb2002 发表于 2025-5-26 14:48
好像1637之类的硬件iic有点问题。。之前在哪里看到过

是么 我试验几次一直没有成功 也不知道是不是无能力不行

vb2002 发表于 2025-5-26 15:21:56

zhaoyun189911 发表于 2025-5-26 15:09
是么 我试验几次一直没有成功 也不知道是不是无能力不行

用io口的没问题。但是用iic硬件的就有点问题。
有人强行弄好过。但是现实有bug
页: [1] 2
查看完整版本: 有没tm1650的硬件写的驱动