一本单片机书中的问题--2,本人初学,大家指教,在线等,谢谢了,很急,谢谢了!!!!!
[复制链接]
下面是代码段的声明例子
unsigned int code unit_id[2]=1234;
unsigned char
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
};---------------这个是怎么回事?是不是写错了?初学,大家不要笑话。
======================================================================================================
C51 支持所有5 个8051/8052 标准中
断从0 到4 和在8051 系列中多达27 个中断源.
-----------------------------------------中断和中断源是怎么对应的,不是一一对应,那么多个中断源引起一个中断程序执行,可以吗?一个中断程序是做一件事啊?
======================================================================================================
因为这些堆栈是模拟的再入函数一般都比较大运行起来也比较慢,模拟栈不允许传递bit 类型的变量也不能定义局部位标量
----------------------------------局部位变量是什么?模拟栈是什么?再入函数是怎么回事?
======================================================================================================
为什么要使用无符号类型呢。原因是8051 不支持符号运算,程序中也不要使用含有带符号变量的外部代码。除了根据变量长度来选择变量类型自外,你还要考虑是否变量是否会用于负数的场合。如果你的程序中可以不需要负数,那么把变量都定义成无符号类型的。
--------------------这块说不支持,下面又说会不会用在负数的场合,要是用在负数的场合怎么办,不可能全都是无符号的数吧?
======================================================================================================
你还要决定所需要的最大精度,一旦你计算出你所需要的浮点运算的最多的位数,应该通知编译器知道,它将把处理的复杂度控制在最低的范围内。
--------------------------怎么通知精度,只是单精度双精度?
======================================================================================================
宏能够使得访问多层结构和数组更加容易。可以用宏来替代程序中经常使用的复杂语句以减少你打字的工作量,且有更好的可读性和可维护性。
------------------------------定义宏和定义函数有什么区别,为什么要定义宏而不是函数呢?
======================================================================================================
动态分配函数要求用户声明一个字节数组作为堆。
-----------------------------------什么是堆?堆有什么作用?是否可以举例?
======================================================================================================
C51 的库函数中包含了printf 函数该函数格式化字符串并把他们输出到标准输出设备对PC 来说标准输出设备就是你的显示设备,对8051 来说是串行口。在这里只有一个显示。就本质来说printf 函数是通过不断的调用putchar 函数来输出字符串的。这样通
过重新定义putchar 函数,就可以改变printf 函数,连接器在连接的时候,将使用源代码中的putchar 函数,而不是运行函数库中的函数。下面的功能将调用printf 函数来格式化时间串并发送显示。
---------------------------------为什么是8051的putchar而不是库函数的putchar,是怎么做到的?
=====================================================================================================
在编写软件之前你首先要明确你的要求。如果你最快的任务执行速度是3ms 一次,那么就以这个时间为准。发生频率比较慢的事件可以很好的被驱动。如果你的系统时间不能很好的兼容,你可以考虑使用两个定时器。
------------------------------------不能很好的兼容是什么意思?
=====================================================================================================
共用一个时标的定时操作可被放入一个只有时标被某个特定数整除才有效的空间中。
--------------------------共用这个,还特定数整除才有效的空间。是什么意思啊?没看明白,大家指点。
=================================================================================================
if (led_timer)
{ // 时间计数器不为0
led_timer--; // 减时间计数器
if (!led_timer)
{ // 显示时间到...
LED=OFF; // turn off the LED
}
}
假设你需要以不少于1 秒的间隔时间执行一些功能,使用上面的时标过程。你只要保存一个计数器,仅当计数器变为0 的时候,查询那些基于秒的定时操作。而不需要系统每隔50ms 就查询一次。
-------------------------------------------这个时标计数器要放在哪里,中断程序还是哪里?还有怎么查询那些基于秒的定时操作。second_cnt = 20是怎么知道这是1秒的?
====================================================================================================
second_cnt--; // 减时标计数器
if (!second_cnt) { // 一秒钟过去了...
... // 进行相应的操作
second_cnt=20; // 重新定时1秒
}
注意你的中断服务程序所需的执行时间,如果执行时间超过50ms 你会发现将丢失时标。在这种情况下,你把一些操作移出中断程序,放到主程序中。通过设置标志位来告诉主程序是否要执行相应的功能。但操作的时间精度就不够高了,因此对时间精度要求很高的操作还是要放在中断程序中。
----------------------------------为什么要移出中断程序,在中断程序中不是可以保留时标?放到主程序中干什么?
=====================================================================================================
从指令计数可以知道一共损失了34 32+2 个指令周期。我们注意到大部分损失的时间是由于把寄存器入栈。因为每个入栈指令又要对应一条出栈指令,这样就要花去52 个指令周期。这使编译器所做的一种数据保护措施,我们可通过指定寄存器组来消除这种保护
措施。
-------------------------------------指定寄存器组是什么意思?这样就不用进栈出栈了吗?指定寄存器组是怎么一回事?具体讲一下。谢谢。
====================================================================================================
因为是每50ms 进行一次中断那么进行时间更新和显示的时间加起来不过是6.246ms,在下一次进行中断之前,有43.754ms 是在空闲模式如果你的功能只有这些,或许你的系统是用电池供电,减少处理器工作时间的最佳方法是用一个更加精简的函数替代printf 函数。
---------------------------------------减少处理器工作时间应该是去掉那些空闲时间,怎么和printf扯上关系了?
====================================================================================================
到此为止,这个时钟程序算是完成了实现了对硬件的简化整个程序如下所示
列表0-10
#include
#include
//定义定时器0 的重装值
#define RELOAD_HIGH 0x3C
#define RELOAD_LOW 0xD2
//定义按键弹跳时间
#define DB_VAL
//定义设置模式的最大时间间隔
#define TIMEOUT 200
//定义光标位置常数
#define HOME 0
#define HOUR 1
#define MIN 2
#define SEC 3
//定义光标状态常数
#define OFF 0
#define ON 1
//定义显示命令常数
#define DISP_BUSY 0x80
#define DISP_FUNC 0x38
#define DISP_ENTRY 0x06
#define DISP_CNTL 0x08
#define DISP_ON 0x04
#define DISP_CURSOR 0x02
#define DISP_CLEAR 0x01
#define DISP_HOME 0x02
#define DISP_POS 0x80
#define DISP_LINE2 0x40
sbit SET=P3^4; //设置按键输入
sbit SELECT=P3^5; //选择按键输入
sbit ENABLE=P3^1; //显示使能输出
sbit REGSEL=P3^7; //显示寄存器选择输出
sbit RDWR=P3^6; //显示模式输出
sfr DISPDATA=0x90; //显示8 位数据总线
typedef struct { //定义存储每日时间的结构
unsigned char hour,min,sec;
}timestruct;
bit set_mode=0; //进入设置模式时置位
disp_updata=0; //需要刷新显示时置位
unsigned char set_mode_to=0; //为每次按键操作的时间间隔计时
switch_debounce=0; //按键跳动计时
cur_field=HOME; //设置模式的当前位置选择
timestruct curtime; //存放当前的时间
timeholder; //存放显示时间
unsigned char code fieldpos[3]={ //
Tel 020 38730916 38730917 38730976 38730977 Fax:38730925
51
DISP_LINE2|0x01;
DISP_LINE2|0x04;
DISP_LINE2|0x07;
};
#define T_HOURT 16
#define T_HOUR 17
#define T_MINT 19
#define T_MIN 20
#define T_SECT 22
#define T_SEC 23
char code bcdmap[60][2]={
“00”,”01”,”02”,”03”,”04”,”05”,”06”,”07”,”08”,”09”,
“10”,”11”,”12”,”13”,”14”,”15”,”16”,”17”,”18”,”19”,
“20”,”21”,”22”,”23”,”24”,”25”,”26”,”27”,”28”,”29”,
“30”,”31”,”32”,”33”,”34”,”35”,”36”,”37”,”38”,”39”,
“40”,“41”,”42”,”43”,”44”,”45”,”46”,”47”,”48”,”49”,
“50”,”51”,”52”,”53”,”54”,”55”,”56”,”57”,”58”,”59”,
};------------------------------------------------------------这个第二列都为0,是怎么回事?为什么要这样做?
======================================================================================================
有时候我们希望把变量存储在指定的地点,特别是在主控制器初始化SRAM之后,从8051系统才开始工作的情况。在这种情况下,两个系统必须在存储器分配上达成一致,否则当8051使用不正确地使用初始化过的数据时将导致数据丢失。
-----------------------------------------------两个 系统指什么?
=====================================================================================================
列表 0-4
Tel 020 38730916 38730917 38730976 38730977 Fax:38730925
66
;定义代码段
CSEG AT 8000H
mytable: DB 1, 2, 3, 4, 5, 6, 7, 8
... ;剩下的表格定义
DSEG AT 70H
cur_field: DS 1
...
END ;
用这种方法,一个变量可被安置在任何地方。如果你在你的C代码中用extern申明了这些变量,那么你的C代码可对他们进行寻址。有了这些信息之后,连接器将能够定位你的变量。
--------------------------------------------没看懂这块,是否可以详细的解释一下。
=====================================================================================================
还有一种方法用来定位中断服务程序,可以把中断入口向量或中断程序放在一个绝对段中.如果你所有的中断服务程序都是用C写的,但是有一个中断程序必须用汇编来写,最好的方法就是把中断程序定位在正确的位置上,这和给变量设置地址很相似。
-------------------------------------------绝对段是什么东西?把中断程序定位在正确的位置上是什么意思?什么是正确的位置?
====================================================================================================
;申明代码段
?PR?clrmem?LOWLVL SEGMENT CODE---------------这个是什么格式?什么东西?是否可以解释下。
;输出函数名
PUBLIC clrmem
;这个函数可被连接器放置在任何地方
RSEG ?PR?clrmem?LOWLVL--------------------这个是什么格式?什么东西?是否可以解释下。RESG是什么?
======================================================================================================
ISR程序在时钟系统的限制下顺利的运行.注意中断中命令的执行可以避免设计上的很多问题.串行中断服务程序和定时器中断服务程序一样都可以修改时间,把这两个中断的优先级设为一样,这样任何一个中断在修该时间的时候都不用担心另一个也在这么做.
--------------------------------这个为什么不用担心?没理解,是否可以解释一下。
======================================================================================================
新的中断服务程序和以前的很相似,不同之处在于当接收完毕数据之后,它会把数据拷贝到另一个缓冲区中并置位缓冲区有效标志位,以前在中断服务程序中的命令执行代码现在放到新的功能段中,当主程序检测到第二个缓冲区中有数据的时候调用该功能段.
------------------------------------为什么要拷贝到另一个缓冲区?
======================================================================================================
有点多,o(∩_∩)o...哈哈,不好意思,大家指点一下,本人以前学得不好,大家指教了。不要笑话。o(∩_∩)o...哈哈!,如果感觉分少,我可以再开贴放分。谢谢大家了!!!!!!!!!!!