4位数码管显示模块TM1637芯片C语言驱动程序

26 篇文章 1 订阅
19 篇文章 2 订阅

一、概述

TM1637 是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数
字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。芯片手册已上传到资源,需要的可以下载,链接https://download.csdn.net/download/wanglong3713/40836173
使用的显示模块在某宝、某多价格很便宜,4位数码管,带时间点,适合做电子时钟,另外还有不带时间点的,使用的芯片是GN1637,还有AIP1637,实际与TM1637通用,驱动程序也可以通用。
在这里插入图片描述
本例采用STM32F103C8T6芯片,在IAR环境下编写,配置采用STM32CubeMX,使用了HAL库。

二、 源代码

2.1 IIC接口驱动

在这里插入图片描述
先看数据手册的接口说明,如上图,看这描述,这是IIC啊,因此找来之前写过的IIC驱动函数移植,但是实际在使用的时候发现给TM1637发送命令时并无响应,后来仔细看手册中的下面的内容:
在这里插入图片描述
我们知道,标准的IIC协议是从高位到低位传输的,即MSB方式,而TM1637实际是非标准的IIC协议,而且这个器件连地址都没有,不能多个TM1637同时使用同一条总线!
所以,IIC驱动需要修改,为了方便移植,采用条件编译的方式:

/*
说明:标准IIC协议传输数据时为MSB方式,即高位在前低位在后,但有些器件为LSB方式,
即低位在前,高位在后,如TM1637数码管驱动芯片。
*/
#define IIC_LSB//定义了则IIC在数据传输时低位在前
/*******************************************************************************
  * 函数名:IIC_Start
  * 功  能:起始信号
  * 参  数:无
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void IIC_Start(void)
{
	IIC_SdaModeOut();
	IIC_SdaOutput_H();
	IIC_SclOutput_H();
	delay_us(5);//>4.7us
	IIC_SdaOutput_L();
	delay_us(4);//>4us
	IIC_SclOutput_L();
}
/*******************************************************************************
  * 函数名:IIC_Stop
  * 功  能:结束信号
  * 参  数:无
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void IIC_Stop(void)
{
	IIC_SdaModeOut();
	IIC_SclOutput_L();
	IIC_SdaOutput_L();
	IIC_SclOutput_H();
	delay_us(5);//>4us
	IIC_SdaOutput_H();
	delay_us(4);//>4.7us
	//IIC_SdaOutput_L();
}
/*******************************************************************************
  * 函数名:IIC_Ack
  * 功  能:应答信号
  * 参  数:无
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void IIC_Ack(void)
{
	IIC_SclOutput_L();
	IIC_SdaModeOut();	
	IIC_SdaOutput_L();
	delay_us(2);
	IIC_SclOutput_H();
	delay_us(4);//>4us
	IIC_SclOutput_L();
}
/*******************************************************************************
  * 函数名:IIC_NoAck
  * 功  能:非应答信号
  * 参  数:无
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void IIC_NoAck(void)
{
	IIC_SclOutput_L();
	IIC_SdaModeOut();
	IIC_SdaOutput_H();
	delay_us(4);
	IIC_SclOutput_H();
	delay_us(4);//>4us
	IIC_SclOutput_L();
}
/*******************************************************************************
  * 函数名:IIC_WaitAck
  * 功  能:等待应答信号
  * 参  数:无
  * 返回值:0应答成功,1应答失败
  * 说  明:从机把总线拉低,为应答成功
*******************************************************************************/
uint8_t IIC_WaitAck(void)
{
	uint8_t u8ErrCnt = 0;
	IIC_SdaModeIn();//输入状态
	IIC_SdaOutput_H();
	IIC_SclOutput_H();
	while (IIC_SdaRead() == 1)
	{
		u8ErrCnt++;
		if (u8ErrCnt > 250)
		{
			IIC_Stop();//发送停止信号
		   	return 1;
		}
	}
	IIC_SclOutput_L();
	return 0;
}
/*******************************************************************************
  * 函数名:IIC_WriteByte
  * 功  能:SDA线上输出一个字节
  * 参  数:u8Data需要写入的数据
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void IIC_WriteByte(uint8_t u8Data)
{
	uint8_t i;
	uint8_t u8Temp;
	IIC_SdaModeOut();
	IIC_SclOutput_L();
	for (i = 0; i < 8; i++)
	{
		delay_us(2);
		#ifdef IIC_LSB//低位在前
		u8Temp = ((u8Data << (7 - i)) & 0x80);
		(u8Temp == 0x80) ? (IIC_SdaOutput_H()) : (IIC_SdaOutput_L());		
		#else//高位在前
		u8Temp = ((u8Data >> (7 - i)) & 0x01);
		(u8Temp == 0x01) ? (IIC_SdaOutput_H()) : (IIC_SdaOutput_L());
		#endif		
		IIC_SclOutput_H();//时钟保持高电平
		delay_us(2);
		IIC_SclOutput_L();//时钟拉低,才允许SDA变化
	}
}
/*******************************************************************************
  * 函数名:IIC_ReadByte
  * 功  能:读一个字节
  * 参  数:无
  * 返回值:读出的数据
  * 说  明:无
*******************************************************************************/
uint8_t IIC_ReadByte(void)
{
	uint8_t i;
	uint8_t bit = 0;
	uint8_t data = 0;
	IIC_SdaModeIn();//输入状态
	for (i = 0; i < 8; i++)
	{
		IIC_SclOutput_L();
		delay_us(2);
		IIC_SclOutput_H();
		bit = IIC_SdaRead();//读出1位
		#ifdef IIC_LSB//低位在前
		data |= (bit << i);		
		#else//高位在前
		data = (data << 1) | bit;
		#endif
		delay_us(2);
	}
	return data;
}

以上代码中的delay_us()函数,如果使用的是STM32F103单片机,可参考通用定时器实现STM32单片机微秒级延时函数
其中的SCL/SDA引脚的操作,采用宏定义:

#define IIC_SdaModeOut()					Port_SetMode(GPIOB, GPIO_PIN_7, GPIO_MODE_OUTPUT_OD)
#define IIC_SdaModeIn()						Port_SetMode(GPIOB, GPIO_PIN_7, GPIO_MODE_INPUT)
#define IIC_SdaOutput_H()					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET)
#define IIC_SdaOutput_L()					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET)
#define IIC_SdaRead()						HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)

#define IIC_SclModeOut()					Port_SetMode(GPIOB, GPIO_PIN_6, GPIO_MODE_OUTPUT_OD)
#define IIC_SclModeIn()						Port_SetMode(GPIOB, GPIO_PIN_6, GPIO_MODE_INPUT)
#define IIC_SclOutput_H()					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET)
#define IIC_SclOutput_L()					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET)

Port_SetMode()函数:

/*******************************************************************************
  * 函数名:Port_SetMode
  * 功  能:GPIO设置输入或输出模式
  * 参  数:*GPIOx 引脚组号
			GPIO_Pin引脚号
			u32Mode输入或输出模式
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void Port_SetMode(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, uint32_t u32Mode)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	GPIO_InitStruct.Pin = GPIO_Pin;
	GPIO_InitStruct.Mode = u32Mode;
	//GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}

2.2 TM1637驱动函数

根据手册,写SRAM数据时,我们采用固定地址的方式,这样可以方便地对任意一个数码管写入数据,
再构造写命令、写数据、设置亮度、开关等功能的函数:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
TM1637.h文件:

/*******************************************************************************
  * 文件:TM1637.h
  * 作者:https://blog.csdn.net/wanglong3713
  * 版本:v1.0
  * 日期:2021-11-2
  * 说明:TM1637驱动
*******************************************************************************/
#ifndef _TM1637_H_
#define _TM1637_H_

#include "Typedefine.h"
#define TUBE_DISPLAY_NULL							26//不显示
#define TUBE_DISPLAY_DECIMAL_PIONT_OFFSET			16//带小数点的偏移量
/*******************************************************************************
Typedefine
*******************************************************************************/
typedef struct 
{
	uint8_t tube0;
	uint8_t tube1;
	uint8_t tube2;
	uint8_t tube3;
}TM1637Tube_ts;
/*******************************************************************************
Global Functions
*******************************************************************************/
void TM1637_WriteCmd(uint8_t u8Cmd);
void TM1637_WriteData(uint8_t u8Addr, uint8_t u8Data);
void TM1637_TubeDisplay(TM1637Tube_ts sData);
void  TM1637_SetBrightness(uint8_t u8Brt);
void  TM1637_Switch(bool bState);
#endif

TM637.c文件:

/*******************************************************************************
  * 文件:TM1637.c
  * 作者:https://blog.csdn.net/wanglong3713
  * 版本:v1.0
  * 日期:2021-11-2
  * 说明:TM1637驱动
*******************************************************************************/
#include "IIC.h"
#include "TM1637.h"

//段码表
const uint8_t u8NumTab[] = 
{
	//0,	1,	2,	3,	4,	   5,	6,   7,  8,   9,    A,   b,  C,   d,   E,   F,  	
	0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
	//0., 1.,	2.,	3.,	 4.,  5.,   6.,  7.,  8.,  9. Null
	0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x00
};
//最左至最右数码管 ,依次为0-3号,对应的显示寄存器地址
const uint8_t u8TubeAddrTab[] = 
{
	0xC0,0xC1,0xC2,0xC3
};
/*******************************************************************************
  * 函数名:TM1637_WriteCmd
  * 功  能:写命令
  * 参  数:无
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void TM1637_WriteCmd(uint8_t u8Cmd)
{
	IIC_Start();
	IIC_WriteByte(u8Cmd);
	IIC_WaitAck();
	IIC_Stop();
}
/*******************************************************************************
  * 函数名:TM1637_WriteData
  * 功  能:向地址中写入数据
  * 参  数:u8Addr地址,u8Data数据
  * 返回值:无
  * 说  明:用于数码管固定地址写入显示数据
*******************************************************************************/
void TM1637_WriteData(uint8_t u8Addr, uint8_t u8Data)
{
	IIC_Start();
	IIC_WriteByte(u8Addr);
	IIC_WaitAck();
	IIC_WriteByte(u8Data);
	IIC_WaitAck();
	IIC_Stop();
}
/*******************************************************************************
  * 函数名:TM1637_TubeDisplay
  * 功  能:4个数码管显示
  * 参  数:sData显示数据结构体
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void TM1637_TubeDisplay(TM1637Tube_ts sData)
{
	uint8_t temp[4], i;
	temp[0] = u8NumTab[sData.tube0];
	temp[1] = u8NumTab[sData.tube1];
	temp[2] = u8NumTab[sData.tube2];
	temp[3] = u8NumTab[sData.tube3];
	for (i = 0; i < 4; i++)
	{
		TM1637_WriteData(u8TubeAddrTab[i], temp[i]);
	}
}
/*******************************************************************************
  * 函数名:TM1637_SetBrightness
  * 功  能:设置亮度
  * 参  数:u8Brt亮度
  * 返回值:无
  * 说  明:0x88为开显示
*******************************************************************************/
void  TM1637_SetBrightness(uint8_t u8Brt)
{
	TM1637_WriteCmd(0x88 | u8Brt);
}
/*******************************************************************************
  * 函数名:TM1637_Switch
  * 功  能:显示开关
  * 参  数:0关,1开
  * 返回值:无
  * 说  明:0x88为开显示,0x80关显示
*******************************************************************************/
void  TM1637_Switch(bool bState)
{
	bState ? TM1637_WriteCmd(0x88) : TM1637_WriteCmd(0x80);
}

2.3 应用层显示控制

应用层函数,用TM1637.h中的类型TM1637Tube_ts定义一个结构体,用来存放4个数码管的显示数据:

static TM1637Tube_ts sDisplayData;
/*******************************************************************************
  * 函数名:Display_Init
  * 功  能:初始化
  * 参  数:无
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void Display_Init(void)
{
	TM1637_Switch(0);//关显示
	TM1637_SetBrightness(0x87);//设置亮度,开显示
	TM1637_WriteCmd(0x44);//写数据到寄存器,固定地址模式
	memset(&sDisplayData, 0xFF, sizeof(sDisplayData));
}

例如显示数据1234,则运行以下函数即可:

/*******************************************************************************
  * 函数名:Display_TubeDataProcess
  * 功  能:显示数据处理
  * 参  数:无
  * 返回值:无
  * 说  明:4位数码管,根据十进制数据位数,不需要的不显示
*******************************************************************************/
void Display_TubeDataProcess(void)
{
	uint16_t u16Data = 1234;//需要显示的数据,自定义,或者从其他接口函数获得,本例程直接赋值为1234
	memset(&sDisplayData, 0xFF, sizeof(sDisplayData));
	if (u16Data > 9999)
	{
		u16Data = 9999;//最多四位数
	}
	if (u16Data > 999)//四位数
	{
		sDisplayData.tube0 = (uint8_t)(u16Data / 1000);//千位
		sDisplayData.tube1 = (uint8_t)(u16Data / 100 % 10);//百位
		sDisplayData.tube2 = (uint8_t)(u16Data % 100 / 10);//十位
	    sDisplayData.tube3 = (uint8_t)(u16Data % 10);//个位
	}else if (u16Data > 99)//三位数
	{
		sDisplayData.tube0 = TUBE_DISPLAY_NULL;//不显示
		sDisplayData.tube1 = (uint8_t)(u16Data / 100);//百位
		sDisplayData.tube2 = (uint8_t)(u16Data / 10 % 10);//十位
	    sDisplayData.tube3 = (uint8_t)(u16Data % 10);//个位	   
	}else if (u16Data > 9)//两位数
	{
		sDisplayData.tube0 = TUBE_DISPLAY_NULL;//不显示
	    sDisplayData.tube1 = TUBE_DISPLAY_NULL;//不显示
		sDisplayData.tube2 = (uint8_t)(u16Data / 10);//十位
	    sDisplayData.tube3 = (uint8_t)(u16Data % 10);//个位
	}else//一位数
	{
		sDisplayData.tube0 = TUBE_DISPLAY_NULL;//不显示
	    sDisplayData.tube1 = TUBE_DISPLAY_NULL;//不显示
		sDisplayData.tube2 = TUBE_DISPLAY_NULL;//不显示
	    sDisplayData.tube3 = (uint8_t)u16Data;//个位
	}
	TM1637_TubeDisplay(sDisplayData);
}

显示效果如图:
在这里插入图片描述

三、总结

  1. 采用模拟IIC的方式,STM322CubeMX配置IIC的引脚时,需要配置为开漏输出模式;
  2. 带时间点的模块,中间的时间点,是它前面的数码管的小数点位。
  • 50
    点赞
  • 193
    收藏
    觉得还不错? 一键收藏
  • 22
    评论
### 回答1: stm32f103单片机可以通过使用tm1637芯片来驱动4数码管。tm1637芯片是一种专门用于数码管控制的驱动芯片,其具有方便的接口和简单的控制方式。 首先,我们需要连接stm32f103单片机tm1637芯片。将stm32f103的SCL引脚连接到tm1637的CLK引脚,将stm32f103的SDA引脚连接到tm1637的DIO引脚。此外,还需要将stm32f103的VCC和GND引脚分别连接到tm1637的VCC和GND引脚,以提供电源。最后,将数码管的共阴极或共阳极引脚连接到tm1637的对应引脚。 接下来,我们可以通过编写代码来控制tm1637芯片。首先需要引入tm1637的库文件,并进行相关的初始化设置。之后,可以使用库文件提供的函数来设置显示内容和控制数码管的亮度等。 在代码中,我们可以使用数字数组来表示需要显示的数字。例如,如果要显示数字1234,可以使用以下代码: ``` uint8_t num[] = {0x03, 0x06, 0x5B, 0x4F}; ``` 然后,我们可以调用库函数来设置数码管的显示内容。例如,使用以下代码来显示数字1234: ``` tm1637_display_all(num); ``` 除了显示数字,tm1637芯片还可以用来显示其他字符和符号。可以通过在数字数组中设置对应的数值来显示特定的字符。例如,使用以下代码来显示字符A: ``` uint8_t chA = 0x77; tm1637_display_all(&chA); ``` 最后,为了方便使用,可以设置tm1637芯片的亮度等级。可以使用以下代码来设置亮度等级为7: ``` tm1637_set_brightness(7); ``` 通过以上的步骤,可以成功驱动4数码管并在stm32f103单片机上显示所需的内容。 ### 回答2: STM32F103单片机可以使用TM1637芯片来驱动4数码管。 首先,需要将TM1637芯片STM32F103单片机进行连接。将TM1637的SCL引脚连接到STM32F103的SCL引脚,将TM1637的SDA引脚连接到STM32F103的SDA引脚,将TM1637的VCC引脚连接到STM32F103的5V电源引脚,将TM1637的GND引脚连接到STM32F103的地引脚。 接下来,在STM32F103的代码中,需要使用相应的库函数来控制TM1637芯片。首先,需要初始化TM1637芯片,可以通过设置相关的寄存器来配置芯片的工作模式和亮度等参数。然后,可以通过发送数据的方式向TM1637芯片传送需要显示的数字或字母等信息。 具体使用TM1637芯片驱动4数码管的步骤如下: 1. 引入相关的头文件和库函数,例如:#include "stm32f10x.h"。 2. 初始化STM32F103的GPIO口和I2C通信模块,例如:GPIO_Init()。 3. 配置TM1637芯片的初始化参数,例如:通过设置相关的寄存器来配置芯片的工作模式和亮度等参数。 4. 编写相应的函数来发送数据到TM1637芯片,例如:通过发送I2C通信协议来向TM1637芯片传送需要显示的数字或字母等信息。 5. 调用上述函数来实现将需要显示的内容发送到TM1637芯片,例如:调用display()函数。 6. 在主函数中调用相关的初始化函数和显示函数,例如:在while循环中不断调用display()函数来更新显示内容。 通过上述步骤,STM32F103单片机就可以使用TM1637芯片来驱动4数码管,并实现需要显示的数字、字母或其他信息的功能。 ### 回答3: STM32F103单片机可以使用TM1637芯片来驱动4数码管。 TM1637是一种常用的数码管驱动芯片,它可以通过IIC总线与单片机进行通信。STM32F103单片机内部集成了多个IIC接口,因此可以直接与TM1637芯片进行通信。 首先,需要在STM32F103单片机上配置IIC通信引脚,可以选择任何可用的GPIO引脚。然后在程序中初始化IIC通信,并将其设置为适当的时钟频率。 然后,可以通过IIC总线向TM1637芯片发送命令和数据,以控制数码管的显示。可以通过设置传输的字节数据,来控制数码管的亮灭状态,数值显示等。 例如,要在数码管上显示数字1234,可以按以下步骤操作: 1. 发送命令设置数码管的亮度和显示格式。 2. 发送第一个字节数据,将数值1的编码发送给第一数码管。 3. 发送第二个字节数据,将数值2的编码发送给第二数码管。 4. 发送第三个字节数据,将数值3的编码发送给第三数码管。 5. 发送第四个字节数据,将数值4的编码发送给第四数码管。 通过这种方式,可以控制TM1637芯片驱动4数码管显示不同的数字、字母和符号等。需要根据具体芯片规格书和数码管的接线情况,正确配置和发送命令和数据。 总之,通过STM32F103单片机使用TM1637芯片驱动4数码管,可以实现方便、精确的数值显示功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值