C#课程设计[简单计算器的设计与实现]【附带项目报告】

课 程 设 计

                   

课程名称:          C#课程设计         

设计课题:     简单计算器的设计与实现  

O二三年 十二 月十一日  

C#课程设计

设计要求 (1)分组后,每组抽取一个题目,每人完成该题目     

     的一个功能模块的设计;                            

     (2)winform应用程序实现(代码须锯齿型书写格式);

     (3)必须上机调试通过;                           

     (4)每人单独完成一份完整的课程设计报告。         

课 题 发 给 日 期     2023年11月30日  

1、程序功能菜单等界面设计情况:

2、功能全面,是否达到设计要求:

3、答辩情况:

4、课设报告完成情况:

5、出勤情况:

评分:           

C#课程设计》

任务书

                二○二三年十二月

一、课程设计目的

C#课程设计是计算机类专业本科专业的集中实践性环节之一,是学习完《C#程序设计》课程后进行的一次全面综合应用练习。目的是要达到理论与实际相结合,使学生能针对现实世界中的实际问题设计C# winform应用程序,培养良好的程序设计技能并为后续课程学习打下基础。

课程设计中,要求学生通过 C#语言来设计与实现简单应用程序。查阅相关资料,根据应用程序的需求进行各阶段设计,编码实现一个相对完整的、具有一定实用价值的功能模块,并以文本方式提交课程设计报告。

在课程设计中可能用到一些教学中未涉及的知识,学生查阅相关文献资料,也可自学必要的内容,教师做出相应指导。学生设计过程中,教师应对每一位学生的学习态度、实践能力以及进度把握等应做到心中有数。

二、课程设计日期、时间、地点

1、日期:20231130--1211日(周末除外)

2、地点:D404

4、答辩时间:15周周一开始。

三、注意事项

1、允许并鼓励同学之间相互讨论。

    2、允许参考文献、网络上的资源,但严禁全盘复制。

3、严禁旷课,有事凭辅导员批准的假条请假。。

4、保持机房卫生,保持工作环境清洁;

5、爱护机房设备,如有损坏照价赔偿。

四、课程设计要求

1.使用C#语言,完成功能设计,按照网站需求分析、概念结构设计、数据库设计与实施、界面设计与实现、代码编写、测试与修正等流程进行,所设设计的模块必须能够正常运行,并实现所要求的功能。

    2. 课程设计要求独立完成,不得抄袭。发现抄袭行为成绩一律记零分。

    3. 课程设计结束时,需每人提交《课程设计报告》一份。课程设计报告以word 编辑,A4双面打印,装订后提交。同时提交程序源代码的电子文档(以小组长的学号+姓名命名)。

3、承担同一项目开发任务的小组成员,每人所从事的程序开发工作(程序模块)应有明确分工,不可有重复部分

    4.课程设计评分标准:

1)出勤 20分(旷课3次及以上,不合格直接重修);

2)程序设计完成情况 50 (答辩成绩25+代码检查25分);

3)课程设计报告30分。

五、课程设计题目及分工

    本次设计根据抽选的题目供同学练习。分工后,不允许自行调换。

计算器的开发与应用

摘要:计算器是一种常见的应用程序,用于执行数学运算和表达式求值。它可以用于简单的日常计算,也可以在科学、工程和金融等领域进行复杂的计算。计算器的产生和发展是建立在电子计算机基础之上的,现代社会很需要一个健全、高效率的计算器。为了提高自己的实践能力和将来开发一个更实用,更全能更智能的计算器,以设计与实现计算器为课题。此次设计的计算器应用软件从visual studio2022编程环境中开发,是一个简单的窗体应用程序,实现简单的计算器功能。以微软自带的计算器为模板,设计了简单易懂的计算器。这款计算器不仅实现了简单的四则运算的功能,还能连续运算,实现小键盘的操作,光标的转移。虽然这个简单的计算器只能实现这些功能,但是具有简洁的图文外观,即时准确的获得所需要要计算的结果,充分降低了数字计算器的难度和所需要的时间,对人们生活和学习具有有很大的帮助。

     关键词:计算器;功能;界面;窗口;事件。

目录

目录... 7

1.需求分析... 8

1.1 实验目的... 8

1.2计算器应用软件的功能分析... 8

1.3 计算器软件的功能图... 9

2.界面设计... 10

2.1窗口切换... 11

3.功能实现... 12

3.1表达式显示的主要代码... 12

3.2添加数字和运算符... 13

3.3清零运算功能代码... 15

3.4求倒数功能... 16

3.5求值功能代码... 17

3.6多项式表达式算法逻辑... 19

4.进制转换... 29

5.项目总结... 30

参考文献... 31

附一:本人完成界面设计、窗口切换、表达式显示等功能模块设计... 31

1.需求分析

通过对微软附件计算器软件进行调研、分析,研究,使用。我们小组了解到了作为一个计算器所应该有的一些简单功能和界面的排版,我们知道了怎样使编写的计算器程序向微软附件计算器靠拢。

1.1 实验目的

设计一个简单计算器,在功能上功能尽量模拟windows操作系统中的计算器,系统界面不做强制要求,实现加、减、乘、除、求开方、求倒数等功能,实现进制间的转换功能:十进制、二进制、十六进制、八进制。

其他要求:应具有一般计算功能,能进行基本的加减乘除运算。其他计算功能作为加分项。界面美观,功能丰富。开发平台:VS2010及以上,团队人数:4人。

1.2计算器应用软件的功能分析

计算器软件的主要功能是:

1)可以显示计算数字的多项式。

2)可以进行加减乘除四则运算,和开方、取余、求倒数等功能。

3)可以进行算术表达式优先级的关系进行求值。

4)可以进行窗口切换

5)可以进行十进制、二进制、十六进制、八进制之间互相转换。

6)可以进行大数据运算不会出现溢出错误。

1.3 计算器软件的功能图

根据以上需求分析,实现了主要的功能,计算器软件功能如图1-1所示。

图 1-1

2.界面设计

计算器软件界面设计采用两个form窗口,一个主要实现计算器的功能,另一个实现进制转换的功能。使用多个button按钮用于获取表达式的输入以及窗口之间的切换,和多个texbox文本框显示进制转换的结果。完成界面如图2-1、2-2。

图 2-1

图 2-2

2.1窗口切换

代码运行之后首次显示的页面为计算器软件的主界面,主界面上方的两个button既有显示功能又有点击事件功能。

左上方button按钮主要显示计算表达式,其次实现计算器主界面跳转到进制转换窗口界面。

主界面右上方主要显示最终的值,其次点击右上方的button按钮会显示表达式最终的结果。

窗口切换的核心代码:

private void  ToolStripMenuItem_Click(object sender, EventArgs e)

        {

            Form2 frm2 = new Form2();//想要打开的窗体界面

            this.Hide();//隐藏当前窗体

            frm2.ShowDialog();

            Application.ExitThread(); //退出当前窗体,这一步很重要,否则最后可能无法将所有进程关闭。最好是在跳转页面后,将之前的页面退出。

        }

3.功能实现

要实现需求分析中软件各功能,需要设计一些事件的功能代码。利用所需的

代码,编写一些计算器的功能,使计算器更加灵活易懂。

3.1表达式显示的主要代码

表达式分为两种:一种是没有包含开方的表达式,另一种是包含开方的表达式。

主要实现代码如下:

if (radication == "")  //判断是否含有开方表达式

{

    string temp;

    string firstStr = showRes.Text.Substring(0, showRes.Text.Length - 1);

    string lastStr = showRes.Text.Substring(showRes.Text.Length - 1);

    temp = (Math.Sqrt(Convert.ToDouble(lastStr))).ToString();

    //含有开发表达式

    radication = firstStr +""+ temp;

    showRes.Text = firstStr + ("" + lastStr).ToString();

}

else

{

    string temp;

    string firstStr = radication.Substring(0, radication.Length - 1);

    string ffirstStr = showRes.Text.Substring(0, showRes.Text.Length - 1);

    string lastStr = showRes.Text.Substring(showRes.Text.Length - 1);

    temp = (Math.Sqrt(Convert.ToDouble(lastStr))).ToString();

    radication = radication+  showRes.Text.Substring(showRes.Text.Length - 2,1) +temp;

    showRes.Text = ffirstStr + ("" + lastStr).ToString();

}

3.2添加数字和运算符

判断是数字还是字符,主要代码如下:

public void AppendNumber(string num)

{

    string vaildStr = ".,0,1,2,3,4,5,6,7,8,9";

    if(vaildStr.IndexOf(num)>= 0)

    {

        //说明是数字

        showRes.Text += num;

        GlobalExpression += num;

        //radication += num;

    }

    else

    {

        //说明是符号

        if (GlobalExpression != "")

        {

            string A_ZStr = "A,B,C,D,E,F";

            if (A_ZStr.IndexOf(num) >= 0)

            {

                //说明是数字

                showRes.Text += num;

                GlobalExpression += num;

                //radication += num;

            }

            //第一次算法

String lastStr=GlobalExpression.Substring(GlobalExpression.Length-1,1);

            if (vaildStr.IndexOf(lastStr) >= 0)

            {

                showRes.Text += num;

                GlobalExpression = Operation(num);

            }

        }

        //GlobalExpression = "需要先填写数字";

    }

    //showRes.Text = GlobalExpression;

    //Expression.Text = GlobalExpression;

}

图 3-1

3.3清零运算功能代码

使用清零功能键,所有用于显示的值和运算的值都将会被清空。

主要代码如下:

        private void Clear_Click(object sender, EventArgs e)

        {

           

            GlobalExpression = "";

            Expression.Text = "";

            showRes.Text = "";

            radication = "";

        }

3.4求倒数功能

输入一个数字,可以快速求出一个数字的倒数。

主要功能代码如下:

private void Rec_Click(object sender, EventArgs e)

{

    string temp;

    string firstStr = showRes.Text.Substring(0, showRes.Text.Length - 1);

    string lastStr = showRes.Text.Substring(showRes.Text.Length - 1);

    showRes.Text = firstStr+(1 + "/"+ lastStr).ToString();

           

}

//需改善的地方,最初设计的时候只考虑到了个位数求倒数,如需多位数求倒数,只需添加一个判断语句。

图 3-2

3.5求值功能代码

主界面右上方button按钮主要的事件功能

其主要代码如下:

private void Expression_Click(object sender, EventArgs e)

{

    try

    {

        double result = 0;

    char[] post = new char[100];

    if (radication != "")

        {

        string temp;

        //string message = $"根号:{radication}";

        //MessageBox.Show("根号表达式"+ message);

        AnalyExpression.postfix(radication + '#', post);

        temp = AnalyExpression.postfixValue(post).ToString();

        showRes.Text += "=";

        //AnalyExpression.AnalyExpressions(radication, out result);

        GlobalExpression = result.ToString();

            Expression.Text = temp;

        //Expression.Text = radication.ToString();

        }

        else

        {

        string temp;

        AnalyExpression.postfix(showRes.Text + '#', post);

        temp = AnalyExpression.postfixValue(post).ToString();

        showRes.Text += "=";

            GlobalExpression = result.ToString();

            Expression.Text = temp;

        }

    }

    catch (Exception)

    {

        return;

    }

}

图 3-3

3.6多项式表达式算法逻辑

多项式表达式算法逻辑是整个软件的核心代码,所有计算都是依赖此代码进行计算的。

using System;

using System.Collections;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

namespace 计算器测试

{

    internal class AnalyExpression

    {

        //栈外优先数

        public static int icp(char ch)

        {

            switch (ch)

            {

                case '#':

                    return 0;

                case '(':

                    return 10;

                case '+':

                case '-':

                    return 2;

                case '*':

                case '/':

                case '%':

                    return 4;

                case '':

                case 't':

                case 's':

                case 'c':

                case 'L':

                case '^':

                    return 8;

                case ')':

                    return 1;

            }

            return -1;

        }

        //栈内优先数

        public static int isp(char ch)

        {

            switch (ch)

            {

                case '#':

                    return 0;

                case '(':

                    return 1;

                case '+':

                case '-':

                    return 3;

                case '*':

                case '/':

                case '%':

                    return 5;

                case '':

                case 't':

                case 's':

                case 'c':

                case 'L':

                case '^':

                    return 9;

                case ')':

                    return 10;

            }

            return -1;

        }

        //判断操作符

        public static bool isOperator(char op)

        {

            switch (op)

            {

                case '+':

                case '-':

                case '*':

                case '/':

                case '%':

                case '(':

                case ')':

                case '':

                case 't':

                case 's':

                case 'c':

                case 'L':

                case '^':

                    return true;

                default:

                    return false;

            }

        }

        //中缀转后缀

        public static void postfix(string e, char[] post)

        {

            int i = 0;

            int j = 0;

            Stack<char> st = new Stack<char>();

            st.Push('#');                                           //将‘#’结束标识符塞入栈底   

            while (e[i] != '#')

            {

                if ((e[i] >= '0' && e[i] <= '9') || e[i] == '.')    //遇到数字和小数点直接写入后缀表达式

                {

                    post[j++] = e[i];

                }

                else if (isOperator(e[i]))

                {

                    post[j++] = ' ';                                // 用空格分开操作数

                    while (isp(st.Peek()) > icp(e[i]))

                    {

                        post[j++] = st.Pop();

                    }

                    if (isp(st.Peek()) == icp(e[i]))

                    {

                        st.Pop();

                    }

                    else

                    {

                        st.Push(e[i]);

                    }

                }

                i++;

            }

            while (!st.Count().Equals(0))                                       // 将所有的操作符加入后缀表达式 

            {

                post[j++] = st.Pop();

            }

        }

        //获取数字

        public static double readNumber(char[] str, ref int i)

        {

Double x = 0.0;                                                     //用于返回数字

int k = 0;                                                          //有小数时,用于确定除以10的个数

            while (str[i] >= '0' && str[i] <= '9')

            {

                x = x * 10 + (str[i] - '0');

                i++;

            }

            if (str[i] == '.')

            {

                i++;

                while (str[i] >= '0' && str[i] <= '9')

                {

                    x = x * 10 + (str[i] - '0');

                    k++;

                    i++;

                }

            }

            while (k != 0)

            {

                x /= 10;

                k--;

            }

            return x;

        }

        //计算

        public static double postfixValue(char[] post)

        {

            Stack<double> num = new Stack<double>();

            int i = 0;

double x1, x2;                                                        //两个操作数

            while (post[i] != '#')

            {

                if (post[i] >= '0' && post[i] <= '9')

                    num.Push(readNumber(post, ref i));

                else if (post[i] == ' ')

                    i++;

                else if (post[i] == '+')

                {

                    x2 = num.Pop();

                    x1 = num.Pop();

                    num.Push(x1 + x2);

                    i++;

                }

                else if (post[i] == '-')

                {

                    x2 = num.Pop();

                    x1 = num.Pop();

                    num.Push(x1 - x2);

                    i++;

                }

                else if (post[i] == '*')

                {

                    x2 = num.Pop();

                    x1 = num.Pop();

                    num.Push(x1 * x2);

                    i++;

                }

                else if (post[i] == '/')

                {

                    x2 = num.Pop();

                    x1 = num.Pop();

                    try

                    {

                        if(x2==0)

 throw new System.DivideByZeroException();

                        num.Push(x1 / x2);

                    }

                    catch (DivideByZeroException)

                    {

MessageBox.Show("被除数不能为0", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);

                        return 0;

                    }

                    i++;

                }

                else if (post[i] == '%')

                {

                    x2 = num.Pop();

                    x1 = num.Pop();

                    try

                    {

                        if (x2 == 0) throw new System.DivideByZeroException();

                        num.Push(x1 % x2);

                    }

                    catch (DivideByZeroException e)

                    {

                        MessageBox.Show("被除数不能为0", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);

                    }

                    i++;

                }

                else if (post[i] == '^')

                {

                    x2 = num.Pop();

                    x1 = num.Pop();

                    num.Push(Math.Pow(x1, x2));

                    i++;

                }

                else if (post[i] == 'L')

                {

                    x1 = num.Pop();

                    num.Push(Math.Log(x1));

                    i++;

                }

                else if (post[i] == 'c')

                {

                    x1 = num.Pop();

                    num.Push(Math.Cos(x1));

                    i++;

                }

                else if (post[i] == 't')

                {

                    x1 = num.Pop();

                    num.Push(Math.Tan(x1));

                    i++;

                }

                else if (post[i] == 's')

                {

                    x1 = num.Pop();

                    num.Push(Math.Sin(x1));

                    i++;

                }

                else if (post[i] == '')

                {

                    x1 = num.Pop();

                    try

                    {

                        if (x1 < 0) throw new System.DivideByZeroException();

                        num.Push(Math.Pow(x1, 0.5));

                    }

                    catch (DivideByZeroException)

                    {

                        MessageBox.Show("请输入正数", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);

                        return 0;

                    }

                    i++;

                }

                else

                {

                    MessageBox.Show("请仔细检查表达式,如:括号对应等", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);

                    return 0;

                }

            }

            try

            {

                return num.Peek();

            }

            catch (Exception)

            {

                MessageBox.Show("请仔细检查表达式,如:括号对应等", "错误", MessageBoxButtons.OK, MessageBoxIcon.Warning);

                return 0;

            }

        }

    }

}

4.进制转换

进制转换功能实现了二进制、八进制、十进制、十六进制之间的相互转换,在软件的文本框中输入任一指定进制,其余三种进制会同时算出来。

其主要的核心代码如下:

         string ConvertTo(string number, int sourceBase, int targetBase)

        {

            try {

            long decimalValue = Convert.ToInt64(number, sourceBase);

            string result = Convert.ToString(decimalValue, targetBase);

            return result;

            }catch {

                textBox1.Text = "";

                textBox2.Text = "";

                textBox3.Text = "";

                textBox4.Text = "";

                return "";

            }

        }

图 4-1

5.项目总结

通过简易计算器这一程序的开发。我更进一步的了解了面向对象程序开发的过程也亲身体验了开发一个简单系统的细节点滴。通过这个例子,我对类的使用和认识有了更深入的体会。

首先这是一个计算器程序,主要的是对十进制数据的简单的四则运算操作。包含了最基本的对一些按钮和文本框的操作。了解到了这类程序的开发过程和基本入手点。可以说这是我第一次用完全的面向对象语言开发一个简单的小程序。这也让我深刻体会到了类在面向对象开发过程中的重要性和便捷之处。只有亲身体验才有真正的收获。

对于这个项目我有一些满意的地方也有感到不足的地方。其中满意的地方是这个程序实现了预计的功能知即对数据的四则运算操作、一些三倒数、开方且计算结果无误。而且我也在这个项目中用到了学到的C语言数据结构的算法逻辑的一些思想。从这点我体会到了不同程序的共通性和不同语言间的共通性。

通过这个程序我解决了窗体的应用问题。把原来只能在DOS提示符下运行的程序是现在了WINDOWS窗体中。当然知这个项目中还是存在很多不足之处的。比如这个计算器程序的计算中没有能够实现多位数的倒数和开方运算。有些地方写的代码效率不高。而且由于对程序设计不是很精通。我觉得这个项目中代码的编写也不足够规范,文档说明也不足、有些东西知道用什么思想,但就是表达不不来。

培养一个良好的编程风格是十分重要的。整齐的代码格式会大大提高程序可读性。完整的技术文档对日后维护和升级十分重要。所以在编程的细节方面我还应该多加注意。

参考文献

[1]邓英伟,袁晓红,张小琳,谭艳,彭伟. 智能系统研究[J]. 海峡科技与产业,2017(10):67-68+74.

[2]魏国利,张成刚. 基于ASP.NET框架管理系统设计与实现[J]. 信息与电脑(理论版),2017(23):121-122+125.

[3]杨晓吟. 多样化题型在线考试系统的实现[J]. 数字通信世界,2017(11):214+217.

[4]蒋玉芳. 基于ASP.NET系统的设计与实现[J]. 科技广场,2017(08):35-38.

[5]颜石,杨琨,刘杰. 预报业务在线学习考试系统设计[J]. 科技风,2018(06):6+8.

[6]郭力子,visual ci#程序设计应用教程[M机械工程出版社

[7]李兰友,杨晓光。Visual C:#程序设计[M.北京:清华大学出版社,北京交通大学出版社,2004.

附一:本人完成界面设计、窗口切换、表达式显示等功能模块设计

计算器主界面包含22个button按钮框,用于和用户进行交互设计。界面设计是计算器开发中的重要一环,它决定了用户与应用程序的交互方式和外观。一个直观、易于使用的界面可以提高用户体验并使操作更加方便。

窗口切换是指在计算器应用程序中切换不同的功能模块或视图,例如从标准计算器切换到进制转换计算器。窗口切换功能使得计算器能够提供更多功能和灵活性,满足不同用户的需求。

表达式显示功能模块负责将用户输入的数学表达式显示在计算器界面上,使用户能够清楚地看到他们输入的表达式。这对于用户检查输入的正确性和可视化计算过程非常重要。

核心代码上文已详细列出,故不多做叙述。

项目报告下载

目录

课 程 设 计

1.需求分析

2.界面设计

3.功能实现

4.进制转换

5.项目总结

参考文献

附一:本人完成界面设计、窗口切换、表达式显示等功能模块设计

项目报告下载


C#课程设计icon-default.png?t=N7T8https://download.csdn.net/download/L152690/89248648

课程程设计,简易议计算器!实验已经成功目录 1、引言……………………………………………………………………………………………… 2 1.1 计算器意义………………………………………………………………………………2 1.2 电子计算器的特殊键 …………………………………………………………………2 2 、单片机概述.……………………………………………………………………………………2 3 、芯片简介 ………………………………………………………………………………………3 3.1 MSC-51芯片简介…………………………………………………………………………3 4 、相关知识 ………………………………………………………………………………………6 4.1数码管显示…………………………………………………………………………………6 4.2矩阵按键 …………………………………………………………………………………6 5 、计算器硬件电路设 …………………………………………………………………………7 6 、计算器程序设计………………………………………………………………………………7 6.1存储单元分配………………………………………………………………………………7 6.2 主程序设计…………………………………………………………………………………7 6.3 数码管显示数据转换子程序CONV ……………………………………………………7 6.4 数码管动态显示子程序………………………………………………………………… 7 7 、系统硬件设计……………………………………………………………………………………7 7.1 系统总框图如下……………………………………………………………………………8 7.2 计算器硬件线路图…………………………………………………………………………8 7.3 系统工作原理 ………………………………………………………………………………9 8、汇编语言程序源代码……………………………………………………………………………10 9 、结语………………………………………………………………………………………………17 10、设计实物图……………………………………………………………………………18 摘要 近年来随着科技的飞速发展,单片机的应用正在不断深入,同时带动传统控制检测技术日益更新。在实时检测和自动控制的单片机应用系统中,单片机往往作为一个核心部件来使用,仅单片机方面知识是不够的,还应根据具体硬件结构软硬件结合,加以完善。 本任务是个简易的两位数的四则运算,程序都是根据教材内和网络中的程序参考编写而成,在功能上还并不完善,限制也较多。本任务重在设计构思团队合作,使得我们用专业知识、专业技能分析和解决问题全面系统的锻炼。 关键词: 单片机 计算器 范围 加减乘除 1 引言 1.1 计算器的历史 说起计算器,值得我们骄傲的是,最早的计算工具诞生在中国。中国古代最早采用的一种计算工具叫筹策,又被叫做算筹。这种算筹多用竹子制成,也有用木头,兽骨充当材料的。约二百七十枚一束,放在布袋里可随身携带。直到今天仍在使用的珠算盘,是中国古代计算工具领域中的另一项发明,明代时的珠算盘已经现代的珠算盘几乎相同。17世纪初,西方国家的计算工具有了较大的发展,英国数学家纳皮尔发明的"纳皮尔算筹",英国牧师奥却德发明了圆柱型对数计算尺,这种计算尺不仅能做加减乘除、乘方、开方运算,甚至可以计算三角函数,指数函数和对数函数,这些计算工具不仅带动了计算器的发展,也为现代计算器发展奠定了良好的基础,成为现代社会应用广泛的计算工具。 1.2 电子计算器的特殊键 在使用电子计算器进行四则运算的时候,一般要用到数字键,四则运算键和清除数据键。除了这些按键,还有一些特殊键,可以使计算更加简便迅速。 2 单片机概述 单片机微型计算机是微型计算机的一个重要分支,也是颇具生命力的机种。单片机微型计算机简称单片机,特别适用于控制领域,故又称为微控制器。 通常,单片机由单块集成电路芯片构成,内部包含有计算机的基本功能部件:中央处理器、存储器和I/O接口电路等。因此,单片机只需要和适当的软件及外部设备相结合,便可成为一个单片机控制系统。 单片机经过1、2、3、3代的发展,目前单片机正朝着高性能和多品种方向发展,它们的CPU功能在增强,内部资源在增多,引角的多功能化,以及低电压底功耗。 3 芯片简介 3.1 MSC-51芯片简介 MCS-51单片机内部结构 AT89C51是MCS-51系列单片机兼容的典型产品,我们以这一代表性的机型进行系统的讲解。 AT89C51单片机包含中央处理器、程序存储器(ROM)、数据存储器(RAM)、定时/计数器、并行接口、串行接口和中断系统等几大单元及数据总线、地址总线和控制总线等三大总线,现在我们分别加以说明: •中央处理器: 中央处理器(CPU)是整个单片机的核心部件,是8位数据宽度的处理器,能处理8位二进制数据或代码,CPU负责控制、指挥和调度整个单元系统协调的工作,完成运算和控制输入输出功能等操作。 •数据存储器(RAM) AT89C51内部有128个8位用户数据存储单元和128个专用寄存器单元,它们是统一编址的,专用寄存器只能用于存放控制指令数据,用户只能访问,而不能用于存放用户数据,所以,用户能使用的RAM只有128个,可存放读写的数据,运算的中间结果或用户定义的字型表。 图1 •程序存储器(ROM): AT89C51共有4096个8位掩膜ROM,用于存放用户程序,原始数据或表格。 •定时/计数器(ROM): AT89C51有两个16位的可编程定时/计数器,以实现定时或计数产生中断用于控制程序转向。 •并行输入输出(I/O)口: AT89C51共有4组8位I/O口(P0、 P1、P2或P3),用于对外部数据的传输。 •全双工串行口: AT89C51内置一个全双工串行通信口,用于其它设备间的串行数据传送,该串行口既可以用作异步通信收发器,也可以当同步移位器使用。 •中断系统: AT89C51具备较完善的中断功能,有两个外中断、两个定时/计数器中断和一个串行中断,可满足不同的控制要求,并具有2级的优先级别选择。 •时钟电路: AT89C51内置最高频率达12MHz的时钟电路,用于产生整个单片机运行的脉冲时序,但AT89C51单片机需外置振荡电容。 单片机的结构有两种类型,一种是程序存储器和数据存储器分开的形式,即哈佛(Harvard)结构,另一种是采用通用计算机广泛使用的程序存储器数据存储器合二为一的结构,即普林斯顿(Princeton)结构。INTEL的MCS-51系列单片机采用的是哈佛结构的形式,而后续产品16位的MCS-96系列单片机则采用普林斯顿结构。 下图是MCS-51系列单片机的内部结构示意图2。 图2 MCS-51的引脚说明: MCS-51系列单片机中的8031、AT89C51及8751均采用40Pin封装的双列直接DIP结构,右图是它们的引脚配置,40个引脚中,正电源和地线两根,外置石英振荡器的时钟线两根,4组8位共32个I/O口,中断口线P3口线复用。现在我们对这些引脚的功能加以说明: MCS-51的引脚说明: MCS-51系列单片机中的8031、AT89C51及8751均采用40Pin封装的双列直接DIP结构,右图是它们的引脚配置,40个引脚中,正电源和地线两根,外置石英振荡器的时钟线两根,4组8位共32个I/O口,中断口线P3口线复用。现在我们对这些引脚的功能加以说明:如图3 图3 Pin9:RESET/Vpd复位信号复用脚,当AT89C51通电,时钟电路开始工作,在RESET引脚上出现24个时钟周期以上的高电平,系统即初始复位。初始化后,程序计数器PC指向0000H,P0-P3输出口全部为高电平,堆栈指针写入07H,其它专用寄存器被清“0”。RESET由高电平下降为低电平后,系统即从0000H地址开始执行程序。然而,初始复位不改变RAM(包括工作寄存器R0-R7)的状态,AT89C51的初始态。 AT89C51的复位方式可以是自动复位,也可以是手动复位,见下图4。此外,RESET/Vpd还是一复用脚,Vcc掉电其间,此脚可接上备用电源,以保证单片机内部RAM的数据不丢失。 图4 •Pin30:ALE/ 当访问外部程序器时,ALE(地址锁存)的输出用于锁存地址的低位字节。而访问内部程序存储器时,ALE端将有一个1/6时钟频率的正脉冲信号,这个信号可以用于识别单片机是否工作,也可以当作一个时钟向外输出。更有一个特点,当访问外部程序存储器,ALE会跳过一个脉冲。 如果单片机是EPROM,在编程其间, 将用于输入编程脉冲。 •Pin29: 当访问外部程序存储器时,此脚输出负脉冲选通信号,PC的16位地址数据将出现在P0和P2口上,外部程序存储器则把指令数据放到P0口上,由CPU读入并执行。 •Pin31:EA/Vpp程序存储器的内外部选通线,8051和8751单片机,内置有4kB的程序存储器,当EA为高电平并且程序地址小于4kB时,读取内部程序存储器指令数据,而超过4kB地址则读取外部指令数据。如EA为低电平,则不管地址大小,一律读取外部程序存储器指令。显然,对内部无程序存储器的8031,EA端必须接地。 在编程时,EA/Vpp脚还需加上21V的编程电压。 4 相关知识 4.1数码管显示 在本任务中用4位数码管显示当前数值的千,百,十,个,由于数码管个数多,如采用静态显示方式,则占用单片机的I/O口线太多,如果用定时器/计数器的串行移位寄存器工作方式及外接串入并出移位寄存器74LS164的方式,则电路复杂。所以,在数码管个数较多时,常采用动态显示方式。 如图1-1所示为单片机应用系统中的一种数码管动态显示电路图,4位数码管的相同段并联在一起,由一个8位I/O(P1口)输出字形码控制显示某一字形,每个数码管的公共端由另外一个I/O口(P0口)输出的字位码控制,即数码管显示的字形是由单片机I/O口输出的字形码确定,而哪个数码管点亮是由单片机I/O口输出的字位码确定的。4个数码管分时轮流循环点亮,在同一时刻只有1个数码管点亮,但由于数码管具有余辉特性及人眼具有视觉暂留特性,所以适当地选取循环扫描频率,看上去所有数码管是同时点亮的,察觉不出闪烁现象。动态显示方式所接数码管不能太多,否则会因每个数码管所分配的实际导通时间太少,使得数码管的亮度不足。在本任务中,为了简便,字形码和字位码都没由加驱动电路,在实际应用中应加驱动电路。数码管有共阴极和共阳极两种,对于共阳数码管,字形驱动输出0有效,字位驱动输出1有效;而对于共阴数码管则相反,即:字形驱动输出1有效,字位驱动输出0有效。 4.2矩阵按键 键盘是单片机系统中最常用的人机对话输入设备,用户通过键盘向单片机输入数据或指令。键盘控制程序需完成的任务有:监测是否有键按下,有键按下时,在无硬件去抖的动电路时,应用软件延时方法消除按键抖动影响;当有多个键同时按下时,只处理一个按键,不管一次按键持续多长时间,仅执行一次按键功能程序。 矩阵按键扫描程序是一种节省IO口的方法,按键数目越多节省IO口就越可观,思路:先判断某一列(行)是否有按键按下,再判断该行(列)是那一只键按下。但是,在程序的写法上,采用了最简单的方法,使得程序效率最高。本程序中,如果检测到某键按下了,就不再检测其它的按键,这完全能满足绝大多数需要,又能节省大量的CPU时间。 本键盘扫描程序的优点在于:不用专门的按键延时程序,提高了CPU效率,也不用中断来扫描键盘,节省了硬件资源。另外,本键盘扫描程序,每次扫描占用CPU时最短,不论有键按下或者无键按下都可以在很短的时间完成一次扫描。 本键盘扫描子程序名叫key,每次要扫描时用lcall key调用即可。 5 计算器硬件电路设计 AT89C51单片机的P2口作键盘口,其中P2.4-P2.7为键盘扫描输出线,P2.0-P2.3为键盘扫描输入线。键盘由4*4共16个按键组成,10个数字键(由0-9组成)5个运算符号(加减乘除等于)组成,1个清除键(作用相当于整体复位)。4个数码管用于显示当前数值的千,百,十,个,采用动态显示方式,P1口接4个数码管的七段,P0口分别接4个数码管的公共端,P1口输出数码管的字形码,P0口输出数码管的字位码。 6 计算器程序设计 6.1存储单元分配 30H单元:数值个位显示单元;31H单元:数值十位显示单元;32H单元:数值百位显示单元;33H单元:数值千位显示单元;23H单元:第一操作数存储单元;24H单元:第二操作数存储单元;25H单元:键值暂存单元;27H单元:清除键状态;34H-37H单元:结果数据转换暂存单元;38H-39H单元:结果高低8位暂存单元;R5单元:操作数计数单元;R4单元:操作数数值位数计数单元;R3单元:运算符号存储单元。 6.2 主程序设计 主程序进行程序中用到的一些存储单元的初始化,数值显示和4*4键盘扫描。首先,进行存储单元初始化,给数码管显示单元30H-33H赋予“0000”字形数据,将数值计数单元,存储单元,23H-25H,34H-37H,38H,39H,3AH,3BH,3CH,赋予初值零。之后,调用键盘扫描子程序,和数码管显示数据转换程序,数码管动态显示子程序。主程序不断进行键盘扫描,数码管显示数据转换子程序和动态显示子程序。 6.3 数码管显示数据转换子程序CONV 由于数值单元存放的是二进制数,而用户熟悉的是十进制数,所以应将数值单元中的二进制转换为十进制数,即BCD码。要通过数码管显示出当前数值,还必须将BCD码进一步转换为七段码,转换的最终结果数据存放于显示缓冲区30H-33H单元中,其中30H单元存放数值的个位七段码,31H单元存放数值的十位七段码,32H单元存放数值的百位七段码,33H单元存放数值的千位七段码。 6.4 数码管动态显示子程序 本任务由P1口输出字形码,P0口输出字位码。先将存放于30H单元的数值个位七段码由P1口输出,同时P0口输出使数值个位显示数码管点亮的字位码。由于采用的是共阳数码管,所以只有该位数码管对应的P0.0为1,其他位P0.1-P0.3位0,点亮延时10MS。然后P1口输出数值十位七段码,P0.1位1,数值十位数码管点亮,延时10MS。接着P1口输出数值百位七段码,P0.2为1,数值百位数码管点亮,延时10MS。最后P1口输出数值千位七段码,P0.3为1,数值千位数码管点亮,延时10MS。 7 系统硬件设计 选用设备AT89C51单片机一片,选用设备:AT89C51单片机一片,17个键盘,4位共阳极的七段数码管一个,连线若干,电容3个,电阻5个,晶振1个。 7.1 系统总框图如下:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值