2016-01-25 11:37:00 baidu_33836580 阅读数 853
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3998 人正在学习 去看看 朱有鹏

一个加数在片内RAM40H、41H、42H单元中,另一个加数在内RAM43H、44H、45H,其和存放在50H、51H、52H单元中,进位位存00H。

求编译程序,小弟谢过

悬赏分:0 - 解决时间:2009-11-11 21:14

;------------------------------------------

最佳答案:题目太简单,只有三个字节参加运算,可不用循环结构。

    MOV A, 40H

    ADD A, 43H

    MOV 50H, A

;

    MOV A, 41H

    ADDC A, 44H

    MOV 51H, A

;

    MOV A, 42H

    ADDC A, 45H

    MOV 52H, A

;

    MOV   20H.0, C

;完

;------------------------------------------

回答者:   做而论道 - 十级   2009-11-10 23:23

提问者对于答案的评价:谢谢   是我当初想的太复杂了

原文网址:http://zhidao.baidu.com/question/125067489.html

;=========================================================

多个单字节数求和。已知有10个单字节数,依次存放在内部RAM 40H 单元开始的存储区中,要求把求和的结果存入寄存器R2,R3中(高位存R2,低位存R3)

悬赏分:0 - 解决时间:2009-11-14 11:50

;------------------------------------------

最佳答案:本题参加运算的数据较多,且地址是连续的,应该使用循环结构,如下即可。

     MOV R2, #0

     MOV R3, #0

     MOV R0, #40H

     MOV R1, #10

LOOP:

     MOV A, R3

    ADD A, @R0

     MOV R3, A

     MOV A, R2

     ADDC A, #0

     MOV R2, A

     INC R0

     DJNZ R1, LOOP

     RET

;完

;------------------------------------------

回答者:   做而论道 - 十级   2009-11-14 09:46

原文网址:http://zhidao.baidu.com/question/125462352.html

;=========================================================

试编写程序,将内部RAM的20H,21H和22H 3个连续单元的内容依次存入2FH、2EH和2DH中。

悬赏分:5 - 解决时间:2009-11-24 12:30

;------------------------------------------

最佳答案:

    ORG 0000H

    MOV 2FH, 20H

    MOV 2EH, 21H

    MOV 2DH, 22H

    SJMP $

    END

呵呵,简单的无与伦比。

;------------------------------------------

回答者:   做而论道 - 九级   2009-11-8 22:51

原文网址:http://zhidao.baidu.com/question/124710350.html

;=========================================================

设机器字长为8位,请用二进制补码的方法计算下题,运算结果分别用十六进制和十进制表示。

这里机器字长为8位是什么意思,有什么用?麻烦写明详细过程,谢谢!

45+55

提问者: 0o錒ke - 二级

悬赏分:20 - 解决时间:2009-11-10 19:28

;------------------------------------------

最佳答案:先把数字都变换成8位的二进制补码:

45: 00101101

55: 00110111

然后相加:

    00101101

+ 00110111

---------------------

   01100100 -> 十进制的 +100

结果就是:

二进制:01100100

16进制:64H

十进制:100

;------------------------------------------

回答者:   做而论道 - 九级   2009-11-10 18:30

提问者对于答案的评价:谢谢,你很厉害么!!

原文网址:http://zhidao.baidu.com/question/125007034.html

;=========================================================

2017-04-30 07:09:29 tian_maer 阅读数 493
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3998 人正在学习 去看看 朱有鹏
1、通过上一节的实例,我们了解到即使相同的数据,如果采用不同的数据类型来表示,最终的运行结果也可能有很大的区别。
在用C51进行程序设计时,对于变量的数据类型选择有如下经验:
1)尽量预算一下变量的数据变化范围,根据变量长度来选择变量类型。尽量选择长度短的数据类型来定义变量。这样不但可以提高代码效率,还能节省CPU时间,减少内存的消耗。
2)尽量使用无符号类型的变量,如果用到负数,则尽可能把符号和数据分开定义,可以用一个位变量来表示数值的正负。
3)如果程序中不需要浮点数,则尽量避免使用浮点数。要知道,浮点数要占用32位数据空间,而51单片机的数据处理能力是8位,不难看出,51单片机处理浮点数会浪费大量时间。
 
2、本例使用单片机的P0口和P1口分别显示两个无符号字符型数据的加法和减法的运算结果
3、在kei c51中新建工程文件ex6,输入如下的程序代码,编译并生成ex6.hex文件
//实例6:使用P0口和P1口分别显示加法和减法的运算结果
#include <reg51.h>   //包含单片机寄存器定义的头文件
void main(void)
{
  unsigned char num1,num2,add,sub;      //定义无符号型字符变量,注意这里的变量都有比较明确的含义
                                      //num1,num2表示数1和数2;add表示两数相加后的和,sub表示两数
           //相减后的差。这样定义变量可以很清晰地表示出变量的意义
 num1 = 100;    //将数1赋值
 num2 = 50;     //将数2赋值
 add = num1 + num2;    //数1+数2所得的和保存到变量add中
 sub = num1 - num2;   //数1-数2所得的差保存到变量sub中
 P0 = add;     //P0显示两数相加后的和
 P1 = sub;    //P1显示两数相减后的差
 while(1)  //无限循环,防止程序跑飞。在单片机的C语言程序中,主函数中的这个
 {     //无限循环函数是必须的,建议尽量不要省略
      //之前有些程序中没有这个无限循环函数,是为了演示方便,实际使用中
 }     //必须要有这个无限循环函数
}
 
4、在proteus中绘制仿真电路图ex6.dsn,电路图如下所示。将上面编译好的ex6.hex文件载入AT89C51。

 
5、启动仿真,程序运行结果如下图所示:我们可以通过手工计算两数相加和相减后的结果与运行结果进行对照检查。


2014-11-13 23:08:07 u014183377 阅读数 665
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3998 人正在学习 去看看 朱有鹏

     在单片机编程中,我们经常会用到一些无符号数与有符号数的混合运算,另外我们所用的单片机很有可能是16位或者8位的,这样,编程时所用的一些变量的取值范围会对我们的 运算有所限制.比如说8位的单片机无符号数最大值为255,有符号最大数为127;16位单片机无符号数最大值为65535,有符号数最大值为32767.对于32的单片机来说,因为我们一般所处理的值很少能超过有符号数的最大取值,所以比较少遇到下面出现的问题.

        在一些运算中,我们希望有些数能表示正负,这就得用有符号数,而有些数的取值会超过有符号数的最大值,这时我们就得用无符数来表示.下面是我编程时遇到的两个问题(用的是MC9S12XS128处理器,16位的单片机).

       变量的声明如下:

        int iError;

        unsigned  int uiExpectSpeed;

        unsigned int uiCurrentSpeed;

       语句如下:

       iError  = (uiExpectSpeed - uiCurrentSpeed)/3;       //(1) 第一个语句

       在调试的过程中发现这个iError的值有时候会特别大,最后才发现是上面的这句语句出错了!然后修改成下面两句结果就对了:

       iError  = uiExpectSpeed - uiCurrentSpeed;            //(2)第二个语句

       iError  = iError/3;                                                          //(3)第三个语句

       不同类型的数据在进行混合运算时会有一个隐试的类型转换过程,有符号数与无符号数混合运算,有符号数会被转换成无符号数后再参加运算.

       在上面的第一个语句中,如果uiExpectSpeed 比uiCurrentSpeed的值大,也就是uiExpectSpeed - uiCurrentSpeed结果为一正值,那不会出现啥问题,但当uiExpectSpeed 比uiCurrentSpeed的值小时就出现问题了,此时uiExpectSpeed - uiCurrentSpeed的临时结果存放在16位的寄存器中,且最高位1,对于有符号数来说会把这一个位解释为符号位,1表示负数,而对于无符号来说这个位就表示数值,接着这个临时的结果除以3后,所得到的结果的最高位变为了0此时该结果会转换为一个有符合数(不管是有符号数,还是无符号数,最高位为0时,所表示的数值就是一样的),赋给iError.本应该得到一个负数的,但最终却得到了一个比较大的正数!在第一个语句中,如果没有除以3,而是两个数作差后直接赋给iError则是不会出错的,虽然uiExpectSpeed - uiCurrentSpeed运算的结果是一个很大的正数(寄存器的最高位为1),但在这个临时结果赋给iError这个变量时,会先把这个值转换为一个有符号数赋给iError.其实,在把uiExpectSpeed - uiCurrentSpeed运算的结果赋给iError时是把所有的位原封不动的复制到iErrorr所表示的内存单元中的,只是我们是以有符号数来解释这个内存单元中的内容,所以这个很大的正数就变成了一个负数!(数据在处理器内是以补码表示的,对于数据是正还是负只是人们的解释不同而已).所以我就用后面的两句替换了第一句,这样不管uiExpectSpeed - uiCurrentSpeed的差值是正还是负都能得到正确的结果了.

   

      下面是我在做超声波测距时遇到的又一个很隐蔽的问题:

       unsigned int start; //表示计时开始时计数器的值
       unsigned int end; //表示计时结束时计数器的值
       unsigned int error;      

      unsigned int distance; //表示距离
      unsigned int time; //表示从计时开始到结束所用的时间
      unsigned int remainder;//余数

      start  = TCNT;// 计时开始, TCNT为16位的计时器寄存器

     ..............一段时间后(这段时间小于计时器TCNT从0计数到最大值65535所表示的时间)...........

     end = TCNT; //计时结束

     error = end - start; //注意,end有可能比start小,但由于都是无符号数,所以最后得到的差值就是这段时间内计数器TCNT的增量.

      time = error/625; //单位为ms  TCNT每1ms内数值增加625(这个数与TCNT所用的时钟有关)
      distance = 17*time; //单位为cm, 距离为速度乘以时间再除以2就是声波所传波的距离

      这块由于是分步计算的,所以会有比较大的误差(主要是由于error/625后的余数被丢弃了)     于是我改成如下语句:

 

     start  = TCNT;// 计时开始, TCNT为16位的计时器寄存器

     ..............一段时间后(这段时间小于计时器TCNT从0计数到最大值65535所表示的时间)...........

     end = TCNT; //计时结束

     error = end - start; //注意,end有可能比start小,但由于都是无符号数,所以最后得到的差值就是这段时间内计数器TCNT的增量.

     distance = (17*error)/625; //单位为cm, 将上面的最后两句结合成一句,先乘后除就会减小误差

     但改后上面distance = (17*error)/625; 这句就错了,因为error的值可能很大,最大可以达到65535,所以17*error结果很有可能会超过65535,但这个处理器是16位的,也就是说这个处理器的数据寄存器为16位,最大的表示数值也就65535,所以17*error大于65535后就会被截断存入寄存器中.也就是说存入寄存器中的值为(17*error)e536,当再用这个值除以625时得到的很有可能就是0或者个位数的值,不管怎样,此时得到的结果都是错误的值了!!

     结合上面两种情况,最后我改成如下:   

      start  = TCNT;// 计时开始, TCNT为16位的计时器寄存器

     ..............一段时间后(这段时间小于计时器TCNT从0计数到最大值65535所表示的时间)...........

     end = TCNT; //计时结束

     error = end - start; //注意,end有可能比start小,但由于都是无符号数,所以最后得到的差值就是这段时间内计数器TCNT的增量.

     time = error/625; //单位为ms
     remainder = error - time*625;//计算上一句中丢弃的余数,没有用remainder = errorb5,是因为除法很耗时!!
     distance = 17*time + (17*remainder + 312)/625; //单位为cm,此处的312(625/2)是考虑到四舍五入的.

 

来自:http://blog.csdn.net/dlutxie/article/details/6709510

2017-01-06 12:48:45 u012866328 阅读数 1698
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3998 人正在学习 去看看 朱有鹏

使用51单片机实现简单的四则运算(只包含+ - * / 和 =)


实验设备 : 普中科技 单片机开发试验仪

开发软件 : Keil uVision3

烧录软件 : PZ-ISP V1.48

设计思路

由于51单片机数据存储空间有限,所以不能开辟过多的数据空间,C语言处理四则运算的代码无法直接通过改写,编译烧录。故此次实验采用状态转换的方式实现计算器的简单四则运算。使用数据空间3个:a, b, c。即可实现。下图为状态转换图。
AT89C51简单四则运算状态图
在程序实现过程中,如果遇到’=’则需要显示结果到显示屏,这部分说明请看代码相应位置。对于错误输入在各自状态有相应处理过程,如不存储该错误输入等。此外,在程序实现过程中添加 状态11:用于清屏重置;状态12:ERROR状态。下面介绍接线及运行结果。

接线

Jp8连JP4 Jp9连Jp5 把1602液晶插入
接线

按键说明

按键说明

输入

输入

计算结果

计算结果

程序代码

/**************************************************************************************
*                     简易四则运算计算器                                           *
*                                                                                     *
*       仪器:普中科技 单片机开发实验仪                                                  *
*       连接方法:Jp8连JP4  Jp9连Jp5 把1602液晶插入                                   *
*                                                                                     *
***************************************************************************************/

#include <reg51.h>     //此文件中定义了51的一些特殊功能寄存器

#define uchar unsigned char
#define uint unsigned int

#define MAXLEN 16

sbit EN=P2^7;  //LCD的使能引脚
sbit RS=P2^6;  //LCD数据命令选择端
sbit RW=P2^5;  //LCD的读写选择端

sbit K1=P3^0;
sbit K2=P3^1;
sbit K3=P3^2;
sbit K4=P3^3;
sbit K8=P3^7;   // 清屏,重置变量

bit flag = 0;   // + 或 - 标识符; 0:+;1:-;

uchar KEY_CODE[]={ 0xed,0xdd,0xbd,0x7d,//3X4矩阵键盘键值表
                   0xeb,0xdb,0xbb,0x7b,
                   0xe7,0xd7,0xb7,0x77};
//定义字符键值表
uchar CHAR_TABLE[]={0x30,0x31,0x32,0x33,//这四个会在液晶显示器中显示0 1 2 3
                    0x34,0x35,0x36,0x37,//这四个会显示4 5 6 7 
                    0x38,0x39,0x2b,0x3d,//这四个会显示8 9 + =
                    0x2b,0x2d,0x2a,0x2f,//这四个会显示+ - * /
                    0x45,0x52,0x4f};    //这三个会显示E R O

uchar QUEUE[2*MAXLEN]={' ',' ',' ',' ',' ',' '};        //定义一个队列

int count = 0;  

unsigned int state=0;
long a=0,b=0,c=0;


void mscanf(uchar *var);                //从矩阵键盘中获取值
void print(uchar *outStr,uint end);     //打印字符串

void delay5MS();            //短延时函数
void delay100MS();          //较长延时函数
void writeCMD(uchar com);       //写命令子程序
void showOneChar(uchar dat);    //写数据子程序

void init();        //初始化子程序,初始化液晶显示屏

void clear();       //清除显示屏上的显示
void clearInit();   //清屏,重置变量

void splitResultNum(long result);       // 分离数值

void number();                  //state0: 数字输入
void middle_add_sub();          //state:1:
void add_sub();                 //state:2:
void middle_add_sub_times();    //state:3;
void middle_add_sub_div();      //state:4;
void add_sub_times();           //state:5;
void add_sub_div();             //state:6;
void mulMidState();             //state7: *中间态
void divMidState();             //state8: /中间态
void mulState();                //state9: *计算态
void divState();                //state10: /计算态
void showError();               //state12:错误状态


/**************** 主函数 ******************/
void main()
{
    // state0:数字输入态
    // state1:+,-中间态
    // state2:+,-计算态
    // state3:+/-,*中间态
    // state4:+/-,/中间态
    // state5:+/-,*计算态
    // state6:+/-,/计算态
    // state7:*中间态
    // state8:/中间态
    // state9:*计算态
    // state10:/计算态
    // state11:清屏重置
    // state12:错误状态
    state = 0;
    init();
    while(1){
        switch(state){
            case 0:     // state0:数字输入态 
                number();
                break;
            case 1:     // state1:+,-中间态
                middle_add_sub();
                break;
            case 2:     // state2:+,-计算态
                add_sub();
                break;
            case 3:     // state3:+,-,*中间态
                middle_add_sub_times();
                break;
            case 4:     // state4:+,-,/中间态
                middle_add_sub_div();
                break;
            case 5:     // state5:+,-,*计算态
                add_sub_times();
                break;
            case 6:     // state6:+,-,/计算态
                add_sub_div();
                break;
            case 7:     // state7:*中间态
                mulMidState();
                break;
            case 8:     // state8:/中间态
                divMidState();
                break;
            case 9:     // state9:*计算态
                mulState();
                break;
            case 10:    // state10:/计算态
                divState();
                break;              
            case 11:    // state11:清屏重置
                clearInit();
                break;
            case 12:    // state12:错误状态
                showError();
                break;
        }
        // 错误状态不输出
        if(state != 12)
        {
            clear();
            print(QUEUE,count); 
        }

    }
}

/**************** 分离数值 ******************/
void splitResultNum(long result)
{
    long tmp;

    if(result > 2000000000) // 如果大于20亿则溢出报错
    {
        state = 12;
        return ;
    }

    tmp = result>0 ? result : -result;

    count = 0;
    while(tmp>0)
    {
        QUEUE[count++] = tmp%10;
        tmp /= 10;  
    }

    if(result < 0)
    {
        QUEUE[count++] = '-';
    }
    else if(result == 0)
    {
        QUEUE[count++] = 0;
    }

    for(tmp = count-1; tmp >= count/2; --tmp)
    {
        result = QUEUE[tmp];
        QUEUE[tmp] = QUEUE[count-1-tmp];
        QUEUE[count-1-tmp] = result;
    }   
}

/**************** state0的数字输入 ******************/
void number(){
    uchar num=0xff; 
    mscanf(&num);//获取字符
    QUEUE[count++]=num;
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        a = a*10+num;
    }else if (num=='+'){    //调整状态 + 
        b = 0;  
        flag = 0;
        state = 1;
    }else if (num=='-'){    //调整状态 -
        b = 0;
        flag = 1;
        state = 1;
    }else if (num=='*'){    //调整状态 *中间态
        c = 0;
        state = 7;
    }else if (num=='/'){    //调整状态 /中间态
        c = 0;
        state = 8;
    }else if (num=='='){    //输出        
        splitResultNum(a);  //拆分
    }else if (num=='C'){
        state = 11;
    }else{
        //输入错误字符,启动报错程序
    }
}
/**************** state1:+,-中间态 ******************/
void middle_add_sub(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        b=num;
        state=2;    
    }else if (num=='C'){    // K8 清屏
        state = 11;
    }else{
        // 错误输入不存储
        count--;
    }
}

/**************** state2:+,-计算态 ******************/
void add_sub(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        b=num+b*10;
    }else if(num=='*'){  
        c=0;
        state=3;
    }else if (num=='/'){
        c=0;
        state=4;
    }else if(num=='+'){     // done
        if(flag == 1){
            a=a-b;
        }else{
            a=a+b;
        }
        b = 0;
        state = 1;
        flag= 0;
    }else if(num=='-'){     // done
        if(flag == 1){
            a=a-b;
        }else{
            a=a+b;
        }
        b = 0;
        state = 1;
        flag = 1;
    }else if(num=='='){
        state = 0;  //按=号之后回到状态0
        if(flag == 1){  // 1 : -        
            splitResultNum(a-b);
            a = a-b;    
        }else{          // 0 : +
            splitResultNum(a+b);
            a = a+b;
        }
        b = c = 0;                  
    }else if (num=='C'){
        state = 11;
    }
}
/**************** state3:+,-,*中间态 ******************/
void middle_add_sub_times(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        c=num;
        state=5;
        return; 
    }else if (num=='C'){
        state = 11;
    }else{          //其他不符合规则的情况,不存储
        count--;
    }   
}
/**************** state4:+,-,/中间态 ******************/
void middle_add_sub_div(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        c = num;
        if(c == 0){     //如果除数为0,则不存储
            count--;
        } else {
            state = 6;  //跳转到state6: +,-,/计算态   
        }   
    }else if (num=='C'){
        state = 11;
    }else{          //其他不符合规则的情况,不存储
        count--;
    }
}
/**************** state5:+,-,*计算态 ******************/
void add_sub_times(){
    uchar num=0xff;
    mscanf(&num);
    QUEUE[count++]=num;
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        c=num+c*10; 
    }else if(num=='+'){
        if(flag==1){
            a=a-b*c;
            b=0;
            c=0;
        }else{
            a=a+b*c;
            b=0;
            c=0;
        }
        flag=0;
        state=1;
    }else if(num=='-'){
        if(flag==1){
            a=a-b*c;
            b=0;
            c=0;
        }else{
            a=a+b*c;
            b=0;
            c=0;
        }
        flag=1;
        state=1;
    }else if(num=='*'){
        b=b*c;
        c=0;
        state=3;
    }else if(num=='/'){
        b=b*c;
        c=0;
        state=4;
    }else if(num=='='){
        state=0;
        if(flag == 1){
            //输出 a-b*c
            splitResultNum(a-b*c);
            a = a-b*c;
        }else{
            //计算 a+b*c
            splitResultNum(a+b*c);
            a = a+b*c;
        }
        b = c = 0;      
    }else if (num=='C'){
        state = 11;
    }
}
/**************** state6:+,-,/计算态 ******************/
void add_sub_div(){
    uchar num=0xff;
    mscanf(&num);
    if(num==0||num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9){
        c=num+c*10; 
    }else if(num=='+'){
        if(flag == 1){
            a=a-b/c;
            b=0;
            c=0;
        }else{
            a=a+b/c;
            b=0;
            c=0;
        }
        flag=0;
        state=1;
    }else if(num=='-'){
        if(flag == 1){
            a=a-b/c;
            b=0;
            c=0;
        }else{
            a=a+b/c;
            b=0;
            c=0;
        }
        flag=1;
        state=1;
    }else if(num=='*'){
        b=b/c;
        c=0;
        state=3;
    }else if(num=='/'){
        b=b/c;
        c=0;
        state=4;
    }else if(num=='='){
        state=0;
        if(flag == 1){
            //计算 a-b/c
            splitResultNum(a-b/c);
            a = a-b/c;
        }else{
            //计算 a+b/c
            splitResultNum(a+b/c);
            a = a+b/c;
        }
        b = c = 0;      
    }else if (num=='C'){
        state = 11;
    }
}

/**************** state7:*中间态 ******************/
void mulMidState()
{
    uchar num=0xff;
    mscanf(&num);   //获取字符
    QUEUE[count++]=num; 
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        c = num;
        state = 9;  //跳转到state9: *计算态
    }else if (num=='C'){
        state = 11;
    }else{          //其他不符合规则的情况,不存储
        //state = 12;
        count--;
    }   
}

/**************** state8:/中间态 ******************/
void divMidState()
{
    uchar num=0xff;
    mscanf(&num);   //获取字符
    QUEUE[count++]=num; 
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        c = num;
        if(c == 0){     //如果除数为0,不存储    
            //state = 12;
            count--;
        } else {
            state = 10; //跳转到state10: /计算态  
        }

    }else if (num=='C'){
        state = 11;
    }else{          //其他不符合规则的情况,不存储
        //state = 12;
        count--;
    }
}   


/**************** state9:*计算态 ******************/
void mulState()
{
    uchar num=0xff;
    mscanf(&num);   //获取字符
    QUEUE[count++]=num; 
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        c = c*10+num;
    }else if(num=='*'){
        a = a*c;
        c = 0;
        state = 7;  // 跳转到state7: *中间态
    }else if(num=='/'){
        a = a*c;
        c = 0;
        state = 8;  // 跳转到state8: /中间态
    }else if(num=='+'){
        a = a*c;
        c = 0;
        flag = 0;
        state = 1;  // 跳转到state1: +,-中间态
    }else if(num=='-'){
        a = a*c;
        c = 0;
        flag = 1;
        state = 1;  // 跳转到state1: +,-中间态
    }else if(num=='='){
        // 输出 a*c
        state = 0;  //按=号之后回到状态0
        splitResultNum(a*c);    //拆分
        a = a*c;
        b = c = 0;                      
    }else if (num=='C'){
        state = 11;
    }else{
        //输入错误字符,启动报错程序
    }   
}

/**************** state10:/计算态 ******************/
void divState()
{
    uchar num=0xff;
    mscanf(&num);   //获取字符
    QUEUE[count++]=num; 
    if(num==1||num==2||num==3||num==4||num==5||num==6||num==7||num==8||num==9||num==0){
        c = c*10+num;
    }else if(num=='/'){
        a = a/c;
        c = 0;
        state = 8;  // 跳转到state8: /中间态
    }else if(num=='*'){
        a = a/c;
        c = 0;
        state = 7;  // 跳转到state7: *中间态
        return ;
    }else if(num=='+'){
        a = a/c;
        c = 0;
        flag = 0;
        state = 1;  // 跳转到state1: +,-中间态
    }else if(num=='-'){
        a = a/c;
        c = 0;
        flag = 1;
        state = 1;  // 跳转到state1: +,-中间态
    }else if(num=='='){
        // 输出 a/c
        state = 0;     //按=号之后回到状态0
        splitResultNum(a/c);    //拆分
        a = a/c;
        b = c = 0;                      
    }else if (num=='C'){
        state = 11;
    }else{
        //输入错误字符,启动报错程序
    }
}
/********************* state11:清屏重置子程序 **********************/
void clearInit()
{
    a = b = c = 0;
    count = 0;
    state = 0;
    EN=0;
    writeCMD(0x01); 
}
/********************* state12:错误状态 **********************/
void showError()
{
    uchar num=0xff;
    a = b = c = 0;
    count = 5;
    state = 0;
    QUEUE[0] = 'E';
    QUEUE[1] = 'R';
    QUEUE[2] = 'R';
    QUEUE[3] = 'O';
    QUEUE[4] = 'R';
    clear();
    print(QUEUE,count);
    while(1)
    {
        mscanf(&num);   //  获取字符
        if(num == 'C')  //  只有按清屏 K8 才会退出 ERROR状态 
        {
            state = 11;
            return ;    
        }
        else
        {
            clear();
            print(QUEUE,count);
        }
    }


}
/**********从键盘获取值得函数类似于C语言的scanf()函数**************/             
void mscanf(uchar *var)
{
   uchar temp,num;
   int i=1;
   temp=i;
    while(1){
        P3=0xff;
        delay100MS(); //延时,软件消除抖动
        if(K1==0){
            *var = '+';
            break;
        }else if (K2==0){
            *var = '-';
            break;
        }else if (K3==0){
            *var = '*';
            break;
        }else if (K4==0){
            *var = '/';
            break;
        }else if (K8==0){
            *var = 'C';
            break;
        }

         P1=0x0f;//置行为高电平,列为低电平。这样用于检测行值。
         if(P1!=0x0f){
             delay100MS(); //延时,软件消除抖动。
             temp=P1;       //保存行值
             P1=0xf0;       //置行为低电平,列为高电平,获取列
               if(P1!=0xf0){
                  num=temp|P1; //获取了按键位置
                  //P2=1;
                  for(i=0;i<12;i++)
                   if(num==KEY_CODE[i]){
                   if(i==10)*var='+';//获取等号的值
                   else if(i==11)*var='=';//获取加号的值
                   else *var=i;//获取数值
                }
               break;   //跳出循环,为了只获取一个值
             }
         }   
     }
}
/*********************短延时函数*************************/
  void delay5MS()
  {
    int n=3000;
    while(n--);
  }

/*****************定义长点的延时程序**********************/
void delay100MS()
{
    uint n=10000;
    while(n--);
}

/*******************写命令子程序**************************/
void writeCMD(uchar com)
{
    P0=com;     //com为输入的命令码。通过P2送给LCD
    RS=0;       //RS=0 写命令
    RW=0;
    delay5MS();   
    EN=1;       //LCD的使能端E置高电平
    delay5MS();
    EN=0;       //LCD的使能端E置低电平
}
/*******************写数据子程序**************************/
void showOneChar(uchar dat)
{
    P0=dat;    //写入数据
    RS=1;       //RS=1写命令
    RW=0;
    EN=1;
    delay5MS();
    EN=0;
}
/*******************初始化函数**************************/
void init()
{
    EN=0;       
    writeCMD(0x38);//设置显示模式
    writeCMD(0x0e);//光标打开,不闪烁
    writeCMD(0x06);//写入一个字符后指针地址+1,写一个字符时整屏不移动
    writeCMD(0x01);//清屏显示,数据指针清0,所以显示清0
    writeCMD(0x80);//设置字符显示的首地址
}
/******************显示函数***************************/
void print(uchar arr[],uint end)
{    
    uint t=0,j=0;
    uint location;

    if(end==0 || end>MAXLEN){
        clear();
        return;
    }
    else {
        for(t=0;t<end;t++){

            //if(t>=MAXLEN){
                //writeCMD(0x40+0x80);  // 光标换行
            //}

            if(arr[t]=='=')         location=11;
            else if(arr[t]=='+')    location=10;
            else if(arr[t]=='+')    location=12;
            else if(arr[t]=='-')    location=13;
            else if(arr[t]=='*')    location=14;
            else if(arr[t]=='/')    location=15;
            else if(arr[t]=='E')    location=16;
            else if(arr[t]=='R')    location=17;
            else if(arr[t]=='O')    location=18;
            else{
                for(j=0;j<10;j++)
                    if(arr[t]==j)   location=j;
            }   
            showOneChar(CHAR_TABLE[location]);
        }
    }
}
/*********************清屏子程序**********************/
void clear()
{   
    EN=0;
    writeCMD(0x01);
}

四则运算C语言程序

以下是计算器四则运算的C语言程序,该程序可以包含( ) + - * / . 和 =

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <string.h>

#define maxn 300

int priv[maxn];     // 运算符优先级数组
double value[maxn]; // 表达式中用到的变量的值

/**** 计算a op b的值并返回 ****/
double calc(double a, double b, char op)
{
    switch(op)
    {
    case '+':
        return a+b;
        break;
    case '-':
        return a-b;
        break;
    case '*':
        return a*b;
        break;
    case '/':
        return a/b;
        break;
    case '^':
        return exp(log(a)*b);
    }
    return 0;   // 默认状况
}

/*********** 运算符优先级赋值 *************/
void initPriv()
{
    // 数值越小优先级越高;数值相同,优先级相同
    priv['+'] = priv['-'] = 3;
    priv['*'] = priv['/'] = 2;
    priv['^'] = 1;
    priv['('] = 10;
}

/***********  字符变量映射数组  *************/
void initValue()
{
    // 表达式中变量初始化代码
    // e.g. : value['x'] = 10;
}

/*********** 计算器函数 ***************
    char str[] : 需要计算的合法表达式
    double val[] : 表达式中变量的值
*/
double calculate(char str[], double val[])
{
    double num[maxn];   // 存储数据的堆栈
    int numi = 0;       // 数据堆栈指针

    char oper[maxn];    // 存储运算符的堆栈
    int operi = 0;      // 运算符堆栈指针

    double x, y;
    int i;
    char last = 0;

    // 运算符优先级赋值
    initPriv();

    // 处理多项式字符串
    for(i = 0; i < strlen(str); ++i)
    {
        if(isalpha(str[i]))         // 如果是变量 'A'-'F' 或 'a'-'z' 则需要用 val 数组进行转换
        {
            num[numi++] = val[str[i]];
        }
        else if(isdigit(str[i]))    // 如果是数字字符 '0'-'9' 则需要
        {
            num[numi++] = atof(str+i);  // 将 str[i] 开头的数字字符串转换为浮点数类型压入栈
            // 将指针指向该数值之后的字符
            for(; i+1 < strlen(str) && isdigit(str[i+1]); ++i);
            if(i+1 < strlen(str) && str[i+1]=='.')
            {
                for(++i; i+1 < strlen(str) && isdigit(str[i+1]); ++i);
            }
        }
        else if(str[i]=='(')
        {
            oper[operi++] = str[i];
        }
        else if(str[i]==')')
        {
            // 计算 '(' 与 ')' 之间的表达式的数值
            while(oper[operi-1] != '(')
            {
                y = num[numi-1];    --numi;
                x = num[numi-1];    --numi;
                char op = oper[operi-1];    --operi;
                num[numi++] = calc(x,y,op);
            }
            --operi;
        }
        else if(str[i]=='-' && (last==0 || last=='('))
        {
            num[numi++] = 0.0;
            oper[operi++] = '-';
        }
        else if(priv[str[i]]>0)
        {
            while(operi>0 && priv[str[i]]>=priv[oper[operi-1]])
            {
                y = num[numi-1];    --numi;
                x = num[numi-1];    --numi;
                char op = oper[operi-1];    --operi;
                num[numi++] = calc(x,y,op);
            }
            oper[operi++] = str[i];
        }
        else
        {
            continue;
        }
        last = str[i];
    }

    // 计算剩余运算的多项式数值
    while(operi>0)
    {
        y = num[numi-1];    --numi;
        x = num[numi-1];    --numi;
        char op = oper[operi-1];    --operi;
        num[numi++] = calc(x,y,op);
    }
    return num[numi-1];
}


int main()
{
    // 初始化value数组
    initValue();

    char str[maxn] = "1+(3+4*5-2)/2+1200";

    printf("%lf", calculate(str,value));

    return 0;
}
2019-07-11 23:21:32 qlexcel 阅读数 249
  • 单片机控制第一个外设-LED灯-第1季第6部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第6个课程,主要讲解LED的工作原理和开发板原理图、实践编程等,通过学习目的是让大家学会给单片机编程控制LED灯,并且为进一步学习其他外设打好基础。

    3998 人正在学习 去看看 朱有鹏

单片机内部的运算都是用的补码,正数的补码=正数的原码,负数的补码=其原码的反码+1,于是:

1、普通的加法,2+3=5:

2的补码:    0000 0010

3的补码:  +0000 0011

得到:          0000 0101,进位标志C=0,表示加法没有进位,最后得到结果0000 0101,然后把这个值赋值给结果变量,如果结果变量是无符号数,那么0000 0101表示5。如果结果变量是有符号数,那么0000 0101的最高位是0表示正数,那么原码也是0000 0101,表示5。(运算结果是补码,要转换成原码才是真实的运算结果。如果结果变量是无符号数,那么原码=补码。如果结果变量是有符号数,如果结果的最高位是0,则原码=补码,如果结果的最高位是1,则原码=补码减1的反码)

2、结果会溢出的加法,如255+255:

255的补码:    1111 1111

255的补码: + 1111 1111     

得到:             1 1111 1110,进位标志C=1,表示加法有进位。因此255+255=0x1FE(510),如果数据只有8位,最高位就会溢出,只得到低8为0xFE。

3、差是正数的减法运算,因为数字电路只有加法器,没有减法器,因此减法是用加法代替的,3-2=1,就是3加-2,-2的原码是:1000 0010,最高位为1表示负数。然后-2的反码是,除了符号位外取反:1111 1101,补码是反码加1:1111 1110

3的补码:    0000 0011

-2的补码:+ 1111 1110

得到:        1 0000 0001,C=1表示减法没有借位 ,得到结果为0000 0001,即1.

4、差是负数的减法运算,1-2=-1,同样的变成1加-2:

1的补码:    0000 0001

-2的补码:+ 1111 1110

得到:          1111 1111,如果保存这个结果的变量是无符号数,则结果为0xFF。如果保存这个结果的变量是有符号数,则结果为1111 1111减1取反:1000 0001,表示-1。这里也解释了单片机中,无符号数运算的风险,比如:

unsigned char c;
C=21-24;

c得到的值为253。

         

推荐这篇文章:https://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html 对原码、补码在CPU中使用的来龙去脉说的很清楚。

没有更多推荐了,返回首页