12下一页
返回列表 发新帖本帖赏金 100.00元(功能说明)

[MM32生态] 【MM32+模块】系列:06、数码管显示(一)

[复制链接]
 楼主| xld0932 发表于 2022-4-12 20:51 | 显示全部楼层 |阅读模式
#申请原创#   @21小跑堂


在之前的多功能单相/三相电表项目上使用的是LED数码管作为显示接口,借此来跟大家分享一下LED数码管的一些驱动方式。
LED数码管是一种比较常见的显示外设,它由多个发光二极管按照图形顺序进行排列的显示器件;我们常见的有7段、8段数码管等,还有一些定制的多段位数码管,点阵序列的数码管也是其中的一种表现形式;
LED数码管按照极性可分为共阴极数码管和共阳极数码管;共阴极数码管就是所有的显示字段共用一个电源负极,另一端高电平时点亮;共阳极数码管就是所有的显示字段共用一个电源正极,另一端低电平时点亮。
数码管的驱动方式有很多,我们将分两篇来讲述数码管的不同驱动实现方式;本篇主要内容如下:
1、数码管显示驱动之74HC595
2、数码管显示驱动之TM1650
3、数码管显示驱动之HT16K33
4、数码管显示驱动之MAX7219

在本篇开始之前,我们先引入SYS中新添加的一个通用程序:模拟I2C程序(下面简称sI2C,在后续的驱动编写时,需要使用到。sI2C是通过结构体的方式,定义了SCLSDA的端口及引脚,设定了模拟I2C的速度;通过传递结构体参数的方式,来实现模拟I2C的时序控制。这样在一个程序中可以通过定义多个sI2C结构体变量,使用不同的引脚来实现对多个I2C设备的操作,底层的模拟I2C时序操作还仅仅只需要一套代码,在节省了代码空间同时也优化了代码框架。对于类似的驱动方式还可以应用到其它的MCU外设上,后面使用到了,我们再详细说明。如下所示,就是模拟I2C的实现源码:
  1. typedef struct
  2. {
  3.     uint32_t      SCL_RCC;
  4.     GPIO_TypeDef *SCL_PORT;
  5.     uint16_t      SCL_PIN;

  6.     uint32_t      SDA_RCC;
  7.     GPIO_TypeDef *SDA_PORT;
  8.     uint16_t      SDA_PIN;

  9.     uint32_t      TIME;
  10. } sI2C_TypeDef;

  11. #define sI2C_SCL_H(sI2C)    GPIO_WriteBit(sI2C->SCL_PORT, sI2C->SCL_PIN, Bit_SET)
  12. #define sI2C_SCL_L(sI2C)    GPIO_WriteBit(sI2C->SCL_PORT, sI2C->SCL_PIN, Bit_RESET)

  13. #define sI2C_SDA_H(sI2C)    GPIO_WriteBit(sI2C->SDA_PORT, sI2C->SDA_PIN, Bit_SET)
  14. #define sI2C_SDA_L(sI2C)    GPIO_WriteBit(sI2C->SDA_PORT, sI2C->SDA_PIN, Bit_RESET)

  15. #define sI2C_SCL_GET(sI2C)  GPIO_ReadOutputDataBit(sI2C->SCL_PORT, sI2C->SCL_PIN)
  16. #define sI2C_SDA_GET(sI2C)  GPIO_ReadInputDataBit( sI2C->SDA_PORT, sI2C->SDA_PIN)
  1. void sI2C_Delay(uint32_t Cnt)
  2. {
  3.     while(Cnt--);
  4. }

  5. void sI2C_SDA_SetDirection(sI2C_TypeDef *sI2C, uint8_t Direction)
  6. {
  7.     GPIO_InitTypeDef GPIO_InitStructure;

  8.     RCC_AHBPeriphClockCmd(sI2C->SDA_RCC, ENABLE);

  9.     GPIO_StructInit(&GPIO_InitStructure);
  10.     GPIO_InitStructure.GPIO_Pin   = sI2C->SDA_PIN;
  11.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  12.     if(Direction)   /* Input */
  13.     {
  14.         GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
  15.     }
  16.     else            /* Output */
  17.     {
  18.         GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  19.     }

  20.     GPIO_Init(sI2C->SDA_PORT, &GPIO_InitStructure);
  21. }

  22. void sI2C_SCL_SetDirection(sI2C_TypeDef *sI2C, uint8_t Direction)
  23. {
  24.     GPIO_InitTypeDef GPIO_InitStructure;

  25.     RCC_AHBPeriphClockCmd(sI2C->SCL_RCC, ENABLE);

  26.     GPIO_StructInit(&GPIO_InitStructure);
  27.     GPIO_InitStructure.GPIO_Pin   = sI2C->SCL_PIN;
  28.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  29.     if(Direction)   /* Input */
  30.     {
  31.         GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
  32.     }
  33.     else            /* Output */
  34.     {
  35.         GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  36.     }

  37.     GPIO_Init(sI2C->SCL_PORT, &GPIO_InitStructure);
  38. }

  39. void sI2C_GenerateStart(sI2C_TypeDef *sI2C)
  40. {
  41.     sI2C_SDA_H(sI2C); sI2C_Delay(sI2C->TIME);
  42.     sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
  43.     sI2C_SDA_L(sI2C); sI2C_Delay(sI2C->TIME);
  44.     sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);
  45. }


  46. void sI2C_GenerateStop(sI2C_TypeDef *sI2C)
  47. {
  48.     sI2C_SDA_L(sI2C); sI2C_Delay(sI2C->TIME);
  49.     sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
  50.     sI2C_SDA_H(sI2C); sI2C_Delay(sI2C->TIME);

  51.     sI2C_Delay(sI2C->TIME); /* Must delay before next start */
  52. }

  53. void sI2C_PutACK(sI2C_TypeDef *sI2C, uint8_t ack)
  54. {
  55.     if(ack) sI2C_SDA_H(sI2C);   /* NACK */
  56.     else    sI2C_SDA_L(sI2C);   /* ACK  */

  57.     sI2C_Delay(sI2C->TIME);

  58.     sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
  59.     sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);
  60. }

  61. uint8_t sI2C_GetACK(sI2C_TypeDef *sI2C)
  62. {
  63.     uint8_t ack = 0;

  64.     sI2C_SDA_H(sI2C); sI2C_Delay(sI2C->TIME);

  65.     sI2C_SDA_SetDirection(sI2C, 1);

  66.     sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);

  67.     ack = sI2C_SDA_GET(sI2C);

  68.     sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);

  69.     sI2C_SDA_SetDirection(sI2C, 0);

  70.     return ack;
  71. }

  72. uint8_t sI2C_ReadByte(sI2C_TypeDef *sI2C)
  73. {
  74.     uint8_t Data = 0;

  75.     sI2C_SDA_H(sI2C);

  76.     sI2C_SDA_SetDirection(sI2C, 1);

  77.     for(uint8_t i = 0; i < 8; i++)
  78.     {
  79.         sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);

  80.         Data <<= 1;

  81.         if(sI2C_SDA_GET(sI2C))
  82.         {
  83.             Data |= 0x01;
  84.         }

  85.         sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);
  86.     }

  87.     sI2C_SDA_SetDirection(sI2C, 0);

  88.     return Data;
  89. }

  90. void sI2C_WriteByte(sI2C_TypeDef *sI2C, uint8_t Data)
  91. {
  92.     for(uint8_t i = 0; i < 8; i++)
  93.     {
  94.         if(Data & 0x80) sI2C_SDA_H(sI2C);
  95.         else            sI2C_SDA_L(sI2C);

  96.         Data <<= 1;

  97.         sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
  98.         sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);
  99.     }
  100. }

  101. void sI2C_Init(sI2C_TypeDef *sI2C)
  102. {
  103.     /* Configure Simulate I2C SCL & SDA In Output Mode */
  104.     sI2C_SDA_SetDirection(sI2C, 0);
  105.     sI2C_SCL_SetDirection(sI2C, 0);

  106.     sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
  107.     sI2C_SDA_H(sI2C); sI2C_Delay(sI2C->TIME);
  108. }

1、数码管显示驱动之74HC595
6.png
很早之前在没有数码管显示驱动芯片时,我们常用的就是使用很多的三极管来搭建驱动电路;这种实现方式占用的MCU引脚资源比较多,一段显示就需要占用一个MCU引脚,一个数码管又需要一个选择引脚,如果要驱动一个8位的8段数码管,就需要16MCU引脚来实现。
后来为了节省资源就使用了74HC595这样的芯片,它可以进行芯片间的级连,加上驱动一个74HC595所需要的引脚数较少,在减少MCU占用引脚资源的同时又大大的提升了可驱动数码管的数量,但缺点和三级管驱动一样,需要通过MCU的程序资源来实现显示和扫描;以常用的8段数码管为例(ABCDEFG DP),如果要驱动88段的数码管时,就需要使用到274HC595芯片,一个芯片做显示段的驱动,另外一个芯片做数码管的选通控制。
在淘宝上买了一个由274HC595驱动的88段数码管,结合MM32F0140的核心板,进行连接驱动和显示:
7.png 8.jpg
1.1、数码管显示驱动之74HC595驱动代码:
  1. #define TM74HC595_ST_H()    GPIO_WriteBit(GPIOB, GPIO_Pin_0,  Bit_SET)
  2. #define TM74HC595_ST_L()    GPIO_WriteBit(GPIOB, GPIO_Pin_0,  Bit_RESET)

  3. #define TM74HC595_CLK_H()   GPIO_WriteBit(GPIOB, GPIO_Pin_1,  Bit_SET)
  4. #define TM74HC595_CLK_L()   GPIO_WriteBit(GPIOB, GPIO_Pin_1,  Bit_RESET)

  5. #define TM74HC595_SER_H()   GPIO_WriteBit(GPIOB, GPIO_Pin_2,  Bit_SET)
  6. #define TM74HC595_SER_L()   GPIO_WriteBit(GPIOB, GPIO_Pin_2,  Bit_RESET)

  7. #define TM74HC595_OE_H()    GPIO_WriteBit(GPIOB, GPIO_Pin_10, Bit_SET)
  8. #define TM74HC595_OE_L()    GPIO_WriteBit(GPIOB, GPIO_Pin_10, Bit_RESET)

  9. uint16_t TM74HC595_RAM[8] =
  10. {
  11.     0xFE00,0xFD00,0xFB00,0xF700,0xEF00,0xDF00,0xBF00,0x7F00,
  12. };

  13. void TM74HC595_Write(uint16_t Data)
  14. {
  15.     TM74HC595_ST_L();

  16.     for(uint8_t i = 0; i < 16; i++)
  17.     {
  18.         if((Data << i) & 0x8000)  TM74HC595_SER_H();
  19.         else                      TM74HC595_SER_L();

  20.         TM74HC595_CLK_L();

  21.         TM74HC595_CLK_H();
  22.     }

  23.     TM74HC595_ST_H();
  24. }

  25. void TM74HC595_DisplayChar(uint8_t Index, char ch)
  26. {
  27.     uint8_t  Data = 0x00;

  28.     if(Index > 8) return;

  29.     for(uint8_t i = 0; i < 38; i++)
  30.     {
  31.         if(DIGITRON_TABLE[i].ch == ch)
  32.         {
  33.             Data = DIGITRON_TABLE[i].Data;
  34.         }
  35.     }

  36.     TM74HC595_RAM[Index] &= 0xFF00;
  37.     TM74HC595_RAM[Index] |= Data;
  38. }

  39. void TM74HC595_DisplayString(char *str)
  40. {
  41.     uint8_t Index = 0;

  42.     while(*str != '\0')
  43.     {
  44.         if(Index == 8) break;

  45.         TM74HC595_DisplayChar(Index++, *str++);
  46.     }
  47. }

  48. void TM74HC595_Init(void)
  49. {
  50.     GPIO_InitTypeDef GPIO_InitStructure;

  51.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);

  52.     GPIO_StructInit(&GPIO_InitStructure);
  53.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_10;
  54.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  55.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
  56.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  57.     TM74HC595_OE_L();

  58.     TM74HC595_DisplayString("--------");
  59. }

  60. void TM74HC595_Handler(void)
  61. {
  62.     static uint8_t Index = 0;

  63.     TM74HC595_Write(TM74HC595_RAM[Index]);

  64.     Index = (Index + 1) % 8;
  65. }

  66. void HMI_Init(void)
  67. {
  68.     TM74HC595_Init();

  69.     TASK_Append(TASK_ID_HMI, HMI_Handler, 2);
  70. }

  71. void HMI_Handler(void)
  72. {
  73.     static uint32_t Count1 = 0;
  74.     static uint32_t Count2 = 0;
  75.     char   Buffer[10];

  76.     TM74HC595_Handler();

  77.     if(Count1++ >= 100)
  78.     {
  79.         Count1 = 0;

  80.         memset(Buffer, 0, sizeof(Buffer));
  81.         sprintf(Buffer, "%08d", Count2++);

  82.         TM74HC595_DisplayString(Buffer);
  83.     }
  84. }
1.2、数码管显示驱动之74HC595运行效果:
TM74HC595.GIF
2、数码管显示驱动之TM1650
9.png
TM1650是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,支持两路显示模式:8*4位、7*4位;提供了8级亮度控制,工作电压在2.8V~5.5V之间均可正常工作。TM1650采用2线串行传输协议进行通讯,类I2C的形式,使用模拟I2C实现更易于编程操作。
由于淘宝上购买的TM1650显示模块仅仅是显示,并没有带有按键部分,所以我们下面的代码只驱动了显示部分,按键部分的功能,我们会在下篇使用TM1638的模块进行分享。
3.jpg
2.1、数码管显示驱动之TM1650驱动代码:
  1. sI2C_TypeDef sI2C_TM1650 =
  2. {
  3.     RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_10,
  4.     RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_11,
  5.     500
  6. };

  7. void TM1650_WriteCMD(sI2C_TypeDef *sI2C, uint16_t Command)
  8. {
  9.     sI2C_GenerateStart(sI2C);

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

  11.     if(sI2C_GetACK(sI2C))
  12.     {
  13.         sI2C_GenerateStop(sI2C);    return;
  14.     }

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

  16.     if(sI2C_GetACK(sI2C))
  17.     {
  18.         sI2C_GenerateStop(sI2C);    return;
  19.     }

  20.     sI2C_GenerateStop(sI2C);
  21. }

  22. void TM1650_DisplayString(char *str)
  23. {
  24.     uint8_t i = 0, j = 0, Data[4];

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

  26.     for(i = 0; i < 4; i++)
  27.     {
  28.         for(j = 0; j < 38; j++)
  29.         {
  30.             if(DIGITRON_TABLE[j].ch == str[i])
  31.             {
  32.                 Data[i] = DIGITRON_TABLE[j].Data;
  33.             }
  34.         }
  35.     }

  36.     TM1650_WriteCMD(&sI2C_TM1650, TM1650_DIG0 | Data[0]);
  37.     TM1650_WriteCMD(&sI2C_TM1650, TM1650_DIG1 | Data[1]);
  38.     TM1650_WriteCMD(&sI2C_TM1650, TM1650_DIG2 | Data[2]);
  39.     TM1650_WriteCMD(&sI2C_TM1650, TM1650_DIG3 | Data[3]);
  40. }

  41. void TM1650_DisplayChar(uint8_t Index, char ch)
  42. {
  43.     uint8_t  Data       = 0;
  44.     uint16_t Command[4] = {TM1650_DIG0, TM1650_DIG1, TM1650_DIG2, TM1650_DIG3};

  45.     if(Index > 3) Index = 3;

  46.     for(uint8_t i = 0; i < 38; i++)
  47.     {
  48.         if(DIGITRON_TABLE[i].ch == ch)
  49.         {
  50.             Data = DIGITRON_TABLE[i].Data;
  51.         }
  52.     }

  53.     TM1650_WriteCMD(&sI2C_TM1650, Command[Index] | Data);
  54. }

  55. void TM1650_Init(void)
  56. {
  57.     sI2C_Init(&sI2C_TM1650);

  58.     TM1650_WriteCMD(&sI2C_TM1650, TM1650_SYSON_7_8SEG_ON);

  59.     TM1650_DisplayString("----");
  60. }

  61. void TM1650_Handler(void)
  62. {
  63.     static uint16_t Count = 0;

  64.     char Number[10];

  65.     memset(Number, 0, sizeof(Number));
  66.     sprintf(Number,  "%03d0",  Count);

  67.     TM1650_DisplayString(Number);

  68.     Count = (Count + 0x1) % 1000;
  69. }

  70. void HMI_Init(void)
  71. {
  72.     TM1650_Init();

  73.     TASK_Append(TASK_ID_HMI, HMI_Handler, 100);
  74. }

  75. void HMI_Handler(void)
  76. {
  77.     TM1650_Handler();
  78. }
2.2、数码管显示驱动之TM1650运行效果:
TM1650.GIF
3、数码管显示驱动之HT16K33
13.png
HT16K33是合泰推出的一个带有显示缓存和按键检测功能的LED控制器驱动芯片,最大支持128段位显示(16个段和8个公共端)和13*3矩阵按键扫描;此外HT16K33还具有16级显示亮度调节、闪烁频率控制等功能;HT16K33采用I2C的通讯方式,I2C从机地址可根据要求进行硬件配置,减少I2C地址冲突。
14.jpg
3.1、数码管显示驱动之HT16K33驱动代码:
  1. void HT16K33_WriteCMD(uint8_t Command)
  2. {
  3.     I2C_SendData(I2C1, Command);
  4.     while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));

  5.     I2C_GenerateSTOP(I2C1, ENABLE);
  6.     while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_STOP_DET));
  7. }

  8. void HT16K33_WriteDAT(uint8_t Address, uint8_t *Buffer, uint8_t Length)
  9. {
  10.     I2C_SendData(I2C1, Address);
  11.     while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));

  12.     for(uint8_t i = 0; i < Length; i++)
  13.     {
  14.         I2C_SendData(I2C1, Buffer[i]);
  15.         while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));

  16.         I2C_SendData(I2C1, 0x00);
  17.         while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
  18.     }

  19.     I2C_GenerateSTOP(I2C1, ENABLE);
  20.     while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_STOP_DET));
  21. }

  22. void HT16K33_Init(void)
  23. {
  24.     GPIO_InitTypeDef GPIO_InitStructure;
  25.     I2C_InitTypeDef  I2C1_InitStructure;

  26.     uint8_t Heart[8] =
  27.     {
  28.         0x00, 0x18, 0x24, 0x42, 0x81, 0x99, 0x66, 0x00
  29.     };

  30.     RCC_APB1PeriphClockCmd(RCC_APB1ENR_I2C1, ENABLE);

  31.     I2C_StructInit(&I2C1_InitStructure);
  32.     I2C1_InitStructure.I2C_Mode       = I2C_Mode_MASTER;
  33.     I2C1_InitStructure.I2C_OwnAddress = 0;
  34.     I2C1_InitStructure.I2C_Speed      = I2C_Speed_STANDARD;
  35.     I2C1_InitStructure.I2C_ClockSpeed = 100000;
  36.     I2C_Init(I2C1, &I2C1_InitStructure);

  37.     I2C_Send7bitAddress(I2C1, 0xE0, I2C_Direction_Transmitter);

  38.     I2C_Cmd(I2C1, ENABLE);

  39.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);

  40.     GPIO_StructInit(&GPIO_InitStructure);
  41.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10 | GPIO_Pin_11;
  42.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  43.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_OD;
  44.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  45.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_1);
  46.     GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_1);

  47.     HT16K33_WriteCMD(0x21); /* System Setup  */
  48.     HT16K33_WriteCMD(0x81); /* Display Setup */
  49.     HT16K33_WriteCMD(0xEA); /* Dimming Set   */

  50.     HT16K33_WriteDAT(0x00, Heart, 0x08);
  51. }

  52. void HT16K33_Handler(void)
  53. {
  54.     uint8_t NUM_FONT[10][8] =
  55.     {
  56.         {0x3E,0x22,0x22,0x22,0x22,0x22,0x3E,0x00},
  57.         {0x04,0x0C,0x04,0x04,0x04,0x04,0x0E,0x00},
  58.         {0x1C,0x22,0x02,0x04,0x08,0x10,0x3E,0x00},
  59.         {0x1C,0x22,0x02,0x04,0x02,0x22,0x1C,0x00},
  60.         {0x04,0x0C,0x14,0x24,0x3E,0x04,0x04,0x00},
  61.         {0x3E,0x20,0x20,0x3E,0x02,0x02,0x3E,0x00},
  62.         {0x3E,0x20,0x20,0x3E,0x22,0x22,0x3E,0x00},
  63.         {0x3E,0x02,0x04,0x08,0x08,0x08,0x08,0x00},
  64.         {0x3E,0x22,0x22,0x3E,0x22,0x22,0x3E,0x00},
  65.         {0x3E,0x22,0x22,0x3E,0x02,0x02,0x3E,0x00},
  66.     };

  67.     static uint8_t Index = 0;

  68.     HT16K33_WriteDAT(0x00, NUM_FONT[Index], 0x08);

  69.     Index = (Index + 1) % 10;
  70. }

  71. void HMI_Init(void)
  72. {
  73.     HT16K33_Init();

  74.     TASK_Append(TASK_ID_HMI, HMI_Handler, 500);
  75. }

  76. void HMI_Handler(void)
  77. {
  78.     HT16K33_Handler();
  79. }
3.2、数码管显示驱动之HT16K33运行效果:
HT16K33.GIF
4、数码管显示驱动之MAX7219
11.png
MAX7219是美信推出的共阴极LED显示驱动芯片,使用3线SPI串行接口进行通讯控制。MAX7219内含硬件动态扫描电路、BCD译码器、段位驱动器;内部还含有8*8位静态RAM用于存放8个数字的显示数据,还可以直接驱动64段的LED点阵显示;此外MAX7219芯片之间还可以进行级连,用于控制显示更多的数码管或者点阵LED
12.jpg
4.1、数码管显示驱动之MAX7219驱动代码:
  1. void MAX7219_InitSPI1(void)
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStructure;
  4.     SPI_InitTypeDef  SPI_InitStructure;

  5.     RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1, ENABLE);

  6.     SPI_StructInit(&SPI_InitStructure);
  7.     SPI_InitStructure.SPI_Mode              = SPI_Mode_Master;
  8.     SPI_InitStructure.SPI_DataSize          = SPI_DataSize_8b;
  9.     SPI_InitStructure.SPI_DataWidth         = 8;
  10.     SPI_InitStructure.SPI_CPOL              = SPI_CPOL_High;
  11.     SPI_InitStructure.SPI_CPHA              = SPI_CPHA_2Edge;
  12.     SPI_InitStructure.SPI_NSS               = SPI_NSS_Soft;
  13.     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
  14.     SPI_InitStructure.SPI_FirstBit          = SPI_FirstBit_MSB;
  15.     SPI_Init(SPI1, &SPI_InitStructure);

  16.     SPI_Cmd(SPI1, ENABLE);

  17.     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);

  18.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_0);   /* PA4 SPI1_NSS  */
  19.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0);   /* PA5 SPI1_SCK  */
  20.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_0);   /* PA6 SPI1_MISO */
  21.     GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0);   /* PA7 SPI1_MOSI */

  22.     GPIO_StructInit(&GPIO_InitStructure);
  23.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
  24.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  25.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
  26.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  27.     GPIO_StructInit(&GPIO_InitStructure);
  28.     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6;
  29.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  30.     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;
  31.     GPIO_Init(GPIOA, &GPIO_InitStructure);

  32.     SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Rx);
  33.     SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);
  34. }

  35. uint8_t MAX7219_SPI1_SendData(uint8_t Data)
  36. {
  37.     SPI_SendData(SPI1, Data);
  38.     while(!SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT));

  39.     while(!SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL));
  40.     return SPI_ReceiveData(SPI1);

  41. }

  42. void MAX7219_Write(uint8_t Address, uint8_t Data)
  43. {
  44.     SPI_CSInternalSelected(SPI1, ENABLE);

  45.     MAX7219_SPI1_SendData(Address);

  46.     MAX7219_SPI1_SendData(Data);

  47.     SPI_CSInternalSelected(SPI1, DISABLE);
  48. }

  49. void MAX7219_DisplayChar(uint8_t Index, char ch)
  50. {
  51.     char CodeBFont[16] = {'0','1','2','3','4','5','6','7','8','9','-','E','H','L','P',' ',};

  52.     for(uint8_t i = 0; i < 16; i++)
  53.     {
  54.         if(ch == CodeBFont[i])
  55.         {
  56.             MAX7219_Write(Index, i);
  57.         }
  58.     }
  59. }

  60. void MAX7219_DisplayString(char *str)
  61. {
  62.     uint8_t Index = 8;

  63.     while(*str != '\0')
  64.     {
  65.         if(Index == 0) break;

  66.         MAX7219_DisplayChar(Index--, *str++);
  67.     }
  68. }

  69. void MAX7219_Init(void)
  70. {
  71.     MAX7219_InitSPI1();

  72.     MAX7219_Write(0x09, 0xFF);  /* Decode Mode  */
  73.     MAX7219_Write(0x0A, 0x03);  /* Intensity    */
  74.     MAX7219_Write(0x0B, 0x07);  /* Scan Limit   */
  75.     MAX7219_Write(0x0C, 0x01);  /* Shut Down    */
  76.     MAX7219_Write(0x0F, 0x00);  /* Display Test */

  77.     MAX7219_DisplayString("--------");
  78. }

  79. void MAX7219_Handler(void)
  80. {
  81.     static uint16_t Count = 0;
  82.     char   Number[10];

  83.     memset(Number, 0, sizeof(Number));
  84.     sprintf(Number, "%08d",  Count++);

  85.     MAX7219_DisplayString(Number);
  86. }

  87. void HMI_Init(void)
  88. {
  89.     MAX7219_Init();

  90.     TASK_Append(TASK_ID_HMI, HMI_Handler, 100);
  91. }

  92. void HMI_Handler(void)
  93. {
  94.     MAX7219_Handler();
  95. }
4.2、数码管显示驱动之MAX7219运行效果:
MAX7219.GIF

附件:
TM74HC595数据手册: TM74HC595_V1.2.PDF (987.3 KB, 下载次数: 10)
TM1650数据手册: TM1650_V1.10.PDF (599.45 KB, 下载次数: 8)
HT16K33数据手册: HT16K33.PDF (1.21 MB, 下载次数: 9)
MAX7219数据手册: MAX7219CWG.PDF (179.88 KB, 下载次数: 6)
软件工程源代码: NIXIETUBE1.zip (716.09 KB, 下载次数: 20)



打赏榜单

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

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

yangxiaor520 发表于 2022-4-12 21:07 来自手机 | 显示全部楼层
现在数码管都很少用到了
 楼主| xld0932 发表于 2022-4-12 21:37 | 显示全部楼层
yangxiaor520 发表于 2022-4-12 21:07
现在数码管都很少用到了

看应用领域的
 楼主| xld0932 发表于 2022-4-13 11:48 | 显示全部楼层
Kevinsirlee 发表于 2022-4-13 09:35
专业IC 原装进口 从业10年
NXP、ST、ON、TI、INFINEON、等半导体代理分销商,现
致力于汽车电子产品的领域 ...

你代理MM32就找你买,在MM32分论坛发其它的代理广告不好吧
www5911839 发表于 2022-4-13 14:10 | 显示全部楼层
楼主,这系列教程质量太高了,请问下会一直连载下去吗,后续会将那些内容?
请问有微信公众号或B站吗,想关注一波
 楼主| xld0932 发表于 2022-4-13 17:33 | 显示全部楼层
本帖最后由 xld0932 于 2022-5-11 11:22 编辑
www5911839 发表于 2022-4-13 14:10
楼主,这系列教程质量太高了,请问下会一直连载下去吗,后续会将那些内容?
请问有微信公众号或B站吗,想关 ...

前期会使用自己做的MM32核心板,结合市面上常见的模块来做应用分享;
 楼主| xld0932 发表于 2022-4-13 20:24 | 显示全部楼层
Kevinsirlee 发表于 2022-4-13 20:18
感谢楼主,希望有机会合作,资源交换,共享

huquanz711 发表于 2022-4-14 08:43 来自手机 | 显示全部楼层
现在数码管基本上已经退出历史舞台了
 楼主| xld0932 发表于 2022-4-14 08:48 | 显示全部楼层
huquanz711 发表于 2022-4-14 08:43
现在数码管基本上已经退出历史舞台了

存在即有市场
shifeng88 发表于 2022-4-16 22:18 | 显示全部楼层
LED数码管有市场。
shifeng88 发表于 2022-4-16 22:21 | 显示全部楼层
MM32性价比好!
麻花油条 发表于 2022-4-26 15:07 来自手机 | 显示全部楼层
干货满满,这一系列教程太棒了
 楼主| xld0932 发表于 2022-4-26 18:14 | 显示全部楼层
麻花油条 发表于 2022-4-26 15:07
干货满满,这一系列教程太棒了

tpgf 发表于 2022-5-3 11:31 | 显示全部楼层
常用的是哪种数码管啊
guanjiaer 发表于 2022-5-3 11:38 | 显示全部楼层
性价比还是相当高的
heimaojingzhang 发表于 2022-5-3 11:47 | 显示全部楼层
市场相当广阔了
keaibukelian 发表于 2022-5-3 11:56 | 显示全部楼层
有没有可能最大化的节省引脚的占用呢
labasi 发表于 2022-5-3 12:02 | 显示全部楼层
很多低成本的都在用啊
paotangsan 发表于 2022-5-3 12:08 | 显示全部楼层
现在大屏幕都是用的这种吧
 楼主| xld0932 发表于 2022-5-3 15:12 | 显示全部楼层
paotangsan 发表于 2022-5-3 12:08
现在大屏幕都是用的这种吧

实现的方案有很多,帖子中只是买了些常见的模块来分享一下的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

粉丝
快速回复 返回顶部 返回列表