zoukankan      html  css  js  c++  java
  • 利用TM1650控制键盘操作

    文章地址:https://www.cnblogs.com/jqdy/p/13865153.html

    1. TM1650简介

        TM1650是深圳市天微电子股份有限公司系列数码管驱动芯片的一个型号,在驱动数码管的同时,可以控制键盘操作,数据手册下载

    • 驱动8段4位共阴数码管
    • 工作电压3-5V
    • 驱动7×4=28个按键

    2. 特点

    • 价格比较便宜:淘宝上大约0.2元/个左右,加上外围电阻、电容,大概总共0.5元
    • 占用I/O资源少:数据线(第3脚SDA)、时钟线(第2脚SCL)各一条
    • 有按键后,第16脚DP会提供低电平,可用作单片机的外部中断,这样可省去单片机轮询按键的动作(7段开屏时)

    3. 原理图

    • CN2连接键盘,适用于最多4×4的键盘(将E、F、G都引出后可适用于4×7键盘)
    • DIG1~DIG4分别连接键盘的4行
    • A~G分别连接键盘的7列,图中只用到4列,因此E、F、G未连线
    • MCU使用的是STC8G1K08-20PIN的
      • sbit KEY_SCL = P1^7
      • sbit KEY_SDA = P1^6
      • sbit KEY_IRQ = P3^7

    4. 根据时序图写出基本操作指令

     

    4.1 START

     1 /********************************************************
     2 *说明:TM1650的START动作
     3 *备注:start之后,CLK和SDA均处于0状态
     4 *TM1650时序图:CLK时钟周期最小为200ns,相当于频率为:1s/200ns=5MHz,
     5 *手册中描述了平均传输速率为4MHz,对应周期为1s/4Mhz=250ns
     6 *同时,根据上位机和硬件接口的配置,平均传输速率会出现较大差异,建议值为100kHz(0.1Mhz)以下
     7 *100kHz的频率对应周期为:1s/100k=10us
     8 *STC8g设定的主频为22.1184MHz,周期为1s/22.1184MHz=45.2ns
     9 *使用_nop_()实现延时已远远不能满足要求,看网上的例子不少都是延时5us,这里也采用一下
    10 *********************************************************/
    11 void start(void)
    12 {
    13     KEY_SCL = 1;
    14     KEY_SDA = 1;
    15     Delay1us(5);
    16     KEY_SDA = 0;
    17     Delay1us(5);
    18     KEY_SCL = 0;
    19     Delay1us(5);
    20 }

    4.2 ACT

     1 /********************************************************
     2 *说明:TM1650的ACT动作
     3 *备注:如果本次通讯正常,芯片在串行通讯的第8个时钟下降沿后,
     4 *      TM1650主动把DAT拉低------因此DAT拉低是TM1650的硬件行为
     5 *      直到检测到CLK来了上升沿,DAT释放为输入状态(本芯片)
     6 *      act结束后,CLK和DAT线均处于低电平状态
     7 *********************************************************/
     8 void act(void)
     9 {
    10     unsigned char i;
    11     i = 0;
    12     while(KEY_SDA && (i < 100))
    13     {
    14         i++;
    15     }
    16     KEY_SCL = 1;
    17     Delay1us(5);
    18     KEY_SCL = 0;
    19     Delay1us(5);
    20 }

    4.3 STOP

    /********************************************************
    *说明:TM1650的stop动作
    *备注:stop后两条线均处于高电平状态
    *********************************************************/
    void stop(void)
    {
        KEY_SCL=1;
        Delay1us(5);
        KEY_SDA=1;
        Delay1us(5);
    }

    4.4 WRITE

     1 /***************************************************
     2 *说明:操作TM1650的底层写函数
     3 *参数:byte为写入TM1650的字节
     4 *备注:io.h中定义了控制TM1650芯片的两个管脚
     5 *      sbit KEY_SCL = P1^7;
     6 *      sbit KEY_SDA = P1^6;
     7 *在wrt之前的start动作已经置CLK和SDA与低电平状态
     8 ***************************************************/
     9 void wrt(unsigned char byte)
    10 {
    11     unsigned char i;
    12     for(i = 8; i > 0; i--)
    13     {
    14         byte <<= 1; //高位在前
    15         if(CY)
    16         {
    17             KEY_SDA = 1;
    18         }
    19         else
    20         {
    21             KEY_SDA = 0;            
    22         }
    23         Delay1us(5);
    24         KEY_SCL = 1;
    25         Delay1us(5);
    26         KEY_SCL = 0;
    27         Delay1us(5);
    28     }
    29     // 写完8bit后CLK处于低电平状态
    30 }

    4.5 READ

     1 /***************************************************
     2 *说明:操作TM1650的底层读函数
     3 *返回:读取按键的TM1650代码
     4 *备注:io.h中定义了控制TM1650芯片的两个管脚
     5 *      sbit KEY_SCL = P1^7;
     6 *      sbit KEY_SDA = P1^6;
     7 *指令顺序:start-command(4f)-ack-读key-ack-stop
     8 ***************************************************/
     9 unsigned char read(void)
    10 {
    11     unsigned char i;
    12     unsigned char coder = 0;
    13     start();
    14     wrt(COMMAND_READ_KEY_DATA); //读按键命令
    15     act();
    16     for(i = 8; i > 0; i--)
    17     {
    18         KEY_SCL = 1;
    19         Delay1us(5);
    20         coder <<= 1;
    21         if(KEY_SDA)
    22         {
    23             coder++;
    24         }
    25         KEY_SCL = 0;
    26         Delay1us(5);
    27     }
    28     act();
    29     stop();
    30     return coder;
    31 }

    4.6 使用的一些宏

     1 //命令宏定义区---------------------------开始*/
     2 #define COMMAND_SET_PARAMETER  0x48 //设置系统参数命令
     3 #define COMMAND_READ_KEY_DATA  0x49 //读取按键数据命令
     4 //命令宏定义区---------------------------结束*/
     5 
     6 //参数宏定义区---------------------------开始*/
     7 #define PARAMETER_BRIGHTNESS_NORMAL 0x00
     8 #define PARAMETER_BRIGHTNESS_ONE    0x10
     9 #define PARAMETER_BRIGHTNESS_TWO    0x20
    10 #define PARAMETER_BRIGHTNESS_THREE  0x30
    11 #define PARAMETER_BRIGHTNESS_FOUR   0x40
    12 #define PARAMETER_BRIGHTNESS_FIVE   0x60
    13 #define PARAMETER_BRIGHTNESS_SIX    0x60
    14 #define PARAMETER_BRIGHTNESS_SEVEN  0x70
    15 
    16 #define PARAMETER_SEGMENT_MODE_EIGHT 0x00 //8段输出(默认)
    17 #define PARAMETER_SEGMENT_MODE_SEVEN 0x08 //7段输出,用于键盘读出时,16脚DP/KP为键盘扫描标识输出
    18                                           //  7段模式且开屏时(48H+09H):
    19                                           //    在没有按键按下时DP/KP脚输出高电平
    20                                           //    在有按键按下时,DP/KP脚会输出低电平
    21                                           //    当下一次按键数据被读取后(或关屏)DP/KP脚输出高电平
    22                                           //    KP可以用作是否有按键的指示,连接MCU的外部中断脚
    23 #define PARAMETER_WORK_MODE_RUNNING  0x00 //正常工作模式
    24 #define PARAMETER_WORK_MODE_STANDBY  0x04 //待机工作模式
    25 
    26 #define PARAMETER_DISPLAY_MODE_OFF 0x00 //关闭屏显示
    27 #define PARAMETER_DISPLAY_MODE_ON  0x01 //打开屏显示
    28                                         //  当发送开屏命令且为正常工作模式时,DIG1-DIG4开始进行扫描
    29                                         //  所以,读键盘时也需要开屏
    30 //参数宏定义区---------------------------结束*/

    5 TM1650的初始化

     1 /***************************************************
     2 *说明:初始化连接键盘芯片的管脚
     3 *备注:io.h中定义了控制TM1650芯片的三个管脚
     4 *      sbit KEY_KEY_SCL = P1^7;
     5 *      sbit KEY_KEY_SDA = P1^6;
     6 *      sbit KEY_IRQ = P3^7; 在7段模式下,在没有按键按下时DP/KP脚输出高电平,
     7 *                           在有按键按下时, DP/KP脚会输出低电平,
     8 *                           当下一次按键数据被读取后(或关屏) DP/KP脚输出高电平
     9 *     (读按键时数据从TM1650输出到MCU,此时与TM1650的DAT相连的IO口必须设置为输入模式且释放总线)
    10 *      将这两个管脚设置成准双向模式(00)
    11 *操作顺序:start-command1(系统命令)-act-command2(系统参数设置)-act-stop
    12 ***************************************************/
    13 void TM1650_Init(void)
    14 {
    15     // 留出上电初始化时间
    16     Delay1ms(60);
    17     // 设置两线管脚工作模式,准双向(00)
    18     P1M1 &= ~(0x03<<6);
    19     P1M0 &= ~(0x03<<6);
    20     // 读键盘功能初始化,7段、正常模式、开屏
    21     start();
    22     wrt(COMMAND_SET_PARAMETER);
    23     act();
    24     wrt(PARAMETER_SEGMENT_MODE_SEVEN | PARAMETER_WORK_MODE_RUNNING | PARAMETER_DISPLAY_MODE_ON);
    25     act();
    26     stop();
    27     //KEY_IRQ P3.7初始化为INT3
    28     INTCLKO |= 1<<5; // 允许INT3(仅支持下降沿中断)
    29     EA = 1;
    30     // TM1650第16脚DP按键触发信号引脚初始化,高阻模式(默认值)
    31     P3M1 |= 0x01 << 7;    // 1
    32     P3M0 &= ~(0x01 << 7); // 0
    33 }

    6. 键盘中断处理

    1 /**************************************************
    2 *说明:按下某个按键时触发INT3中断,这是INT3的中断处理程序
    3 **************************************************/
    4 void Int3_Irq(void) interrupt 11
    5 {
    6     g_FlagKeyPressed = TRUE;
    7 }

        g_FlagKeyPressed是一个全局变量,main函数中只需要查看该变量的值就知道是否有按键被按下了。

    7. 按键的读取

         通过外部中断得到有按键被按下的消息后,就可读取按键值了。

     1 /***************************************************
     2 *说明:读取按键的值
     3 *返回:根据自己的键盘布局,将得到的值与所按键的ASCII码进行对应
     4 ***************************************************/
     5 unsigned char TM1650_GetKeyAscii(void)
     6 {
     7     unsigned char key;
     8     do{
     9         key = read();
    10     }while(key > 0x40); // 等待按键松开
    11     init(); // 初始化TM1650
    12     
    13     //BeepBlink(); //声光提示(其他功能,与操作TM1650无关)
    14     
    15     switch(key)
    16     {
    17         case 0x0f:
    18             return '0';
    19         break;
    20         case 0x17:
    21             return '#';
    22         break;
    23         case 0x07:
    24             return '*';
    25         break;
    26         case 0x0e:
    27             return '8';
    28         break;
    29         case 0x16:
    30             return '9';
    31         break;
    32         case 0x06:
    33             return '7';
    34         break;
    35         case 0x0d:
    36             return '5';
    37         break;
    38         case 0x15:
    39             return '6';
    40         break;
    41         case 0x05:
    42             return '4';
    43         break;
    44         case 0x0c:
    45             return '2'; 
    46         break;
    47         case 0x14:
    48             return '3';
    49         break;
    50         case 0x04:
    51             return '1'; 
    52         break;
    53         default:
    54             return 0;
    55     }
    56 }

        上段程序中,第11行init()非常重要,其作用是再次初始化TM1650。具体原因如下:

        1)当某个按键被按下时,DP给出低电平,触发外部中断,进而可以读取改键的键值。

        2)此时DP会一直保持低电平状态,不能再次触发外部中断。

        3)执行init(),再次初始化TM1650,DP将恢复到高电平状态,为下次按键做好准备。

     1 /***************************************************
     2 *说明:恢复第16脚DP的低电平状态
     3 *备注:第一次按键后,DP会从高电平变成低电平状态,只有再次初始化TM1650才能
     4 *      将DP恢复成高电平状态,从而为第二次按键做好准备
     5 ***************************************************/
     6 void init()
     7 {
     8     start();
     9     wrt(COMMAND_SET_PARAMETER);
    10     act();
    11     wrt(PARAMETER_SEGMENT_MODE_SEVEN | PARAMETER_WORK_MODE_RUNNING | PARAMETER_DISPLAY_MODE_ON);
    12     act();
    13     stop();
    14 }

    8 main函数

        去掉其他功能,简化的main函数非常简单。

     1 void main(void)
     2 {
     3     unsigned char key;
     4     TM1650_Init();
     5     while(1)
     6     {
     7         if(g_FlagKeyPressed == TRUE)
     8         {
     9             g_FlagKeyPressed = FALSE;
    10             key = TM1650_GetKeyAscii();
    11             // 处理key。。。。。。
    12         }
    13     }
    14 }
  • 相关阅读:
    JDK1.8源码之HashMap(一)——实现原理、查找及遍历
    JDK1.8源码之ArrayList
    03、Swagger2和Springmvc整合详细记录(爬坑记录)
    02、Java的lambda表达式和JavaScript的箭头函数
    Java-IO流之输入输出流基础示例
    JDBC API 事务的实践
    JDBC API 可滚动可编辑的结果集
    Java虚拟机----垃圾回收与内存分配
    Java数据库连接与查询
    Java虚拟机-对象的创建和访问
  • 原文地址:https://www.cnblogs.com/jqdy/p/13865153.html
Copyright © 2011-2022 走看看