新手村中打满级大BOSS 2025-05-22 10:28 采纳率: 0%
浏览 30
已结题

使用辉芒的TF61E145,通过IIC驱动TM1650

使用辉芒的TF61E145,通过IIC驱动TM1650控制KD5641AU-07共阴数码管和按键
代码如下

//Project: KeyBoard.prj
// Device: FT61E14X
// Memory: Flash 4KX14b, EEPROM 128X8b, SRAM 512X8b
// Author: 
//Company: 
//Version:
//   Date: 
//===========================================================
//===========================================================
#include    "SYSCFG.h"
//===========================================================
//Variable definition
volatile char W_TMP  @ 0x70 ;//系统占用不可以删除和修改
volatile char BSR_TMP  @ 0x71 ;//系统占用不可以删除和修改
void user_isr();//用户中断程序,不可删除

void TM1650_Display_Clear(void);
void TM1650_Display_One(unsigned char pos, unsigned char data);
void _TM1650_Init (unsigned char add,unsigned char data);
void Update_Display(void);
void LED_Blink_101010(void);
void LED_Wait_Ack_1010(void);
void TM1650_SetBrightness(unsigned char level);
//===========================================================

//===========================================================
//Function name:interrupt ISR
//parameters:无
//returned value:无
//===========================================================
void interrupt ISR(void)
{
#asm;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
    NOP;//系统设置不可以删除和修改
#endasm;//系统设置不可以删除和修改
    user_isr(); //用户中断函数
}
void user_isr() //用户中断函数
{
}

//***********************宏定义*****************************
#define  unchar     unsigned char 
#define  unint        unsigned int
#define  unlong     unsigned long

#define READ_PIN(port, pin) (((port) & (1 << (pin))) ? 1 : 0)
#define READ_SDAT_PORT  READ_PIN(PORTB, 1)

#define  IIC_SCL        RB0   
#define  IIC_SDA        RB1

#define SDA_OUT  TRISB1 =0
#define SDA_IN     TRISB1 =1           

#define LED  RC0
//全局查看变量定义
volatile unchar IICReadData;
/*-------------------------------------------------
 *  函数名:POWER_INITIAL
 *    功能:  上电系统初始化
 *  输入:  无
 *  输出:  无
 --------------------------------------------------*/    
void POWER_INITIAL (void) 
{ 
    OSCCON = 0B01110001;    //WDT 32KHZ IRCF=111=16MHZ
                             //Bit0=1,系统时钟为内部振荡器
                             //Bit0=0,时钟源由FOSC<2:0>决定即编译选项时选择
    INTCON = 0;              //暂禁止所有中断
    
    PORTA = 0B00000000;        
    TRISA = 0B11100111;        //PA输入输出 0-输出 1-输入
    PORTB = 0B00000000;        
    TRISB = 0B11111100;        //PB输入输出 0-输出 1-输入++++++
    PORTC = 0B00000000;     
    TRISC = 0B11111110;        //PC输入输出 0-输出 1-输入      
    
    WPUA = 0B00000000;         //PA端口上拉控制 1-开上拉 0-关上拉。弱上拉电阻
    WPUB = 0B00000000;         //PB端口上拉控制 1-开上拉 0-关上。弱上拉电阻
    WPUC = 0B00000000;         //PC端口上拉控制 1-开上拉 0-关上。弱上拉电阻
    
    WPDA = 0B00000000;         //PA端口上拉控制 1-开下拉 0-关下拉内部弱下拉电阻
    WPDB = 0B00000000;         //PB端口上拉控制 1-开下拉 0-关?  内部弱下拉电阻
    WPDC = 0B00000000;         //PC端口上拉控制 1-开下拉 0-关下内部弱下拉电阻
    
    PSRC0  = 0B11111111;      //PORTA,PORTB源电流设置最大
    //BIT7~BIT6:PORTB[7:4]源电流能力控制,BIT5~BIT4:PORTB[3:0]源电流能力控制 
    //BIT3~BIT2:PORTA[7:4]源电流能力控制,BIT1~BIT0:PORTA[3:0]源电流能力控制
    
    PSRC1  = 0B11111111;    //PORTC,PORTD源电流设置最大    
    //BIT7~BIT6:PORTD[7:4]源电流能力控制,BIT5~BIT4:PORTD[3:0]源电流能力控制 
    //BIT3~BIT2:PORTC[7:4]源电流能力控制,BIT1~BIT0:PORTC[3:0]源电流能力控制
    
    PSINK0 = 0B11111111;      //PORTA灌电流设置最大 0:最小,1:最大
    PSINK1 = 0B11111111;     //PORTB灌电流设置最大 0:最小,1:最大
    PSINK2 = 0B11111111;    //PORTC灌电流设置最大 0:最小,1:最大
    
    ANSELA = 0B00000000;    //全为数字管脚
 
}
/*------------------------------------------------- 
 *    函数名称:DelayUs
 *    功能:   短延时函数 --16M-2T--大概快1%左右.
 *    输入参数:Time延时时间长度 延时时长Time Us
 *    返回参数:无 
 -------------------------------------------------*/
void DelayUs(unsigned char Time)
{
    unsigned char a;
    for(a=0;a<Time;a++)
    {
        NOP();//16MHZ的MCU一个NOP为62.5纳秒
    }
}                  
/*-------------------------------------------------
 *    函数名称:DelayMs
 *    功能:   短延时函数
 *    输入参数:Time延时时间长度 延时时长Time ms
 *    返回参数:无 
 -------------------------------------------------*/
void DelayMs(unsigned char Time)
{
    unsigned char a,b;
    for(a=0;a<Time;a++)
    {
        for(b=0;b<5;b++)
        {
             DelayUs(197); //快1%
        }
    }
}
/*-------------------------------------------------
 *    函数名称:DelayS
 *    功能:   短延时函数
 *    输入参数:Time延时时间长度 延时时长Time S
 *    返回参数:无 
 -------------------------------------------------*/
void DelayS(unsigned char Time)
{
    unsigned char a,b;
    for(a=0;a<Time;a++)
    {
        for(b=0;b<10;b++)
        {
             DelayMs(100); 
        }
    }
}
/*-------------------------------------------------
 *  函数名:IIC_Start
 *    功能:  产生IIC起始信号
 *  输入:  无
 *  输出:  无
 --------------------------------------------------*/
void IIC_Start(void)
{
    SDA_OUT;          //SDA线输出0
    IIC_SDA=1;            
    IIC_SCL=1;
    DelayUs(4);
     IIC_SDA=0;        //START:when CLK is high,DATA change form high to low 
    DelayUs(4);
    IIC_SCL=0;        //钳住I2C总线,准备发送或接收数据 
    DelayUs(4);
}      
/*-------------------------------------------------
 *  函数名:IIC_Stop
 *    功能:  产生IIC停止信号
 *  输入:  无
 *  输出:  无
 --------------------------------------------------*/
 void IIC_Stop(void)
{
    SDA_OUT;          //SDA线输出
    IIC_SCL=0;
    IIC_SDA=0;        //STOP:when CLK is high DATA change form low to high
     DelayUs(4);
    IIC_SCL=1; 
    DelayUs(4);
    IIC_SDA=1;        //发送I2C总线结束信号
    DelayUs(4);                                   
}
///*-------------------------------------------------
// *  函数名:IIC_Wait_Ack
// *    功能:  等待应答信号到来
// *  输入:  无
// *  输出:  返回值:1,接收应答失败
// *               0,接收应答成功
// --------------------------------------------------*/
//unsigned char IIC_Wait_Ack(void)
//{
//    unsigned char ucErrTime=0;      
//    SDA_IN;               //SDA设置为输入  
//    IIC_SDA=1;
//    DelayUs(2);       
//    IIC_SCL=1;
//    DelayUs(2);     
//    while(IIC_SDA)
//    {
//        ucErrTime++;
//        if(ucErrTime>100) //等待超时
//        {
//            IIC_Stop();
//            LED_Wait_Ack_1010();
//            return 1;
//        }
//    }
//    IIC_SCL=0;            //时钟输出0       
//    return 0;  
//} 
///*-------------------------------------------------
// *  函数名:IIC_Ack
// *    功能:  产生ACK应答
// *  输入:  无
// *  输出:  无
// --------------------------------------------------*/
//void IIC_Ack(void)
//{
//    IIC_SCL=0;
//    SDA_OUT;              //SDA线输出
//    IIC_SDA=0;
//    DelayUs(2);    
//    IIC_SCL=1;
//    DelayUs(2);    
//    IIC_SCL=0;
//}
///*-------------------------------------------------
// *  函数名:IIC_NAck
// *    功能:  不产生ACK应答
// *  输入:  无
// *  输出:  无
// --------------------------------------------------*/        
//void IIC_NAck(void)
//{
//    IIC_SCL=0;
//    SDA_OUT;              //SDA线输出
//    IIC_SDA=1;
//    DelayUs(2);    
//    IIC_SCL=1;
//    DelayUs(2);    
//    IIC_SCL=0;
//}

//IIC总线复位
void I2c_ResetBus(void)
{
    SDA_OUT;
    IIC_SDA=1;
    for(int i=0;i<9;i++)
    {
        IIC_SCL=1;
        DelayUs(10);
        IIC_SCL=0;
        DelayUs(10);        
    }
    IIC_Start();
}
                                          
/*-------------------------------------------------
 *  函数名:IIC_Send_Byte
 *    功能:  IIC发送一个字节
 *  输入:  写入要发送的一个人字节数据txd
 *  输出:  无
 --------------------------------------------------*/          
void IIC_Send_Byte(unsigned char txd)
{                        
    unsigned char t;   
    SDA_OUT;              // SDA线输出   
    IIC_SCL = 0;          // 拉低时钟开始数据传输
    for(t = 0; t < 8; t++)
    {              
        if((txd & 0x80) >> 7)
        {
            IIC_SDA = 1;
        }
        else
        {
            IIC_SDA = 0;
        }
        txd <<= 1;     // 左移数据位
        DelayUs(4);    
        IIC_SCL = 1;   // 产生时钟上升沿
        DelayUs(4);    
        IIC_SCL = 0;   // 产生时钟下降沿
        DelayUs(2);  
    }
    SDA_IN;
    IIC_SCL = 1; 
    DelayUs(2); 
    int timeout = 1000; // 超时 1ms
    while (READ_SDAT_PORT && timeout--) {
        DelayUs(2);
    }
    IIC_SCL = 0; 
    SDA_OUT;
    if (timeout==0)
    {
        I2c_ResetBus();
        
    }
    
} 
/*-------------------------------------------------
 *  函数名:IIC_Read_Byte
 *    功能:  IIC读一个字节
 *  输入:  无
 *  输出:  读出存储器里面的数据并返回receive
 --------------------------------------------------*/
 unsigned char IIC_Read_Byte(void)
{
    unsigned char i,receive=0;
    SDA_IN;               //SDA设置为输入,1
    IIC_SDA=1;
    for(i=0;i<8;i++ )
    {
        receive<<=1;
        IIC_SCL=1; 
        DelayUs(5);
        
        if(IIC_SDA)receive |0x01;   
        IIC_SCL=0;
        DelayUs(4);    
    }
    SDA_OUT;
    IIC_SDA=1;    
    IIC_SCL=1;
    DelayUs(5);    
    IIC_SCL=0;
    
    SDA_IN;
    IIC_SDA=1; 
    return receive;
}
/*=================================TM1650====================================*/    
//TM1650
#define TM1650_display_cmd  0x48 //发送模式命令
#define TM1650_key_read_cmd 0x49 //按键读取命令

//显存地址定义
#define TM1650_DIG1_ADDR 0x68
#define TM1650_DIG2_ADDR 0x6A
#define TM1650_DIG3_ADDR 0x6C
#define TM1650_DIG4_ADDR 0x6E

// 显示控制命令
#define TM1650_DISPLAY_ON  0x01  // 开显示
#define TM1650_DISPLAY_OFF 0x00  // 关显示   

// 按键定义 
#define KEY_S1   0x4C
#define KEY_S2   0x4D
#define KEY_S3   0x5E
#define KEY_S4   0x44
#define KEY_S5   0x45
#define KEY_S6   0x46
#define KEY_S7   0x64
#define KEY_S8   0x65
#define KEY_S9   0x66
#define KEY_S10  0x74
#define KEY_S11  0x75
#define KEY_S12  0x76
#define KEY_S13  0x6C
#define KEY_S14  0x6D
#define KEY_S15  0x6E

// 全局变量 - 存储当前显示的数字和位数
unsigned char display_number[4] = {0, 0, 0, 0}; // 最多4位数
unsigned char current_digits = 0;               // 当前位数(0-4)

const unsigned char seg_code[] = {
        0x3F,  // 0
        0x06,  // 1
        0x5B,  // 2
        0x4F,  // 3
        0x66,  // 4
        0x6D,  // 5
        0x7D,  // 6
        0x07,  // 7
        0x7F,  // 8
        0x6F   // 9
    };
   
void LED_Blink_101010(void)
{
            LED = 1;
            DelayMs(100);
            LED = 0;
            DelayMs(100);
            LED = 1;
            DelayMs(100);
            LED = 0;
            DelayMs(100);
            LED = 1;
            DelayS(3);
            LED = 0;        
}  
void LED_Wait_Ack_1010(void)
{
            LED = 1;
            DelayMs(100);
            LED = 0;
            DelayMs(100);
            LED = 1;
            DelayS(3);
            LED = 0;       
} 
//TM1650初始化
void _TM1650_Init (unsigned char add,unsigned char data)
{
    IIC_Start();
    IIC_Send_Byte(add);
    IIC_Send_Byte(data);//0x09
            //8级亮度 \7段\正常工作\开屏
    IIC_Stop();
    
}
void power_init (unsigned char sdate1, unsigned char sdate2, unsigned char sdate3, unsigned char sdate4)
{
    _TM1650_Init(0X68,sdate1);
    _TM1650_Init(0X6A,sdate2);
    _TM1650_Init(0X6C,sdate3);
    _TM1650_Init(0X6E,sdate4);
    
}
//S15按键,清空数码管
void TM1650_Display_Clear(void)
{
    display_number[0] = 0;
    display_number[1] = 0;
    display_number[2] = 0;
    display_number[3] = 0;
    current_digits = 0;
    
    TM1650_Display_One(1, 0x00);  // 关闭第1位数码管
    TM1650_Display_One(2, 0x00);  // 关闭第2位数码管
    TM1650_Display_One(3, 0x00);  // 关闭第3位数码管
    TM1650_Display_One(4, 0x00);  // 关闭第4位数码管
}
//TM1650显示亮度
void TM1650_SetBrightness(unsigned char level)
{
    if(level>7)level=7;
    IIC_Start();
    IIC_Send_Byte(TM1650_display_cmd);
    IIC_Wait_Ack();
    IIC_Send_Byte(0x01|(level<<4));
    IIC_Wait_Ack();
    IIC_Stop();

}
//显示单个数码管
void TM1650_Display_One(unsigned char pos,unsigned char data )
{
    unsigned char addr;
    switch (pos)
    {
        case 1:
            addr=TM1650_DIG1_ADDR;
            break;
        case 2:
            addr=TM1650_DIG2_ADDR;
            break;
        case 3:
            addr=TM1650_DIG3_ADDR;
            break;
        case 4:
            addr=TM1650_DIG4_ADDR;
            break;
        default:
            addr=TM1650_DIG1_ADDR;
            break;
    }
    IIC_Start();
    IIC_Send_Byte(addr);
    IIC_Send_Byte(data);   
    IIC_Stop();
}
//显示数字
void TM1650_Display_Number(unsigned char num)
{
    
    if(num > 9) num = 0;  
    
    unsigned char data = seg_code[num];
    
    //数字左移逻辑
      if(current_digits >= 4) 
    {
        // 如果已经显示4位,则左移丢弃最高位,新数字加到最低位
        for(unsigned char i = 3; i > 0; i--)
        {
            display_number[i] = display_number[i-1];
        }
        display_number[0] = num;
    }
    else//<4
    {
        // 左移现有数字
        for(unsigned char i = current_digits; i > 0; i--)
        {
            display_number[i] = display_number[i-1];
        }
        // 添加新数字到最低位
        display_number[0] = num;
        current_digits++;
    }
    
    // 更新显示
    Update_Display();
    
}


//更新数码管显示
void Update_Display(void)
{
    // 更新4位数码管显示
    for(unsigned char i = 0; i < 4; i++)
    {
        if(i < current_digits)
        {
            TM1650_Display_One(i+1, seg_code[display_number[i]]);
        }
        else
        {
            TM1650_Display_One(i+1, 0x00); // 关闭未使用的数码管
        }
    }
}

#define NUM_KEYS 15
const unsigned char keys[NUM_KEYS] = {KEY_S1, KEY_S2, KEY_S3, KEY_S4, KEY_S5, 
                                      KEY_S6, KEY_S7, KEY_S8, KEY_S9, KEY_S10, 
                                      KEY_S11, KEY_S12, KEY_S13, KEY_S14, KEY_S15};
        
// S10按键,当前数字减一位
// S12按键,当前数字加一位
// S13按键,配码
// S14按键,响铃呼叫

//接收从机发送的按键扫描码
unsigned char ReceiveKeyScanCode(void)
{
    unsigned char key_scan_code=0xFF;
    
    IIC_Start();
    IIC_Send_Byte(TM1650_key_read_cmd);//0x49
    key_scan_code=IIC_Read_Byte();
    IIC_Stop();
    
    for (int i = 0; i < NUM_KEYS; i++) {
        if (key_scan_code == keys[i]) {
            LED_Blink_101010();
        }
    }
//    if(key_scan_code==0x2E)
//    {
//        LED_Blink_101010();
//    }
    
    return key_scan_code;
    
}
//所有处理按键事件
void Process_Key(unsigned char key)
{
     
    switch(key)
    {
        case 0x4C: TM1650_Display_Number(1); //KEY_S1   
            break;
        case 0x4D: TM1650_Display_Number(2); //KEY_S2 
            break;
        case 0x5E: TM1650_Display_Number(3); //KEY_S3 
            break;
        case 0x44: TM1650_Display_Number(4); //KEY_S4 
            break;
        case 0x45: TM1650_Display_Number(5); //KEY_S5 
            break;
        case 0x46: TM1650_Display_Number(6); //KEY_S6 
            break;
        case 0x64: TM1650_Display_Number(7); //KEY_S7 
            break;
        case 0x65: TM1650_Display_Number(8); //KEY_S8 
            break;
        case 0x66: TM1650_Display_Number(9); //KEY_S9 
            break;
//        case 0x74: //KEY_S10 
//            break;
        case 0x75:TM1650_Display_Number(0);  //KEY_S11
            break;
//        case 0x76: //KEY_S12 
//            break;
//        case 0x6C: //KEY_S13 
//            break;
//        case 0x6D: OFF_NO();          //KEY_S14 
//            break;
        case 0x6E: 
            TM1650_Display_Clear(); //KEY_S15 
            break;
        default: break;
    }
}


//===========================================================
//Function name:main
//parameters:无
//returned value:无
//===========================================================
main()
{ 
    POWER_INITIAL();        //系统初始化
    _TM1650_Init(0x48,0x09);         // 初始化TM1650
    power_init(0x3F, 0x06, 0x5B, 0x4F);
    TM1650_Display_Clear();//上电清零
    while(1)
    {
        // 读取按键状态
        unsigned char key =ReceiveKeyScanCode(); 
               
        if(key != 0)
        {          
            // 有按键按下,处理按键
            Process_Key(key);
            //防抖
            DelayMs(5);
            while(ReceiveKeyScanCode() != 0); // 等待按键释放
            DelayMs(5);
        }     
        DelayMs(5000);  
    }

return 0;

}
//=====================
上述代码,在执行到_TM1650_Init(0x48,0x09);和power_init(0x3F, 0x06, 0x5B, 0x4F);  的时候,为何开发板分别显示这样,请问是什么原因,如何解决

img

img

  • 写回答

5条回答 默认 最新

  • 阿里嘎多学长 2025-05-22 10:28
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    使用辉芒的TF61E145,通过IIC驱动TM1650

    你使用辉芒的TF61E145通过IIC驱动TM1650控制KD5641AU-07共阴数码管和按键。下面是一个简单的示例代码,使用C语言实现:

    #include <stdint.h>
    #include <stdbool.h>
    #include "ft61e145.h"
    #include "tm1650.h"
    
    #define TM1650_ADDRESS 0x20
    #define KD5641AU_07_ADDRESS 0x3F
    
    int main() {
        // 初始化FT61E145
        ft61e145_init();
    
        // 初始化TM1650
        tm1650_init(TM1650_ADDRESS);
    
        // 设置KD5641AU-07共阴数码管
        tm1650_write(TM1650_ADDRESS, KD5641AU_07_ADDRESS, 0x00);
    
        // 读取按键状态
        uint8_t key_state = ft61e145_read_key_state();
    
        // 处理按键事件
        if (key_state & 0x01) {
            // 按键1被按下
            tm1650_write(TM1650_ADDRESS, KD5641AU_07_ADDRESS, 0x01);
        } else if (key_state & 0x02) {
            // 按键2被按下
            tm1650_write(TM1650_ADDRESS, KD5641AU_07_ADDRESS, 0x02);
        }
    
        return 0;
    }
    

    这个示例代码初始化FT61E145和TM1650,然后设置KD5641AU-07共阴数码管的初始状态。最后,它读取按键状态,并根据按键状态来控制KD5641AU-07共阴数码管的显示。

    请注意,这只是一个简单的示例代码,你可能需要根据你的实际需求进行修改和优化。

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 5月29日
  • 创建了问题 5月22日