TM1637四数码管驱动详解
创作时间:
作者:
@小白创作中心
TM1637四数码管驱动详解
引用
CSDN
1.
https://blog.csdn.net/successhand/article/details/138411933
TM1637
1. TM1637概述
TM1637是一种用于驱动共阳极8段数码管的专用芯片,可以同时驱动6个数码管。此外,它还集成了按键扫描功能,支持亮度调节,并通过串行接口进行数据传输。芯片内部包含自动消隐电路,可以有效避免显示闪烁。
模块图:
2. 管脚定义
从模块图可以看出,TM1637有两个I/O引脚用于串行数据的输入和输出。除了驱动数码管外,该芯片还可以作为矩阵按键的扫描接口使用。
3. 接口说明
根据手册描述,数据在CLK为低电平时需要准备好,当CLK上升沿到来时,数据被传输。每传输一个字节,在第八个时钟下降沿,1637都会产生一个ACK信号,此时DIO总线会被拉低。
本文采用的是地址自动加1模式。在通信开始时,所有信号都处于空闲高电平状态。通信过程包括以下几个步骤:
- 发送start信号
- 发送命令字节
- 从机ACK应答(拉低DIO)
- 发送stop信号
- 再次发送start信号
- 设置地址
- 从机ACK应答
- 发送数据字节
- 最后发送stop信号
4. 数据指令
数据指令分为三类:
- 数据命令设置:0x40用于写数据到显示寄存器并自动地址增加
- 地址命令设置:0xC0用于设置第一个数码管显示寄存器地址,后续地址依次递增
- 显示控制:通过脉冲宽度来控制显示亮度,0x88表示开启显示
5. 四位数码管模块原理图
6. 程序驱动
采用固定地址的程序流程图
程序代码
main.c
#include "tm1637.h"
int main(void)
{
tm1637_init(); //数码管初始化
smg_display(2142,0); //显示2142,冒号不显示
while(1)
{
}
}
tm1637.c
#include "tm1637.h"
#include "main.h"
#include "uart.h"
#include <stdio.h>
#include <string.h>
#include "retarget.h"
//段码表
const uint8_t num_tab[] =
{
//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,0x80
};
//显示缓冲区,要准备显示的段码值,从左到右
uint8_t show_buffer[4] = {0};
/**
* @brief: tm1637初始化
* @param: void
* @return: none
*/
void tm1637_init(void)
{
GPIO_InitTypeDef tm1637_gpio_init;
TM1637_CLK_GPIO_CLK_ENABLE();
TM1637_DIO_GPIO_CLK_ENABLE();
/// tm1637 CLK
tm1637_gpio_init.Pin = TM1637_CLK_GPIO_PIN;
tm1637_gpio_init.Pull = GPIO_PULLUP;
tm1637_gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
tm1637_gpio_init.Speed = GPIO_SPEED_HIGH;
HAL_GPIO_Init(TM1637_CLK_GPIO_PORT,&tm1637_gpio_init);
/// tm1637 DIO
tm1637_gpio_init.Pin = TM1637_DIO_GPIO_PIN;
HAL_GPIO_Init(TM1637_DIO_GPIO_PORT,&tm1637_gpio_init);
TM1637_CLK_HIGH;
TM1637_DIO_HIGH;
}
/**
* @brief: 初略延时,n ns
* @param i
* @return: none
*/
void delay_ns(uint32_t i)
{
while(i--);
}
/**
* @brief: tm1637 start 信号
* @param: void
* @return: none
*/
void tm1637_start(void)
{
TM1637_DIO_GPIO_OUTPUT;
TM1637_CLK_HIGH;
TM1637_DIO_HIGH;
delay_ns(6);
TM1637_DIO_LOW;
}
/**
* @brief: 检测应答信号,默认有超时时间
* @param: void
* @return: 0: nack, 1: ack
*/
uint8_t tm1637_is_ack(void)
{
uint8_t ack_flag = 0,time = 60;
TM1637_DIO_GPIO_INPUT;
TM1637_CLK_LOW;
while(time)
{
time--;
if(HAL_GPIO_ReadPin(TM1637_DIO_GPIO_PORT,TM1637_DIO_GPIO_PIN) == GPIO_PIN_RESET)
{
ack_flag = 1;
break;
}
}
TM1637_CLK_HIGH;
delay_ns(6);
TM1637_CLK_LOW;
return ack_flag;
}
/**
* @brief: 停止信号
* @param: void
* @return: none
*/
void tm1637_stop(void)
{
TM1637_DIO_GPIO_OUTPUT;
TM1637_CLK_LOW;
delay_ns(5);
TM1637_DIO_LOW;
delay_ns(5);
TM1637_CLK_HIGH;
delay_ns(5);
TM1637_DIO_HIGH;
}
/**
* @brief: 写一个字节,地址自动递增模式
* @param data
* @return: none
*/
void tm1637_write_byte(uint8_t data)
{
uint8_t i;
TM1637_DIO_GPIO_OUTPUT;
for (i = 0; i < 8;i++)
{
TM1637_CLK_LOW;
if(data & 0x01)
{
TM1637_DIO_HIGH;
}
else
{
TM1637_DIO_LOW;
}
delay_ns(3);
data = data >> 1;
TM1637_CLK_HIGH;
delay_ns(3);
}
}
/**
* @brief: 数码管显示数值
* @param show_num : 0000 ~ 9999
* @param colon_flag: 冒号标志位,0:不显示,1:显示
*/
void smg_display(uint16_t show_num , uint8_t colon_flag)
{
uint8_t i;
uint8_t ack_flag = 0;
memset(show_buffer,0,sizeof(show_buffer));
show_buffer[0] = num_tab[show_num/1000];
if (colon_flag) //冒号标志位
{
show_buffer[1] = num_tab[show_num/100%10] | 0x80;
}
else
{
show_buffer[1] = num_tab[show_num/100%10];
}
// show_buffer[1] = 0x80;
show_buffer[2] = num_tab[show_num/10%10];
show_buffer[3] = num_tab[show_num%10];
tm1637_start();
tm1637_write_byte(0x40); //0x40,地址自动加1模式
ack_flag = tm1637_is_ack();
if(!ack_flag)
{
return; //结束
}
tm1637_stop();
tm1637_start();
tm1637_write_byte(0xc0); //设置数码管显示的首地址
ack_flag = tm1637_is_ack();
if(!ack_flag)
{
return; //结束
}
for (i = 0; i < 4; i++)
{
tm1637_write_byte(show_buffer[i]);
// tm1637_write_byte(0x5b); //显示数值,从左到右
ack_flag = tm1637_is_ack();
if(!ack_flag)
{
return; //结束
}
}
tm1637_stop();
tm1637_start();
// tm1637_write_byte(0x8f); //开显示,最大亮度,14/16
tm1637_write_byte(0x8b); //开显示,亮度,10/16
// tm1637_write_byte(0x8a); //开显示,亮度,4/16
// tm1637_write_byte(0x88); //开显示,亮度,1/16
ack_flag = tm1637_is_ack();
if(!ack_flag)
{
// printf("error 0x8f ack.\r\n");
return; //结束
}
tm1637_stop();
}
tm1637.h
#ifndef CLOCK_TM1637_H
#define CLOCK_TM1637_H
#include <stdbool.h>
#include "stm32f1xx.h"
#define TM1637_CLK_GPIO_PORT GPIOB
#define TM1637_CLK_GPIO_PIN GPIO_PIN_8
#define TM1637_CLK_GPIO_CLK_ENABLE() do{__HAL_RCC_GPIOB_CLK_ENABLE();}while(0)
#define TM1637_CLK_HIGH do{HAL_GPIO_WritePin(TM1637_CLK_GPIO_PORT,TM1637_CLK_GPIO_PIN,GPIO_PIN_SET);}while(0)
#define TM1637_CLK_LOW do{HAL_GPIO_WritePin(TM1637_CLK_GPIO_PORT,TM1637_CLK_GPIO_PIN,GPIO_PIN_RESET);}while(0)
#define TM1637_DIO_GPIO_PORT GPIOB
#define TM1637_DIO_GPIO_PIN GPIO_PIN_9
#define TM1637_DIO_GPIO_CLK_ENABLE() do{__HAL_RCC_GPIOB_CLK_ENABLE();}while(0)
#define TM1637_DIO_HIGH do{HAL_GPIO_WritePin(TM1637_DIO_GPIO_PORT,TM1637_DIO_GPIO_PIN,GPIO_PIN_SET);}while(0)
#define TM1637_DIO_LOW do{HAL_GPIO_WritePin(TM1637_DIO_GPIO_PORT,TM1637_DIO_GPIO_PIN,GPIO_PIN_RESET);}while(0)
//切换方向,输入或者输出
#define TM1637_DIO_GPIO_OUTPUT {GPIOB->CRH &= 0xFFFFFF0F; GPIOB->CRH |= (uint32_t)(3<<4);}
#define TM1637_DIO_GPIO_INPUT {GPIOB->CRH &= 0xFFFFFF0F; GPIOB->CRH |= (uint32_t)(8<<4);}
/**
* @brief: tm1637初始化
* @param: void
* @return: none
*/
void tm1637_init(void);
/**
* @brief: 初略延时,n ns
* @param i
* @return: none
*/
void delay_ns(uint32_t i);
/**
* @brief: tm1637 start 信号
* @param: void
* @return: none
*/
void tm1637_start(void);
/**
* @brief: 检测应答信号,默认有超时时间
* @param: void
* @return: 0: nack, 1: ack
*/
uint8_t tm1637_is_ack(void);
/**
* @brief: 停止信号
* @param: void
* @return: none
*/
void tm1637_stop(void);
/**
* @brief: 写一个字节,地址自动递增模式
* @param data
* @return: none
*/
void tm1637_write_byte(uint8_t data);
void smg_display(uint16_t show_num , uint8_t colon_flag);
#endif //CLOCK_TM1637_H
7. 遇到的问题
问题1:无法点亮数码管
在使用TM1637时,按照手册编写时序,发现数码管不亮。检查时序后发现,在发送data1~data n后,直接发送停止信号,接着又发送1个字节的数据,应答时刻等待了29us多,时间过长。经分析发现,最后一个字节命令是用来开显示和调整亮度的,缺少了一个开始信号。添加开始信号后,问题得以解决。
热门推荐
认识五六式冲锋枪:外观材质、弹药类型、射击模式与刺刀特色
后循环缺血的症状是什么
科学健身就要做到“多样化健身”
为什么明明开了空气净化器,房间内还是很多灰尘?
AI智能云盘技术详解:从智能分类到安全防护
科研配色 | 第30期 柱状图配色?一文搞定!
请示有高度,汇报有速度,反馈有准度
手机前置录像是反的怎么办
AT、DCT、CVT:选车时,如何挑出最合心意的变速箱
酸枣妙用:从养生茶到特色糕点,解锁多重美味
波罗的海沿岸战役的起因是什么?是在什么背景下发生的
2024-2025学年度小学体育设施建设计划
同样是牛肉,摆在案上和挂起来有啥区别?记住3点,谁也骗不了你
动态之美:运动对象的拍摄方法
如何使用万用表测试贺德克温度传感器
如何判断黄金被套后的损失情况?这种情况如何影响投资者的心态和决策?
黔西牛肉粉:百年传承的美食名片
肿瘤患者在什么情况下会危及生命?
温度传感器的工作原理与应用场景
物理中的电动势之谜:为什么两个磁场变化仍只有一个感应电动势?
胎儿入盆后多久会生
扎克伯格康复后5KM跑进21分钟!跑者如何提升5KM能力,建议这样练....
爱情细水长流的星座:没有激情却有温情,择一人终老,伴一人白头
能否跑马拉松一测便知!专家详解心肺功能检测与最大摄氧量
多图直击特警春训现场
MES管理系统在柔性制造中有何重要作用
探索“John”名字的发音与文化背景,提升英语学习自信与交流能力
ADC的时域和频域分析方法
维生素检测怎么做
电视柜留几个插座好?提高家居实用性的必备指南