使用STM32模拟I2C控制TM1650数码管显示电压和电流

模拟I2C控制TM1650数码管显示电压电流

  • 数码管的逻辑
  • TM1650 原理
  • 模拟I2C的实现
  • TM1650驱动
  • 电压电流显示
  • 数码管的逻辑

    通过数码管来表示字符。

    数码管的abcdefg和dp分别对应这发送过去的8位数据位比如0x3F -> 0011 1111 表示0字符。
    如果要加上小数点则在最高位加一,变成了 1011 1111。

    TM1650 原理

    SCL:串行通信时钟线

    SDA:串行通信数据线

    做数码管驱动使用时

    DIGx:数码管的位选引脚,灌电流驱动,最大可吸收150mA电流
    A~DP:数码管的段驱动引脚,拉电流驱动,最大可输出25mA电流

    这个指令用于设置数码管显示的相关参数。例如亮度,7段或者8段显示,显示的开关。模式命令固定为0x48,而显示命令则满足以下格式:

    TM1650内部有4字节的显存,地址分别为0x68,0x6A,0x6C,0x6E,分别用于存放显示在DIG1,DIG2,DIG3,DIG4的段码数据。例如想要让DIG1对应的数码管位显示数字2,则要往0x68单元写入数字2的共阴段码0x5b。

    模拟I2C的实现

    这边主要参考了Leung_ManWah老哥

    static void SDA_OUT_MODE(void);
    static void SDA_IN_MODE(void);
    
    void IIC2_Init(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
        __HAL_RCC_GPIOA_CLK_ENABLE();
    
        GPIO_InitStructure.Pin    = IIC_SCL_PIN;
        GPIO_InitStructure.Speed  = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStructure.Mode   = GPIO_MODE_OUTPUT_OD;
        GPIO_InitStructure.Pull   = GPIO_PULLDOWN;
        HAL_GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);
    
        GPIO_InitStructure.Pin = IIC_SDA_PIN;
        HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
    
        IIC_Stop();
    }
    
    void IIC_Start(void)
    {
        SDA_OUT_MODE();
    
        IIC_SDA_1();
        IIC_SCL_1();
        HAL_Delay(1);
        IIC_SDA_0();
        HAL_Delay(1);
        IIC_SCL_0();
    }
    
    void IIC_Stop(void)
    {
        SDA_OUT_MODE();
    
        IIC_SCL_0();
        IIC_SDA_0();
        IIC_SCL_1();
        HAL_Delay(1);
        IIC_SDA_1();
        HAL_Delay(1);
    }
    
    void IIC_SendByte(uint8_t ucByte)
    {
        uint8_t i;
    
        SDA_OUT_MODE();
    
        IIC_SCL_0();
    
        for (i = 0; i < 8; i++)
        {
            if (ucByte & 0x80)
            {
                IIC_SDA_1();
            }
            else
            {
                IIC_SDA_0();
            }
            ucByte <<= 1;
            HAL_Delay(1);
            IIC_SCL_1();
            HAL_Delay(1);
            IIC_SCL_0();
            HAL_Delay(1);
        }
    }
    
    uint8_t IIC_ReadByte(void)
    {
        uint8_t i = 0;
        uint8_t value = 0;
    
        SDA_IN_MODE();
    
        for (i = 0; i < 8; i++)
        {
            value <<= 1;
            IIC_SCL_1();
            HAL_Delay(1);
            if (IIC_SDA_READ())
            {
                value++;
            }
            IIC_SCL_0();
            HAL_Delay(1);
        }
        IIC_Ack();
    
        return value;
    }
    
    uint8_t IIC_WaitAck(void)
    {
        uint8_t result = 0;
    
        SDA_IN_MODE();
    
        IIC_SDA_1();
        HAL_Delay(1);
        IIC_SCL_1();
        HAL_Delay(1);
        if (IIC_SDA_READ())
        {
            result = 1;
        }
        else
        {
            result = 0;
        }
        IIC_SCL_0();
        HAL_Delay(1);
    
        return result;
    }
    
    void IIC_Ack(void)
    {
        SDA_OUT_MODE();
    
        IIC_SDA_0();
        HAL_Delay(1);
        IIC_SCL_1();
        HAL_Delay(1);
        IIC_SCL_0();
        HAL_Delay(1);
        IIC_SDA_1();
    }
    
    void IIC_NAck(void)
    {
        SDA_OUT_MODE();
    
        IIC_SDA_1();
        HAL_Delay(1);
        IIC_SCL_1();
        HAL_Delay(1);
        IIC_SCL_0();
        HAL_Delay(1);
    }
    
    uint8_t IIC_CheckDevice(uint8_t address)
    {
        uint8_t ucAck;
    
        IIC2_Init();
        IIC_Start();
        IIC_SendByte(address);
        ucAck = IIC_WaitAck();
        IIC_Stop();
    
        return ucAck;
    }
    
    static void SDA_OUT_MODE(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        GPIO_InitStructure.Pin   = IIC_SDA_PIN;
        GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStructure.Mode  = GPIO_MODE_OUTPUT_OD;
        HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
    }
    
    static void SDA_IN_MODE(void)
    {
        GPIO_InitTypeDef GPIO_InitStructure;
    
        GPIO_InitStructure.Pin  = IIC_SDA_PIN;
        GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
        HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
    }
    
    

    TM1650驱动

    这边在老哥的基础上增加了对字符 A P V的显示

    
    static uint8_t s_7number[13] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x73, 0x3E, 0x77}; // 7display 0~9 %(P) V A
    static uint8_t s_8number[13] = {0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87, 0xFF, 0xEF, 0xF3, 0xBE, 0xF7}; // 8display 0~9 %(P) V A
    
    void TM1650_Write(uint8_t addr, uint8_t data)
    {
        IIC_Start();
        IIC_SendByte(addr);
        IIC_WaitAck();
        IIC_SendByte(data);
        IIC_Ack();
        IIC_Stop();
    }
    
    void TM1650_SetDisplay(uint8_t brightness, uint8_t mode, uint8_t state)
    {
        if(state)
        {
            if(mode == 7)                                                   // 7display
            {
                TM1650_Write(0x48, brightness*16 + 1*4 + 1);
            }
            else if(mode == 8)												// 8display
            {
                TM1650_Write(0x48, brightness*16 + 1);
            }
        }
        else
        {
            TM1650_Write(0x48, 0x00);                                       // close
        }
    }
    
    void TM1650_SetNumber(uint8_t index, uint8_t mode, uint8_t num)
    {
        uint8_t indexAddr = 0;
        uint8_t numValue = 0;
    
        if(index == 1)
        {
            indexAddr = 0x68;
        }
        else if(index == 2)
        {
            indexAddr = 0x6A;
        }
        else if(index == 3)
        {
            indexAddr = 0x6C;
        }
        else if(index == 4)
        {
            indexAddr = 0x6E;
        }
    
        if(mode == 7)                                                   	// 7display
        {
            numValue = s_7number[num];
        }
        else if(mode == 8)													// 8display
        {
            numValue = s_8number[num];
        }
    
        TM1650_Write(indexAddr, numValue);
    }
    
    

    电压电流显示

    这边应用层 对电压采用两位整数一位小数的显示方式,对电流采用一位整数两位小数的显示方式

    int current_display(float current)
    {
        int display_num;
        TM1650_SetDisplay(3, 8, 0);
    
        if (current <= 0)
        {
            return OPEN_ERR;
        }
    
        TM1650_SetDisplay(0, 8, 1);
    
        if (current > 10)
        {
            display_num = (int)(current * 0.1f);
            TM1650_SetNumber(1, 7, (display_num % 10));
        }
        else
        {
            TM1650_SetNumber(1, 7, 0);
        }
    
        if (current >= 1)
        {
            display_num = (int)current;
            TM1650_SetNumber(2, 8, (display_num % 10));
        }
        else
        {
            TM1650_SetNumber(2, 8, 0);
        }
    
        display_num = (int)(current*10.0f);
        TM1650_SetNumber(3, 7, (display_num % 10));
    
        TM1650_SetNumber(4, 7, A);
    
        return OK;
    }
    
    int voltage_display(float voltage)
    {
        int display_num;
        TM1650_SetDisplay(3, 8, 0);
    
        if (voltage <= 0)
        {
            return OPEN_ERR;
        }
    
        TM1650_SetDisplay(0, 8, 1);
    
        if (voltage > 10)
        {
            display_num = (int) (voltage *0.1f);
            TM1650_SetNumber(1, 7, display_num % 10);
        }
        else
        {
            TM1650_SetNumber(1, 7, 0);
        }
    
        if (voltage >= 1)
        {
            display_num = (int) voltage;
            TM1650_SetNumber(2, 8, (display_num % 10));
        }
        else
        {
            TM1650_SetNumber(2, 8, 0);
        }
    
        display_num = (int) (voltage * 10.0f);
        TM1650_SetNumber(3, 7, (display_num % 10));
    
        TM1650_SetNumber(4, 7, V);
    
        return OK;
    }
    

    作者:爱煲汤的夏二

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用STM32模拟I2C控制TM1650数码管显示电压和电流

    发表回复