当前位置:网站首页>Matrix Keyboard & Calculator Small Project Based on 51 (UcosII)

Matrix Keyboard & Calculator Small Project Based on 51 (UcosII)

2022-08-10 13:21:00 not enough

矩阵键盘

I'm going to give it to a younger brother and a younger sister recently(应该没有)Training the matrix keyboard,Just to write about my thoughts on writing a matrix keyboard,By the way, I will share a based on what I did beforeucosiismall calculator project

原理

原理就不介绍了,CSDNThere is a lot to share,Two references are recommended:

参考:矩阵键盘_Danshan Qifeng's blog-CSDN博客_矩阵键盘
参考:This article will take you to explain the working principle of the matrix keyboard in detail_Z小旋的博客-CSDN博客_矩阵键盘工作原理

代码

行列扫描法:

原理:

我习惯用x,y轴,Abstract the matrix keyboard into a binary function

  1. Scan the column first,The row port outputs a low level,The column port outputs a high level.Read column port(是否被拉低)获取列值;

  2. Scan the line again,The column port outputs a low level,The row port outputs a high level.Read line port(是否被拉低)获取行值.

  3. Finally, the key value is calculated from the row value and the column value.

PS:The relationship between the key value and the row and column values ​​can be solved through the equation system,Refer to the diagram below to set up the equation:ax+by+c=key_num(a,b,c为系数,x和yfor the row and column values,key_num为键值,Remember to bring in the verification when you solve it)

PS:Row and column coordinates can be customized,Just solve the corresponding calculation formula

1 	2	3	4		S7	S11	S15	S19
5	6	7	8		S6	S10	S14	S18
9	10	11	12		S5	S9	S13	S17
13	14	15	16		S4	S8	S12	S16

如下图:

​ S7: 1 * a + 4 * b + c = 1; S4: 1 * a + 1 * b + c = 13; S16: 4 * a + 1 * b + c = 16

解得: x + 4 * y - 16 = key_num

矩阵键盘原理图

源码:

/*********4*4键盘扫描*********** 对应键值关系 1 2 3 4 S7 S11 S15 S19 5 6 7 8 S6 S10 S14 S18 9 10 11 12 S5 S9 S13 S17 13 14 15 16 S4 S8 S12 S16 在stc15上无P36 P37,对应的是P42 P44!!!!!!!! 函数返回值为0-16 ***************************/
unsigned char key_scanf()
{
    
	uchar x=0,y=0;
    //io口赋值
	P30=0;P31=0;P32=0;P33=0;//Pull the row down
	P34=1;P35=1;P42=1;P44=1;//Pull up the column
	if(!(P34&P35&P42&P44))//Determine if it is pressed
	{
    
		Delay20us();		//消抖
		if(!(P34&P35&P42&P44))//Check again whether it is pressed
		{
    
			if(!P34)
				x=4;
			if(!P35)
				x=3;
			if(!P42)
				x=2;
			if(!P44)
				x=1;//Get column value
			P30=1;P31=1;P32=1;P33=1;//Pull up the row
			P34=0;P35=0;P42=0;P44=0;//Pull the column down
			if(!P30)
				y=1;
			if(!P31)
				y=2;
			if(!P32)
				y=3;
			if(!P33)
				y=4;//获取行值
			while(!(P30&P31&P32&P33));//等待释放
			return (x-4*y+16);	//计算键值
		}
	}
	return 0;//无按键按下返回0
}

计算方法2:

在使用Proteus仿真时,The previous calculation method does not work very well,不清楚原因,I found a way to use the simulation effect on the Internet.
Emulates calculator keys
源码:

unsigned char code a[]={
    0xFE,0xFD,0xFB,0xF7};
//按键扫描函数
int Sacn_Key(void)
{
    
 	unsigned char row,col,i;
 	P1=0xf0;
 	if((P1&0xf0)!=0xf0)
 	{
    
	   	//delay(10);
   		if((P1&0xf0)!=0xf0)
		{
    
			row=P1^0xf0;          //确定行线
			i=0;
			P1=a[i];	          //精确定位
			while(i<4)
			{
    
	 			if((P1&0xf0)!=0xf0)
	  			{
    
	   				col=~(P1&0xff);	  //确定列线
	   				break;            //已定位后提前退出 
	  			}
				else 
	  			{
    
	   				i++;
	   				P1=a[i];
	  			}
			}
		}
		else 
		{
    
			return 0;
		}
	
		while((P1&0xf0)!=0xf0);

		return (row|col);	 		//行线与列线组合后返回
 	}
 	else return 0;	         		//无键按下时返回0
}

This scanning method can be used with a parsing program to analyze the pressed keys,我用的是switch函数实现,Refer to the picture above for the button:

//Parse the value of the key scan function
char coding(int k)
{
    
	char res;
	switch (k)
	{
    
		case 0: res = 0; break;
		case 17:res = '7';break;
		case 18:res = '4';break;
		case 20:res = '1';break;
		case 24:res = ' ';break;
		case 33:res = '8';break;
		case 34:res = '5';break;
		case 36:res = '2';break;
		case 40:res = '0';break;
		case 65:res = '9';break;
		case 66:res = '6';break;
		case 68:res = '3';break;
		case 72:res = '=';break;
		case 129:res = '/';break;
		case 130:res = '*';break;
		case 132:res = '-';break;
		case 136:res = '+';break;
	}
	return res;
}

小项目:基于51的计算器:

简介:

基于Proteus仿真,51芯片,搭载ucosii.The complete simulation project and project code will be packaged and uploaded(will be at the end of the article).
仿真图
PS:1. 小黑框Virtual Terminal 在菜单栏DebugOh the last one

​ 2. The emulation should configure the serial port baud rate as 19200(Double-click the external black box on the schematic),点击ok

设计思路:

  1. 三个任务:计算任务,输出任务,按键任务

    • 计算任务:Get the formula,传送结果
    • 输出任务:The serial port outputs what needs to be displayed
    • 按键任务:检测矩阵键盘,获取输入内容
  2. 结构体

    Used to store input calculations,Posted by the key task to the calculation task

    typedef struct {
          
    	int num1;//数字1
    	int num2;//数字2
    	char cal;//运算符
    }my_cal_t;
    my_cal_t my_cc;
    
  3. 邮箱

    Calculator struct mailbox:It is used for the key function to output the calculation task to the calculation task

    Serial output data mailbox:Serial output data mailbox,Used to output content to the virtual serial port

    OS_EVENT * Num_Box;//Calculator struct mailbox
    OS_EVENT * Mes_Box;//Serial port display data mailbox code implementation:
    

代码:

部分代码:

  1. 主函数

    //初始化系统,初始化外设,初始化任务,启动调度
    void main(void)
    {
          
        OSInit();
        
        InitTimer0();
        InitSerial();
        InitSerialBuffer();
    	
    	Num_Box = OSMboxCreate((void*)0);
    	Mes_Box = OSMboxCreate((void*)0);
        //Matrix keyboard tasks
        OSTaskCreate(TaskStartyya, (void *)0, &TaskStartStkyya[0],4);
    	//计算任务
        OSTaskCreate(TaskStartyyb, (void *)0, &TaskStartStkyyb[0],3);
    	//Serial display tasks
    	OSTaskCreate(TaskStartyyc, (void *)0, &TaskStartStkyyc[0],2);
        
        OSStart();
    }
    
  2. 键盘任务

    //Loop to get the calculation formula,Delivery to mailbox
    for(;;){
          
    		my_cc.num1 = 0;
    		my_cc.num2 = 0;
    		my_cc.cal = 0;
    		PrintStr("\nPlease enter num1 (end by /,*,+,-):\n");
    		//Number one and operator input
    		for(i = 0;i < 4;)
    		{
          //Loop to get keys
    			temp = 0;
    			temp = Sacn_Key();
    			t = coding(temp);
    			//判断是否为运算符
    			if(t == '/'||t == '*'||t == '+'||t == '-')
    			{
          
    				sprintf(txt, "%c", t);
    				OSMboxPost(Mes_Box, txt);
    				my_cc.cal = t;
    				break;
    			}
    			//判断输入是否为数字
    			if(t <= '9'&&t >= '0')
    			{
          
    				num1[i] = t - 0x30;
    				sprintf(txt, "%d", num1[i]);
    				OSMboxPost(Mes_Box, txt);
    				i++;
    				if(i==4)
    				{
          
    					//输入满4bit exit,获取运算符号
    					PrintStr("\nPlease enter /,*,+,-\n");
    					//The loop waits for operator input
    					while(1)
    					{
          
    						temp = Sacn_Key();
    						t = coding(temp);
    						if(t == '/'||t == '*'||t == '+'||t == '-')
    						{
          
    							my_cc.cal = t;
    							sprintf(txt, "%c", t);
    							OSMboxPost(Mes_Box, txt);
    							break;
    							//是运算符,Exit digital one input
    						}
    					}
    				}
    			}
    			OSTimeDlyHMSM(0,0,0,10);
    		}
    		//Calculate the number one
    		for(temp=0;temp<i;temp++)
    		{
          
    			my_cc.num1*=10;
    			my_cc.num1+=num1[temp];
    		}
    		//输入数字二
    		PrintStr("\nPlease enter num2 (end by =):\n");
    		for(i = 0;i < 4;)
    		{
          
    			temp = 0;
    			temp = Sacn_Key();
    			t = coding(temp);
    			//判断是否输入等于号
    			if(t == '=')
    			{
          
    				break;
    			}
    			//判断是否输入数字
    			if(t <= '9'&&t >= '0')
    			{
          
    				num2[i] = t - 0x30;
    				sprintf(txt, "%d", num2[i]);
    				OSMboxPost(Mes_Box, txt);
    				i++;
    			}
    			OSTimeDlyHMSM(0,0,0,10);
    		}
    		//Calculate the number two
    		for(temp=0;temp<i;temp++)
    		{
          
    			my_cc.num2*=10;
    			my_cc.num2+=num2[temp];
    			
    		}
    		//Put the struct into the mailbox
    		OSMboxPost(Num_Box, &my_cc);
        }
    
  3. 计算任务

    //Hang up and wait for the key task to wake up,After the calculation is completed, the result is sent to the output task
    for(;;){
          
    		//等待邮箱
    		cc = OSMboxPend(Num_Box,0,&err);
    		res = 0;
    		//PrintStr("\nok\n");
    		//Calculate the result according to the operator
    		switch (cc->cal)
    		{
          
    			case '/':if(cc->num2 == 0)
    					{
          	
    						sprintf(txt,"\nillegal value!\n",res);
    						OSMboxPost(Mes_Box, txt);
    						continue;
    					}
    					else{
          res=(float)cc->num1/(float)cc->num2;}break;
    			case '*':res=cc->num1*cc->num2;break;
    			case '+':res=cc->num1+cc->num2;break;
    			case '-':res=cc->num1-cc->num2;break;
    		}
    		//输出结果
    		sprintf(txt,"\nresult is %.02f\n",res);
    		OSMboxPost(Mes_Box, txt);   
        }    
    
  4. 输出任务

    //没啥实际意义,Simple encapsulated tasks
    void TaskStartyyc(void *yydata) reentrant
    {
          
    	char *txt;
    	int err;
        yydata=yydata; 
        
        for(;;){
          
    		//接收邮件,And print with serial port
    		txt = OSMboxPend(Mes_Box,0,&err);
    		PrintStr(txt);
        }    
    }
    

感想

Because it is written in a hurry,I feel the code is very crude myself,Many places may still need scrutiny;Of course because of the rush to write,Functionality is also limited,Only binocular calculations are possible.Consider using51系列芯片,还跑了ucosii,So it may be replaced later in the improvement32来仿真.This project I use is transplanted,Download it and use it,It is difficult to modify if it is not transplanted by yourself,Many files have permissions,So it is for reference.

My current ideas for improvement:

  1. Use stack instead of struct(Everything is a data structure)
  2. Optimize output tasks(还没想好,Generally speaking, it is possible to transplant digital tubes or other display methods)

The simulation project and project source code are being packaged and uploaded,可以关注公众号,发送:计算器,Automatically reply to cloud disk links.欢迎留言讨论~请添加图片描述

原网站

版权声明
本文为[not enough]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/222/202208101234197404.html