本文使用EmWin,如果不使用EmWin,本文也很有参考价值,只是将触摸屏拆解成键盘和显示而已。

我使用的是安富莱V6的板子,如果是其他板子的话,参照进行最基础的EmWin的移植就可以使用EmWin。

总体来说,代码分为两部分,一部分是GUI,负责算式的输入和结果的显示,用GUIBuilder做,做好了以后就是一个带有Button的window:

stm32F407 emwin 移植_使用栈

写好之后就是一个没有功能的壳子,所以我们要给壳子赋予功能:先建立一个储存中间算式字符串的栈,然后在按键按下的时候把输入的字符入栈(对于非EmWin的,就是键盘驱动以后,检测到相应的按键按下就入栈就好)

typedef struct
{
    char symbol[maxSize];
    int top ; //头地址
} Stack_symbol;

Stack_symbol*  inputstack;

inputstack = (Stack_symbol *)malloc(sizeof(Stack_number));
	

/* 输入算式字符栈出栈 */
char pop_symbol(Stack_symbol *ss)
{
    int p;
    char symbol;
    if(ss->top == 0)
    {
        return 0;
    }
    p = ss -> top - 1;
    symbol = ss -> symbol[p];
    --(ss -> top);
    ss -> symbol[p] = '\0';
    return symbol;
}

/* 输入算式字符栈入栈 */
void push_symbol(char symbol,Stack_symbol *ss)
{
    int p;
    if(ss->top == maxSize)
    {
        errorflag = 1;
    }
    else
    {
        p = ss -> top;
        ss -> symbol[p] = symbol;
        ++(ss -> top);
    }
}

在按键按下的时候(就是回调函数里面检测到按键按下或者是非EmWin的朋友扫描到相应的按键按下),进行字符的入栈,为了按下一个键子就能相应的显示输入的字符,每次入栈之后还要显示字符串栈:

这个函数的作用就是刷新显示:                   GUI_show_num_briefLiu(pMsg);

case WM_NOTIFY_PARENT:
    Id    = WM_GetId(pMsg->hWinSrc);
    NCode = pMsg->Data.v;
    switch(Id) {
    case ID_BUTTON_0: // Notifications sent by 'B2'
      switch(NCode) {
      case WM_NOTIFICATION_CLICKED:
		push_symbol('2',(Stack_symbol *)inputstack);
		GUI_show_num_briefLiu(pMsg);//每一次都要显示一次输入字符串
        break;
      case WM_NOTIFICATION_RELEASED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      // USER START (Optionally insert additional code for further notification handling)
      // USER END
      }
      break;
    case ID_BUTTON_1: // Notifications sent by 'B3'
      switch(NCode) {
      case WM_NOTIFICATION_CLICKED:
        // USER START (Optionally insert code for reacting on notification message
		push_symbol('3',(Stack_symbol *)inputstack);
		GUI_show_num_briefLiu(pMsg);//每一次都要显示一次输入字符串
        // USER END
        break;
      case WM_NOTIFICATION_RELEASED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      // USER START (Optionally insert additional code for further notification handling)
      // USER END
      }
      break;

代码分的第二部分就是运算部分:

输入字符串,摘出来数字和运算符,进行运算符的优先级排序,按照运算符优先级顺序进行计算:

/**********************************************************************
* void final_result(Stack_number *num,Stack_symbol *sym,char *expression)
* 输入:num,       数字栈,分开字符串的数字符号的时候储存数字
* 输入:sym,       符号栈,分开字符串的数字符号的时候储存符号
* 输入:expression,输入字符串,本函数进行加工的原料
***********************************************************************/
void final_result(Stack_number *num,Stack_symbol *sym,char *expression)
{
    int length = getLength(expression);
    int i = 0,zero = 1;
    int t;
    char temp,st,num_temp[maxSize];
    long x,y,result;
	//初始化符号栈和数字栈
    num->top = 0;
	sym->top = 0;
	push_symbol('=',sym);
    while(i < length && zero == 1)
    {
        temp =  expression[i];
        if(!(temp >= '0' && temp <= '9')) //遇到运算符时
        {
			char cmp;
            t = sym->top;
            -- t;
           s t = sym->symbol[t];
            cmp = symbol_priority(temp,st);
            if( cmp == '>')
            {
                push_symbol(temp,sym);
            }
            else if(cmp == '<')
            {

                y = pop_number(num);  //操作数1出栈

                if (st == '/' && y == 0)  //除数不能为0的校验
                {
                    zero = 0;
                    break;
                }
                else
                {
                    x = pop_number(num);//操作数2出栈
                    result = out_result(x,y,st); //计算结果
                    pop_symbol(sym);//运算符出栈
                    push_number(result, num);//运算结果入栈
                    -- i;
//此时i自减,在判断执行完后再i自加,则i不变,下一步还是从这个字符开始判断
//当遇到多个操作符需要计算时需要这样
                }
            }
            else  // 当cmp == '=' 时
            {
                pop_symbol(sym);
            }
            ++ i;
        }
        else  //遇到数字时
        {
            int count = 0;
			int j;
            num_temp[count] = expression[i];//将数字字符赋给temp字符数组
            j = i + 1;//j是从i的下一个字符开始的下标,一次向后遍历,直到遇到的不是数字字符
            while(j < length)
            {
                //若遍历到的是数字字符,则进行相应的处理
                if(expression[j] >= '0' && expression[j] <= '9')
                {
                    count ++;//数字字符个数加1
                    num_temp[count] = expression[j];//将数字字符赋给temp字符数组
                    j ++;//j相应自增
                }
                else
                {
                    break;//一旦遇到的是非数字字符,则跳出循环
                }
            }
            num_temp[count + 1] = '\0';//给temp字符数组赋上一个结束字符
            i = j;//外层循环从j的位置开始
            push_number(atoi(num_temp), num);
        }
    }
    if(zero == 1)
    {
        rusultnum = pop_number(num);//printf("计算结果为%ld\n",pop_number(num));
    }
    else
    {
       // printf("除数不能为0,请重新输入需要计算的表达式!\n");
    }
}

得到长整型结果进行显示,在按下等号之后进行运算和显示:

case ID_BUTTON_13: // Notifications sent by 'B_eql'
      switch(NCode) {
      case WM_NOTIFICATION_CLICKED:
        // USER START (Optionally insert code for reacting on notification message)
		push_symbol('=',(Stack_symbol *)inputstack);
		startcul();	
		GUI_show_briefLiu(pMsg);
		// USER END
        break;
      case WM_NOTIFICATION_RELEASED:
        // USER START (Optionally insert code for reacting on notification message)
        // USER END
        break;
      // USER START (Optionally insert additional code for further notification handling)
      // USER END
      }
      break;

void GUI_show_briefLiu(WM_MESSAGE * pMsg)
{
	WM_HWIN hWinOld;
	char testsring[50];
	sprintf(testsring,"The answer IS %ld",rusultnum);
	hWinOld = WM_SelectWindow(WM_GetClientWindow(pMsg->hWin));
	GUI_SetFont(&GUI_Font8x16x1x2);
	GUI_SetColor(GUI_RED);
	GUI_SetTextMode(GUI_TM_TRANS);
	GUI_DispStringAt((char*)testsring,0,50);
	WM_SelectWindow(hWinOld);
		
}

成品图:

stm32F407 emwin 移植_EmWin计算器_02