发新帖本帖赏金 100.00元(功能说明)我要提问
12下一页
返回列表
打印
[MM32生态]

【MM32+模块】系列:07、数码管显示(二)

[复制链接]
1203|30
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xld0932|  楼主 | 2022-4-13 10:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#申请原创#   @21小跑堂   

随着集成电路的快速发展,LED驱动芯片的功能也随之丰富,很多在驱动LED的同时增加了按键检测的功能,支持矩阵式的按键扫描;使用这类的LED驱动在驱动LED的同时,又提供了按键功能,尽最大程度上节省了MCU所占用的软件、硬件等资源。
本篇将主要实现带有按键功能的LED驱动模块的显示及按键检测的功能:
1、数码管显示驱动之AiP650
2、数码管显示驱动之TM1638

1、数码管显示驱动之AiP650
AiP650是无锡中微爱芯推出的一款带有键盘扫描电路接口的LED驱动控制专用芯片。最多可驱动48段的共阴极数码管,最大支持7*4个按键;芯片内置了上电复位电路和时钟振荡电路,通过高速两线串行通讯接口进行控制;芯片工作在3V~5.5V之间,提供不小于25mA的段驱动电流和不小于150mA的字驱动电路,满足了市场上决大多数的数码管驱动能力。由于在淘宝上没有买到带按键检测的AiP650模组,所以就自己画了一个块来调试验证。
1.1、数码管显示驱动之AiP650原理图设计
参考AiP650数据手册上的应用线路图进行绘制,使用立创EDA进行设计,原理图如下所示:

1.2、数码管显示驱动之AiP650 PCB设计2D

1.3、数码管显示驱动之AiP650焊接调试
根据AiP650数据手册上应用线路图的设计,在R1~R4起初都是选用的2K的电路,但在实际调试程序的时候,矩阵按键的扫描结果会出现异常,同一个按键会出现不同按键值的问题,在咨询了原厂以及把板子寄给他们调试都没法确认问题出在哪里,因为完全是参考数据手册来设计的;在后来的调试、尝试下不断的去修改R1~R4的阻值,加大阻值会有明显的改善效果,最后将R1~R4的阻值定在了4.7K

1.4、数码管显示驱动之AiP650驱动程序
sI2C_TypeDef sI2C_AiP650 = 
{
    RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_10,
    RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_11,
    500
};

uint8_t AiP650_GetKey(sI2C_TypeDef *sI2C)
{
    uint8_t KeyValue = 0;

    sI2C_GenerateStart(sI2C);

    sI2C_WriteByte(sI2C, 0x4F);

    if(sI2C_GetACK(sI2C))
    {
        sI2C_GenerateStop(sI2C);    return 0x00;
    }

    KeyValue = sI2C_ReadByte(sI2C);

    sI2C_PutACK(sI2C, 1);

    sI2C_GenerateStop(sI2C);

    return KeyValue;
}

void AiP650_WriteCMD(sI2C_TypeDef *sI2C, uint16_t Command)
{
    sI2C_GenerateStart(sI2C);

    sI2C_WriteByte(sI2C, (Command >> 8) & 0xFF);

    if(sI2C_GetACK(sI2C))
    {
        sI2C_GenerateStop(sI2C);    return;
    }

    sI2C_WriteByte(sI2C, (Command >> 0) & 0xFF);

    if(sI2C_GetACK(sI2C))
    {
        sI2C_GenerateStop(sI2C);    return;
    }

    sI2C_GenerateStop(sI2C);
}

void AiP650_Display(char *str)
{
    uint8_t i = 0, j = 0, Data[4];

    memset(Data, 0, sizeof(Data));

    for(i = 0; i < 4; i++)
    {
        for(j = 0; j < 38; j++)
        {
            if(DIGITRON_TABLE[j].ch == str[i])
            {
                Data[i] = DIGITRON_TABLE[j].Data;
            }
        }
    }

    AiP650_WriteCMD(&sI2C_AiP650, AiP650_DIG0 | Data[0]);
    AiP650_WriteCMD(&sI2C_AiP650, AiP650_DIG1 | Data[1]);
    AiP650_WriteCMD(&sI2C_AiP650, AiP650_DIG2 | Data[2]);
    AiP650_WriteCMD(&sI2C_AiP650, AiP650_DIG3 | Data[3]);
}

void AiP650_DisplayNumber(uint16_t Value)
{
    char Number[10];

    memset(Number, 0, sizeof(Number));
    sprintf(Number,  "%04d",  Value);

    AiP650_Display(Number);
}

void AiP650_Init(void)
{
    /* 初始化模拟I2C引脚 */
    sI2C_Init(&sI2C_AiP650);

    /* AiP650芯片配置 */
    AiP650_WriteCMD(&sI2C_AiP650, AiP650_SYSON_7_8SEG_ON);

    /* 在LED数码管上显示内容 */
    AiP650_Display("----");
}

void AiP650_Handler(void)
{
    static uint8_t OldKeyValue = 0;

    uint8_t KeyTable[][4] =
    {
        {0x74, 0x75, 0x76, 0x77},
        {0x6C, 0x6D, 0x6E, 0x6F},
        {0x64, 0x65, 0x66, 0x67},
        {0x5C, 0x5D, 0x5E, 0x5F},
        {0x54, 0x55, 0x56, 0x57},
        {0x4C, 0x4D, 0x4E, 0x4F},
        {0x44, 0x45, 0x46, 0x47},
    };

    uint8_t KeyValue = AiP650_GetKey(&sI2C_AiP650);

    if(KeyValue != OldKeyValue)
    {
        OldKeyValue = KeyValue;

        for(uint8_t i = 0; i < 4; i++)
        {
            for(uint8_t j = 0; j < 7; j++)
            {
                if(KeyValue == KeyTable[j][i])
                {
                    AiP650_DisplayNumber(i * 7 + j + 1);

                    printf("\r\nSW%02d : 0x%02x", i * 7 + j + 1, KeyValue);
                }
            }
        }
    }
}

void HMI_Init(void)
{
    AiP650_Init();

    TASK_Append(TASK_ID_HMI, HMI_Handler, 10);
}

void HMI_Handler(void)
{
    AiP650_Handler();
}

1.5、数码管显示驱动之AiP650运行演示


2、数码管显示驱动之TM1638
TM1638是深圳天微电子推出的一款带按键扫描接口的LED(发光二极管显示器)驱动控制专用IC。最多可驱动810段的数码管(共阳极、共阴极都支持),最大支持8*3个按键;芯片内置了上电复位电路和RC振荡电路;通过3线串行通讯接口进行控制;在数据手册上提供典型的带矩阵按键扫描的共阳极和共阴极的应用硬件电路图。

2.1、数码管显示驱动之TM1638驱动程序
#define TM1638_STB_H()  GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_SET)
#define TM1638_STB_L()  GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_RESET)

#define TM1638_CLK_H()  GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_SET)
#define TM1638_CLK_L()  GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_RESET)

#define TM1638_DIO_H()  GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_SET)
#define TM1638_DIO_L()  GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET)

#define TM1638_DIO_GET()   GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2)

uint8_t TM1638_RAM[16];

void TM1638_WriteCMD(uint8_t Command)
{
    TM1638_STB_L();

    for(uint8_t i = 0; i < 8; i++)
    {
        TM1638_CLK_L();

        if(Command & (0x01 << i)) TM1638_DIO_H();
        else                      TM1638_DIO_L();

        TM1638_CLK_H();
    }

    TM1638_STB_H();
}

void TM1638_WriteRAM(uint8_t Address, uint8_t Data)
{
    TM1638_STB_L();

    for(uint8_t i = 0; i < 8; i++)
    {
        TM1638_CLK_L();

        if(Address & (0x01 << i)) TM1638_DIO_H();
        else                      TM1638_DIO_L();

        TM1638_CLK_H();
    }

    for(uint8_t i = 0; i < 8; i++)
    {
        TM1638_CLK_L();

        if(Data    & (0x01 << i)) TM1638_DIO_H();
        else                      TM1638_DIO_L();

        TM1638_CLK_H();
    }

    TM1638_STB_H();
}

void TM1638_Read(uint8_t Command, uint8_t *Buffer)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    uint8_t Data = 0;

    TM1638_STB_L();

    for(uint8_t i = 0; i < 8; i++)
    {
        TM1638_CLK_L();

        if(Command & (0x01 << i)) TM1638_DIO_H();
        else                      TM1638_DIO_L();

        TM1638_CLK_H();
    }

    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    for(uint8_t j = 0; j < 4; j++)
    {
        Data = 0;

        for(uint8_t i = 0; i < 8; i++)
        {
            TM1638_CLK_L();

            Data >>= 1;

            if(TM1638_DIO_GET() != Bit_RESET)
            {
                Data |= 0x80;
            }

            TM1638_CLK_H();
        }

        Buffer[j] = Data;
    }

    TM1638_STB_H();

    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    TM1638_DIO_H();
}

void TM1638_RAM_Refresh(void)
{
    TM1638_WriteCMD(0x88);
    TM1638_WriteCMD(0x40);

    for(uint8_t i = 0; i < 16; i++)
    {
        TM1638_WriteRAM(0xC0 + i, TM1638_RAM[i]);
    }
}

void TM1638_DisplayChar(uint8_t Index, char ch, uint8_t Update)
{
    uint8_t  Data = 0x00;

    if(Index > 8) return;

    for(uint8_t i = 0; i < 38; i++)
    {
        if(DIGITRON_TABLE[i].ch == ch)
        {
            Data = DIGITRON_TABLE[i].Data;
        }
    }

    for(uint8_t i = 0; i < 8; i++)
    {
        if(Data & (0x01 << i))
        {
            TM1638_RAM[i*2] |=  (0x01 << Index);
        }
        else
        {
            TM1638_RAM[i*2] &= ~(0x01 << Index);
        }
    }

    if(Update) TM1638_RAM_Refresh();
}

void TM1638_DisplayString(char *str)
{
    uint8_t Index = 8;

    while(*str != '\0')
    {
        if(Index == 0) break;

        TM1638_DisplayChar(--Index, *str++, 0);
    }

    TM1638_RAM_Refresh();
}

void TM1638_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    memset(TM1638_RAM, 0, sizeof(TM1638_RAM));

    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);

    GPIO_StructInit(&GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_SET);
    GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_SET);
    GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_SET);

    TM1638_RAM_Refresh();

    TM1638_DisplayString("--------");
}

void TM1638_Handler(void)
{
    uint8_t Buffer[4] = {0, 0, 0, 0};
    uint8_t String[10];

    TM1638_Read(0x42, Buffer);

    if((Buffer[0] != 0) || (Buffer[1] != 0) || (Buffer[2] != 0) || (Buffer[3] != 0))
    {
        printf("\r\n");

        if(Buffer[0] & 0x02) printf("S09");
        if(Buffer[0] & 0x20) printf("S10");
        if(Buffer[0] & 0x04) printf("S01");
        if(Buffer[0] & 0x40) printf("S02");

        if(Buffer[1] & 0x02) printf("S11");
        if(Buffer[1] & 0x20) printf("S12");
        if(Buffer[1] & 0x04) printf("S03");
        if(Buffer[1] & 0x40) printf("S04");

        if(Buffer[2] & 0x02) printf("S13");
        if(Buffer[2] & 0x20) printf("S14");
        if(Buffer[2] & 0x04) printf("S05");
        if(Buffer[2] & 0x40) printf("S06");

        if(Buffer[3] & 0x02) printf("S15");
        if(Buffer[3] & 0x20) printf("S16");
        if(Buffer[3] & 0x04) printf("S07");
        if(Buffer[3] & 0x40) printf("S08");

        memset(String, 0,  sizeof(String));
        sprintf((char *)String, "%02x%02x%02x%02x", Buffer[0], Buffer[1], Buffer[2], Buffer[3]);

        TM1638_DisplayString((char *)String);
    }
}

void HMI_Init(void)
{
    TM1638_Init();

    TASK_Append(TASK_ID_HMI, HMI_Handler, 200);
}

void HMI_Handler(void)
{
    TM1638_Handler();
}

2.2、数码管显示驱动之TM1638运行演示

附件:
AiP650数据手册: AiP650.PDF (641.27 KB)
AiP650原理图设计: AiP650原理图.PDF (88.71 KB)
TM1638数据手册: TM1638_V1.4.PDF (657.09 KB)
软件工程源代码: NIXIETUBE2.zip (715.6 KB)

使用特权

评论回复

打赏榜单

21小跑堂 打赏了 50.00 元 2022-04-15

21小跑堂 打赏了 50.00 元 2022-04-14
理由:恭喜通过原创文章审核!请多多加油哦!

沙发
xld0932|  楼主 | 2022-4-13 10:39 | 只看该作者
AiP650的矩阵按键扫描是单个按键的,无法检测2个按键被同时按下;而TM1638的矩阵按键每一个都有独立的检测码,支持任意个按键的组合!!!

使用特权

评论回复
板凳
www5911839| | 2022-4-14 12:01 | 只看该作者
太高产了

使用特权

评论回复
地板
xld0932|  楼主 | 2022-4-14 13:34 | 只看该作者

多多捧场哈

使用特权

评论回复
5
simonwifi| | 2022-4-19 17:36 | 只看该作者
本帖最后由 simonwifi 于 2022-4-19 17:38 编辑

太棒了 想要222

使用特权

评论回复
6
xld0932|  楼主 | 2022-4-19 17:40 | 只看该作者

MM32F0140的最小系统板在这个系列帖子的第一篇附件中有提供哦
下面这个是AiP650板子的Gerber文件,可以直接打板哦,供参考: Gerber_AiP650E0.zip (75.97 KB)

使用特权

评论回复
7
lzm199516| | 2022-4-19 18:11 | 只看该作者
太强了,整成一个系列的

使用特权

评论回复
8
xld0932|  楼主 | 2022-4-20 08:45 | 只看该作者
lzm199516 发表于 2022-4-19 18:11
太强了,整成一个系列的

使用特权

评论回复
9
tpgf| | 2022-5-3 13:18 | 只看该作者
不同的驱动有什么具体的区别呀

使用特权

评论回复
10
renzheshengui| | 2022-5-3 13:25 | 只看该作者
楼主手上的资源太丰富了

使用特权

评论回复
11
wakayi| | 2022-5-3 13:35 | 只看该作者
这种小板子感觉不好飞线啊

使用特权

评论回复
12
wowu| | 2022-5-3 13:46 | 只看该作者
我就看这个小板子真是不错

使用特权

评论回复
13
xiaoqizi| | 2022-5-3 14:26 | 只看该作者
各种大板子都能用啊

使用特权

评论回复
14
木木guainv| | 2022-5-3 14:35 | 只看该作者
板子的成本大概是多少啊

使用特权

评论回复
15
xld0932|  楼主 | 2022-5-3 15:12 | 只看该作者
木木guainv 发表于 2022-5-3 14:35
板子的成本大概是多少啊

哪块板子的成本呀?

使用特权

评论回复
16
xld0932|  楼主 | 2022-5-4 21:57 | 只看该作者
tpgf 发表于 2022-5-3 13:18
不同的驱动有什么具体的区别呀

只是硬件方案不同而已,在使用的时候也需要根据你们需求来判断,选择的驱动芯片能否满足功能需求。

使用特权

评论回复
17
xld0932|  楼主 | 2022-5-4 21:57 | 只看该作者
renzheshengui 发表于 2022-5-3 13:25
楼主手上的资源太丰富了

使用特权

评论回复
18
xld0932|  楼主 | 2022-5-4 21:58 | 只看该作者
wowu 发表于 2022-5-3 13:46
我就看这个小板子真是不错

使用特权

评论回复
19
xld0932|  楼主 | 2022-5-4 21:59 | 只看该作者
wakayi 发表于 2022-5-3 13:35
这种小板子感觉不好飞线啊

核心板方便连线,连接外部各种模块;功能板只是特定功能画的,功能相对固定,就不需要太多飞线了;具体看想怎么用

使用特权

评论回复
20
keydongle2| | 2022-5-26 16:16 | 只看该作者
不错

使用特权

评论回复
发新帖 本帖赏金 100.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:上海灵动微电子股份有限公司资深现场应用工程师
简介:诚信·承诺·创新·合作

67

主题

2993

帖子

29

粉丝