OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 20881|回复: 17

分享个小技巧,STM32快速操作8位IO(我的观点错了,见10楼)

[复制链接]

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
发表于 2012-5-4 13:51:05 | 显示全部楼层 |阅读模式
比较忙,就忽忽帖上我的测试代码,和反汇编结果,相信大家应该看得懂。

typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  union{
          struct{
                  __IO uint8_t LL;
                  __IO uint8_t LH;
          }odr;
          __IO uint32_t ODR; 
  }ODR;

  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef2;

这两条是测试代码:

        GPIOA->ODR = 0xaa55;
        
        ((GPIO_TypeDef2*)GPIOA)->ODR.odr.LL = 0xaa;

以下是反汇编结果,效率很高,和以往的32位机操作8位很慢之说截然相反哦,

    62:         GPIOA->ODR = 0xaa55;
0800019C    0x2055F64A    MOVW  R0 , #0x0000AA55
080001A0    0x49B3        LDR  R1 , [PC , #0x000002CC]
080001A2    0x6008        STR  R0 , [R1 , #0x00000000]



    64:         ((GPIO_TypeDef2*)GPIOA)->ODR.odr.LL = 0xaa;
080001A4    0x20AA        MOVS  R0 , #0x000000AA
080001A6    0x7008        STRB  R0 , [R1 , #0x00000000]

作为测试,代码有点古怪,而且不规范,见谅哈
https://github.com/roxma
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

27

主题

274

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
472
金钱
472
注册时间
2011-11-2
在线时间
11 小时
发表于 2012-5-5 17:16:54 | 显示全部楼层
联合体用的太棒了,我还从没用过这个UNION。
说一下我的理解了一半半,期待准确解说。
联合体只能表达一个,好像是共用一个地址。那么是不是结果odr与__IO uint32_t ODR共用一个地址
那么要表达__IO uint32_t ODR前8口只要对其前面内存操作 后8口也是同样道理。
还有大端小端形式?
然后是这个UINT32是不是4个字节  那么char型应该只占用一个字节  这个有点犯迷糊。
期待楼主详细解说。
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-5-5 18:18:25 | 显示全部楼层
回复【2楼】 zenghi :
---------------------------------
嗯,你对联合体的理解没错,

而 uint32_t 是标准库里的定义,32位无符号整数,32位也就是4个字节,
因为STM32是小端字节序的,如果假定
假定一个32位变量的首地址是 0x20000000,这个变量的值是(0x01020304),那个这个变量的各个字节在内存中的分布这样的,
(地址:0x20000000)低16位的低8位, 值为 0x04
(地址:
0x20000001)低16位的高8位, 值为 0x03
(地址:0x20000002)高16位的低8位, 值为 0x02
(地址:0x20000003)高16位的高8位, 值为 0x01
大端的变量的内部的字节顺序的分布正好相反。
所谓大小端,只不过是CPU对内存中的变量的解释罢了。CPU存取变量,都按照它自己对变量的解释来进行存取。

另外,C++的标准是这样说的:(参考http://en.cppreference.com/w/cpp/language/types) (不知上哪找C的标准)
ejaVuSerif, 'DejaVu Serif', verdana, sans-serif;font-size:13px;line-height:19px;">1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long long).
char 是只占一个字节的

因为C语言的基本数据类型(short, int, long int 等...)的大小是和平台和编译器有关的,
而C的标准库里定义的 uint32_t, uint16_t, uint8_t 就是为了保证平台无关性。ejaVuSerif, 'DejaVu Serif', verdana, sans-serif;font-size:13px;line-height:19px;">

联合体确实用的很少,也不是必须用的联合体才能完成这个功能的,利用指针强制转换也可以完成同样的功能的。

https://github.com/roxma
回复 支持 反对

使用道具 举报

27

主题

274

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
472
金钱
472
注册时间
2011-11-2
在线时间
11 小时
发表于 2012-5-5 18:55:57 | 显示全部楼层
回复【3楼】Pony279:
---------------------------------
很详细,专研的很深,辛苦了。
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-5-5 21:18:18 | 显示全部楼层
C++版本的测试代码可以看这个帖子的48偻

http://www.openedv.com/posts/list/3210.htm?fromAll=0
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-5-15 22:50:00 | 显示全部楼层
再回来做一点说明,
我的这份代码和C++版本的代码都使用了结构体,
而且默认结构体成员变量在内存里面是<紧凑地>顺序排列的,
但是有时候不是这样的,这也是我最近才知道的,有时候是需要注意这些问题的,
可以搜索 padding in struct 
也可以参考我的这个帖子,http://www.keil.com/forum/20856/#msg108669,呵呵,被教育了,所以我就不解释了
https://github.com/roxma
回复 支持 反对

使用道具 举报

12

主题

216

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
313
金钱
313
注册时间
2011-4-7
在线时间
3 小时
发表于 2012-5-16 00:15:16 | 显示全部楼层
不太懂mark
回复 支持 反对

使用道具 举报

0

主题

2

帖子

0

精华

新手上路

积分
31
金钱
31
注册时间
2012-6-6
在线时间
1 小时
发表于 2012-6-6 09:01:49 | 显示全部楼层
回复【楼主位】Pony279:
---------------------------------
不能这么使用,STM32 的IO口必须按16位以上操作,否则高8位和低8位会被设置成一样的值!!
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-6-7 10:07:21 | 显示全部楼层
回复【8楼】zhixian:
---------------------------------
请问你做过实验没? 你知道汇编代码里的 STRB 是什么意思吗?
https://github.com/roxma
回复 支持 反对

使用道具 举报

23

主题

143

帖子

1

精华

高级会员

Rank: 4

积分
933
金钱
933
注册时间
2012-4-23
在线时间
68 小时
发表于 2012-7-11 21:30:05 | 显示全部楼层
回复【楼主位】Pony279:
---------------------------------
超出我理解范围了
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-7-19 21:59:11 | 显示全部楼层
今天看手册的时候发现这句, 
9.2 GPIO registers
Refer to Section 2.1 on page 46for a list of abbreviations used in register descriptions.
The peripheral registers have to be accessed by words (32-bit).

然后我又测试了一遍,发现 7 楼说的是对的,
之前只做过简单的流水灯测试,以为就可以了,
https://github.com/roxma
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-7-19 22:03:14 | 显示全部楼层
硬件上不支持,就没办法了,终究还是不能像51那样灵活操作8位的IO口啊。。。
https://github.com/roxma
回复 支持 反对

使用道具 举报

头像被屏蔽

93

主题

160

帖子

0

精华

禁止发言

积分
457
金钱
457
注册时间
2012-4-3
在线时间
7 小时
发表于 2012-7-20 02:00:55 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-7-20 11:21:19 | 显示全部楼层
回复【13楼】noip0726:
---------------------------------
当然可以,但是那对于未定的值,还需要自己合成,会被拆解为多条指令,所以从指令上来看这一点是比不过8位机的
https://github.com/roxma
回复 支持 反对

使用道具 举报

7

主题

33

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
231
金钱
231
注册时间
2012-7-11
在线时间
0 小时
发表于 2012-7-20 17:03:42 | 显示全部楼层
好像也可以通定义结构体进行bit位定义~
稍稍可以节省点内存哈~
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2012-7-20 17:48:51 | 显示全部楼层
回复【15楼】liash:
---------------------------------
硬件上不支持,怎么定义都是白搭,位定义的操作被翻译成汇编结果还是read-modify-write
https://github.com/roxma
回复 支持 反对

使用道具 举报

头像被屏蔽

6168

主题

7036

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
19705
金钱
19705
注册时间
2012-12-27
在线时间
25 小时
发表于 2013-6-18 21:28:04 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

36

主题

1105

帖子

5

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
2201
金钱
2201
注册时间
2012-2-8
在线时间
35 小时
 楼主| 发表于 2013-6-19 11:39:13 | 显示全部楼层
回复【17楼】xouou_53320:
---------------------------------
是的,用BSRR是可以的,BSRR的高16位和低16位是有优先级的,好像是 reset 位优先级比较低,所以要对低8端口位赋值为value的时候,可以使用一个类似 <0x00,0xff, 0x00, value>这样的32位数写入BSRR,来给8位端口赋值(BSRR具体格式忘了,现在电脑里没有文档)
https://github.com/roxma
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-18 20:51

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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