大家好,欢迎来到IT知识分享网。
TM1637
1. TM1637概述
共阳,8段数码管x6个,还有按键扫描,可以调节亮度,串行接口、内置自动消隐电路。
模块图:
2. 管脚定义
可以看出,有两个IO用于串行数据输入/输出。此芯片不仅能够驱动数码管,还能够作为矩阵按键扫描。
3.接口说明
根据手册描述,数据在CLK为低时刻准备好,CLK为高(上升沿)被传输过去,每传输一个字节,在第八个时钟下降沿,1637都会产生一个ACK,会拉低DIO总线。
我使用的是地址自动加1模式,首先空闲状态都为高电平,发送start信号,然后命令,从机ack应答(拉低DIO),接着stop信号。然后start信号,设置地址,从机ack应答,然后data1,ack…,最后stop信号。
4.数据指令
可以看出,这两位是来区分,数据命令或者显示控制命令,或者地址命令的。
1.数据命令设置
0x40为写数据到显示寄存器、自动地址增加
2.地址命令设置
0xC0为第一个数码管显示寄存器地址,下一个地址加一,依次类推。
3.显示控制
脉冲宽度表示这个是控制显示亮度的,可根据自己场景选择。
下面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多,很长。发现这部分不对劲,对照手册里面发送的最后一个字节命令是用来开显示和调整亮度的,然后发现少了个开始信号,加上去,就正常了。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/121997.html