xld0932 发表于 2022-4-13 10:29

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

#申请原创#   @21小跑堂   

随着集成电路的快速发展,LED驱动芯片的功能也随之丰富,很多在驱动LED的同时增加了按键检测的功能,支持矩阵式的按键扫描;使用这类的LED驱动在驱动LED的同时,又提供了按键功能,尽最大程度上节省了MCU所占用的软件、硬件等资源。 本篇将主要实现带有按键功能的LED驱动模块的显示及按键检测的功能:1、数码管显示驱动之AiP6502、数码管显示驱动之TM1638 static/image/hrline/line1.png
1、数码管显示驱动之AiP650 AiP650是无锡中微爱芯推出的一款带有键盘扫描电路接口的LED驱动控制专用芯片。最多可驱动4位8段的共阴极数码管,最大支持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;

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

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

    AiP650_WriteCMD(&sI2C_AiP650, AiP650_DIG0 | Data);
    AiP650_WriteCMD(&sI2C_AiP650, AiP650_DIG1 | Data);
    AiP650_WriteCMD(&sI2C_AiP650, AiP650_DIG2 | Data);
    AiP650_WriteCMD(&sI2C_AiP650, AiP650_DIG3 | Data);
}

void AiP650_DisplayNumber(uint16_t Value)
{
    char Number;

    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[] =
    {
      {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)
                {
                  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。最多可驱动8位10段的数码管(共阳极、共阴极都支持),最大支持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;

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 = 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);
    }
}

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

    if(Index > 8) return;

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

    for(uint8_t i = 0; i < 8; i++)
    {
      if(Data & (0x01 << i))
      {
            TM1638_RAM |=(0x01 << Index);
      }
      else
      {
            TM1638_RAM &= ~(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 = {0, 0, 0, 0};
    uint8_t String;

    TM1638_Read(0x42, Buffer);

    if((Buffer != 0) || (Buffer != 0) || (Buffer != 0) || (Buffer != 0))
    {
      printf("\r\n");

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

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

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

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

      memset(String, 0,sizeof(String));
      sprintf((char *)String, "%02x%02x%02x%02x", Buffer, Buffer, Buffer, Buffer);

      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原理图设计:TM1638数据手册:软件工程源代码:

xld0932 发表于 2022-4-13 10:39

AiP650的矩阵按键扫描是单个按键的,无法检测2个按键被同时按下;而TM1638的矩阵按键每一个都有独立的检测码,支持任意个按键的组合!!!

www5911839 发表于 2022-4-14 12:01

太高产了

xld0932 发表于 2022-4-14 13:34

www5911839 发表于 2022-4-14 12:01
太高产了

多多捧场哈

simonwifi 发表于 2022-4-19 17:36

本帖最后由 simonwifi 于 2022-4-19 17:38 编辑

太棒了 想要222

xld0932 发表于 2022-4-19 17:40

simonwifi 发表于 2022-4-19 17:36
太棒了 想要222

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

lzm199516 发表于 2022-4-19 18:11

太强了,整成一个系列的

xld0932 发表于 2022-4-20 08:45

lzm199516 发表于 2022-4-19 18:11
太强了,整成一个系列的

tpgf 发表于 2022-5-3 13:18

不同的驱动有什么具体的区别呀

renzheshengui 发表于 2022-5-3 13:25

楼主手上的资源太丰富了

wakayi 发表于 2022-5-3 13:35

这种小板子感觉不好飞线啊

wowu 发表于 2022-5-3 13:46

我就看这个小板子真是不错

xiaoqizi 发表于 2022-5-3 14:26

各种大板子都能用啊

木木guainv 发表于 2022-5-3 14:35

板子的成本大概是多少啊

xld0932 发表于 2022-5-3 15:12

木木guainv 发表于 2022-5-3 14:35
板子的成本大概是多少啊

哪块板子的成本呀?

xld0932 发表于 2022-5-4 21:57

tpgf 发表于 2022-5-3 13:18
不同的驱动有什么具体的区别呀

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

xld0932 发表于 2022-5-4 21:57

renzheshengui 发表于 2022-5-3 13:25
楼主手上的资源太丰富了

xld0932 发表于 2022-5-4 21:58

wowu 发表于 2022-5-3 13:46
我就看这个小板子真是不错

xld0932 发表于 2022-5-4 21:59

wakayi 发表于 2022-5-3 13:35
这种小板子感觉不好飞线啊

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

keydongle2 发表于 2022-5-26 16:16

不错
页: [1] 2
查看完整版本: 【MM32+模块】系列:07、数码管显示(二)