1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > 4位数码管显示模块TM1637芯片C语言驱动程序

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

时间:2020-05-13 23:27:51

相关推荐

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

一、概述

TM1637 是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数

字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。芯片手册已上传到资源,需要的可以下载,链接/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.7usIIC_SdaOutput_L();delay_us(4);//>4usIIC_SclOutput_L();}/******************************************************************************** 函数名:IIC_Stop* 功 能:结束信号* 参 数:无* 返回值:无* 说 明:无*******************************************************************************/void IIC_Stop(void){IIC_SdaModeOut();IIC_SclOutput_L();IIC_SdaOutput_L();IIC_SclOutput_H();delay_us(5);//>4usIIC_SdaOutput_H();delay_us(4);//>4.7usIIC_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);//>4usIIC_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);//>4usIIC_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());#endifIIC_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;#endifdelay_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* 作者:/wanglong3713* 版本:v1.0* 日期:-11-2* 说明:TM1637驱动*******************************************************************************/#ifndef _TM1637_H_#define _TM1637_H_#include "Typedefine.h"#define TUBE_DISPLAY_NULL26//不显示#define TUBE_DISPLAY_DECIMAL_PIONT_OFFSET16//带小数点的偏移量/*******************************************************************************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* 作者:/wanglong3713* 版本:v1.0* 日期:-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. Null0xBF,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;//需要显示的数据,自定义,或者从其他接口函数获得,本例程直接赋值为1234memset(&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);}

显示效果如图:

三、总结

采用模拟IIC的方式,STM322CubeMX配置IIC的引脚时,需要配置为开漏输出模式;带时间点的模块,中间的时间点,是它前面的数码管的小数点位。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。