szxszx 发表于 2021-12-29 08:22:28

请教,51单片机,如何将IO端口作为形参传递给一个函数?

请教,51单片机,如何将IO端口作为形参传递给一个函数,这个函数根据不同的形参进行输入输出操作?
比如:
void PortOut(port,value)
{
   port = value;
}

void main()
{
   PortOut(P0,0x11);
   PortOut(P1,0x22);
}
这里只是简单的举例示意。

项目中经常会用到单片机驱动多个I2C芯片,每个芯片接的IO口不同,需要为每个芯片写同样的发送函数,如何简化为一个发送函数,形参是不同的IO,函数中根据传递的IO操作不同的芯片?

szxszx 发表于 2021-12-29 08:35:19

有些资料是这样说的:
C51对ANSI C做了一些扩展,针对单片机增加sfr16、sfr、sbit、bit数据类型,用它定义特殊功能寄存器、特殊功能寄存器位和位变量。相当于取个别名,方便操作,与普通变量又有区别,有的只能读,有的只能写,每个位都有具体的定义。
sfr是c51系列单片机扩充的类型,用来声明寄存器的。
编译器帮你做了转换例如 sfr P0 = 0x80;

P0 =3

逻辑上等价

*(byte*)80 = 3

但是程序不能这么写,为什么呢,这跟51单片机的哈弗结构有关系

ackyee 发表于 2021-12-29 08:40:07

里面PORT 的判断用 if吧

t3486784401 发表于 2021-12-29 08:49:17

标准 51 访问 IO 口,在硬件指令集层面,要么使用 SFR 直接寻址,要么使用按位直接寻址。
所谓直接寻址,就是一条指令访问哪个口,是在指令里写死的,而不能通过第三方寄存器来动态更改访问的 IO.

上述硬件结构决定了,51访问 IO 只能形如:

* (volatile byte *) 地址常数 = 0xXX

而不能使用:

* (volatile byte *) 地址变量 = 0xXX

因为后者需要产生间接寻址指令。
回到最开始的疑问,是否能用参数指定被访问的 IO?从间接寻址层面显然不行,但可以自己穷举,形如:

if( index==0 )
P0_0= state;
else if(index==1)
P0_1= state;
else if(index==2)
P0_2= state;
else.....

redroof 发表于 2021-12-29 08:55:45

51系列的一个搞笑的设计,不存在指向sfr的指针。sfr只能被直接地址访问,通过指针访问的话你操作的是内与sfr同地址的普通内存
唯一的封装方法是上面说的,函数内部判断每个输入的sfr地址,然后执行直接访问

iamseer 发表于 2021-12-29 09:05:59

架构原因楼上讲的都挺清楚。我是这么写的

https://github.com/DeqingSun/ch55xduino/blob/ch55xduino/ch55xduino/ch55x/cores/ch55xduino/wiring_digital.c

hjjnt2008 发表于 2021-12-29 09:29:12

这个我还真做了一个,方法可能比较笨,大概就是对每个Port口做一个Setbit 和ResteBit的函数,然后把这些port的函数做成两个指向函数指针的数粗,然后就可以了

hjjnt2008 发表于 2021-12-29 09:43:21

方法笨是笨了点,可以参考参考













ecbm 发表于 2021-12-29 11:29:20

可以参考ECBM库,我的做法就是建立一个gpio_in和gpio_out,把引脚作为参数。这样就可以复用软件IIC代码了

下一页 发表于 2021-12-29 13:34:51

51里面io本身不是用户定义的变量,即便非得认为是变量的话,也是全局变量。因为io口本身就是那个地址,那个名字,而变量不单单是数据是可变的,其地址也是编译器在编译过程中自行指定的,不用也不能由编程者指定。

另外上面有人说51单片机是哈佛结构,那个真心不是,就像不能说原始社会是共产主义一样,虽然其存储区地址不是统一编制的,但是那是因为那个年代的局限性导致。哈佛结构的特点是数据存储器和程序存储器分别有各自的总线,当然也就有各自独立的地址,这个目的是为了能够同时访问数据存储器和程序存储器,,好处是可以流水线,一边执行前一条指令,一边把后一条指令就取出来了。51单片机明显不具备这个能力,12个clk才一个机器周期,肯定不是哈佛结构。

rube 发表于 2021-12-29 13:36:54

hjjnt2008 发表于 2021-12-29 09:43
方法笨是笨了点,可以参考参考

代码看起来顺眼{:victory:}

dz20062008 发表于 2021-12-29 22:10:53

sfr属于内部ram,51支持扩展外部ram为了。内外ram存在低段256字节地址重叠,所以在设计上分别用mov与movx 指令区分。在c这里体现就是可能同一条指令变汇编后有两条。简单理解就是想要把数据传到io结果数据传到相同地址的外部ram去了,操作无效果。汇编指令集层来看就是没有这条指令,地图未标注有这条路。硬件层就是根本没有这个电路。c语言用户,看到外面的马路想要从此处出去,结果碰到玻璃墙,能看到外面马路但是此路不通绕道通行。透光就是形容访问同地址的外部ram,出去指的是访问同地址的sfr。玻璃墙就是mcu内部具体电路。

dz20062008 发表于 2021-12-29 22:30:07

redroof 发表于 2021-12-29 08:55
51系列的一个搞笑的设计,不存在指向sfr的指针。sfr只能被直接地址访问,通过指针访问的话你操作的是内与sf ...

大神,如今看来这个设计搞笑。但是想想51内核可能是所知的处理器内核的祖宗,简称盘古。"51骂骂咧咧道,在坐各位处理器通通是我孙子"标准51内核是可以扩展外部rom与外部ram的,别看只有40条腿,实力强的很。那个时代能支持64k的rom与ram简直不要太豪华。

redroof 发表于 2021-12-30 08:44:02

本帖最后由 redroof 于 2021-12-30 09:07 编辑

dz20062008 发表于 2021-12-29 22:30
大神,如今看来这个设计搞笑。但是想想51内核可能是所知的处理器内核的祖宗,简称盘古。"51骂骂咧咧道, ...

51并不是现代cpu的唯一祖先,在早期有一大堆流行的系列呢。甚至51的岀货量也不是最多的,好像最多的是6502,就是红白机和文曲星的cpu
只不过51系列是被国内最多的学校选做单片机课程教学的而已。不要神话它了。
相比之下6502还更接近现代处理器一点。统一的地址空间,外设都映射到内存。
从51以后就没什么单片机选择让外设和ram重叠只靠寻址方式区分了。这是个失败的尝试。
页: [1]
查看完整版本: 请教,51单片机,如何将IO端口作为形参传递给一个函数?