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

           基于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

三 接线测试:

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

你可能感兴趣的:(嵌入式,arm,stm32,芯片,四则运算计算器,f103vb)