ARM开发(9)基于STM32的简单四则运算计算器

来源:互联网 发布:upchina是什么软件 编辑:程序博客网 时间:2024/06/05 15:18
           基于STM32的简单四则运算计算器

一 计算器原理:

1.1 本实验实现基于STM32的简单四则运算计算器1.2 实验思路:理解计算器原理(按键扫描,字符实时显示,运算表达式计算,浮点数转字符串,字符串结果显示)1.3 开发环境 : MDK5 库函数版本开发 JLINK仿真  STM32F103VBT6芯片

二 实验步骤:
2.1 key.h代码:

#ifndef __KEY_H#define __KEY_H  #include"sys.h"#define      KEY_NULL            0       //  no key#define      KEY_0               40     // value 0 #define      KEY_1               41#define      KEY_2               42#define      KEY_3               43#define      KEY_4               44#define      KEY_5               45#define      KEY_6               46#define      KEY_7               47#define      KEY_8               48#define      KEY_9               49     // #define      KEY_POINT           50     // decimal point#define      KEY_OP_ADD          64     //  '+'   addition#define      KEY_OP_SUB          65     //  '-'   substract#define      KEY_OP_MUL          66     //  '*'   multiplication#define      KEY_OP_DIV          67     //  '/'   divide#define      KEY_EQU             81    //   '='void KEY_Init(void);//IO³õʼ»¯void    funcScanKey(void);u8  Key_Read(void);#endif

2.2 key.c代码(按键扫描函数):

#include "stm32f10x.h"#include "key.h"#include "delay.h"typedef     struct  {    u8  flagKeyDown:1;    u8  flagKeyRelease:1;    u8  flagKeyLong:1;} TEMP_FLAGS_Type;TEMP_FLAGS_Type tempFlags;u8 specialKey;void KEY_Init(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);  GPIO_InitStructure.GPIO_Pin  = KEY_OUT_PINS ;//0x7f ;//GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6;//ROWPINS; ÐÐ   GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP;     GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;  GPIO_Init(GPIOE, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin  = KEY_IN_PINS ;  //GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10| GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14;//COLPINS; ÁÐ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOE, &GPIO_InitStructure); GPIO_SetBits(GPIOE,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6); GPIO_ResetBits(GPIOE, GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10| GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14);} static  u8  Timer2of16ms = 0;static  u8  sourceKey = 0;static  u8  keyCol, keyRow;u8  const keyTableMax = 7;u8  const keyTableMaxCol = 8;u16 const  scanTable[keyTableMax] = { 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};u16 const  scanTable2[keyTableMaxCol] = { 0x01, 0x02, 0x04, 0x08, 0x010, 0x20, 0x40, 0x80};u8  const   keyTable[keyTableMax][keyTableMaxCol] = {    { KEY_FUNC_UP, KEY_FUNC_DOWN, KEY_ABS_INC, KEY_ENTER, 0, KEY_Z_SET, KEY_Y_SET, KEY_X_SET},    { KEY_SDM, 0, KEY_HA, 0, KEY_0, KEY_1, KEY_4, KEY_7},    { KEY_FUNC_RARC, KEY_CLS, KEY_HALF, 0, KEY_POINT, KEY_2, KEY_5, KEY_8},    { KEY_FUNC_LINE, KEY_FUNC_CIRCLE, 0, KEY_MM_INCH, KEY_SIGN, KEY_3, KEY_6, KEY_9},     { KEY_CALL, KEY_TOOL, KEY_OP_ADD, KEY_OP_SUB, KEY_OP_MUL, KEY_OP_DIV, KEY_EQU, KEY_CLEAR},    { KEY_OP_INV, 0, KEY_OP_SIN, KEY_OP_COS, KEY_OP_TAN, KEY_ARC, KEY_OP_SQRT, KEY_CALCU},    { KEY_ZHUIDU, 0, 0, 0, 0, KEY_Z_ZERO, KEY_Y_ZERO, KEY_X_ZERO }}; void   funcScanKey(void)  {    u16  x ;    uint16_t tempdata;    static  u16 keyDelay = 0;    static  u8  keyRelDelay = 0;    static  u8  row = 0;    u8  currKey,keyLongCnt;    Timer2of16ms ++;    if(Timer2of16ms >= keyTableMax)         Timer2of16ms = 0;    tempdata =  GPIO_ReadOutputData(KEY_PORT)  ;     tempdata &= ~KEY_OUT_PINS;    tempdata |= scanTable[Timer2of16ms ];    GPIO_Write(KEY_PORT, tempdata);    tempdata = 0;    x = tempdata;    tempdata =  GPIO_ReadInputData(KEY_PORT) ;     tempdata &= 0x7f80;    tempdata >>= 7;    x = tempdata;    if(x>0) //  有按键按下了    {        currKey = x;        if((currKey != sourceKey) || (row != Timer2of16ms) )    //  按键判断        {            keyDelay = 0;            sourceKey = currKey;            tempFlags.flagKeyDown = 0;            tempFlags.flagKeyLong = 0;            row = Timer2of16ms;            keyLongCnt = 0;            return;        }        else        {            if((row != Timer2of16ms))                return;            keyDelay++;            keyLongCnt++;            if(keyDelay > 10)            {                keyRelDelay = 0;                if(tempFlags.flagKeyDown)                {                    if(keyLongCnt >= 100)                    {                        specialKey = x;                        tempFlags.flagKeyLong = 1;  //  长按键处理                        for(currKey = 0; currKey < keyTableMaxCol; currKey++)                        {                            if(x == scanTable2[currKey])                                break;                        }                        keyCol = currKey;   keyRow = row;                    }                }                else                {                    tempFlags.flagKeyDown = 1;                    for(currKey = 0; currKey < keyTableMaxCol; currKey++)                    {                        if(x == scanTable2[currKey])                            break;                    }                    keyCol = currKey;   keyRow = row;                }            }        }    }    else    //  没按键按下    {        if(row != Timer2of16ms)            return;        keyDelay = 0;        if(tempFlags.flagKeyLong)        {            keyRelDelay++;            if(keyRelDelay > 3)            {                tempFlags.flagKeyLong = 0;                tempFlags.flagKeyDown = 0;                tempFlags.flagKeyRelease = 0;                keyLongCnt = 0;            }        }        if(tempFlags.flagKeyDown)        {            keyRelDelay++;            if(keyRelDelay > 3)            {                tempFlags.flagKeyDown = 0;                tempFlags.flagKeyRelease = 1;                keyLongCnt = 0;            }        }    }}u8  Key_Read(void) //扫描得到按键值{    if(tempFlags.flagKeyRelease)    {        tempFlags.flagKeyRelease = 0;        return keyTable[keyRow][keyCol];    }    else if(tempFlags.flagKeyLong)        return keyTable[keyRow][keyCol];    return KEY_NULL;}

2.3 calcalator.h代码

#ifndef __CALCALATOR_H#define __CALCALATOR_H   #include "sys.h"extern double Jud(char str[],int begin, int  end);  //动态规划四则运算过程extern double displaynum(char str[],int  len);   //四则运算结果函数extern void float_to_str(char *str,double num);  //双精度化为字符串函数extern u8 str_to_ma(char st);  //字符转为数码管段选码值extern char key(u8 c); //判断按键扫描值是否是四则运算符或者0~9字符#endif

2.4 calcalator.c代码(计算器运算)

#include "calcalator.h"#include"stdio.h"#include"stdlib.h"#include"string.h"#include"math.h"#include "sys.h"int fst[1005];u8  const  seg88Code[17] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0X7C, 0x39, 0x5E, 0x79, 0x71,0x01};double Jud(char str[],int begin, int end)// 动态规划四则运算过程{          int  i;        double k;        for(i = begin; i <= end; i++)          {            if(str[i]== '+' && fst[i] == fst[begin])            {                k = Jud(str,begin, i - 1) + Jud(str,i + 1, end);                  return k;            }        }        for(i = end; i >= begin; i--)          {            if(str[i]=='-' && fst[i] == fst[begin])            {                k = Jud(str,begin, i - 1) - Jud(str,i + 1, end);                     return k;            }        }        for(i = begin; i <= end; i++)            {            if(str[i] == '*' && fst[i] == fst[begin])            {                k = Jud(str,begin, i - 1) * Jud(str,i + 1, end);                    return k;            }        }        for(i = end; i >= begin; i--)           {            if(str[i] == '/' && fst[i] == fst[begin])            {                k = Jud(str,begin, i - 1) / Jud(str,i + 1, end);                  return k;            }        }        if(str[begin]=='(')         {            for(i = begin + 1; fst[i] >= fst[begin + 1]; i++);            k = Jud(str,begin + 1, i - 1);        }        else          {            char *p = str;            sscanf(p+begin, "%lf", &k);          }        return k;}double displaynum(char str[],int len)// 四则运算结果函数{        int  i;        double ans;        memset(fst, 0, sizeof(fst));         fst[0] = 1;        for(i = 1; i <= len - 1; i++)          {                                      if(str[i - 1]== '(')                     fst[i] = fst[i - 1] + 1;            else if(str[i] == ')')                fst[i] = fst[i - 1] - 1;            else                fst[i] = fst[i - 1];        }        ans = Jud(str,0, len - 1);          return ans;} void float_to_str(char *str,double num)// 双精度化为字符串函数{     int high;     double low,tp;      char *start=str;     int n=0;    char ch[20];     int i;    high=(int)num;    low=num-high;     while(high>0){        ch[n++]='0'+high%10;         high=high/10;    }     for(i=n-1;i>=0;i--){        *str++=ch[i];    }    num -= (int)num;     tp = 0.1;    *str++='.';    while(num > 1e-8){         num -= tp * (int)(low * 10);        tp /= 10;         *str++='0'+(int)(low*10);         low=low*10.0-(int)(low*10);     }    *str='\0';    str=start;} extern u8 str_to_ma(char s)// 字符转为数码管段选码值  {         if(s=='.')          return 0x10;         else return  seg88Code[s-'0']; }

2.5 main.c代码(具体实现计算器四则运算):

#include "sys.h"    #include "delay.h"  #include "led.h" #include "beep.h" #include "key.h" #include "keyled.h" #include "calcalator.h"#include"stdlib.h"#include"stdio.h"#include"string.h" char key(u8 c)// 判断按键扫描值是否是四则运算符或者0~9字符 {     char ckey;  if(c>=40&&c<=49) {      ckey=(char)(c-40+'0');   return ckey; }  else if(c==50) {     ckey='.';   return ckey; }  else  if(c==64) {     ckey='+';   return ckey; } else if(c==65) {     ckey='-';   return ckey; } else if(c==66) {     ckey='*'; return ckey; } else  if(c==67) {     ckey='/';   return ckey; } else return 'o';} int main(void){        u8 c,i,n,t,q;        double m;        char str[20];        char dispay_num[20];        u8 led_num[8]={0};        u8 dnum[20];u8  const  seg88Code[17] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0X7C, 0x39, 0x5E, 0x79, 0x71,0x01};            char ckey;            delay_init();            KEY_Init();                       BEEP_Init();            Initial_LED();            while(1)            {              c=0;              i=0;             t=0;             m=0;             q=0;                               while(1)            {            funcScanKey();            c=Key_Read();            if(c != KEY_NULL)            {                      ckey=key(c);                if(ckey!='o')                dispay_num[i++]=ckey;                if(c>=40&&c<=49)                     {                          led_num[t++]=seg88Code[c-40];                     }                 else if ((c>=64&&c<=67)||c==81)                 {                     DisplayOn(1);                Displayy(led_num,t);                   t=0;                 delay_ms (1000);                   DisplayOn(0);                     if(c==81)                       break;                 }                delay_ms(10);            }            }            if(c==81)           {               int h;            h=(int)(i);            m=displaynum(dispay_num,h);            float_to_str(str,m);            n=strlen(str);            for(q=0;q<n;q++)            {                dnum[q]=str_to_ma(str[q]);            }           DisplayOn(1);           Displayy(dnum,n);           delay_ms(1000);           DisplayOn(0);                                                }                                               }           }   

三 接线测试:

 3.1 与板子接线测试效果良好,基本四则运算结果较好,唯一缺点对tm1629a的显示不是很好,因为数码管排列顺序不是顺序,可以在上面修改,基本思路是这样。