The road of hardware learning-TM1638 of STM32

1. Introduction to the chip

TM1638 is a dedicated circuit for LED (light emitting diode display) drive control with keyboard scan interface, which integrates MCU digital interface, data latch, LED high voltage drive, keyboard scan and other circuits. Mainly used in high-end display drivers for refrigerators, air conditioners, home theaters and other products.
• Adopting power CMOS technology • Display mode 10 segments×8 bits • Key scan (8×3bit) • Brightness adjustment circuit (8-level adjustable duty cycle)
• Serial interface (CLK, STB, DIO) • Oscillation mode: RC oscillation (450KHz+5%) • Built-in power-on reset circuit • SOP28 package

For more detailed information, please download the TM1638 official website data sheet

2. Module introduction

  1. Eight digital tubes, eight light-emitting diodes, eight buttons (this module is really auspicious)
  2. Five pins VCC-GND-STB-CLK-DIO lead to the left
    TM1638 module
  3. The platform uses the smallest STM32F103C8T6 system board at hand, J-Link downloader
    Master

Three. Code implementation

1) some explanation

  • By studying the relevant code 1 of other bloggers’ explanations of the chip , I have integrated and modified some of my own elements, and I have optimized some of the logic to improve the efficiency of code execution, but there are also shortcomings. Please also Please correct me.
  • The parameters of TM1638_Display_Num() function here can be optimized to string type, and then use C language string related functions to perform string related conversion inside the function. I will not do it here. If you are interested, you can try it.

2) On the code

  1. TM1638.h
#ifndef _TM1638_H_
#define _TM1638_H_
/**
  ***************************************************************************************
  * TM1638模块功能实现源文件
  * 硬件连接:PA5--STB,PA6--CLK,PA7--DIO
  * 创建人:郭凯瑞_carry
  * 最后修改时间:2021-2-26
  ***************************************************************************************
**/
#include "stm32f10x.h"
 
typedef enum {
    
    N = 0x00, Y = 0x80} PointState; //是否带小数点 Y:带,N:不带
 
typedef enum {
    
    OFF = 0x00, ON = 0x01} LightState; //灯开关状态 On:开,Off:关

//TM1638模块相关引脚定义
#define STB GPIO_Pin_5
#define CLK GPIO_Pin_6
#define DIO GPIO_Pin_7
#define GPIO_TM1638 GPIOA
#define GPIO_Pin_TM1638 STB|CLK|DIO
#define RCC_TM1638 RCC_APB2Periph_GPIOA

//引脚高低电平设置
#define STB_0() GPIO_ResetBits(GPIO_TM1638,STB)
#define STB_1() GPIO_SetBits(GPIO_TM1638,STB)

#define CLK_0() GPIO_ResetBits(GPIO_TM1638,CLK)
#define CLK_1() GPIO_SetBits(GPIO_TM1638,CLK)

#define DIO_0() GPIO_ResetBits(GPIO_TM1638,DIO)
#define DIO_1() GPIO_SetBits(GPIO_TM1638,DIO)

#define DIO_Read() GPIO_ReadInputDataBit(GPIO_TM1638,DIO)

//用户层函数
void TM1638_Init(void); //TM1638初始化函数
void TM1638_Display_Num(u32 data); //显示数字
void TM1638_Display_SEG(unsigned int num,unsigned char seg,PointState p); //选择数码管显示0-F
void TM1638_Display_LED(unsigned int num,LightState light); //指定led亮灭

unsigned char TM1638_ReadKey(void); //TM1638读键扫数据函数
void TM1638_SEG_Off(unsigned char num);  //TM1638关闭指定数码管函数
void TM1638_Clear(void); //TM1638全清

//底层函数
void TM1638_Write_Byte(u8 byte); //TM1638单写数据,需要在函数外对STB操作
void TM1638_Write_Data(u8 data); //TM1638一个完整数据写入
void TM1638_Write_Addr_Bond(u8 addr,u8 data); //TM1638指定地址写入数据
unsigned char TM1638_Read(void); //TM1638读数据函数
void TM1638_GPIO_Init(void); //TM1638引脚初始化函数

#endif

  1. TM1638.c
/**
  ***************************************************************************************
  * TM1638模块功能实现源文件
  * 硬件连接:PA5--STB,PA6--CLK,PA7--DIO
  * 创建人:郭凯瑞_carry
  * 最后修改时间:2021-2-26
  ***************************************************************************************
**/

#include "stm32f10x.h"  //stm32f10x系列芯片头文件
#include "TM1638.h"  //tm1638模块实现头文件

unsigned char TM1638_Arr_SEG[]= {
    
    0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07, //共阴极数码管段码,不带小数点
                                 0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
                                 0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,  //共阴极数码管段码,带小数点
                                 0xFF,0xEF,0xF7,0xFC,0xB9,0xDE,0xF9,0xF1
                                }; //0~F,1亮0灭

//共阴极数码管段码,不带小数点,display函数用
unsigned char TM1638_Arr_SEG_Display[]= {
    
       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
                                            0,   0,   0,   0,   0,   0,0x3F,0x06,0x5B,0x4F,//0-9
                                            0x66,0x6D,0x7D,0x07,0x7F,0x6F,   0,   0,   0,   0,
                                            0,   0,   0,0x77,0x7C,0x39,0x5E,0x79,0x71,   0
                                        };

u8 TM1638_Addr_SEG[8]= {
    
    0xC0,0xC2,0xC4,0xC6,0xC8,0xCA,0xCC,0xCE}; //模块从右到左的八个数码管
u8 TM1638_Addr_LED[8]= {
    
    0xC1,0xC3,0xC5,0xC7,0xC9,0xCB,0xCD,0xCF}; //模块从右到左的八个发光二极管

void TM1638_Write_Byte(u8 byte) //TM1638单写数据
{
    
    
    u8 i;
    for(i=0; i<8; i++)
    {
    
    
        CLK_0(); //CLK=0
        if(byte&0x01)
        {
    
    
            DIO_1(); //DIO=1
        }
        else
        {
    
    
            DIO_0(); //DIO=0
        }
        byte>>=1;
        CLK_1(); //CLK=1
    }
}
/***************************************************************************************/
/**
  * TM1638写数据/命令函数
  * 参数:data:要写入的8位数据
  * 返回值:无
  */
void TM1638_Write_Data(u8 data) //TM1638写数据函数
{
    
    
    STB_0();
    TM1638_Write_Byte(data);
    STB_1();
}

void (*TM1638_Write_Cmd)(u8)=TM1638_Write_Data;//给函数起一个别名,函数指针
/***************************************************************************************/

/***************************************************************************************/
/**
	* TM1638写地址+数码组合函数,用于固定地址显示
  * 参数:cmd:要写入的8位数据
  * 返回值:无
  */
void TM1638_Write_Addr_Bond(u8 addr,u8 data) //TM1638写数据函数
{
    
    
    STB_0();
    TM1638_Write_Byte(addr);
    TM1638_Write_Byte(data);
    STB_1();
}
/***************************************************************************************/

/***************************************************************************************/
/**
	* TM1638固定地址显示函数
  * 参数1:data:写入的数字,长度八位
  * 返回值:无
  */
void TM1638_Display_Num(u32 data)
{
    
    
    unsigned int dataL=0,dataR=0;
    dataL=data/10000;
    dataR=data%10000;
    TM1638_Write_Cmd(0x44);//固定地址,写数据
    TM1638_Write_Cmd(0x88);//显示开,亮度1

    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[0],TM1638_Arr_SEG[dataL/1000]);
    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[1],TM1638_Arr_SEG[dataL%1000/100]);
    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[2],TM1638_Arr_SEG[dataL%100/10]);
    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[3],TM1638_Arr_SEG[dataL%10]);
    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[4],TM1638_Arr_SEG[dataR/1000]);
    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[5],TM1638_Arr_SEG[dataR%1000/100]);
    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[6],TM1638_Arr_SEG[dataR%100/10]);
    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[7],TM1638_Arr_SEG[dataR%10]);
}
/***************************************************************************************/

/***************************************************************************************/
/**
  * TM1638指定地址显示数码,0-F
  * 参数1:num:数码管位置12345678
  * 参数2:seg:字符0-F
  * 参数3:p:N/Y
  * 返回值:无
  */
void TM1638_Display_SEG(unsigned int num,unsigned char seg,PointState p)
{
    
    
    TM1638_Write_Cmd(0x44);//固定地址,写数据
    TM1638_Write_Cmd(0x88);//显示开,亮度1

    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[num-1],TM1638_Arr_SEG_Display[seg-32]|p);
}
/***************************************************************************************/

/***************************************************************************************/
/**
  * TM1638指定LED亮灭
  * 参数1:num:LED位置
  * 参数2:light:OFF/ON
  * 返回值:无
  */
void TM1638_Display_LED(unsigned int num,LightState light)
{
    
    
    TM1638_Write_Cmd(0x44);//固定地址,写数据
    TM1638_Write_Cmd(0x88);//显示开,亮度1

    TM1638_Write_Addr_Bond(TM1638_Addr_LED[num],light);
}
/***************************************************************************************/

/***************************************************************************************/
/**
  * TM1638全清
  * 参数1:无
  * 返回值:无
  */
void TM1638_Clear(void)
{
    
    
    u8 i;
    TM1638_Write_Data(0x44); //普通模式,固定地址,写数据到显示寄存器
    TM1638_Write_Data(0x88); //显示开,亮度第1级
    for(i=0; i<16; i++)
    {
    
    
        TM1638_Write_Addr_Bond(0XC0+i,0X00); //全地址写入0X00
    }
}
/***************************************************************************************/

/***************************************************************************************/
/**
  * TM1638关闭指定数码管函数
  * 参数:serial:数码管序号1-8
  * 返回值:无
  */
void TM1638_SEG_Off(unsigned char num)  //TM1638关闭指定数码管函数
{
    
    
    TM1638_Write_Cmd(0x44);//固定地址,写数据
    TM1638_Write_Cmd(0x88);//显示开,亮度1

    TM1638_Write_Addr_Bond(TM1638_Addr_SEG[num-1],0x80);
}
/***************************************************************************************/

/***************************************************************************************/
/**
  * TM1638读数据函数
  * 参数:无
  * 返回值:读取的8位数据
  */
unsigned char TM1638_Read(void) //读数据函数
{
    
    
    unsigned char i,data,temp=0;

    DIO_1();  //DIO=1,设置为输入
    for(i=0; i<8; i++)
    {
    
    
        temp>>=1;
        CLK_0(); //CLK=0
        data = DIO_Read();  //读取DIO值
        if(data) temp|=0x80; //按位或:与0或不变、与1或置1
        CLK_1(); //CLK=1
    }
    return temp;
}
/***************************************************************************************/

/***************************************************************************************/
/**
  * TM1638读键扫数据函数
  * 参数:无
  * 返回值:读取的按键号,1~8
  */
unsigned char TM1638_ReadKey(void)  //TM1638读键扫数据函数
{
    
    
    unsigned char c[4],i,key_value=0;

    STB_0();  //STB=0,开始写命令
    TM1638_Write_Byte(0x42);  //普通模式,地址自动增加,读键扫数据
    for(i=0; i<4; i++)	c[i]=TM1638_Read(); //读取键值
    STB_1();  //STB=1,读键值结束

    //数据处理
    for(i=0; i<4; i++)
        key_value|=c[i]<<i;
    for(i=0; i<8; i++)
        if((0x01<<i)==key_value) break;
    return (i+1);//返回按键值,与模块上的相对应
}
/***************************************************************************************/

/***************************************************************************************/
/**
  * TM1638-GPIO初始化函数
  * 参数:无
  * 返回值:无
  */
void TM1638_GPIO_Init(void)
{
    
    
    GPIO_InitTypeDef GPIO_InitStructure; //GPIO参数设置结构体
    RCC_APB2PeriphClockCmd(RCC_TM1638,ENABLE);  //APB2外设时钟使能:GPIOA

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_TM1638; //选定引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //工作方式:推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //最大速度50MHz
    GPIO_Init(GPIO_TM1638, &GPIO_InitStructure); //初始化引脚
}
/***************************************************************************************/

/***************************************************************************************/
/**
  * TM1638初始化函数
  * 参数:无
  * 返回值:无
  */
void TM1638_Init(void) //TM1638初始化函数
{
    
    
    TM1638_GPIO_Init();//GPIO初始化
    TM1638_Clear();
}
/***************************************************************************************/

  1. main.h and the complete test project have been uploaded and are under review. Fans can download it here .

4. End of sentence

Finally, let's take a look at the renderings. Later, when I have time, I will write an article about writing module drivers in the data manual. I have been busy with the game recently.
effect


  1. https://blog.csdn.net/qtyt567/article/details/79827436 ↩︎

Guess you like

Origin blog.csdn.net/qq_44764316/article/details/114154830