TM1637驱动4段数字管
1、TM1637介绍
TM1637 带键盘扫描接口的一种LED(发光二极管显示器) 驱动控制专用电路, 内部集成有MCU 数字接口,数据锁存器,LED 高压驱动、键盘扫描等电路。本产品性能优良,质量可靠。主要用于电磁炉、微波炉和小家电的显示驱动。

在前面的文章中,是的TM详细描述了1637的驱动,请参考:
- ESP32-IDF传感器模块编程实例-TM1637数码管
- Arduino与Proteus仿真实例-TM1637驱动4位7段数字仿真
2、TM1637配置
请参考开发环境建设、系统时钟配置、调试配置和串口配置:
- STM32F1与STM32CubeIDE快速入门-开发环境建设
- STM32F1与STM32CubeIDE快速入门-GPIO概述与点亮LED
- STM32F1与STM32CubeIDE快速入门-USART/UART串口通信
本次实例的TM1637配置如下:
3、TM1637驱动实现
/* * tm1637_simple.h * * Created on: May 5, 2022 * Author: jenson */ #ifndef TM1637_SIMPLE_TM1637_SIMPLE_H_ #define TM1637_SIMPLE_TM1637_SIMPLE_H_ #include <stdio.h> #include <stm32f1xx_hal.h> #include <stdbool.h> #define TM1637_ADDR_AUTO 0x40 // 自动地址 #define TM1637_ADDR_FIXED 0x44 // 固定地址 #define MINUS_SIGN_IDX 16 #define TM1637_DELAY_US 3 #define TM1637_MAX_BRIGHTNESS 0x07 #define TM_DEG 0x63 #define INDEX_NEGATIVE_SIGN 16 #define INDEX_BLANK 0 // 17 nothing ,0 zero beter for clock typedef struct {
uint16_t id; GPIO_TypeDef *CLK_GPIOx; // CLK端口 uint16_t CLK_GPIO_Pinx; // CLK引脚 GPIO_TypeDef *DIO_GPIOx; // DIO端口 uint16_t DIO_GPIO_Pinx; // DIO引脚 uint8_t brightness; // 亮度 uint8_t digital_bits; // 位数 bool dot_blink_state; } tm1637_t; /** * @brief 初始化 * @param tm1637 tm1637_t对象 */ void tm1637_init(tm1637_t *tm1637); /** * @brief 设置亮度 * @param tm1637 tm1637_t对象 * @param level uint8_t 亮度级别,最大值为7 */ void tm1637_set_brightness(tm1637_t *tm1637, uint8_t level); /** * @brief 在指定位显示数字 * @param tm1637 tm1637_t对象 * @param segment_idx uint8_t 位数,不能超过tm1637_t对象的最大位数 * @param number uint8_t 需要显示的数字(0~9) * @param dot bool 是否显示点 */ void tm1637_set_segment_number(tm1637_t *tm1637, uint8_t segment_idx, const uint8_t number, const bool dot); /** * @brief 显示带有前导0及小数点的数字 * @param tm1637 tm1637_t对象 * @param number uint16_t 所要显示的数字,数字最大位数和小点和前导0的总位数不能超过tm1637_t的最大位数。 * @param lead_zero bool 是否显示前导0 * @param dot_mask uint8_t 点掩码 */ void tm1637_set_number_lead_dot(tm1637_t *tm1637, uint16_t number, bool lead_zero, const uint8_t dot_mask); /** * @brief 显示温度 * @param tm1637 tm1637_t对象 * @param temperature uint16_t 温度值,值范围为[-99~999]之间 */ void tm1637_display_temperature(tm1637_t *tm1637, int16_t temperature); /** * @brief 显示温度 * @param tm1637 tm1637_t对象 * @param number int16_t 数字,范围[-999~9999] */ void tm1637_display_number(tm1637_t *tm1637, int16_t number); /** * @brieef 显示浮点值 * @param tm1637 tm1637_t对象 * @param value float 显示的浮点值 */ void tm1637_display_float(tm1637_t *tm1637, float value); /** * @brief 显示字符 * @param tm1637 tm1637_t对象 * @param data uint8_t* 字符 */ void tm1637_display_string(tm1637_t *tm1637, const int8_t *data); /** * @brief 显示时间 * @param tm1637 tm1637_t对象 * @param hours uint8_t 时 * @param minutes uint8_t 分 */ void tm1637_display_time(tm1637_t* tm1637,uint8_t hours,uint8_t minutes,bool dot_blink); /** * @brief 清屏 * @param tm1637 tm1637_t对象 */ void tm1637_clear(tm1637_t *tm1637); #endif /* TM1637_SIMPLE_TM1637_SIMPLE_H_ */ /* * 七段管定义 //Segments // --0x01-- // | | //0x20 0x02 // | | // --0x40- - // | | //0x10 0x04 // | | // --0x08-- * */
static const int8_t __tm1637_symbols[] = {
// XGFEDCBA
0x3f,// 0b00111111, // 0
0x06, // 0b00000110, // 1
0x5b, // 0b01011011, // 2
0x4f, // 0b01001111, // 3
0x66, // 0b01100110, // 4
0x6d, // 0b01101101, // 5
0x7d, // 0b01111101, // 6
0x07, // 0b00000111, // 7
0x7f, // 0b01111111, // 8
0x6f, // 0b01101111, // 9
0x77, // 0b01110111, // A
0x7c, // 0b01111100, // b
0x39, // 0b00111001, // C
0x5e, // 0b01011110, // d
0x79, // 0b01111001, // E
0x71, // 0b01110001 // F
0x40, // 0b01000000 // minus sign
};
static const uint8_t __s_ascii[] = {
0x00, // 032 (Space)
0x30, // 033 !
0x22, // 034 "
0x41, // 035 #
0x6D, // 036 $
0x52, // 037 %
0x7C, // 038 &
0x20, // 039 '
0x39, // 040 (
0x0F, // 041 )
0x21, // 042 *
0x70, // 043 +
0x08, // 044 ,
0x40, // 045 -
0x80, // 046 .
0x52, // 047 /
0x3F, // 048 0
0x06, // 049 1
0x5B, // 050 2
0x4F, // 051 3
0x66, // 052 4
0x6D, // 053 5
0x7D, // 054 6
0x07, // 055 7
0x7F, // 056 8
0x6F, // 057 9
0x48, // 058 :
0x48, // 059 ;
0x39, // 060 <
0x48, // 061 =
0x0F, // 062 >
0x53, // 063 ?
0x5F, // 064 @
0x77, // 065 A
0x7C, // 066 B
0x39, // 067 C
0x5E, // 068 D
0x79, // 069 E
0x71, // 070 F
0x3D, // 071 G
0x76, // 072 H
0x30, // 073 I
0x1E, // 074 J
0x7A, // 075 K
0x38, // 076 L
0x55, // 077 M
0x54, // 078 N
0x5C, // 079 O
0x73, // 080 P
0x67, // 081 Q
0x50, // 082 R
0x6D, // 083 S
0x78, // 084 T
0x3E, // 085 U
0x7E, // 086 V
0x6A, // 087 W
0x36, // 088 X
0x6E, // 089 Y
0x48, // 090 Z
0x39, // 091 [
0x64, // 092 (backslash)
0x0F, // 093 ]
0x23, // 094 ^
0x08, // 095 _
0x20, // 096 `
0x77, // 097 a
0x7C, // 098 b
0x58, // 099 c
0x5E, // 100 d
0x79, // 101 e
0x71, // 102 f
0x3D, // 103 g
0x74, // 104 h
0x10, // 105 i
0x1E, // 106 j
0x7A, // 107 k
0x18, // 108 l
0x55, // 109 m
0x54, // 110 n
0x5C, // 111 o
0x73, // 112 p
0x67, // 113 q
0x50, // 114 r
0x6D, // 115 s
0x78, // 116 t
0x1C, // 117 u
0x1C, // 118 v
0x6A, // 119 w
0x36, // 120 x
0x6E, // 121 y
0x48, // 122 z
0x39, // 123 {
0x30, // 124 |
0x0F, // 125 }
0x40, // 126 ~
0x00 // 127
};
// CLK引脚设置高电平
void __tm1637_clk_high(tm1637_t *tm1637);
// CLK引脚设置低电平
void __tm1637_clk_low(tm1637_t *tm1637);
// DIO引脚设置高电平
void __tm1637_dio_high(tm1637_t *tm1637);
// DIO引脚设置低电平
void __tm1637_dio_low(tm1637_t *tm1637);
// 将DIO设置为输入
void __tm1637_dio_set_input(tm1637_t *tm1637);
// 将DIO设置为输出
void __tm1637_dio_set_output(tm1637_t *tm1637);
void __tm1637_delay_us(uint32_t us);
// TM1637固定延时3us
void __tm1637_delay();
// 发送开始信号
void __tm1637_start(tm1637_t *tm1637);
// 发送结束信号
void __tm1637_stop(tm1637_t *tm1637);
// 读取响应
void __tm1637_ack(tm1637_t *tm1637);
// 发送一位数据
void __tm1637_send_byte(tm1637_t *tm1637, uint8_t byte);
// 调节亮度
void __tm1637_adjust_brightness(tm1637_t *tm1637);
// 向TM1637发送数据
void __tm1637_set_segment_raw_data(tm1637_t *tm1637, const uint8_t segment_idx,
const uint8_t data);
// 设置前导点
void __tm1637_set_lead_dot(tm1637_t *tm1637, const bool lead_zero);
// 查找ASCII表码
uint8_t __tm1637_encode(uint8_t chr);
// 查询位
uint8_t __tm1637_digit_map(tm1637_t *tm1637, uint8_t digits, uint8_t digit);
static inline float nearestf(float val, int precision) {
int scale = pow(10, precision);
return roundf(val * scale) / scale;
}
// CLK引脚设置高电平
void __tm1637_clk_high(tm1637_t *tm1637) {
HAL_GPIO_WritePin(tm1637->CLK_GPIOx, tm1637->CLK_GPIO_Pinx, GPIO_PIN_SET);
}
// CLK引脚设置低电平
void __tm1637_clk_low(tm1637_t *tm1637) {
HAL_GPIO_WritePin(tm1637->CLK_GPIOx, tm1637->CLK_GPIO_Pinx, GPIO_PIN_RESET);
}
// DIO引脚设置高电平
void __tm1637_dio_high(tm1637_t *tm1637) {
HAL_GPIO_WritePin(tm1637->DIO_GPIOx, tm1637->DIO_GPIO_Pinx, GPIO_PIN_SET);
}
// DIO引脚设置低电平
void __tm1637_dio_low(tm1637_t *tm1637) {
HAL_GPIO_WritePin(tm1637->DIO_GPIOx, tm1637->DIO_GPIO_Pinx, GPIO_PIN_RESET);
}
// 将DIO设置为输入
void __tm1637_dio_set_input(tm1637_t *tm1637) {
GPIO_InitTypeDef GPIO_InitStruct = {
0 }; //To read ACK from TM1637 and to write data to it
GPIO_InitStruct.Pin = tm1637->DIO_GPIO_Pinx;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(tm1637->DIO_GPIOx, &GPIO_InitStruct);
}
// 将DIO设置为输出
void __tm1637_dio_set_output(tm1637_t *tm1637) {
GPIO_InitTypeDef GPIO_InitStruct = {
0 }; //To read ACK from TM1637 and to write data to it
GPIO_InitStruct.Pin = tm1637->DIO_GPIO_Pinx;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
HAL_GPIO_Init(tm1637->DIO_GPIOx, &GPIO_InitStruct);
}
// TM1637固定延时3us
void __tm1637_delay() {
// __tm1637_delay_us(TM1637_DELAY_US);
__tm1637_delay_us(TM1637_DELAY_US);
}
// 发送开始信号
void __tm1637_start(tm1637_t *tm1637) {
__tm1637_clk_high(tm1637);
__tm1637_dio_high(tm1637);
__tm1637_delay_us(2);
__tm1637_dio_low(tm1637);
}
// 发送结束信号
void __tm1637_stop(tm1637_t *tm1637) {
__tm1637_clk_low(tm1637);
__tm1637_delay_us(2);
__tm1637_dio_low(tm1637);
__tm1637_delay_us(2);
__tm1637_clk_high(tm1637);
__tm1637_delay_us(2);
__tm1637_dio_high(tm1637);
}
void __tm1637_ack(tm1637_t *tm1637) {
__tm1637_clk_low(tm1637);
__tm1637_delay_us(5);
__tm1637_clk_high(tm1637);
__tm1637_delay_us(2);
__tm1637_clk_low(tm1637);
}
// 发送一位数据
void __tm1637_send_byte(tm1637_t *tm1637, uint8_t byte) {
uint8_t data = byte;
for (uint8_t i = 0; i < 8; ++i) {
__tm1637_clk_low(tm1637);
if (data & 0x01) {
__tm1637_dio_high(tm1637);
} else {
__tm1637_dio_low(tm1637);
}
__tm1637_delay();
data >>= 1;
__tm1637_clk_high(tm1637);
__tm1637_delay();
}
/* * TM1637 通过在发送第 8 位后将 DIO 从 CLK 的下降沿拉低到 CLK 的下一个下降沿来发出 ACK 信号。 * 在此期间需要将 DIO 设置为输入。 * */
__tm1637_dio_set_input(tm1637);
// 开始ACK信号
__tm1637_clk_low(tm1637);
__tm1637_delay();
__tm1637_clk_high(tm1637);
__tm1637_delay();
// 结束ACK信号
__tm1637_clk_low(tm1637);
__tm1637_delay();
__tm1637_dio_set_output(tm1637);
}
// 调节亮度
void __tm1637_adjust_brightness(tm1637_t *tm1637) {
if (tm1637->brightness < 0) {
tm1637->brightness = 0;
} else if (tm1637->brightness > TM1637_MAX_BRIGHTNESS) {
tm1637->brightness = TM1637_MAX_BRIGHTNESS;
}
// 发送开开始信号
__tm1637_start(tm1637);
__tm1637_send_byte(tm1637, tm1637->brightness | 0x88);
// 发送结束信号
__tm1637_stop(tm1637);
}
// 向TM1637发送数据
void __tm1637_set_segment_raw_data(tm1637_t *tm1637, const uint8_t segment_idx,
const uint8_t data) {
// 发送开开始信号
__tm1637_start(tm1637);
// 选择地址
__tm1637_send_byte(tm1637, TM1637_ADDR_FIXED);
// 发送结束信号
__tm1637_stop(tm1637);
// 发送数据
// 发送开开始信号
__tm1637_start(tm1637);
__tm1637_send_byte(tm1637, segment_idx | 0xC0);
__tm1637_send_byte(tm1637, data);
// 发送结束信号
__tm1637_stop(tm1637);
// 调节亮度
__tm1637_adjust_brightness(tm1637);
}
// 设置前导点
void __tm1637_set_lead_dot(tm1637_t *tm1637, const bool lead_zero) {
tm1637_set_number_lead_dot(tm1637, lead_zero, lead_zero, 0x00);
}
// 查找ASCII表码
uint8_t __tm1637_encode(uint8_t chr) {
if (chr > 127 || chr < 32) {
return 0;
}
return __s_ascii[chr - 32];
}
// 查询位
uint8_t __tm1637_digit_map(tm1637_t *tm1637, uint8_t digits, uint8_t digit) {
uint8_t result = digit;
if (digits == 6) {
switch (digit) {
case 0:
result = 2;
break;
case 1:
result = 1;
break;
case 2:
result = 0;
break;
case 3:
result = 5;
break;
case 4:
result = 4;
break;
case 5:
result = 3;
break;
}
}
return result;
}
void __tm1637_delay_us(uint32_t us) {
for (int j = 0; j < us; j++) {
__NOP();
}
}
void tm1637_init(tm1637_t *tm1637) { // dwt_init(); __tm1637_clk_low(tm1637); __tm1637_delay(); __tm1637_dio_high(tm1637); __tm1637_delay(); __tm1637_clk_high(tm1637) 标签:tm的传感器