打印
[STC单片机]

请教 模拟两路I2C接口,怎么避免重复写代码

[复制链接]
3272|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
eyuge2|  楼主 | 2022-4-15 21:13 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 eyuge2 于 2022-4-15 21:15 编辑

大家好,请教一下。用的是keil开发环境。
我用两个IO口已经写好了模拟I2C接口的代码。

现在还需要用另外两个IO口,模拟另外一路I2C。
大家知道模拟I2C程序中有比较多的都是 sbit变量的操作。

sbit不能作为函数参数传递。

只能写两份模拟I2C的程序,很苦恼。

可有什么好的办法解决这个问题?谢谢!

使用特权

评论回复
沙发
eyuge2|  楼主 | 2022-4-15 22:48 | 只看该作者
本帖最后由 eyuge2 于 2022-4-16 10:35 编辑

目前是按这个方法解决的。

sbit SCL_0=P0^0 ;
sbit SCL_1=P0^1 ;


#define SET_SCL(bus_no)                 \
                {                                                 \
                        switch(bus_no)                 \
                        {                                         \
                                case 0:                        \
                                        SCL_0=1;        \
                                        break;                \
                                case 1:                        \
                                        SCL_1=1;        \
                                        break;                \                                
                                default:                \
                                        break;                \
                        }                                        \
                }

使用特权

评论回复
板凳
lyjian| | 2022-4-16 09:41 | 只看该作者
就没几句代码,写两个又咋滴?

使用特权

评论回复
地板
STCMCUNT018| | 2022-4-16 09:54 | 只看该作者
IO-I2C-master-slave.rar (16.36 KB)

使用特权

评论回复
5
Prry| | 2022-4-16 10:38 | 只看该作者
将时序部分抽象出来,变化部分通过函数指针传入,抽象部分与cpu无关。非常方便移植和模拟多路i2c。spi、onewire、8080等模拟总线这些同理。
1.模式i2c:https://acuity.blog.csdn.net/article/details/78878211?spm=1001.2014.3001.5502
2.模拟spi:https://acuity.blog.csdn.net/article/details/79060103?spm=1001.2014.3001.5502
3.模拟onewire:https://acuity.blog.csdn.net/article/details/81152511?spm=1001.2014.3001.5502

使用特权

评论回复
6
Prry| | 2022-4-16 10:40 | 只看该作者
lyjian 发表于 2022-4-16 09:41
就没几句代码,写两个又咋滴?

编程思维要改变,复用代码比复制代码要来得方便。做过模拟20路i2c的项目,这下复制代码就难受了

使用特权

评论回复
7
eyuge2|  楼主 | 2022-4-16 14:35 | 只看该作者
本帖最后由 eyuge2 于 2022-4-16 14:36 编辑

谢谢,这是汇编语言实现的模拟I2C。我已经用C语言实现了模拟I2C

使用特权

评论回复
8
eyuge2|  楼主 | 2022-4-16 14:40 | 只看该作者
本帖最后由 eyuge2 于 2022-4-16 14:48 编辑
Prry 发表于 2022-4-16 10:38
将时序部分抽象出来,变化部分通过函数指针传入,抽象部分与cpu无关。非常方便移植和模拟多路i2c。spi、one ...

谢谢!
这个主要是受到51单片机的限制。

位操作的SETB和CLR指令是直接寻址的。没有办法通过变量传递的方法 来切换不同的引脚。
只是个人的理解,不知可对。

使用特权

评论回复
评论
18971591125 2022-4-18 09:46 回复TA
应该是可以的,因为控制引脚实际也是控制寄存器,通过一个变量让代码去选择控制那个寄存器,就可以实现控制那个引脚,仅个人看法, 
Prry 2022-4-16 23:11 回复TA
跟51无关,把翻转io的函数作为函数指针传入即可 
9
cooldog123pp| | 2022-4-16 16:16 | 只看该作者
虽然我不是很明白,但是路过了就帮忙楼主顶贴一下,希望楼主问题早日解决。

使用特权

评论回复
10
cjseng| | 2022-4-16 16:43 | 只看该作者
我是用笨办法,把所有函数写了两遍,确保万无一失

使用特权

评论回复
11
banyai| | 2022-4-16 17:34 | 只看该作者
可以用预编译指令 ## 试试,比如:
sbit SCL0A = P0^0 ;
sbit SCL1A = P0^1 ;
#define SCL(x)  SCL##x##A
SCL(0) = 1;   SCL(1) = 0;

使用特权

评论回复
12
guojin0273| | 2022-4-16 19:07 | 只看该作者
采用函数指针,CLK,DAT的高低做成函数指针数组

使用特权

评论回复
13
lyjian| | 2022-4-16 21:33 | 只看该作者
Prry 发表于 2022-4-16 10:40
编程思维要改变,复用代码比复制代码要来得方便。做过模拟20路i2c的项目,这下复制代码就难受了 ...

有这纠结的时间够复制好几遍了

使用特权

评论回复
评论
lyjian 2022-4-17 08:49 回复TA
@Prry :按实际而言,不适合随便类比。就这个案例,就几句代码复制1遍比什么都简单。真有1000编的情况再纠结方法。 
Prry 2022-4-16 23:13 回复TA
没毛病,复制10000遍也行;维护起来一个有问题,再改10000遍。 
14
eyuge2|  楼主 | 2022-4-16 22:07 | 只看该作者
本帖最后由 eyuge2 于 2022-4-16 22:36 编辑
banyai 发表于 2022-4-16 17:34
可以用预编译指令 ## 试试,比如:
sbit SCL0A = P0^0 ;
sbit SCL1A = P0^1 ;

这个主意好!但是应该也不行。
写代码的时候,无法确定x的值,可能是0,可能是1。

只有执行代码的时候,才能确定x的值。

预处理是发生在编译阶段(准确的说是在编译之前),无法确定x的值。

使用特权

评论回复
15
eyuge2|  楼主 | 2022-4-16 22:27 | 只看该作者
lyjian 发表于 2022-4-16 21:33
有这纠结的时间够复制好几遍了

这怎么说呢。每个人的想法不一样。
复制几遍,占用的code段空间会变大。
另外,程序也不好修改和维护。

使用特权

评论回复
16
lyjian| | 2022-4-16 23:12 | 只看该作者
eyuge2 发表于 2022-4-16 22:27
这怎么说呢。每个人的想法不一样。
复制几遍,占用的code段空间会变大。
另外,程序也不好修改和维护。 ...

你觉得你这样写就能减少code空间?
想多了吧。
自己对比一下哪个code空间大。

使用特权

评论回复
17
ayb_ice| | 2022-4-18 08:45 | 只看该作者
复制,批量修改都不会吗

使用特权

评论回复
18
18971591125| | 2022-4-18 09:41 | 只看该作者
我以前设计原理图时,没注意,导致STM32连接的多个I2C中有一个SCK和SDA反了,我就写了一个切换I2C的函数,来修改引脚,因为在一个GPIO组,比如Set_I2C_ch(0)就让SCK_PIN = Gpio_Pin_6,SDA_PIN = Gpio_pin_7,Set_I2C_ch(1)就让SCK_PIN = Gpio_Pin_7,SDA_PIN = Gpio_pin_6,而且SCK_PIN和SDA_PIN是两个16位数,反正最后模式读写的时候,都是SetPin(SCK_PORT,SCK_PIN)等这样类似的操作,反正后面用起来是没问题的。

使用特权

评论回复
19
qiangtech| | 2022-4-18 11:24 | 只看该作者
可以这样试一下:
1.定义好引脚和模式。

2.定义一个包含四个操作引脚高低的函数指针的结构体。



3.定义好具体操作引脚高低的函数。每个BUS四个函数,两个引脚的拉高和拉低。



4.定义一个设置函数,让结构体的指针指向具体的操作函数。



5.在底层引用时,只需要先设置一下要操作的BUS,就可以用相同的调用方法调用了。



这样底壳不用写两遍了,先把引脚操作定义好,让结构体指针指向要操作的函数。底层调用就不用管了。

以上写法用KEIL编译通过了,但没有实机运行测试。

使用特权

评论回复
评论
cmyldd 2024-7-30 16:13 回复TA
一直是这样做的 
20
eyuge2|  楼主 | 2022-4-18 11:28 | 只看该作者
本帖最后由 eyuge2 于 2022-4-18 11:34 编辑
qiangtech 发表于 2022-4-18 11:24
可以这样试一下:
1.定义好引脚和模式。

你的这个方法应该可以。

https://github.com/pranjal-joshi/Arduino-for-8051/blob/master/ARDUINO51.h
这个是从github找到的,模仿arduino的做法。void digitalWrite(unsigned char pin, unsigned char val)
{
        unsigned char p;
        if(pin > -1 && pin < 8 )
        {
                p = pinToPort[pin];
                if(val == HIGH)
                {
                        P1 |= p;
                }
                else if(val == LOW)
                {
                        p = 0xFF - p;
                        P1 &= p;
                }
        }
        else if(pin > 9 && pin < 18)
        {
                p = pinToPort[pin - 10];
                if(val == HIGH)
                {
                        P3 |= p;
                }
                else if(val == LOW)
                {
                        p = 0xFF - p;
                        P3 &= p;
                }
        }


https://developer.arm.com/documentation/ka003762/latest
这是keil官方提供的参考,是针对sfr变量的,sbit可以参考。
sfr SFR_0x80 = 0x80;
sfr SFR_0x81 = 0x81;
sfr SFR_0x82 = 0x82;
.
.
.
void write_sfr (
  unsigned char sfr_address,
  unsigned char value)
{
switch (sfr_address)
  {
  case 0x80: SFR_0x80 = value; break;
  case 0x81: SFR_0x81 = value; break;
  case 0x82: SFR_0x82 = value; break;
  }

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

105

主题

1366

帖子

9

粉丝