STM32模拟I2C控制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;
}

相关推荐

  1. <span style='color:red;'>STM</span><span style='color:red;'>32</span> <span style='color:red;'>I</span><span style='color:red;'>2</span><span style='color:red;'>C</span>

    STM32 I2C

    2024-03-14 10:14:03      49 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-14 10:14:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-14 10:14:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-14 10:14:03       82 阅读
  4. Python语言-面向对象

    2024-03-14 10:14:03       91 阅读

热门阅读

  1. python使用rabbitmq发送消息和接收消息数据

    2024-03-14 10:14:03       45 阅读
  2. 【Leetcode】top 100 矩阵

    2024-03-14 10:14:03       44 阅读
  3. Vuex和Pinia

    2024-03-14 10:14:03       41 阅读
  4. 虚拟环境创建笔记

    2024-03-14 10:14:03       37 阅读
  5. 面试经典-9-跳跃游戏

    2024-03-14 10:14:03       41 阅读
  6. 【C++】每日一题 146 LRU缓存

    2024-03-14 10:14:03       41 阅读
  7. 无线业务配置建议

    2024-03-14 10:14:03       43 阅读
  8. nginx配置websocket

    2024-03-14 10:14:03       35 阅读