#申请原创# @21小跑堂
在之前的多功能单相/三相电表项目上使用的是LED数码管作为显示接口,借此来跟大家分享一下LED数码管的一些驱动方式。 LED数码管是一种比较常见的显示外设,它由多个发光二极管按照图形顺序进行排列的显示器件;我们常见的有7段、8段数码管等,还有一些定制的多段位数码管,点阵序列的数码管也是其中的一种表现形式; LED数码管按照极性可分为共阴极数码管和共阳极数码管;共阴极数码管就是所有的显示字段共用一个电源负极,另一端高电平时点亮;共阳极数码管就是所有的显示字段共用一个电源正极,另一端低电平时点亮。 数码管的驱动方式有很多,我们将分两篇来讲述数码管的不同驱动实现方式;本篇主要内容如下: 1、数码管显示驱动之74HC595 2、数码管显示驱动之TM1650 3、数码管显示驱动之HT16K33 4、数码管显示驱动之MAX7219
在本篇开始之前,我们先引入SYS中新添加的一个通用程序:模拟I2C程序(下面简称sI2C),在后续的驱动编写时,需要使用到。sI2C是通过结构体的方式,定义了SCL和SDA的端口及引脚,设定了模拟I2C的速度;通过传递结构体参数的方式,来实现模拟I2C的时序控制。这样在一个程序中可以通过定义多个sI2C结构体变量,使用不同的引脚来实现对多个I2C设备的操作,底层的模拟I2C时序操作还仅仅只需要一套代码,在节省了代码空间同时也优化了代码框架。对于类似的驱动方式还可以应用到其它的MCU外设上,后面使用到了,我们再详细说明。如下所示,就是模拟I2C的实现源码: typedef struct
{
uint32_t SCL_RCC;
GPIO_TypeDef *SCL_PORT;
uint16_t SCL_PIN;
uint32_t SDA_RCC;
GPIO_TypeDef *SDA_PORT;
uint16_t SDA_PIN;
uint32_t TIME;
} sI2C_TypeDef;
#define sI2C_SCL_H(sI2C) GPIO_WriteBit(sI2C->SCL_PORT, sI2C->SCL_PIN, Bit_SET)
#define sI2C_SCL_L(sI2C) GPIO_WriteBit(sI2C->SCL_PORT, sI2C->SCL_PIN, Bit_RESET)
#define sI2C_SDA_H(sI2C) GPIO_WriteBit(sI2C->SDA_PORT, sI2C->SDA_PIN, Bit_SET)
#define sI2C_SDA_L(sI2C) GPIO_WriteBit(sI2C->SDA_PORT, sI2C->SDA_PIN, Bit_RESET)
#define sI2C_SCL_GET(sI2C) GPIO_ReadOutputDataBit(sI2C->SCL_PORT, sI2C->SCL_PIN)
#define sI2C_SDA_GET(sI2C) GPIO_ReadInputDataBit( sI2C->SDA_PORT, sI2C->SDA_PIN)
void sI2C_Delay(uint32_t Cnt)
{
while(Cnt--);
}
void sI2C_SDA_SetDirection(sI2C_TypeDef *sI2C, uint8_t Direction)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(sI2C->SDA_RCC, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = sI2C->SDA_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
if(Direction) /* Input */
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
}
else /* Output */
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
}
GPIO_Init(sI2C->SDA_PORT, &GPIO_InitStructure);
}
void sI2C_SCL_SetDirection(sI2C_TypeDef *sI2C, uint8_t Direction)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(sI2C->SCL_RCC, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = sI2C->SCL_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
if(Direction) /* Input */
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
}
else /* Output */
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
}
GPIO_Init(sI2C->SCL_PORT, &GPIO_InitStructure);
}
void sI2C_GenerateStart(sI2C_TypeDef *sI2C)
{
sI2C_SDA_H(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SDA_L(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);
}
void sI2C_GenerateStop(sI2C_TypeDef *sI2C)
{
sI2C_SDA_L(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SDA_H(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_Delay(sI2C->TIME); /* Must delay before next start */
}
void sI2C_PutACK(sI2C_TypeDef *sI2C, uint8_t ack)
{
if(ack) sI2C_SDA_H(sI2C); /* NACK */
else sI2C_SDA_L(sI2C); /* ACK */
sI2C_Delay(sI2C->TIME);
sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);
}
uint8_t sI2C_GetACK(sI2C_TypeDef *sI2C)
{
uint8_t ack = 0;
sI2C_SDA_H(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SDA_SetDirection(sI2C, 1);
sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
ack = sI2C_SDA_GET(sI2C);
sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SDA_SetDirection(sI2C, 0);
return ack;
}
uint8_t sI2C_ReadByte(sI2C_TypeDef *sI2C)
{
uint8_t Data = 0;
sI2C_SDA_H(sI2C);
sI2C_SDA_SetDirection(sI2C, 1);
for(uint8_t i = 0; i < 8; i++)
{
sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
Data <<= 1;
if(sI2C_SDA_GET(sI2C))
{
Data |= 0x01;
}
sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);
}
sI2C_SDA_SetDirection(sI2C, 0);
return Data;
}
void sI2C_WriteByte(sI2C_TypeDef *sI2C, uint8_t Data)
{
for(uint8_t i = 0; i < 8; i++)
{
if(Data & 0x80) sI2C_SDA_H(sI2C);
else sI2C_SDA_L(sI2C);
Data <<= 1;
sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SCL_L(sI2C); sI2C_Delay(sI2C->TIME);
}
}
void sI2C_Init(sI2C_TypeDef *sI2C)
{
/* Configure Simulate I2C SCL & SDA In Output Mode */
sI2C_SDA_SetDirection(sI2C, 0);
sI2C_SCL_SetDirection(sI2C, 0);
sI2C_SCL_H(sI2C); sI2C_Delay(sI2C->TIME);
sI2C_SDA_H(sI2C); sI2C_Delay(sI2C->TIME);
}
1、数码管显示驱动之74HC595 很早之前在没有数码管显示驱动芯片时,我们常用的就是使用很多的三极管来搭建驱动电路;这种实现方式占用的MCU引脚资源比较多,一段显示就需要占用一个MCU引脚,一个数码管又需要一个选择引脚,如果要驱动一个8位的8段数码管,就需要16个MCU引脚来实现。 后来为了节省资源就使用了74HC595这样的芯片,它可以进行芯片间的级连,加上驱动一个74HC595所需要的引脚数较少,在减少MCU占用引脚资源的同时又大大的提升了可驱动数码管的数量,但缺点和三级管驱动一样,需要通过MCU的程序资源来实现显示和扫描;以常用的8段数码管为例(ABCDEFG DP),如果要驱动8个8段的数码管时,就需要使用到2片74HC595芯片,一个芯片做显示段的驱动,另外一个芯片做数码管的选通控制。 在淘宝上买了一个由2个74HC595驱动的8位8段数码管,结合MM32F0140的核心板,进行连接驱动和显示: 1.1、数码管显示驱动之74HC595驱动代码: #define TM74HC595_ST_H() GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_SET)
#define TM74HC595_ST_L() GPIO_WriteBit(GPIOB, GPIO_Pin_0, Bit_RESET)
#define TM74HC595_CLK_H() GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_SET)
#define TM74HC595_CLK_L() GPIO_WriteBit(GPIOB, GPIO_Pin_1, Bit_RESET)
#define TM74HC595_SER_H() GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_SET)
#define TM74HC595_SER_L() GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET)
#define TM74HC595_OE_H() GPIO_WriteBit(GPIOB, GPIO_Pin_10, Bit_SET)
#define TM74HC595_OE_L() GPIO_WriteBit(GPIOB, GPIO_Pin_10, Bit_RESET)
uint16_t TM74HC595_RAM[8] =
{
0xFE00,0xFD00,0xFB00,0xF700,0xEF00,0xDF00,0xBF00,0x7F00,
};
void TM74HC595_Write(uint16_t Data)
{
TM74HC595_ST_L();
for(uint8_t i = 0; i < 16; i++)
{
if((Data << i) & 0x8000) TM74HC595_SER_H();
else TM74HC595_SER_L();
TM74HC595_CLK_L();
TM74HC595_CLK_H();
}
TM74HC595_ST_H();
}
void TM74HC595_DisplayChar(uint8_t Index, char ch)
{
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;
}
}
TM74HC595_RAM[Index] &= 0xFF00;
TM74HC595_RAM[Index] |= Data;
}
void TM74HC595_DisplayString(char *str)
{
uint8_t Index = 0;
while(*str != '\0')
{
if(Index == 8) break;
TM74HC595_DisplayChar(Index++, *str++);
}
}
void TM74HC595_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TM74HC595_OE_L();
TM74HC595_DisplayString("--------");
}
void TM74HC595_Handler(void)
{
static uint8_t Index = 0;
TM74HC595_Write(TM74HC595_RAM[Index]);
Index = (Index + 1) % 8;
}
void HMI_Init(void)
{
TM74HC595_Init();
TASK_Append(TASK_ID_HMI, HMI_Handler, 2);
}
void HMI_Handler(void)
{
static uint32_t Count1 = 0;
static uint32_t Count2 = 0;
char Buffer[10];
TM74HC595_Handler();
if(Count1++ >= 100)
{
Count1 = 0;
memset(Buffer, 0, sizeof(Buffer));
sprintf(Buffer, "%08d", Count2++);
TM74HC595_DisplayString(Buffer);
}
}
1.2、数码管显示驱动之74HC595运行效果: 2、数码管显示驱动之TM1650 TM1650是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,支持两路显示模式:8段*4位、7段*4位;提供了8级亮度控制,工作电压在2.8V~5.5V之间均可正常工作。TM1650采用2线串行传输协议进行通讯,类I2C的形式,使用模拟I2C实现更易于编程操作。 由于淘宝上购买的TM1650显示模块仅仅是显示,并没有带有按键部分,所以我们下面的代码只驱动了显示部分,按键部分的功能,我们会在下篇使用TM1638的模块进行分享。 2.1、数码管显示驱动之TM1650驱动代码: sI2C_TypeDef sI2C_TM1650 =
{
RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_10,
RCC_AHBENR_GPIOB, GPIOB, GPIO_Pin_11,
500
};
void TM1650_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 TM1650_DisplayString(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;
}
}
}
TM1650_WriteCMD(&sI2C_TM1650, TM1650_DIG0 | Data[0]);
TM1650_WriteCMD(&sI2C_TM1650, TM1650_DIG1 | Data[1]);
TM1650_WriteCMD(&sI2C_TM1650, TM1650_DIG2 | Data[2]);
TM1650_WriteCMD(&sI2C_TM1650, TM1650_DIG3 | Data[3]);
}
void TM1650_DisplayChar(uint8_t Index, char ch)
{
uint8_t Data = 0;
uint16_t Command[4] = {TM1650_DIG0, TM1650_DIG1, TM1650_DIG2, TM1650_DIG3};
if(Index > 3) Index = 3;
for(uint8_t i = 0; i < 38; i++)
{
if(DIGITRON_TABLE[i].ch == ch)
{
Data = DIGITRON_TABLE[i].Data;
}
}
TM1650_WriteCMD(&sI2C_TM1650, Command[Index] | Data);
}
void TM1650_Init(void)
{
sI2C_Init(&sI2C_TM1650);
TM1650_WriteCMD(&sI2C_TM1650, TM1650_SYSON_7_8SEG_ON);
TM1650_DisplayString("----");
}
void TM1650_Handler(void)
{
static uint16_t Count = 0;
char Number[10];
memset(Number, 0, sizeof(Number));
sprintf(Number, "%03d0", Count);
TM1650_DisplayString(Number);
Count = (Count + 0x1) % 1000;
}
void HMI_Init(void)
{
TM1650_Init();
TASK_Append(TASK_ID_HMI, HMI_Handler, 100);
}
void HMI_Handler(void)
{
TM1650_Handler();
}
2.2、数码管显示驱动之TM1650运行效果: 3、数码管显示驱动之HT16K33 HT16K33是合泰推出的一个带有显示缓存和按键检测功能的LED控制器驱动芯片,最大支持128段位显示(16个段和8个公共端)和13*3矩阵按键扫描;此外HT16K33还具有16级显示亮度调节、闪烁频率控制等功能;HT16K33采用I2C的通讯方式,I2C从机地址可根据要求进行硬件配置,减少I2C地址冲突。 3.1、数码管显示驱动之HT16K33驱动代码: void HT16K33_WriteCMD(uint8_t Command)
{
I2C_SendData(I2C1, Command);
while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
I2C_GenerateSTOP(I2C1, ENABLE);
while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_STOP_DET));
}
void HT16K33_WriteDAT(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
I2C_SendData(I2C1, Address);
while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
for(uint8_t i = 0; i < Length; i++)
{
I2C_SendData(I2C1, Buffer[i]);
while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
I2C_SendData(I2C1, 0x00);
while(!I2C_GetFlagStatus(I2C1, I2C_STATUS_FLAG_TFE));
}
I2C_GenerateSTOP(I2C1, ENABLE);
while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_STOP_DET));
}
void HT16K33_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C1_InitStructure;
uint8_t Heart[8] =
{
0x00, 0x18, 0x24, 0x42, 0x81, 0x99, 0x66, 0x00
};
RCC_APB1PeriphClockCmd(RCC_APB1ENR_I2C1, ENABLE);
I2C_StructInit(&I2C1_InitStructure);
I2C1_InitStructure.I2C_Mode = I2C_Mode_MASTER;
I2C1_InitStructure.I2C_OwnAddress = 0;
I2C1_InitStructure.I2C_Speed = I2C_Speed_STANDARD;
I2C1_InitStructure.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &I2C1_InitStructure);
I2C_Send7bitAddress(I2C1, 0xE0, I2C_Direction_Transmitter);
I2C_Cmd(I2C1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_1);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_1);
HT16K33_WriteCMD(0x21); /* System Setup */
HT16K33_WriteCMD(0x81); /* Display Setup */
HT16K33_WriteCMD(0xEA); /* Dimming Set */
HT16K33_WriteDAT(0x00, Heart, 0x08);
}
void HT16K33_Handler(void)
{
uint8_t NUM_FONT[10][8] =
{
{0x3E,0x22,0x22,0x22,0x22,0x22,0x3E,0x00},
{0x04,0x0C,0x04,0x04,0x04,0x04,0x0E,0x00},
{0x1C,0x22,0x02,0x04,0x08,0x10,0x3E,0x00},
{0x1C,0x22,0x02,0x04,0x02,0x22,0x1C,0x00},
{0x04,0x0C,0x14,0x24,0x3E,0x04,0x04,0x00},
{0x3E,0x20,0x20,0x3E,0x02,0x02,0x3E,0x00},
{0x3E,0x20,0x20,0x3E,0x22,0x22,0x3E,0x00},
{0x3E,0x02,0x04,0x08,0x08,0x08,0x08,0x00},
{0x3E,0x22,0x22,0x3E,0x22,0x22,0x3E,0x00},
{0x3E,0x22,0x22,0x3E,0x02,0x02,0x3E,0x00},
};
static uint8_t Index = 0;
HT16K33_WriteDAT(0x00, NUM_FONT[Index], 0x08);
Index = (Index + 1) % 10;
}
void HMI_Init(void)
{
HT16K33_Init();
TASK_Append(TASK_ID_HMI, HMI_Handler, 500);
}
void HMI_Handler(void)
{
HT16K33_Handler();
}
3.2、数码管显示驱动之HT16K33运行效果: 4、数码管显示驱动之MAX7219 MAX7219是美信推出的共阴极LED显示驱动芯片,使用3线SPI串行接口进行通讯控制。MAX7219内含硬件动态扫描电路、BCD译码器、段位驱动器;内部还含有8*8位静态RAM用于存放8个数字的显示数据,还可以直接驱动64段的LED点阵显示;此外MAX7219芯片之间还可以进行级连,用于控制显示更多的数码管或者点阵LED。 4.1、数码管显示驱动之MAX7219驱动代码: void MAX7219_InitSPI1(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2ENR_SPI1, ENABLE);
SPI_StructInit(&SPI_InitStructure);
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_DataWidth = 8;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_0); /* PA4 SPI1_NSS */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0); /* PA5 SPI1_SCK */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_0); /* PA6 SPI1_MISO */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0); /* PA7 SPI1_MOSI */
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Rx);
SPI_BiDirectionalLineConfig(SPI1, SPI_Direction_Tx);
}
uint8_t MAX7219_SPI1_SendData(uint8_t Data)
{
SPI_SendData(SPI1, Data);
while(!SPI_GetFlagStatus(SPI1, SPI_FLAG_TXEPT));
while(!SPI_GetFlagStatus(SPI1, SPI_FLAG_RXAVL));
return SPI_ReceiveData(SPI1);
}
void MAX7219_Write(uint8_t Address, uint8_t Data)
{
SPI_CSInternalSelected(SPI1, ENABLE);
MAX7219_SPI1_SendData(Address);
MAX7219_SPI1_SendData(Data);
SPI_CSInternalSelected(SPI1, DISABLE);
}
void MAX7219_DisplayChar(uint8_t Index, char ch)
{
char CodeBFont[16] = {'0','1','2','3','4','5','6','7','8','9','-','E','H','L','P',' ',};
for(uint8_t i = 0; i < 16; i++)
{
if(ch == CodeBFont[i])
{
MAX7219_Write(Index, i);
}
}
}
void MAX7219_DisplayString(char *str)
{
uint8_t Index = 8;
while(*str != '\0')
{
if(Index == 0) break;
MAX7219_DisplayChar(Index--, *str++);
}
}
void MAX7219_Init(void)
{
MAX7219_InitSPI1();
MAX7219_Write(0x09, 0xFF); /* Decode Mode */
MAX7219_Write(0x0A, 0x03); /* Intensity */
MAX7219_Write(0x0B, 0x07); /* Scan Limit */
MAX7219_Write(0x0C, 0x01); /* Shut Down */
MAX7219_Write(0x0F, 0x00); /* Display Test */
MAX7219_DisplayString("--------");
}
void MAX7219_Handler(void)
{
static uint16_t Count = 0;
char Number[10];
memset(Number, 0, sizeof(Number));
sprintf(Number, "%08d", Count++);
MAX7219_DisplayString(Number);
}
void HMI_Init(void)
{
MAX7219_Init();
TASK_Append(TASK_ID_HMI, HMI_Handler, 100);
}
void HMI_Handler(void)
{
MAX7219_Handler();
}
4.2、数码管显示驱动之MAX7219运行效果:
附件:
|