找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 363|回复: 4
打印 上一主题 下一主题
收起左侧

关于单片机不同IO口编组程序

[复制链接]
跳转到指定楼层
楼主
ID:1054576 发表于 2024-1-8 21:52 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
请问有没有哪位大神百忙中抽点时间指点一下这一段代码,卡了两天了没搞懂。下面是一段异组非顺序端口编组的程序
本人业余爱好者,半路出家没有系统学习过之前在网上学了一些89c51皮毛做了一些流水灯,4*4矩阵之类的
最近想做个实物矩阵键盘,但是由于之前用的是89c51,然后想着只做一个矩阵键盘带几个LED没必要用那么多引脚的单片机,
就选了个STC15W SOP16的
然后就悲剧了 STC15单组IO最多才6个P1.0-P1.5,4*4键盘要用8个口,跟之前学的0x**就完成扫描的程序不一样,搞了两天就只会分开一个一个口的写代码
虽然也能用,但是这样太修饰了,然后就去网上找了一些资料(这方面的资料超级少),研究后发觉我看不懂代码了(主要是运算符)
单个运算符拿出来可以理解,但是放在一起就搞不懂为什么会有这样的结果。

#define PD ((P2<<3&0x80)|(P2<<4&0x40)|(P3&0x3f)) //P2.4/P2.2


不懂1:宏定义 P2向左移3位跟0x80进行按位与......
       根据运算优先级,这里的位移3位是指P2口低位往高位移3位后的结果是2.2口吗?(P2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7)
        既:P2=0X04(0000 0100) & 0x80(1000 0000) 结果为0x00 (0000 0000) ??
        P2向左移4位跟0x40进行按位与..... .这里的位移4位是指P2口低位往高位移3位后的结果是2.3口吗??
    之后
          P2=0X08(0000 1000) & 0x40(0100 0000)  结果为0x00 (0000 0000) ??
再之后
                   不算P3的情况 按位或结果  0000 0000 | 0000 0000 = 0000 0000   那就跟程序运行的结果就不一样了

void PX(uchar x)
{
        P3&=0xc0;                //低6位清0,P3.6、P3.7不变
        P3|=(x&0x3f);        //P3低6位赋值
        P2&=0xeb;                //P2.4、P2.2清0,其它位不变
        P2|=((x>>3&0x10)|(x>>4&0x04)); //P2.4、P2.2赋值

不懂2:  无字符型变量X 取值范围是 0-255   这里的X移位是怎么移?0 1 2 3 -255  位移3位是2吗?移位后的值是10进制还是2进制或者16进制

}


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:57657 发表于 2024-1-9 10:36 | 只看该作者
十进制是给人类看的,无论任何进制,在单片机都是二进制处理的。
回复

使用道具 举报

板凳
ID:161164 发表于 2024-1-9 11:02 | 只看该作者
不懂1:
位数弄反了
正确顺序:P2.7/6/5/4/3/2/1/0
P24取值放到第7位:
P2<<3 & 0x80 = 0B00010000<<3 & 0x80 = 0B10000000 & 0x80
P22取值放到第6位:
P2<<4 & 0x40 = 0B00000100<<4 & 0x40 = 0B01000000 & 0x40

不懂2:
楼上说了,所有计算都是2进制

不用宏定义改用函数
  1. uchar PD()
  2. {
  3.         u8 dat = 0;
  4.         if(P2&0x10)dat|=0x80;
  5.         if(P2&0x04)dat|=0x40;
  6.         dat|=P3&0x3F;
  7.         return dat;
  8. }
复制代码
回复

使用道具 举报

地板
ID:485350 发表于 2024-1-9 11:02 | 只看该作者
能用最简单易懂的办法做出就可以了,先没必要在意复杂的方式,等你用了几年C之后再研究研究吧
回复

使用道具 举报

5#
ID:1054576 发表于 2024-1-9 18:23 | 只看该作者
lkc8210 发表于 2024-1-9 11:02
不懂1:
位数弄反了
正确顺序:P2.7/6/5/4/3/2/1/0

大致搞明白了,用流水灯正反测试了一下没发现什么问题
我的方向错了
问题1那里是宏定义端口组(就是等于新建一个8位的组),
以原代码为例
我错以为是直接把P2口的2.4 2.2运算出来,然后跟P3口的P3.5-3.0或运算取出要用的io后再调用。
所以我一直以为位移之后的位置是2.4或者2.2,而不是把2.4 2.2的低位移到高位
而实际情况是直接新建一个8位的组,然后把要用的io口运算出来再通过位移调整各个位的io的高低位置再加进这个组。
再一个是位移是0(当前位)开始,我错误当作是1开始

问题2
我是直接理解为把位移的步数转换成2进制直接进行&运算
修改后 我的理解为把宏定义移位到高位的位(2.4 2.2)移位回原来的位并赋值
(不知道有没理解错,毕竟宏定义都的IO组为PD,这里的移位的是P2口,有点小迷惘)

最后是修改后测试代码,我把P2的2.4 2.2改成P1的1.1 1.0(运行没问题,不知道有没有错误)
如有不当,万望指正。

另外函数的那个方法因为没学到dat,暂时没办法测试了 (不过我保存下来了)


  1. #include "RELA.H"
  2. #include"delay.h"

  3. #define MAIN_Fosc  12000000L //定义内部时钟为12MHz
  4. #define uchar unsigned char
  5. void DelayXms(unsigned int xms);       

  6. #define PD ((P1<<6&0x80)|(P1<<6&0x40)|(P3&0x3f))//宏定义IO口并排列顺序           
  7. /*********************************************************************************
  8. * P1.1/P1.0 定义IO组并排列顺序从高到低位依次为P1.1 1.0 P3.5 3.4 3.3 3.2 3.1 3.0  *
  9. * 把想编组的IO口移动到想要的IO口组的位置重并排列顺序                             *
  10. * (P1<<6&0x80)相当于把P1.1的口移动到编组的第6位,也就是1000 0000                 *
  11. * (P1<<6&0x40)相当于把P1.0的口移动到编组的第6位,也就是0100 0000                 *
  12. **********************************************************************************/

  13. void PX(uchar x)
  14. {
  15.         P3&=0xc0;                //低6位清0,P3.6、P3.7不变
  16.         P3|=(x&0x3f);        //P3低6位赋值
  17.         P1&=0xfc;                //P1.1、P1.0清0,其它位不变
  18.         P1|=((x>>6&0x02)|(x>>6&0x01));//P1.1、P1.0赋值,X的取值范围 0-255
  19.         }
  20. /**************************************************************************************       
  21.         //(x>>6&0x02)等于把宏定义的第7位右移6位0000 0010&0x02运算后等P1口的P1.1位置并赋值
  22.         //(x>>6&0x01)等于宏定义后的第6位右移6位0000 0001&0x10运算后等P1口的P1.0位置并赋值
  23. ***************************************************************************************/

  24. /***************************************************************************************
  25. uchar PD()
  26. {
  27.         u8 dat = 0;
  28.         if(P2&0x10)dat|=0x80;
  29.         if(P2&0x04)dat|=0x40;
  30.         dat|=P3&0x3F;
  31.         return dat;
  32. }
  33. //上函数为不用宏定义该用函数方法(未测试)
  34. ******************************************************************************************/       
  35. void main()
  36. {  
  37.         unsigned char temp = 0x80;
  38.         unsigned char i;
  39.         while(1)
  40.         {
  41.                 for(i=0;i<8;i++)
  42.                 {
  43.       PX(~(temp>>i));  
  44.                   DelayXms(3000);
  45.                 }
  46.   }
  47. }
复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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