zhouwenjing 发表于 2013-1-15 22:15:40

IO口线性映射的用法

本帖最后由 zhouwenjing 于 2013-1-16 09:53 编辑

第一种情况,所有的IO都在同一个寄存器上。如下图:
我使用了P0口上的1,4,7三个IO口,作为输出,用于控制三个继电器,继电器编号分别为1,2,3
P01         P04      P07
   |      |       |         |
-----------------------------------------
|                MCU               |
|______________________|
   |         |         |      |
P22      P25      P27   P29

如果按一般的操作,代码该是如下写:void RelayOpen(int rid)
{
        if(rid==1)
        {
                P0|=(1<<1);
        }
        else if(rid==2)
        {
                P0|=(1<<4);
        }
        else if(rid==3)
        {
                P0|=(1<<7);
        }
}但是想一想,如果要控制的IO口很多,这样写是不是过于繁琐呢!
如何简化这段代码呢?其实仔细想一想,这段代码还是很有规律的,除了IO口德编号不一样,其他的都很相似。根据这个规律,我把代码改写成如下的样子
const INT8U RELAY_IO_MAP[]={1<<1,1<<4,1<<7};
void RelayOpen(int rid)
{
        if((rid<=3)&&(rid>0))
        {
                P0|=RELAY_IO_MAP;
        }
}
这样吧IO口编号线性映射一下,代码就简化很多了,可维护性也增强了很多

第二种情况,有的IO不在同一个寄存器上。如下图:
我使用了P0口上的1,7和P2口的2和5四个IO口,作为输出,编号分别为1,2,3,4
P01         P04      P07
   |      |       |         |
-----------------------------------------
|                MCU               |
|______________________|
   |         |         |      |
P22      P25      P27   P29

通常我们会这样写:void RelayOpen(int rid)
{
        if(rid==1)
        {
                P0|=(1<<1);
        }
        else if(rid==2)
        {
                P0|=(1<<7);
        }
        else if(rid==3)
        {
                P2|=(1<<2);
        }
        else if(rid==4)
        {
                P2|=(1<<5);
        }
}那由如何简化这段代码呢??
后面的跟上。。。。。。。


NJ8888 发表于 2013-1-15 22:20:27

m3能将端口的位映射到专用地址,操作时不影响其他位

whatcanitbe 发表于 2013-1-15 22:34:24

这个基本上很难

而且不简化可读性更强,可移植性强些

zhouwenjing 发表于 2013-1-16 09:17:25

whatcanitbe 发表于 2013-1-15 22:34 static/image/common/back.gif
这个基本上很难

而且不简化可读性更强,可移植性强些

1、第二个问题也是很容易简化的
2、普通写法是很直观,但是可移植性不见得强哦,简化后的代码,如果使用宏定义的话,基本上只需配置几个参数就OK了。

zhouwenjing 发表于 2013-1-16 09:18:40

NJ8888 发表于 2013-1-15 22:20 static/image/common/back.gif
m3能将端口的位映射到专用地址,操作时不影响其他位

有吗,我怎么没有看到过呢??
能否截个图看看

kevinstar888 发表于 2013-1-16 09:28:23

const INT8U RELAY_IO_MAP[]={1<<1,1<<7,1<<2,1<<5};
void RelayOpen(int rid)
{
      if((rid<3)&&(rid>0))
      {
                P0|=RELAY_IO_MAP;
      }
       else
      {
      P2|=RELAY_IO_MAP;
      }
}
根据楼主的思路,照抄了一份

zhouwenjing 发表于 2013-1-16 09:52:55

本帖最后由 zhouwenjing 于 2013-1-16 11:09 编辑

kevinstar888 发表于 2013-1-16 09:28 static/image/common/back.gif
根据楼主的思路,照抄了一份

这样做,也是可以的,但是局限性很大哦,这可不是我的思路,我的思路在下面。
进一步考虑的话,可以吧P0口和P2也采用查表方式:
把端口地址存放到一个数组里面
const INT8U RELAY_IO_MAP[]={1<<1,1<<7,1<<2,1<<5};

const INT8U PORT_MAP[]={ADDR_P0,ADDR_P0,ADDR_P2,ADDR_P2};
#define RELAY_COUNT (sizeof(RELAY_IO_MAP)/sizeof(*RELAY_IO_MAP))


void RelayOpen(int rid)
{
      if((rid<=RELAY_COUNT)&&(rid>0))
      {
                *((INT8U *)PORT_MAP)|=RELAY_IO_MAP;
      }
}

NJ8888 发表于 2013-1-16 10:26:27

本帖最后由 NJ8888 于 2013-1-16 10:27 编辑

zhouwenjing 发表于 2013-1-16 09:18 static/image/common/back.gif
有吗,我怎么没有看到过呢??
能否截个图看看

你用bit band stm32上网找


例如点亮LED

// 使用STM32库
   GPIO_ResetBits(GPIOC, GPIO_Pin_4); //关LED5
   GPIO_SetBits(GPIOC, GPIO_Pin_7);   //开LED2

// 一般读操作
    STM32_Gpioc_Regs->bsrr.bit.BR4 =1;// 1:清除对应的ODRy位为0
    STM32_Gpioc_Regs->bsrr.bit.BS7 =1;// 1:设置对应的ODRy位为1

//如果使用 位带别名区操作
STM32_BB_Gpioc_Regs->BSRR.BR =1;// 1:清除对应的ODRy位为0
STM32_BB_Gpioc_Regs->BSRR.BS =1;// 1:设置对应的ODRy位为1

代码比STM32库 高效 十倍 !

whatcanitbe 发表于 2013-1-16 20:58:32

zhouwenjing 发表于 2013-1-16 09:52 static/image/common/back.gif
这样做,也是可以的,但是局限性很大哦,这可不是我的思路,我的思路在下面。
进一步考虑的话,可以吧P0 ...

如果我需要17个输出23个输入

这样写有可能写错

如果真要这样写还不如写成而为数组
至少可读性得到保证了

但是占空间

zhouwenjing 发表于 2013-1-16 22:25:56

难到普通写法就不要空间了吗

zhouwenjing 发表于 2013-1-16 22:27:57

whatcanitbe 发表于 2013-1-16 20:58:32 static/image/common/back.gif

如果我需要17个输出23个输入

这样写有可能写错

如果真要这样写还不如写成而为数组
至少可读性得到保证了

但是占空间

如果你写程序不细心,怎么写都会有错,
页: [1]
查看完整版本: IO口线性映射的用法