芯片:STM32F103C8T6、TM1638 驱动方式:模拟IO(需要驱动88个数码管,每个TM1638可以驱动8个数码管,一共需要11个TM1638芯片,需要11个IO口) 数码管:共阴方式
前言
TM1638数据手册的解读可以参考[文章](https://blog.csdn.net/qq_39829913/article/details/104661381),写得非常详细,相信可以帮助新手理解,我这篇文章主要是想给出一个工程的例子。
一、项目详情
1、引脚连接
STM32 PA5–>TM1638_CLK; PA7–>TM1638_DIO; PB0–>STB_1 PB1–>STB_2 … 依次连接11个TM1638芯片; TM1638 SEG1~10:连接数码管的对应引脚; GRID1~8:连接两个TM1638的对应引脚; 2、实现效果 编写了一个动画,具体看后面介绍。
二、代码
1.所用结构体和数组
#define NUM_OF_TMCHIP 11
#define NUM_OF_SEGLED 88
const uint8_t CODE[17]={
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
0x77,0x7C,0x39,0x5E,0x79,0x71,0x00
};
const uint8_t COLOR[8]={
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
};
typedef struct NSS_IO{
GPIO_TypeDef * NSS_Port;
uint16_t NSS_PIN;
}NSS_IO_t;
static NSS_IO_t NSS_List[NUM_OF_TMCHIP]={
{SEGLED_STB1_GPIO_Port,SEGLED_STB1_Pin},
{SEGLED_STB2_GPIO_Port,SEGLED_STB2_Pin},
{SEGLED_STB3_GPIO_Port,SEGLED_STB3_Pin},
{SEGLED_STB4_GPIO_Port,SEGLED_STB4_Pin},
{SEGLED_STB5_GPIO_Port,SEGLED_STB5_Pin},
{SEGLED_STB6_GPIO_Port,SEGLED_STB6_Pin},
{SEGLED_STB7_GPIO_Port,SEGLED_STB7_Pin},
{SEGLED_STB8_GPIO_Port,SEGLED_STB8_Pin},
{SEGLED_STB9_GPIO_Port,SEGLED_STB9_Pin},
{SEGLED_STB10_GPIO_Port,SEGLED_STB10_Pin},
{SEGLED_STB11_GPIO_Port,SEGLED_STB11_Pin},
};
2.函数
void TM1638_GPIO_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_1);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
GPIO初始化。
void Write_Byte(u8 byte)
{
u8 i;
u8 temp;
temp=byte;
for(i=0;i<8;i++)
{
GPIO_ResetBits(SEGLED_SCLK_GPIO_Port,SEGLED_SCLK_Pin);
delay_us(3);
if(temp & 0x01) GPIO_SetBits(SEGLED_DIO_GPIO_Port,SEGLED_DIO_Pin);
else GPIO_ResetBits(SEGLED_DIO_GPIO_Port,SEGLED_DIO_Pin);
delay_us(3);
GPIO_SetBits(SEGLED_SCLK_GPIO_Port,SEGLED_SCLK_Pin);
delay_us(3);
temp >>= 1;
}
}
void Write_Cmd(GPIO_TypeDef* NSS_Port, uint16_t NSS_PIN, u8 cmd)
{
GPIO_SetBits(NSS_Port,NSS_PIN);
delay_us(3);
GPIO_ResetBits(NSS_Port,NSS_PIN);
delay_us(3);
Write_Byte(cmd);
}
STB先拉高,再拉低,就可以开始写入数据或命令了。
void Write_Data(GPIO_TypeDef* NSS_Port, uint16_t NSS_PIN, u8 addr, u8 data, u8 data2 )
{
Write_Cmd(NSS_Port, NSS_PIN, 0x8F);
Write_Cmd(NSS_Port, NSS_PIN, 0x40);
Write_Cmd(NSS_Port, NSS_PIN, 0xC0 | addr);
Write_Byte(data);
Write_Byte(data2);
delay_us(3);
GPIO_SetBits(NSS_Port,NSS_PIN);
}
根据数据手册的流程图,先写入若干命令。
void TM1638_SendData(u8 chipNum, u8 data, u8 data2)
{
u8 temp;
temp=data2;
temp=temp>>2;
temp=temp<<7;
Write_Data(NSS_List[chipNum/8].NSS_Port, NSS_List[chipNum/8].NSS_PIN, chipNum%8*2, data |temp ,data2 & 0x03);
}
此函数用于在指定的数码管显示数字和颜色。
void TM1638_clear(void)
{
u8 i;
for(i=0;i<NUM_OF_SEGLED;i++)
{
TM1638_SendData(i,0x00,0x00);
}
}
用于数码管清零。
void TM1638_SHOW()
{
TM1638_clear();
u8 i;
for(i=0;i<=3;i++)
{
TM1638_SendData(i,CODE[5],Color_LessBlue);
delay_ms(40);
}
delay_ms(1000);
TM1638_clear();
for(i=4;i<=7;i++)
{
TM1638_SendData(i,CODE[4],Color_Blue);
delay_ms(40);
}
delay_ms(1000);
TM1638_clear();
for(i=8;i<=11;i++)
{
TM1638_SendData(i,CODE[3],Color_Green);
delay_ms(40);
}
delay_ms(1000);
TM1638_clear();
for(i=12;i<=15;i++)
{
TM1638_SendData(i,CODE[2],Color_Pink);
delay_ms(40);
}
delay_ms(1000);
TM1638_clear();
for(i=0;i<=15;i++)
{
TM1638_SendData(i,CODE[1],COLOR[i%7+1]);
delay_ms(60);
}
delay_ms(1000);
TM1638_clear();
for(i=0;i<=15;i++)
{
TM1638_SendData(i,0x00,Color_Blue);
TM1638_SendData(15-i,0x00,Color_Green);
delay_ms(60);
TM1638_clear();
delay_ms(10);
}
for(i=0;i<=15;i++)
{
TM1638_SendData(i,0x00,COLOR[i%7+1]);
TM1638_SendData(15-i,0x00,COLOR[i%7+1]);
delay_ms(60);
TM1638_clear();
delay_ms(10);
}
}
编写了一个动画效果:首先是5、4、3、2、1的倒计时,然后彩色的灯同时从左到右、从右到左循环两次。 实现效果如下:
总结
网上的资料质量参差不齐,希望这篇文章对大家学习TM1638有所帮助。
|