TM1618扫描按键问题

2019-08-17 09:34发布

本人用STM32F103RCT6进行数码管的实验,试验中,数码管显示无问题(即MCU与1618的通讯没有问题),但是按键扫描一直不能成功。特开此帖请教!!!
以下是原理图
QQ截图20170328112739.png
以下是TM1618.c文件的全部代码
#include "tm1618.h"
#include "delay.h"
#include "usart.h"       
/*
* DIO引脚用的PB5,CLK引脚用PB4,STB引脚用PB3
*****************************************************/
void        tm1618_clear(void);
void        tm1618_WrByte(u8 oneByte);
void         tm1618_DisPlay(void);
u8                 tm1618_ScanKey(void);

/*****************************************************
* name:        tm1618_init
* param:
* return:
* desc:        驱动芯片初试化,先把所有的显示清零
**************************************************/
void tm1618_init(void)
{
        u8 data0[4] = {0,1,2,3};
        u8 data1[4] = {4,5,6,7};
        u8 data2[4] = {8,9,0,1};
        u8 i;
        u8 key;
        GPIO_InitTypeDef GPIO_InitStructure;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);

        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//关闭jtag,使能SWD,可以用SWD模式调试

        // 如果要输出为5V,可以用开漏输出,不能用推挽输出
        // PB3.4可以耐受5V,PB5不能耐受5V
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 ;
//        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;                // 复用开漏输出
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;        // 开漏输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        // 通用推挽输出
        GPIO_Init(GPIOB, &GPIO_InitStructure);

        TM1618_DIO = 1;
        TM1618_CLK = 1;
        TM1618_STB = 1;
       
        delay_us(2);

        tm1618_DisPlay();        // 设置显示模式
        tm1618_clear();                // 清除所有显示
       
       
        while(1){
                switch(i){
                        case 0:
                                tm1618_DisData(data0);
                                break;
                        case 1:
                                tm1618_DisData(data1);
                                break;
                        case 2:
                                tm1618_DisData(data2);
                                break;
                }
                key = tm1618_ScanKey();
                if( key != 0 ){        // 如果有按键按下,则改变显示内容
                        i++;
                }
                if(i == 3){
                        i = 0;
                }
                delay_ms(5000);
                delay_ms(60000);
        }
       
}

/*****************************************************
* name:        tm1618_WrByte
* param:
* return:
* desc:        写一个字节,字节按照MSB来写,发送按照LSB发送
**************************************************/
void tm1618_WrByte(u8 oneByte){
        u8 i;
        for(i = 0;i < 8;i++){
                TM1618_CLK = 0;
                if(oneByte & 0x01){        // 低位在前
                        TM1618_DIO = 1;
                }else{
                        TM1618_DIO = 0;
                }
                delay_us(3);
                oneByte = oneByte>>1;
                TM1618_CLK = 1;
                delay_us(3);
        }
}

/*****************************************************
* name:        tm1618_clear
* param:
* return:
* desc:        清除数码管显示的数字
**************************************************/
void tm1618_clear(void){
        u8 i;
        u8 byte;
       
        byte = 0x40;        // 数据命令,写数据到显示寄存器,自动地址增加
        TM1618_STB = 0;
        tm1618_WrByte( byte );       
        TM1618_STB = 1;
        delay_us(3);
       
        byte = 0xc0;        // 显示地址从0xc0开始
        TM1618_STB = 0;
        tm1618_WrByte( byte );       
        byte = 0x00;        // 写入数据,全部写为0
        for(i = 0; i < 14; i++){
                tm1618_WrByte( byte );               
        }
        TM1618_STB = 1;
        delay_us(3);
       
        byte = 0x8f;        // 显示开关开,辉度为最亮14/16
        TM1618_STB = 0;
        tm1618_WrByte( byte );       
        TM1618_STB = 1;
        delay_us(3);
}

/*****************************************************
* name:        tm1618_ScanKey
* param:
* return:SUCCESS:有按键按下
*                ERROR: 无按键按下
* desc:        读按键,只需要关心K1即可
**************************************************/
u8 tm1618_ScanKey(void){
        u8 status = ERROR;
        u8 byte = 0x42;        // 读键扫程序
        u8 i,j;
        GPIO_InitTypeDef GPIO_InitStructure;        // PB5要改成输入
       
        u8 temp;
       
        TM1618_STB = 0;       
        tm1618_WrByte( byte );
        TM1618_DIO = 1;
        // 如果DIO用开漏输出,可以直接用GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)读IO的值
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;        // 下拉输入
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        //
        delay_us(2);        // 在第八个时钟下降沿之后延时5us,开始判断ACK信号
        for(i=0; i<3;i++){
                for(j=0; j<8; j++){
                        TM1618_CLK = 0;
                        delay_us(3);
                       
                        temp = GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5);
                        usart_send_char(USART1,"PB5:%d        ",temp );
                       
                        if((i== 0) && (j == 1)){
                                status = temp;
                        }
                        TM1618_CLK = 1;
                        delay_us(3);
                }
                delay_us(6);
        }
        TM1618_STB = 1;
        delay_us(2);
        // 改回推挽输出
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        // 通用推挽输出
        GPIO_Init(GPIOB, &GPIO_InitStructure);
        TM1618_DIO = 1;
        return status;
}
/*****************************************************
* name:        tm1618_DisPlay
* param:
* return:
* desc:        写显示寄存器,开启显示;四位八段
**************************************************/
void tm1618_DisPlay(void){
        u8 byte = 0x00;        // 显示模式,四位八段
        TM1618_STB = 0;       
        tm1618_WrByte( byte );       
        TM1618_STB = 1;
        delay_us(3);
}
/*****************************************************
* name:        dataConvert
* param:
* return:数字的数码管寄存器值
* desc:        将数字转化为数码管显示的寄存器值
**************************************************/
DisData_Structre dataConvert(u8 data){
        DisData_Structre disData;
        switch( data ){
                case 0:
                        disData.byte0 = 0x1f;
                        disData.byte1 = 0x08;
                        break;
                case 1:
                        disData.byte0 = 0x06;
                        disData.byte1 = 0x00;
                        break;
                case 2:
                        disData.byte0 = 0x1b;
                        disData.byte1 = 0x10;
                        break;
                case 3:
                        disData.byte0 = 0x0f;
                        disData.byte1 = 0x10;
                        break;
                case 4:
                        disData.byte0 = 0x06;
                        disData.byte1 = 0x18;
                        break;
                case 5:
                        disData.byte0 = 0x0d;
                        disData.byte1 = 0x18;
                        break;
                case 6:
                        disData.byte0 = 0x1d;
                        disData.byte1 = 0x18;
                        break;
                case 7:
                        disData.byte0 = 0x07;
                        disData.byte1 = 0x00;
                        break;
                case 8:
                        disData.byte0 = 0x1f;
                        disData.byte1 = 0x18;
                        break;
                case 9:
                        disData.byte0 = 0x0f;
                        disData.byte1 = 0x18;
                        break;
        }
        return disData;
}
/*****************************************************
* name:        tm1618_DisData
* param:要显示数据数组的头地址
* return:
* desc:        写显示寄存器,开启显示;四位八段
**************************************************/
void tm1618_DisData(u8* data){
        u8 i;
        u8 byte;
        DisData_Structre disData;
       
        byte = 0xc0;        // 显示地址从0xc0开始
        TM1618_STB = 0;
        tm1618_WrByte( byte );       
        for(i=0; i<4; i++){
                disData = dataConvert(data);
                if( i == 1){        // 显示小数点
                        disData.byte1 = disData.byte1 | 0x20;       
                }
                tm1618_WrByte( disData.byte0 );       
                tm1618_WrByte( disData.byte1 );       
        }               
        TM1618_STB = 1;
        delay_us(3);
       
        byte = 0x8f;        // 显示开关开,辉度为最亮14/16
        TM1618_STB = 0;
        tm1618_WrByte( byte );       
        TM1618_STB = 1;
        delay_us(3);
}
以下为串口1的输出,复位以后,从始至终没有按过按键
QQ截图20170328112951.png



友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
4条回答
lu
1楼-- · 2019-08-17 12:49
 精彩回答 2  元偷偷看……
lu
2楼-- · 2019-08-17 16:56
以下是从天微电子官方要的demo代码:

/*****************************************************************************
*版权信息:深圳天微电子有限公司
*文 件 名:TM1618-V1.0
*当前版本:V1.0
*MCU 型号:STC12C5608AD
*开发环境:Keil uVision4
*晶震频率:11.0592MHZ      
*完成日期:2013-07-18
*程序功能:1.数码管驱动:驱动7段5位LED共阴数码管显示0~4;
            2.按键功能  : 包含按键读程序驱动函数
*免责声明:1.此程序为TM1618驱动LED数码管演示程序,仅作参考之用。
            2.如有直接使用本例程程序造成经济损失的,本公司不承担任何责任            
********************************************************************************/
#include <reg52.h>                                 //MCU头文件
#include "intrins.h"                               //包含nop指令头文件

#define uchar unsigned char                               //数据类型宏定义
#define uint unsigned int                               //数据类型宏定义

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


/********************定义控制端口**********************/
sbit DIO=P1^0;                                           //定义TM1618 DIO为P1^0;
sbit CLK=P1^1;                                           //定义TM1618 CLK为P1^1;
sbit STB=P1^2;                                           //定义TM1618 STB为P1^2;


/********************定义数据*************************/

//********************        0    1    2   3     4
uchar code CODE_L[5]={0x1F,0x06,0x1B,0x0F,0x06,};      //共阴数码管0~5字型码
uchar code CODE_H[5]={0x08,0x00,0x10,0x10,0x18,};  

uchar code CODE_L_OFF[6]={0x00,0x00,0x00,0x00,0x00,};  //共阴数码管不显示
uchar code CODE_H_OFF[6]={0x00,0x00,0x00,0x00,0x00,};

uchar KEY[3]={0};                                          //为存储按键值定义的数组

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

/***************发送8bit数据,从低位开始**************/
void send_8bit(uchar dat)                                //发送8位数据,从低位开始
{
  uchar i;
  for(i=0;i<8;i++)
  {       
          CLK=0;
    if(dat&0x01)
           DIO=1;
        else         
           DIO=0;
        _nop_();
        _nop_();
        _nop_();
        CLK=1;         
        dat>>=1;         
  }
  CLK=0;
  DIO=0;
}

/******************发送控制命令***********************/
void send_command(uchar com)                             //发送命令字节
{
        STB=1;                                                         //STB置高
        nop;
        STB=0;                                                        //STB置低
        send_8bit(com);                                        //发送8bit数据
}

/****************读取按键值并存储*******************/
void read_key(void)                                          //读取3字节按键值并存入数组KEY[],从低字节、低位开始
{
        unsigned char i,j;
        //DIO 输出
        send_command(0x42);                                 //发送读按键命令
        DIO=1;                                                     //释放DIO数据总线
        //DIO 输入
        for(j=0;j<3;j++)                                   //连续读取3个字节
        {
                for(i=0;i<8;i++)
                {
                        CLK=0;
                        KEY[j]=KEY[j]>>1;
                        CLK=1;
                        if(DIO==1)
                        {
                                KEY[j]=KEY[j]|0x80;
                        }
                        nop;
                } //0x00
                nop;
                nop;
        }
        CLK=0;
        DIO=0;
        STB=1;
}

/************显示函数,数码管1~7位显示0~6************/
void display(uchar *p1,uchar *p2)   //显示函数,1~5位数码管显示0~4
{
        uchar i;
        send_command(0x01);         //设置显示模式,5位7段模式
        send_command(0x40);        //设置数据命令,采用地址自动加1模式
        send_command(0xc0);        //设置显示地址,从00H开始

        for(i=0;i<5;i++)
        {
                send_8bit(*p1);            //从00H开始,向地址送显示数据
                send_8bit(*p2);               
                p1++;
                p2++;
        }
        send_command(0x8F);         //设置显示命令,打开显示并设置占空比14/16.
        STB=1;
}
       
/*****************按键处理函数*********************/
void key_process()                // 按键处理函数
{
    if(KEY[0]!=0x00)
   {
    if((KEY[0]==0x02)) {display(CODE_L,CODE_H);}          //K2与KS1按键按下,数码管显示数字0~4
    if((KEY[0]==0x10)) {display(CODE_L_OFF,CODE_H_OFF);}  //K2与KS2按键按下,数码管显示关闭
   }
}

void main()
{
        display(CODE_L,CODE_H);            //上电显示0~4
        delay_nms(1);
        while(1)
        {
                read_key();                   //读按键值
                key_process();                   //按键处理
                delay_nms(200);           //延时200ms再读按键
        }
}

正点原子
3楼-- · 2019-08-17 21:20
帮顶
lu
4楼-- · 2019-08-18 00:39
本帖最后由 lu 于 2017-6-7 15:52 编辑

一周热门 更多>