矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
查看: 3807|回复: 32

学习51单片机编程,显示TM1637模块

[复制链接]
     
发表于 2022-4-17 02:23:46 | 显示全部楼层 |阅读模式
本帖最后由 乙猪 于 2022-4-17 02:26 编辑

以前学习单片机编程,都是一古脑地把所有函数都放在main.c文件里,对H文件零知零解,现在也是一知半解。记得读大学时就学过库函数库文件了(读书时只学过一年的pascal语言),现试着把函数都放在头文件里,看看行不行?


main.c文件就简单了:

/*******************************************************************************
* 程序设计         : 乙猪,2022.04.12
* 程序功能                   : 实验输出到TM637模块
*******************************************************************************/
#include "reg51.h"                         //此文件中定义了单片机的一些特殊功能寄存器
#include  <intrins.h>
#include  "TM1637.h"                         //TM1637相关函数定义


/*******************************************************************************
* 函 数 名       : main
* 函数功能                 : 主函数
* 输    入       : 无
* 输    出             : 无
*******************************************************************************/
void main()                         //测试
{       
    TM1637_Display(21,21,21,21,0);        //黑屏
        TM1637_DisplayChar(7,2);
        TM1637_DisplayChar(6,0);
        while(1);               
}

然后就是TM1637.h 头文件了:

/*---------------------------------------------------
TM1637.H
TM637模块
----------------------------------------------------*/

#ifndef __TM1637_H__
#define __TM1637_H__

#include "reg51.h"                 //此文件中定义了单片机的一些特殊功能寄存器                  

sbit TM1637_CLK = P2^7;   //定义模拟IIC总线的时钟线
sbit TM1637_DIO = P2^6;   //定义模拟IIC总线的数据线


void Delay_us(unsigned  int i);        // 延迟
void TM1637_Start(void);           //IIC开始
void TM1637_Ack(void);          //IIC应答
void TM1637_Stop(void);          //IIC停止
void TM1637_Write(unsigned char DATA); //写数据函数  
unsigned char TM1637_ScanKey(void);          /////读按键
void TM1637_Display(unsigned char a,unsigned char b,unsigned char c,unsigned char d,unsigned char h);  //按顺序显示
void TM1637_DisplayChar(unsigned char ch,unsigned char p);        //向指定地址显示一个字节内容


#endif


与TM1637.h 相对应的TM1637.c 文件:

/*---------------------------------------------------
TM1637.C
TM637模块
----------------------------------------------------*/                  
#include "reg51.h"                         //此文件中定义了单片机的一些特殊功能寄存器                  
#include  <intrins.h>
#include  "TM1637.h"

  
code unsigned char tab[] =
{
        0x3F,/*0*/
        0x06,/*1*/
        0x5B,/*2*/
        0x4F,/*3*/
        0x66,/*4*/
        0x6D,/*5*/
        0x7D,/*6*/
        0x07,/*7*/
        0x7F,/*8*/
        0x6F,/*9*/
        0x77,/*10 A*/
        0x7C,/*11 b*/
        0x58,/*12 c*/
        0x5E,/*13 d*/
        0x79,/*14 E*/
        0x71,/*15 F*/
        0x76,/*16 H*/
        0x38,/*17 L*/
        0x54,/*18 n*/
        0x73,/*19 P*/
        0x3E,/*20 U*/
    0x00,/*21 黑屏*/
};

void Delay_us(unsigned  int i)
{
    for(;i>0;i--)
        _nop_();;
}

//IIC开始
void TM1637_Start(void)
{
     TM1637_CLK=1;
     TM1637_DIO=1;
     Delay_us(2);
     TM1637_DIO=0;
}


//IIC应答
void TM1637_Ack(void)
{
    unsigned char i;
    TM1637_CLK=0;
    Delay_us(5);
     //DIO=1;   
    while(TM1637_DIO==1&&(i<250))i++;
    TM1637_CLK=1;
    Delay_us(2);
    TM1637_CLK=0;
}

//IIC停止
void TM1637_Stop(void)
{
     TM1637_CLK=0;
     Delay_us(2);
     TM1637_DIO=0;
     Delay_us(2);
     TM1637_CLK=1;
     Delay_us(2);
     TM1637_DIO=1;
     Delay_us(2);
}

//写数据函数
void TM1637_Write(unsigned char DATA)   
{
    unsigned char i;   
    for(i=0;i<8;i++)        
    {
        TM1637_CLK=0;     
        if(DATA & 0x01)
            TM1637_DIO=1;
        else TM1637_DIO=0;
         Delay_us(3);
        DATA=DATA>>1;      
        TM1637_CLK=1;
        Delay_us(3);
    }  
    //TM1637_ack();
}

  /////读按键
unsigned char TM1637_ScanKey(void)
{
     unsigned char rekey,i;
     TM1637_Start();
     TM1637_Write(0x42); //读按键命令
     TM1637_Ack();
     TM1637_DIO=1; // 在读按键前拉高数据线
     for(i=0;i<8;i++) //从低位开始读
     {
            TM1637_CLK=0;
        rekey=rekey>>1;
        Delay_us(30);
        TM1637_CLK=1;
        if(TM1637_DIO)
        {
           rekey=rekey|0x80;
        }
        else
        {
           rekey=rekey|0x00;
        }
        Delay_us(30);
     }
     TM1637_Ack();
     TM1637_Stop();
     return (rekey);
}

//按顺序显示
void TM1637_Display(unsigned char a,unsigned char b,unsigned char c,unsigned char d,unsigned char h)
{

    TM1637_Start();
    TM1637_Write(0x40);   //写数据+自动地址加1+普通模式
    TM1637_Ack();
    TM1637_Stop();
    TM1637_Start();
    TM1637_Write(0xc0);//设置显示首地址即第一个LED
    TM1637_Ack();

    TM1637_Write(tab[a]);
    TM1637_Ack();
    TM1637_Write(tab[ b ]|h<<7);     //h为1时显示时钟中间的两点
    TM1637_Ack();
    TM1637_Write(tab[c]);
    TM1637_Ack();
    TM1637_Write(tab[d]);
    TM1637_Ack();

    TM1637_Stop();
    TM1637_Start();
    TM1637_Write(0x89);//开显示,2/16亮度
    TM1637_Ack();
    TM1637_Stop();
}

//向指定地址显示一个字节内容
void TM1637_DisplayChar(unsigned char ch,unsigned char p)
{
        if(ch>21) ch=21;//防止数组越界
        TM1637_Start();
        TM1637_Write(0x44);//0x44固定模式有利于控制显示位,0x40则采用显示地址自加模式这里不使用
        TM1637_Ack();
        TM1637_Stop();
        TM1637_Start();
        
        TM1637_Write(0xC0+p);//0X00地址开始显示
        TM1637_Ack();
               
        TM1637_Write(tab[ch]);//显示
        TM1637_Ack();               
        TM1637_Stop();
                TM1637_Start();
        TM1637_Write(0x89);//开显示,2/16亮度
        TM1637_Ack();
        TM1637_Stop();            
}


实验结果:
微信图片_20220417020417.jpg

以后如果用到这个模块,就可以重复利用这个头文件了,不需要重复编写有关它的程序了。
原本是想买这个模块来做收音机频率显示的,发觉少了小数点。郁闷~~

评分

2

查看全部评分

     
 楼主| 发表于 2022-4-17 11:04:18 来自手机 | 显示全部楼层
闻太师 发表于 2022-4-17 08:13
猪大堕落了,尽然玩起了单片机这等奇技淫巧。真空管、锗管才是一等玩家,退一步也得玩分立硅管、搭棚、铆钉 ...

家里小孩,正在本科学习计算机专业。为了增加交流谈资,只好如此了。
回复 支持 1 反对 0

使用道具 举报

     
发表于 2022-4-17 08:13:45 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

     
发表于 2022-4-17 18:21:06 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

     
发表于 2022-4-18 08:41:04 | 显示全部楼层
1637这个是比较奇特的芯片,明明是共阳驱动,却用了一个共阴的数据表。4位数码管用1637浪费了,用1650足够。另外程序里7级调亮度的没有体现。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-4-18 08:54:28 | 显示全部楼层
CXFLBH 发表于 2022-4-18 08:41
1637这个是比较奇特的芯片,明明是共阳驱动,却用了一个共阴的数据表。4位数码管用1637浪费了,用1650足够 ...

也许1637产量大?便宜量又足??
回复 支持 反对

使用道具 举报

     
发表于 2022-4-18 09:11:44 | 显示全部楼层
乙猪 发表于 2022-4-18 08:54
也许1637产量大?便宜量又足??

1650五毛多,1637七毛多。这还是涨价以后的价钱。而且封装还大很多。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-4-18 11:43:59 | 显示全部楼层
CXFLBH 发表于 2022-4-18 09:11
1650五毛多,1637七毛多。这还是涨价以后的价钱。而且封装还大很多。


哈哈,记下了。
下次设计LED显示电路时或许能用上。
现在手头上有的芯片有1628和1639,准备用它们搞点小动作。
我觉得有点奇怪的是,天薇生产这么多类似的芯片为啥??

我在网上经常看到这样的例程说明:
/*
* 深圳天微电子
*文件名: TM1637
*当前版本: 1.0
*单片机型号: AT89S52
*开发环境: Keil uVision3
*晶震频率: 11.0592M
*程序功能: 把 TM1637 所有显示寄存器地址全部写满数据 0xff,并开显示,然后再读按键值。
*/

想请教一下,去哪里能找到天薇电子芯片对应的程序库(官方例程)?
回复 支持 反对

使用道具 举报

     
发表于 2022-4-18 11:54:43 | 显示全部楼层
乙猪 发表于 2022-4-18 11:43
哈哈,记下了。
下次设计LED显示电路时或许能用上。
现在手头上有的芯片有1628和1639,准备用它们搞 ...

找天微的售后服务技术就可以了
/*****************************************************************************
*版权信息:深圳天微电子有限公司
*文 件 名:TM1637-V1.0
*当前版本:V1.0
*MCU 型号:STC12C5608AD
*开发环境:Keil uVision4
*晶震频率:11.0592MHZ      
*完成日期:2013-07-19
*程序功能:数码管驱动和按键:驱动8段6位LED共阳数码管显示,当对应按键按下时显示1~7,原理图请参考TM1637规格书;         
*免责声明:1.此程序为TM1637驱动共阳LED数码管和按键演示程序,仅作参考之用。
            2.如有直接使用本例程程序造成经济损失的,本公司不承担任何责任            
********************************************************************************/
#include <reg52.h>                                                //头文件
#include "intrins.h"                                                //包含_nop_()指令头文件

#define nop _nop_();_nop_();_nop_();_nop_();_nop_();                 //宏定义


/********************定义控制端口**********************/
sbit CLK=P2^2;                                                                 //定义CLK
sbit DIO=P2^3;                                                                 //定义DIO


/********************定义数据*************************/
unsigned char code CODE[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,};//共阳数码管0~9字型码
unsigned char code TAB[10]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,};//数码管不显示

/********************延时函数,延时nms******************/
void delay_nms(unsigned int n)
{
unsigned int i;
while(n--)
   for(i=0;i<550;i++);
}

/********************Start函数*************************/
void I2CStart()
{
DIO=1;
CLK=1;
nop;
DIO=1;
nop;
DIO=0;
nop;
CLK=0;
}

/********************Stop函数*************************/
void I2CStop()
{
    CLK=0;
        nop;
        nop;
        DIO=0;
        nop;
        nop;
        CLK=1;
        nop;
        nop;
        nop;
        DIO=1;
        nop;
        CLK=0;
        DIO=0;
}

/***************发送8bit数据,从低位开始**************/
void I2CWritebyte(unsigned char oneByte)
{
  unsigned char i;
  for(i=0;i<8;i++)
  {
    CLK=0;
        if(oneByte&0x01)
          DIO=1;
        else
          DIO=0;
        nop;
    CLK=1;
    oneByte=oneByte>>1;
  }
                                                                                  //8位数据传送完                 
        CLK = 0;                                                                //判断芯片发过来的ACK应答信号
        nop;
        while(DIO==1);
        nop;
        CLK = 1;
        nop;
}

/***************读按键程序**************/
unsigned char read_key()
{
unsigned char rekey,i;
I2CStart();
I2CWritebyte(0x42);                                                         //写读键指令0x42
DIO=1;                                                                          //释放DIO   
for(i=0;i<8;i++)
{
        CLK=0;
        nop;
        nop;
        rekey=rekey>>1;                                                           //先读低位
        nop;
        nop;
        CLK=1;
        if(DIO)
          rekey=rekey|0x80;
        else
          rekey=rekey|0x00;
        nop;
}
        CLK = 0;                                                          //判断芯片发过来的ACK应答信号
        nop;
        nop;
        while(DIO==1);
        nop;
        nop;
        CLK = 1;
        nop;
        nop;
        I2CStop();
       
        return rekey;
}

/************显示函数,地址自加一************/
void disp0(unsigned char *p)                              
{
unsigned char i;
I2CStart();
I2CWritebyte(0x40);                                  //数据命令设置:地址自动加1,写数据到显示寄存器
I2CStop();

I2CStart();
I2CWritebyte(0xc0);                                  //地址命令设置:初始地址为00H
for(i=0;i<6;i++)                                  //发送4字节数据到显存
{
I2CWritebyte(*p);
p++;
}
I2CStop();

I2CStart();
I2CWritebyte(0x8C);                                 //显示控制命令:开显示,脉冲宽度为11/16.
I2CStop();

}

/************显示函数,固定地址写数据************/
void disp(unsigned char add, unsigned char value)
{
I2CStart();
I2CWritebyte(0x44);                                 //数据命令设置:固定地址,写数据到显示寄存器
I2CStop();

I2CStart();
I2CWritebyte(add);                                //地址命令设置:写入add对应地址

I2CWritebyte(CODE[value]);                        //给add地址写数据
I2CStop();

I2CStart();
I2CWritebyte(0x8C);                                //显示控制命令:开显示,脉冲宽度为11/16.
I2CStop();

}

/************按键处理函数,按键数据低位在前高位在后************/
void key_process()
{
unsigned char temp;
temp=read_key();                                   //读取按键返回值
if(temp!=0xff)
{
  disp0(TAB);                                           //清屏
  switch(temp)
  {
        case 0xf7 : disp(0xc0,1);break;                  //K1与SG1对应按键按下,显示1
        case 0xf6 : disp(0xc1,2);break;                  //K1与SG2对应按键按下,显示2
        case 0xf5 : disp(0xc2,3);break;                  //K1与SG3对应按键按下,显示3
        case 0xf4 : disp(0xc3,4);break;                  //K1与SG4对应按键按下,显示4
        case 0xef : disp(0xc4,5);break;                  //K2与SG1对应按键按下,显示5
        case 0xee : disp(0xc5,6);break;                  //K2与SG2对应按键按下,显示6
        case 0xed : disp(0xc0,7);break;                  //K2与SG3对应按键按下,显示7
        default   : break;
  }
}
}

void main()
{

disp0(CODE);                                      //上电数码管显示0~5
delay_nms(1);
while(1)                                     //按键后显示按键内容
{
key_process();
delay_nms(100);
}
}

评分

1

查看全部评分

回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-4-18 11:57:49 | 显示全部楼层
CXFLBH 发表于 2022-4-18 11:54
找天微的售后服务技术就可以了
/****************************************************************** ...

每个人都去找售后,它岂不是会烦死??
回复 支持 反对

使用道具 举报

     
发表于 2022-4-18 12:05:41 | 显示全部楼层
乙猪 发表于 2022-4-18 11:57
每个人都去找售后,它岂不是会烦死??

这个不至于,加个微信传个程序都是分分钟的事情。我买了国内几家的芯片,他们的技术支持都是很给力的。
回复 支持 反对

使用道具 举报

     
发表于 2022-4-18 13:43:28 | 显示全部楼层
不过也有例外,上次转STC8的芯片,STC15的程序移植到STC8竟然不工作,找了STC售后,都说不可能,经过2天费尽心思的排查,还是15的工作8不工作。最后目标集中在中断上,一开中断所有IO口就全是低。售后表示无能为力。最后还是我自己找到了问题,竟然原因是STC的后缀为O的烧写软件有问题!打电话给STC的销售,她说忘了提醒我了,这个版本的烧写软件是因为刚刚把STC32加进去导致不可描述的错误~白白浪费了我几天宝贵的时间。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2022-4-18 14:53:04 | 显示全部楼层
CXFLBH 发表于 2022-4-18 13:43
不过也有例外,上次转STC8的芯片,STC15的程序移植到STC8竟然不工作,找了STC售后,都说不可能,经过2天费 ...

在其他论坛听坛友说,宏晶的售后态度不太好,动不动就会教你怎做人。
回复 支持 反对

使用道具 举报

     
发表于 2022-4-18 16:26:07 | 显示全部楼层
乙猪最好一步到位,收音机用四位远远不够,频道数两位,只有频率四位是不够的,频率数不含短波四位,特别注意还得第三位后小数点,怎么也得七位数码管,再扩展一些还得八个发光二极管场强指示灯,直接天威TM1629,我是过来人,提醒你不要绕弯
回复 支持 反对

使用道具 举报

     
发表于 2022-4-18 17:01:56 | 显示全部楼层
乙猪 发表于 2022-4-18 14:53
在其他论坛听坛友说,宏晶的售后态度不太好,动不动就会教你怎做人。

那倒没有,看你的水平如何了。如果大家都是千年的狐狸,他就不敢给你装什么大尾巴狼。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2024-5-3 17:25

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表