搜索
bottom↓
回复: 10

IO口线性映射的用法

[复制链接]

出0入0汤圆

发表于 2013-1-15 22:15:40 | 显示全部楼层 |阅读模式
本帖最后由 zhouwenjing 于 2013-1-16 09:53 编辑

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

如果按一般的操作,代码该是如下写:
  1. void RelayOpen(int rid)
  2. {
  3.         if(rid==1)
  4.         {
  5.                 P0|=(1<<1);
  6.         }
  7.         else if(rid==2)
  8.         {
  9.                 P0|=(1<<4);
  10.         }
  11.         else if(rid==3)
  12.         {
  13.                 P0|=(1<<7);
  14.         }
  15. }
复制代码
但是想一想,如果要控制的IO口很多,这样写是不是过于繁琐呢!
如何简化这段代码呢?其实仔细想一想,这段代码还是很有规律的,除了IO口德编号不一样,其他的都很相似。根据这个规律,我把代码改写成如下的样子

  1. const INT8U RELAY_IO_MAP[]={1<<1,1<<4,1<<7};
  2. void RelayOpen(int rid)
  3. {
  4.         if((rid<=3)&&(rid>0))
  5.         {
  6.                 P0|=RELAY_IO_MAP[rid-1];
  7.         }
  8. }
复制代码
这样吧IO口编号线性映射一下,代码就简化很多了,可维护性也增强了很多

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

通常我们会这样写:
  1. void RelayOpen(int rid)
  2. {
  3.         if(rid==1)
  4.         {
  5.                 P0|=(1<<1);
  6.         }
  7.         else if(rid==2)
  8.         {
  9.                 P0|=(1<<7);
  10.         }
  11.         else if(rid==3)
  12.         {
  13.                 P2|=(1<<2);
  14.         }
  15.         else if(rid==4)
  16.         {
  17.                 P2|=(1<<5);
  18.         }
  19. }
复制代码
那由如何简化这段代码呢??
后面的跟上。。。。。。。


阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出0入0汤圆

发表于 2013-1-15 22:20:27 | 显示全部楼层
m3能将端口的位映射到专用地址,操作时不影响其他位

出100入85汤圆

发表于 2013-1-15 22:34:24 | 显示全部楼层
这个基本上很难

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

出0入0汤圆

 楼主| 发表于 2013-1-16 09:17:25 | 显示全部楼层
whatcanitbe 发表于 2013-1-15 22:34
这个基本上很难

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

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

出0入0汤圆

 楼主| 发表于 2013-1-16 09:18:40 | 显示全部楼层
NJ8888 发表于 2013-1-15 22:20
m3能将端口的位映射到专用地址,操作时不影响其他位

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

出0入0汤圆

发表于 2013-1-16 09:28:23 | 显示全部楼层
  1. const INT8U RELAY_IO_MAP[]={1<<1,1<<7,1<<2,1<<5};
  2. void RelayOpen(int rid)
  3. {
  4.         if((rid<3)&&(rid>0))
  5.         {
  6.                 P0|=RELAY_IO_MAP[rid-1];
  7.         }
  8.        else
  9.       {
  10.         P2|=RELAY_IO_MAP[rid-1];
  11.       }
  12. }
复制代码
根据楼主的思路,照抄了一份

出0入0汤圆

 楼主| 发表于 2013-1-16 09:52:55 | 显示全部楼层
本帖最后由 zhouwenjing 于 2013-1-16 11:09 编辑
kevinstar888 发表于 2013-1-16 09:28
根据楼主的思路,照抄了一份


这样做,也是可以的,但是局限性很大哦,这可不是我的思路,我的思路在下面。
进一步考虑的话,可以吧P0口和P2也采用查表方式:
把端口地址存放到一个数组里面

  1. const INT8U RELAY_IO_MAP[]={1<<1,1<<7,1<<2,1<<5};

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


  4. void RelayOpen(int rid)
  5. {
  6.         if((rid<=RELAY_COUNT)&&(rid>0))
  7.         {
  8.                 *((INT8U *)PORT_MAP[rid-1])|=RELAY_IO_MAP[rid-1];
  9.         }
  10. }
复制代码

出0入0汤圆

发表于 2013-1-16 10:26:27 | 显示全部楼层
本帖最后由 NJ8888 于 2013-1-16 10:27 编辑
zhouwenjing 发表于 2013-1-16 09:18
有吗,我怎么没有看到过呢??
能否截个图看看


你用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[4] =1;// 1:清除对应的ODRy位为0
  STM32_BB_Gpioc_Regs->BSRR.BS[7] =1;// 1:设置对应的ODRy位为1

代码比STM32库 高效 十倍 !

出100入85汤圆

发表于 2013-1-16 20:58:32 | 显示全部楼层
zhouwenjing 发表于 2013-1-16 09:52
这样做,也是可以的,但是局限性很大哦,这可不是我的思路,我的思路在下面。
进一步考虑的话,可以吧P0 ...

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

这样写有可能写错

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

但是占空间

出0入0汤圆

 楼主| 发表于 2013-1-16 22:25:56 来自手机 | 显示全部楼层
难到普通写法就不要空间了吗

出0入0汤圆

 楼主| 发表于 2013-1-16 22:27:57 来自手机 | 显示全部楼层
whatcanitbe 发表于 2013-1-16 20:58:32

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

这样写有可能写错

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

但是占空间

如果你写程序不细心,怎么写都会有错,
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-10-3 04:30

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表