8 IO ports detect 64 keys, algorithm implementation and key points of mental method

8 IO ports detect 64 keys, algorithm implementation and key points of mental method

On the basis of this article< 8 IO ports to detect 64 keys, nixie tube display (Proteus simulation) >The principle of algorithm implementation and key points for attention are explained.

The scanning principle has been figured out. It is very simple to detect the status of the other 7 IO ports by pulling down an IO. If it is detected that the IO port is pulled down, it means that a key is pressed, because the IO port detected to be pulled down is pulled down by the IO port used to detect. It's equivalent to I touch a high-level IO port with a probe connected to GND. It will certainly be pulled down. According to the circuit principle, using the unidirectional conduction characteristic of the diode, if the IO port is pulled low during the inspection, only one circuit can be formed.

  • Knowing the principle of key scanning and then implementing it is not very difficult. I think the most difficult thing is the various problems encountered in the debugging process. Mastering its principle is not so complex. After writing, the code does not run smoothly according to its own ideas. Maybe it is a project learning process. A DIY idea may be very simple. There are still many fine nodes to get through to make it run according to your own ideas.
  • The time spent tossing about small bug s is much more than the experience and time spent writing code. Think about a stable and easy-to-use product that requires several versions of iteration.

Summary Essentials

  • The most difficult thing is to control the nixie tube display in the last row of 56-64, because this is your scanning of the P0 bus port itself. It is also the place where you are most likely to have problems and get stuck in this place for the longest time. Be sure to understand its single chip microcomputer operation and key scanning principle. Without delay or interruption, the time of key action must be faster than the running speed of MCU. Therefore, when processing the last row of keys, you need to pay special attention. The display time should be longer than that of other line scanning processing, otherwise it is easy to skip. The pressed keys and displayed values are not the results you want. I will write down the experience one by one below.

When dealing with the last row of keys, I have thought of two ways to deal with the problem of logical judgment:

  • Using compound logic to write is very intuitive, but code reading and executability look relatively bloated. It's cool to write. The MCU will process logic and run more time.

The first way to think of is as follows:

if(P0==0x7f||P0==0xbf||P0==0xdf||P0==0xef||P0==0xf7||P0==0xfb||P0==0xfd||P0==0xfe)

The second way is through binary search: (why can we use binary search algorithm to quickly screen objects? There is stress): the condition of binary search is precautions, and the defined array must be an ordered sequence. It doesn't matter if you don't understand the best method. Just use the search algorithm directly! It is written as follows:

int Search(uchar arr[], int len, int flag)
{
    int right = len - 1;
    int left = 0;
    while (left <= right)
    {
        int mid = (right + left) / 2;
        if (arr[mid] > flag)
        {
            right = mid - 1;
        }
        else if (arr[mid] < flag)
        {
            left = mid + 1;
        }
        else
        {
            return arr[mid];
        }
    }
    return 0;
}

The third traversal method does not need to consider any precautions like the binary search algorithm. Just write a simple traversal program. Although the execution efficiency is slower, it is at least simple to implement and the code is knockable. Compared with the binary search algorithm, it is easier to write.

uchar libian(uchar a[], int value, int n)
{
	int i;
  for (i = 0; i < n; i++)
  {
    if (value == a[i])
    {
      return a[i];
    }
  }
  return 0;
}
  • For 0-64 keys, only the response of 8 keys in the last row of 56-64 needs to be considered. Why do you say that? This is because the key from the design principle and implementation point of view. No matter how long or short you press the keys of 0-56, the response value given to you by the single chip microcomputer is the same and will not change. However, when dealing with the eight keys of 56-64, special treatment is made, and GND is connected. If you don't pay attention to the code, it is easy to cause number skipping. For single chip machine scanning, you first pull points for the specified IO port according to the regulations, Then detect the level status of the other seven IOS. Therefore, when processing the 56th-64th keys, if the speed of the single chip microcomputer scanning keys has exceeded your speed from the time you press the key to the time it bounces up, it will cause the single chip microcomputer to read the wrong response data. The processing method is as follows:
/****************Self port read*********************/
		P0=0xff;//Scan line 8
//    delay(5);
		tmp=P0;
    if (Search(arr, 8, tmp))
    {
        //Assign the detected P0 status value to the temporary variable
        switch(Search(arr, 8, tmp))
        {   //Temporary variables query IO ports one by one
        case 0xfe:
            keynum=57;
            break;//Press the first key in line 1
        case 0xfd:
            keynum=58;
            break;//Press the second key in line 1
        case 0xfb:
            keynum=59;
            break;//Press the 3rd key in line 1
        case 0xf7:
            keynum=60;
            break;//Press the 4th key in line 1
        case 0xef:
            keynum=61;
            break;//Press the 5th key in line 1
        case 0xdf:
            keynum=62;
            break;//Press the 6th key in line 1
        case 0xbf:
            keynum=63;
            break;//Press the 7th key in line 1
        case 0x7f:
            keynum=64;
            break;//Press the 8th key in line 1
        }	
			display();//The IO detection and display of P0 must be handled separately, otherwise it is easy to skip
			delay(80);//Block the key scanning to prevent the nixie tube from jumping. The delay here is not required for other line scanning.
    }

Complete code

#include <reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
//Common cathode nixie tube 0 ~ 9
uchar code table[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//0-9 common cathode nixie tube
uchar code arr[] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe};

uchar duanZhi[]= {0,0};//Save the number of digits displayed by each segment of nixie tube
sbit P36=P3^6;//Time energy terminal of nixie tube
sbit P37=P3^7;
sbit ST=P3^0;//Define 74HC595 shift register
sbit SH=P3^2;
sbit DS=P3^1;
sbit P33=P3^3;
sbit P34=P3^4;
sbit P35=P3^5;

uchar shi,ge;//Digital tube single digit and ten digit display
uchar tmp;//Temporarily store the value of P0
static uchar keynum=0;//Key value
unsigned char Trg;
unsigned char Cont;
static char count=1;
//Millisecond delay
void delay(uint z)
{
    uint x,y;
    for(x=z; x>>0; x--)
        for(y=110; y>>0; y--);
}
void SendTo595(uchar byteData);
int Search(uchar arr[], int len, int flag)
{
    int right = len - 1;
    int left = 0;
    while (left <= right)
    {
        int mid = (right + left) / 2;
        if (arr[mid] > flag)
        {
            right = mid - 1;
        }
        else if (arr[mid] < flag)
        {
            left = mid + 1;
        }
        else
        {
            return arr[mid];
        }
    }
    return 0;
}
/*----------------------------------------------------------------------------------
                                display

void display2()
{
    ge = keynum%10;
    shi = keynum/10;
    duanZhi[0]=table[ge];
    duanZhi[1]=table[shi];
    P34=0x00;
    SendTo595(duanZhi[0]); 		//
    delay(5);
    P34=0x01;//Blanking

    P33=0x00;
    SendTo595(duanZhi[1]);//
    delay(5);
    P33=0x01;//Blanking

}
----------------------------------------------------------------------------------*/
void display()
{
    ge = keynum%10;
    shi = keynum/10;
    duanZhi[0]=table[ge];
    duanZhi[1]=table[shi];
    //Display bits
    P37=0;
    SendTo595(duanZhi[0]); 		//
    delay(2);
    P37=1;//Blanking
    //Display ten digits
    P36=0;
    SendTo595(duanZhi[1]);//
    delay(2);
    P36=1;//Blanking

}
/***********************************************************
*Function name 		:  SendTo595
*function 		: Serial transmission of 8 bits (one byte) of data to 595, and then parallel output
*parameter 		:  byteData
************************************************************/
void SendTo595(uchar byteData)
{
    uchar i=0;
    ST = 0;   //ST / / pull down first to prepare for the rising edge
    for(i; i<8; i++)
    {
        SH = 0;//Pull down first,
        if(byteData&0x80)DS=1;
        else DS=0;
//        DS = (byteData&0x80)?1:0;
        byteData = byteData <<1;		//The byte is shifted one bit to the right

        SH = 1;//The rising edge changes the serial input clock to high level and delays 2 clock cycles
        _nop_();
        _nop_();
        SH = 0;        //The rising edge changes the serial input clock to high level and delays 2 clock cycles
    }
    /*The displacement register data is ready and transferred to the storage register*/
    ST =1;
    _nop_();
    _nop_();
    ST = 0;
}

void key_scan()
{
//    P0=0xff;
//    delay(6);
    
    /********************Line 1 scan**************************/

    P0=0x7F;//Scan line 1 0111 1111
    delay(5);
    if (!Search(arr, 8, tmp))//A key is pressed
    {
        tmp=P0;//Assign the detected P0 status value to the temporary variable
        switch(tmp)
        {   //Temporary variables query IO ports one by one
        case 0x7e:
            keynum=50;
            break;//Press the first key in line 1
        case 0x7d:
            keynum=51;
            break;//Press the second key in line 1
        case 0x7b:
            keynum=52;
            break;//Press the 3rd key in line 1
        case 0x77:
            keynum=53;
            break;//Press the 4th key in line 1
        case 0x6f:
            keynum=54;
            break;//Press the 5th key in line 1
        case 0x5f:
            keynum=55;
            break;//Press the 6th key in line 1
        case 0x3f:
            keynum=56;
            break;//Press the 7th key in line 1
        }
    }
    /********************Line 2 scan**************************/
    P0=0xbf;//Scan line 2
    delay(5);
    if(P0!=0xbf)//A key is pressed
    {
        tmp=P0;//Assign the detected P0 status value to the temporary variable
        switch(tmp)
        {   //Temporary variables query IO ports one by one
        case 0xbe:
            keynum=43;
            break;//Press the first key in line 2
        case 0xbd:
            keynum=44;
            break;//Press the second key in line 2
        case 0xbb:
            keynum=45;
            break;//Press the 3rd key in line 2
        case 0xb7:
            keynum=46;
            break;//Press the 4th key in line 2
        case 0xaf:
            keynum=47;
            break;//Press the 5th key in line 2
        case 0x9f:
            keynum=48;
            break;//Press the 6th key in line 2
        case 0x3f:
            keynum=49;
            break;//Press the 7th key in line 2
        }	
    }
    /********************Line 3 scan**************************/

    P0=0xdf;//Scan line 3
    delay(5);
     if(P0!=0xdf)//A key is pressed
    {
        tmp=P0;//Assign the detected P0 status value to the temporary variable
        switch(tmp)
        {   //Temporary variables query IO ports one by one
        case 0xde:
            keynum=36;
            break;//Press the first key in line 3
        case 0xdd:
            keynum=37;
            break;//Press the 2nd key in line 3
        case 0xdb:
            keynum=38;
            break;//Line 3 press the 3rd key
        case 0xd7:
            keynum=39;
            break;//Press the 4th key in line 3
        case 0xcf:
            keynum=40;
            break;//Press the 5th key in line 3
        case 0x9f:
            keynum=41;
            break;//Press the 6th key in line 3
        case 0x5f:
            keynum=42;
            break;//Press the 7th key in line 3
        }
	
    }
    /********************Line 4 scan**************************/

    P0=0xef;//Scan line 4
    delay(5);
    if(P0!=0xef)//A key is pressed
    {
        tmp=P0;//Assign the detected P0 status value to the temporary variable
        switch(tmp)
        {   //Temporary variables query IO ports one by one
        case 0xee:
            keynum=29;
            break;//Press the first key in line 4
        case 0xed:
            keynum=30;
            break;//The second key in line 4 is pressed
        case 0xeb:
            keynum=31;
            break;//Press the 3rd key in line 4
        case 0xe7:
            keynum=32;
            break;//Press the 4th key in line 3
        case 0xcf:
            keynum=33;
            break;//Press the 5th key in line 4
        case 0xaf:
            keynum=34;
            break;//Press the 6th key in line 4
        case 0x6f:
            keynum=35;
            break;//Press the 7th key in line 4
        }		
    }
    /********************Line 5 scan**************************/

    P0=0xf7;//Scan line 5
    delay(5);
    if(P0!=0xf7)//A key is pressed
    {
        tmp=P0;//Assign the detected P0 status value to the temporary variable
        switch(tmp)
        {   //Temporary variables query IO ports one by one
        case 0xf6:
            keynum=22;
            break;//Press the first key in line 5
        case 0xf5:
            keynum=23;
            break;//Press the 2nd key in line 5
        case 0xf3:
            keynum=24;
            break;//Press the 3rd key in line 5
        case 0xe7:
            keynum=25;
            break;//Press the 4th key in line 5
        case 0xd7:
            keynum=26;
            break;//Line 5 press the 5th key
        case 0xb7:
            keynum=27;
            break;//Press the 6th key in line 5
        case 0x77:
            keynum=28;
            break;//Press the 7th key in line 5
        }		
    }
    /********************Line 6 scan**************************/

    P0=0xfb;//Scan line 6
    delay(5);
    if(P0!=0xfb)//A key is pressed
    {
        tmp=P0;//Assign the detected P0 status value to the temporary variable
        switch(tmp)
        {   //Temporary variables query IO ports one by one
        case 0xfa:
            keynum=15;
            break;//Press the first key in line 6
        case 0xf9:
            keynum=16;
            break;//Press the second key in line 6
        case 0xf3:
            keynum=17;
            break;//Press the 3rd key in line 6
        case 0xeb:
            keynum=18;
            break;//Press the 4th key in line 6
        case 0xdb:
            keynum=19;
            break;//Press the 5th key in line 6
        case 0xbb:
            keynum=20;
            break;//Line 6 press the 6th key
        case 0x7b:
            keynum=21;
            break;//Press the 7th key in line 6
        }
    }
    /********************Line 7 scan**************************/
    P0=0xfd;//Scan line 7
    delay(5);
    if(P0!=0xfd)//A key is pressed
    {
        tmp=P0;//Assign the detected P0 status value to the temporary variable
        switch(tmp)
        {   //Temporary variables query IO ports one by one
        case 0xfc:
            keynum=8;
            break;//Press the first key in line 7
        case 0xf9:
            keynum=9;
            break;//The second key in line 7 is pressed
        case 0xf5:
            keynum=10;
            break;//Press the 3rd key in line 7
        case 0xed:
            keynum=11;
            break;//Press the 4th key in line 7
        case 0xdd:
            keynum=12;
            break;//Press the 5th key in line 7
        case 0xbd:
            keynum=13;
            break;//Press the 6th key in line 7
        case 0x7d:
            keynum=14;
            break;//Line 7 press the 7th key
        }
    }
    /********************Line 8 scan**************************/

    P0=0xfe;//Scan line 8
    delay(5);
    if(P0!=0xfe)//A key is pressed
    {
        tmp=P0;//Assign the detected P0 status value to the temporary variable
        switch(tmp)
        {   //Temporary variables query IO ports one by one
        case 0xfc:
            keynum=1;
            break;//Press the first key in line 8
        case 0xfa:
            keynum=2;
            break;//The second key in line 8 is pressed
        case 0xf6:
            keynum=3;
            break;//Press the 3rd key in line 8
        case 0xee:
            keynum=4;
            break;//Press the 4th key in line 8
        case 0xde:
            keynum=5;
            break;//Press the 5th key in line 8
        case 0xbe:
            keynum=6;
            break;//Press the 6th key in line 8
        case 0x7e:
            keynum=7;
            break;//Press the 7th key in line 8
        }
    }
/****************Self port read*********************/
		P0=0xff;//Scan line 8
//    delay(5);
		tmp=P0;
    if (Search(arr, 8, tmp))
    {
        //Assign the detected P0 status value to the temporary variable
        switch(Search(arr, 8, tmp))
        {   //Temporary variables query IO ports one by one
        case 0xfe:
            keynum=57;
            break;//Press the first key in line 1
        case 0xfd:
            keynum=58;
            break;//Press the second key in line 1
        case 0xfb:
            keynum=59;
            break;//Press the 3rd key in line 1
        case 0xf7:
            keynum=60;
            break;//Press the 4th key in line 1
        case 0xef:
            keynum=61;
            break;//Press the 5th key in line 1
        case 0xdf:
            keynum=62;
            break;//Press the 6th key in line 1
        case 0xbf:
            keynum=63;
            break;//Press the 7th key in line 1
        case 0x7f:
            keynum=64;
            break;//Press the 8th key in line 1
        }	
			display();//The IO detection and display of P0 must be handled separately, otherwise it is easy to skip
			delay(80);//Block the key scanning to prevent the nixie tube from jumping. The delay here is not required for other line scanning.
    }
   display();//The display here is to save the last display value 
		
}
void main()
{
    keynum=0;
    P0=0xff;
    while(1)
    {		
        key_scan();

    }
}

Tags: Algorithm Single-Chip Microcomputer Proteus

Posted on Sun, 12 Sep 2021 01:06:23 -0400 by flyersun