历史上的今天
今天是:2024年10月21日(星期一)
2021年10月21日 | 【自学51单片机】4---进制转换、C语言变量种类和运算符
2021-10-21 来源:eefocus
不同进制之间转换、C语言变量种类和运算符、keil的Debug用法及应用 和 流水灯的实现
1、二进制、十进制、十六进制转换
1.1 进制介绍
十进制:逢十进位,一个为有十个值:0~~9。
二进制:逢二进位,它的一个位只有两个值:0 和 1,是实现计算机系统的最基本的理论基础,计算机(包括单片机)芯片是基于成万上亿个的开关管组合而成的,他们每一个都只能有开和关两种状态,对应于二进制的 1 和 0 两个值,书写二进制数据时需加前缀 0b,每一位的值只能是 0 或 1。八位二进制称为一个字节。
十六进制:把 4 个二进制位组合为一位来表示,用 0~9 再加上 A~F(或 a~f)表示,逢十六进位,是二进制的一种缩写形式,也是我们程序编写中常用的形式。书写十六进制数据时需加前缀 0x,两位十六进制称为一个字节。
下表为三种进制间对应关系:

进制说明:对于进制来说,只是数据的表现形式,而数据的大小不会因为进制表现形式不同而不同,比如二进制的 0b1、十进制的 1、十六进制的 0x01,他们本质上是数值大小相等的同一个数据。我们在进行 C 语言编程的时候,我们只用到十进制和十六进制。
1.2 进制转换
二进制转十六进制
16进制有16个数,0–15,用二进制表示15的方法就是1111,从而可以推断出,16进制用2进制可以表现成0000~1111,顾名思义,也就是每四个为一位。举例:
00111101可以这样分:
0011|1101(最高位不够可用零代替),对照着二进制的表格, 8 4 2 1 (一般例举这么多就够了,如果有小数的话就继续往右边列举,如0.5 0.25 0.125 0.0625……)
8 4 2 1
0 0 1 1| 1 1 0 1
左半边=2+1=3 右半边=8+4+1=13=D
结果,00111101就可以换算成16进制的3D。
二进制转十进制
从最低位(最右)算起,位上的数字乘以本位的权重,权重就是2的第几位的位数减一次方。比如第2位就是2的(2-1次)方,就是2;第8位就是2的(8-1)次方是128。把所有的值加起来。
2(1-1)代表2的0次方,就是1;其他类推
比如二进制1101,换算成十进制就是:12(1-1)+02(2-1)+12(3-1)+12(4-1)=1+0+4+8=13。
十六进制到二进制
由于在二进制的表示方法中,每四位所表示的数的最大值对应16进制的15,即16进制每一位上最大值,所以,我们可以得出简便的转换方法,将16进制上每一位分别对应二进制上四位进行转换,即得所求:
例:2AF5换算成2进制:
第0位: (5)16 = (0101) 2
第1位: (F)16 = (1111) 2
第2位: (A) 16 = (1010) 2
第3位: (2) 16 = (0010) 2
得:(2AF5)16=(0010|1010|1111|0101)
十进制转二进制:
连续除以2举个例子把
13(10进制)
转化为二进制,我们需要做的就是
13 / 2 = 6 … 1
6 / 2 = 3…0
3 / 2 = 1…1
1 / 2 = 0… 1
然后自下而上写出来: ob1101。
十六进制转十进制
16进制数的第0位的权值为16的0次方,第1位的权值为16的1次方,第2位的权值为16的2次方……
所以,在第N(N从0开始)位上,如果是是数 X (X 大于等于0,并且X小于等于 15,即:F)表示的大小为 X * 16的N次方。
例:2AF5换算成10进制:
用竖式计算:
第0位: 5 * 16^0 = 5
第1位: F * 16^1 = 240
第2位: A * 16^2= 2560
第3位: 2 * 16^3 = 8192
直接计算就是:
5 * 16^0 + F * 16^1 + A * 16^2 + 2 * 16^3 = 10997(十进制)
十进制转十六进制
十六进制转换有16进制每一位上可以是从小到大为0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F16个大小不同的数,即逢16进1,其中用A,B,C,D,E,F(字母不区分大小写)这六个字母来分别表示10,11,12,13,14,15。
例如:(1)1=1;
(2)2=2;
(3)30=30/16=1余下14,14对应的是E。所以30=1E
(4)500=500/16=31余下4,所以个位是4
第二步将31化为16进制,31=31/16=1余下15,找出15对应的数字是F
所以 500=1F4
(5)321=321/16=20余下1,即各位数是1
又将20化为16进制,20=20/16=1余下4
所以321=141
(6)1024=1024/16=64余下0
再将64化为16进制,64=64/16=4余下0
所以1024=400
(7)2000=2000/16=125余下0
再将125化为16进制,125=125/16=7余下13,找到13对应的数是D
所以2000=7D0
对于10进制化为16进制,当数字大于16的时候就一直除以16,从低位往高位写。
2、C语言基础
2.1 C语言变量类型及在C51的范围
变量类型:C 语言的数据基本类型分为字符型、整型、长整型以及浮点型,每个基本类型又包含了两个类型。字符型、整型、长整型,除了可表达的数值大小范围不同之外,都只能表达整数,表达小数的话,必须用浮点型。
变量在C51的范围:见下表

(注:C51指51单片机里的C语言标准)
编程宗旨:能用小的变量类型不用大的。 1 个字节 char 解决问题的就不定义成 int,一方面节省 RAM 空间,另外一方面,程序占空间小运算速度更快。
2.2 C语言运算符
左移 << 右移 >> (注:移位都是二进制移位,左移,最低位填0补充;右移,最高位填0补充),举例说明用法,a = 0x01 << 2; 就是将0x01转换为二进制数据0b0000 0001左移2位移完右边补两个0,即(二进制下)0b0000 0100 (十六进制下)0x04
按位取反符号 ~ : 取反后1变成0,0变成1(注:理按位取反也是针对二进制而言)。比如 a = ~(0x01); 0x01 的二进制是 0b00000001,按位取反后就是 0b11111110,那么a 的值就是 0xFE 了。
3、keil软件的Debug教程
3.1 延时引入
在上节闪烁LED小灯中我们知道程序中的for(i=0; i<30000;i++);用于小灯延时,除了这种延时方法外,还有3中常见的延时方法。见下图:

for(i=0; i<30000;i++);用循环来达到延时小灯目的,延时时长随i的变化而变化,那么如何确保延时的时长足以让小灯闪烁呢?这时可以程序Debug就可以观察小灯延时时长。
3.2程序Debug的应用
观察非精确延长时间
步骤:1. 选择 Keil 菜单项 Project–>Options forTarget ‘Target1’…—>打开 Target 这个选项卡,找到里边的 Xtal(MHz)这个位置,这是填写我们进行模拟时间的晶振选项,填写自己单片机所使用的晶振 (博主的STC89C52为11.0592MHz)–>找到 Debug 这个选项卡,选择左侧的 Use Simulator,然后点击最下边的 OK 就可以了.如下图:
2. 点击选择菜单项 Debug–>Start/Stop Debug Session,如图:

窗口介绍:最左侧Register窗口为显示单片机一些寄存器的当前值和系统信息,通过这个窗口sec 选项就可以观察C语言代码运行的时间。上侧Disassembly窗口为keil将C语言转换为汇编语言的代码。
三个按钮介绍:三个按钮如下图所示

第一个是复位按钮,点击一下之后,程序就会跑到最开始的位置运行;第二个是全速运行按钮,点击一下程序就会全速跑起来;再第三个是停止按钮。
3. 点击复位按钮,然后双击需要观察时间的代码前后行设置断点,如下图所示:

4. 点击全速运行按钮后并观察记录程序运行时间1,然后再次点击全速运行按钮并观察记录程序运行时间2,程序运行时间2 减去 程序运行时间1 就是for(i=0; i<30000;i++);的延时时间。如下图所示:


通过计算for(i=0; i<30000;i++);的延时时间大概在163ms。
(注:非精确延时时间受Xtal模拟单片机晶振及程序优化等级影响)
观察寄存器和变量的数值变化
点击 View 菜单里的 Watch Windows–>Watch 1,可以通过双击或按 F2 键,输入我们想观察的变量或寄存器的名字,后边就会显示出它的数值。如下图:

3.3 断点设置
双击需要观察代码前后行即可,但有些地方设置不了断点,这是因为keil软件本身有程序优化功能,想在所有代码设置断点,选择 Keil 菜单项 Project–>Options forTarget ‘Target1’…—>打开C51选项把level优化等级设置为0即可,如下图所示:

4、 流水灯的实现
介绍:第三节中我们知道引脚 P0.0 经过 74HC245 控制了 DB0,P0.1 控制DB1……P0.7 控制 DB7,一个字节八位,那么一个P0就代表 P0.0到 P0.7 的全部 8 个位。我们写 P0 = 0xFE;转换成二进制就是 0b11111110,就能点亮 LED2。下面0xFE、0xFD、0xFB、0xF7、0xEF、0xDF、0xBF、0x7F分别代表点亮LED2 到LED9。
通过前面的硬件知识学习,及C语言运算符的介绍,下面来写流水灯程序。
流水灯左移程序:
#include sbit ADDR0 = P1^0; sbit ADDR1 = P1^1; sbit ADDR2 = P1^2; sbit ADDR3 = P1^3; sbit ENLED = P1^4; void main() { unsigned int i = 0;//定义循环变量i,用于软件延时 unsigned char cnt = 0;//定义计算变量cnt,用于位移控制 ENLED = 0; ADDR3 = 1;//开启三八译码器 ADDR2 = 1; ADDR1 = 1; ADDR0 = 0;//导通三极管 while(1)//主循环,程序无限循环执行该循环体语句 { P0 = ~(0x01 << cnt);//P0等于1左移cnt位,控制8个LED小灯 for(i = 0; i < 30000; i++);//软件延时 cnt++; //位移计数变量自加1 if(cnt > 7) //位移计数超过7后,再重新从0开始计数 { cnt = 0; } } } 流水灯右移程序 只需把流水灯左移的程序中P0 = ~(0x01 << cnt);修改成P0 = ~(0x80 >> cnt);即可实现流水灯右移。 左移后右移花样流水灯程序 #include sbit ADDR0 = P1^0; sbit ADDR1 = P1^1; sbit ADDR2 = P1^2; sbit ADDR3 = P1^3; sbit ENLED = P1^4; void main() { unsigned int i = 0;//定义循环变量i,用于软件延时 unsigned char cnt = 0;//定义计算变量cnt,用于位移控制 unsigned char sign = 0;// 流水灯移向标志,0代表左移,1代表右移 ENLED = 0; ADDR3 = 1;//开启三八译码器 ADDR2 = 1; ADDR1 = 1; ADDR0 = 0;//导通三极管 while(1)//主循环,程序无限循环执行该循环体语句 { //左移部分 if(sign == 0) { P0 = ~(0x01 << cnt);//P0等于1左移cnt位,控制8个LED小灯 for(i = 0; i < 30000; i++); //软件延时 cnt++;//位移计数变量自加1 if(cnt > 7) //位移计数超过7后,再重新从0开始计数 { sign = 1;//当左移到最后一个LED小灯,移向标志赋值为1让小灯右移 cnt = 0; } } //右移部分 if(sign == 1) { P0 = ~(0x80 >> cnt);//P0等于1右移cnt位,控制8个LED小灯 for(i = 0; i < 30000; i++); cnt++; if(cnt > 7) { sign = 0;//当右移到最后一个LED小灯,移向标志赋值为0让小灯左移 cnt = 0; } } } } 右移后左移花样流水灯程序 只需把左移后右移花样流水灯的程序中unsigned char sign = 0;修改成unsigned char sign = 1;并将左移代码部分和右移代码部分调换顺序即可实现先右移后左移花样流水灯。
史海拾趣
|
在这我只想发发牢骚……因为我现在就是在闲着,时时刻刻都开着EEWORLD 快毕业了,本来找工作都几乎没什么搭理的,发过好多简历都石沉大海。毕竟我只是专科学历,虽然参加过几次比赛,但感觉这些经历并没给我找工作带来什么的。 ...… 查看全部问答> |
|
C:\\icc\\bin\\imakew -f xiaoche.mak iccavr -c -IC:\\icc\\include\\ -e -l -g -Wa-W C:\\DOCUME~1\\Administrator\\MYDOCU~1\\小车\\xiaoche.c !W C:\\DOCUME~1\\Administrator\\MYDOCU~1\\小车/drv.h(14 ...… 查看全部问答> |
|
在TI-2812开发板上调试485通讯,用串口调试器向下发数据时,RX状态寄存器显示有帧错误,从下望上发数据时,串口调试器接受的数据是错误的,但发送0是接受到的也是0.请高手帮帮忙! … 查看全部问答> |
|
最近在思考一个问题,就是有关SD卡升级的。 我看到过三星发布2442下的SD卡升级,但有个缺陷是只支持FAT格式的小容量卡,而且,在EBOOT里面去读写卡的block、sector,简直有点复杂。 我在想,如果是FAT32格式的(现在基本上都是FAT32格式了)SD卡能 ...… 查看全部问答> |
|
Wince 下用C#实现媒体播放,最好是Media Player的调用。希望有经验的各位前辈随便露两手绝艺,让俺开开眼届。最好有源码!! Wince 下用C#实现媒体播放,最好是Media Player的调用。希望有经验的各位前辈随便露两手绝艺,让俺开开眼届。最好有源码!! … 查看全部问答> |
|
初学者问个简单问题:关于WINXP SP2下的环境配置问题! 小弟的机器是WinXP SP2 HOME EDITION,想问一下,在这个系统下如何配置编译环境? 相关软件:DriverStudio3.2 XP SP1 DDK ...… 查看全部问答> |
|
我在VS2005中建了一个c++的移动设备的MFC,是一个264 的解码器,现在要加一个显示的程序,最好能解一点播一点,本来VC上有源程序,移植后无法使用,现在毕设中,急啊,哪位仁兄能帮我看看用什么方法显示,谢谢,本人菜鸟,不好意思!! ...… 查看全部问答> |
|
我用STM32 控制一个320x240的 TFT屏,需要显示jpg的文件,感觉刷整屏的时候速度很慢;显示bmp文件时刷整屏的时候就很快。STM32是不是不适合解码jpg文件呢?… 查看全部问答> |
|
广大DIY爱好者们,随着你们DIY程度的不断深入,你们的DIY工具是不是也在一点点的增加,随着工具的增加,DIY的水平是不是也在不断地提高,随着水平的不断提高,DIY的作品是不是也是愈加的丰富,显摆的时刻到了! 活动要求: 1、显摆自己所有用于D ...… 查看全部问答> |






