发新帖本帖赏金 3.00元(功能说明)我要提问
返回列表
打印

论Keil C51下如何实现模块驱动文件复用

[复制链接]
楼主: 幸福至上
手机看帖
扫描二维码
随时随地手机跟帖
21
幸福至上|  楼主 | 2016-1-21 12:42 | 只看该作者 回帖奖励 |倒序浏览
whtwhtw 发表于 2016-1-21 10:47
比如P1口接8个18B20,能不能以数据流的方式与这8个传感器通信?即给P1口发数据和接收数据的方式,接收后的 ...

你的意思是同时和8个DS18B20通信吗?如果是这样的话,也是可以的,直接将数据送给P0口即可。

使用特权

评论回复
22
laoxu| | 2016-1-21 14:04 | 只看该作者
幸福至上 发表于 2016-1-21 12:42
你的意思是同时和8个DS18B20通信吗?如果是这样的话,也是可以的,直接将数据送给P0口即可。 ...

这种整体读取8个DS18B20数据的话,读取程序是最简洁速度最快的,只是后期数据纵横变转,在 51上是挺费时的。 .

使用特权

评论回复
23
幸福至上|  楼主 | 2016-1-21 15:14 | 只看该作者
laoxu 发表于 2016-1-21 14:04
这种整体读取8个DS18B20数据的话,读取程序是最简洁速度最快的,只是后期数据纵横变转,在 51上是挺费时 ...

是的啊。如果其中一个有问题,那么全部都会出问题。我现在的方法还是一个一个的选中操作,用管脚移位的方式来封装底层的数据总线操作,超过八个的话就只好考虑使用函数指针数组方式了。

使用特权

评论回复
24
laoxu| | 2016-1-21 16:50 | 只看该作者
幸福至上 发表于 2016-1-21 15:14
是的啊。如果其中一个有问题,那么全部都会出问题。我现在的方法还是一个一个的选中操作,用管脚移位的方 ...

其中一个有问题,并不会影响其他的数据,这点程序很容易做到。关键是 51的指针操作效率太低,后期的数据纵横变换,是挺费时的一件事。

用管脚移位的方式来封装底层的数据总线操作,这个方法比较实用,超过八个的话,建议不要用函数指针数组方式(太费时了)。
还是用移位的方式比较合理,只是多几条映射指令而已。
方法是,把输入的ID号赋给变量(可指定为int或long类型, 即扩展为16个或32个),先将变量移位,再将值赋给管脚。

使用特权

评论回复
25
幸福至上|  楼主 | 2016-1-21 18:21 | 只看该作者
本帖最后由 幸福至上 于 2016-1-21 18:25 编辑
laoxu 发表于 2016-1-21 16:50
其中一个有问题,并不会影响其他的数据,这点程序很容易做到。关键是 51的指针操作效率太低,后期的数据 ...

您是说这样吗:
假设有16个传感器需要控制,分别连接在MCU的P0和P1口,则这样封装总线操作函数:
u16 pin_mask;

#define DS18B20_Master_Control(index)       pin_mask = 0x0001 << index;\
                                                                      P0 |= pin_mask;\
                                                                      P1 |= (pin_mask>>8);
#define DS18B20_Master_Release(index)      pin_mask = 0x0001 << index;\
                                                                      P0 &= ~pin_mask;
                                                                      P1 &= ~(pin_mask>>8);


函数指针方式是我最初想出来的,但一直觉得效率不高,因为每个总线动作都需要入栈、出栈一次。:lol

使用特权

评论回复
26
laoxu| | 2016-1-22 08:27 | 只看该作者
幸福至上 发表于 2016-1-21 18:21
您是说这样吗:
假设有16个传感器需要控制,分别连接在MCU的P0和P1口,则这样封装总线操作函数:

对!

不过变量可以不命名,采用隐性指定变换,这样,程序结构更简洁。

使用特权

评论回复
27
laoxu| | 2016-1-22 08:35 | 只看该作者
#define DS18B20_Master_Control(index)    P0 |= (1<<(u16)index);  \
                                         P1 |= ((1<<(u16)index)>>8);
#define DS18B20_Master_Release(index)    P0 &= ~(1<<(u16)index); \
                                         P1 &= ~((1<<(u16)index)>>8);

使用特权

评论回复
28
laoxu| | 2016-1-22 08:43 | 只看该作者
如果 index不是以递增形式赋值,而是以移动方式赋值,则c51的执行效率最高,
即 1#:  0x0001,  2#:  0x0002,  3#:  0x0004,  4#:  0x0008,  5#:  0x0010,  6#:  0x0020,  7#:  0x0040,  8#:  0x0080, .........
程序可写成:
#define DS18B20_Master_Control(index)    P0 |= index;  \
                                         P1 |= (index>>8);
#define DS18B20_Master_Release(index)    P0 &= ~index; \
                                         P1 &= ~(index>>8);
   

使用特权

评论回复
29
幸福至上|  楼主 | 2016-1-22 10:12 | 只看该作者
laoxu 发表于 2016-1-22 08:35
#define DS18B20_Master_Control(index)    P0 |= (1

对头,这样更好,节省一个变量空间。又学习了:D

使用特权

评论回复
30
幸福至上|  楼主 | 2016-1-22 10:26 | 只看该作者
本帖最后由 幸福至上 于 2016-1-22 10:32 编辑
laoxu 发表于 2016-1-22 08:43
如果 index不是以递增形式赋值,而是以移动方式赋值,则c51的执行效率最高,
即 1#:  0x0001,  2#:  0x0002 ...

这方式着实不错,效率又高了些,就是需要预先对每个传感器进行宏定义其index.今早我也琢磨出一个类似的方法,如下请看:
首先定义一个本地变量和一个宏定义,用于存储传感器管脚位置和参数判断:
#define DS18B20_NUM     16
static u16 pin_mask;

在多个传感器操作时,都需要先进行传感器的选定操作,所以在驱动文件里,我定义了这样一个函数:
u8 DS18B20_Select(u8 index)
{
        if(index < DS18B20_NUM)
        {
                pin_mask = 1<<(u16)index;
                return 0;        
        }
       else
       {
               return 1;
       }
}

之后的数据总线操作函数就这样封装:
#define DS18B20_Master_Control()     P0 |=pin_mask;P1 |=pin_mask>>8;
#define DS18B20_Master_Release()     P0 &=~pin_mask;P1 &=~(pin_mask>>8);

这样的话,每次数据操作动作都不再需要根据index参数进行移位运算后再赋值给管口。只需要在对每个传感器进行操作前,调用DS18B20_Select()函数选中并计算下pin_mask,然后动作时直接将pin_mask赋给管口即可。:P 唯一就是多占用了两个字节的数据空间

使用特权

评论回复
31
laoxu| | 2016-1-22 11:21 | 只看该作者
c语言推荐,尽量少用全局变量,这样函数的可控性好,不易出问题。

你用全局变量 pin_mask 来传递参数,数据量少还能凑合,数据量大的话,还是建议少用,否则,程序中在某种情况下发生冲突易出问题。

使用特权

评论回复
32
幸福至上|  楼主 | 2016-1-22 11:32 | 只看该作者
laoxu 发表于 2016-1-22 11:21
c语言推荐,尽量少用全局变量,这样函数的可控性好,不易出问题。

你用全局变量 pin_mask 来传递参数,数 ...

嗯,也是。不过我能确定在DS18B20的驱动文件中,pin_mask只在一个地方赋值,其余地方都是运用。:)谢谢指点。

使用特权

评论回复
33
huarana| | 2016-1-23 11:06 | 只看该作者
用宏替换
给你个最简单的例子,后面可以发挥下。

驱动代码只需要改参数就行。
#include<reg52.h>
sbit P1_0=P1^0;
sbit P1_1=P1^1;
#define P10  0
#define P11  1
#define SETH(pin)        (P1_##pin##=1)
#define SETL(pin)        (P1_##pin##=0)
#define SET_IO_H(pin)          SETH(pin)
#define SET_IO_L(pin)          SETL(pin)
void delay(unsigned int z)
{
unsigned char x,y;
for(x=100;x>0;x--)
for(y=200;y>0;y--)
for(z;z>0;z--);
}

void main()
{  while(1){
          SET_IO_H(P10);
          delay(10000);
          SET_IO_L(P10);
          delay(10000);
          SET_IO_H(P11);
          delay(10000);
          SET_IO_L(P11);
          delay(10000);
}
}

使用特权

评论回复
34
幸福至上|  楼主 | 2016-1-25 14:48 | 只看该作者
huarana 发表于 2016-1-23 11:06
用宏替换
给你个最简单的例子,后面可以发挥下。

谢谢建议,##的用法很是奇特,我试了一下,将数据操作函数如此封装:
sbit DS18B20_1_DQ_PORT = P7^2;
sbit DS18B20_2_DQ_PORT = P7^3;

#define DS18B20_Master_Control(pin_index)                      (DS18B20_##pin_index##_PORT = 1)
#define DS18B20_Master_Release(pin_index)                      (DS18B20_##pin_index##_PORT = 0)
#define DS18B20_ReadIO(pin_index)                              (DS18B20_##pin_index##_PORT)

然后在API函数中调用:
static volatile u8 ds18b20_index;

DS18B20_Master_Control(ds18b20_index);

在这之中ds18b20_index用于选中要操作的管脚,但编译会报错:error C202: 'DS18B20_ds18b20_index_PORT': undefined identifier,这个错误也能理解,即ds18b20_index并不会和DS18B20_ _PORT组成已声明的合法变量。而如果在API函数中,以指定的索引号来进行操作,如:
DS18B20_Master_Control(0); 

虽然可行,但程序烧写后就不能切换到对其它传感器对应管脚的操作了。我即总结,宏定义毕竟是在程序编译时进行处理的,在程序运行中是不能进行动态赋值的。不知我所采用的方式和说法是否正确,请大家指正。

使用特权

评论回复
35
huarana| | 2016-1-26 10:48 | 只看该作者
幸福至上 发表于 2016-1-25 14:48
谢谢建议,##的用法很是奇特,我试了一下,将数据操作函数如此封装:

然后在API函数中调用:

问题出在宏展开的时候没有完全展开。

你仔细看我贴出来的例程,需要做2次宏定义,才能完全展开。
然后就可以引用了。

要深入理解,请参考下我的blog
http://blog.sina.com.cn/s/blog_55ad85100101kvgp.html

使用特权

评论回复
36
nefusmzj| | 2016-1-26 11:38 | 只看该作者
用C++来操作,在初始化类的时候传递引脚进去。或许更方便些!

使用特权

评论回复
37
幸福至上|  楼主 | 2016-1-26 15:51 | 只看该作者
nefusmzj 发表于 2016-1-26 11:38
用C++来操作,在初始化类的时候传递引脚进去。或许更方便些!

你好,谢谢建议。在前面一位仁兄也说过,但并未提出具体如何来实现。另外据我查阅资料,Keil C51似乎并不支持C++.如果可以,请给一个简单的代码示例以参考。;)

使用特权

评论回复
38
lxg123321| | 2016-1-26 21:23 | 只看该作者
指针

使用特权

评论回复
39
kk118a| | 2016-1-26 22:10 | 只看该作者
用一个P口,一位定为数据口,剩下的扩展一个多路开关,

使用特权

评论回复
40
picasso101| | 2016-1-27 09:44 | 只看该作者
我觉得18B20既然给了序列号,其实多路采集用单总线是比较好的方式,简化了外部布线,同时也减少了你的代码冗余,我以前做过一个这样的项目,当时使用STC的小单片机写的,速度什么的完全够用,需要的话可以@我。

使用特权

评论回复
发新帖 本帖赏金 3.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则