你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32寄存器配置、位操作的一些用法归纳

[复制链接]
mizhinian 发布时间:2019-11-27 23:31
对于STM32芯片的使用,之前一直用库函数来进行配置,最近发现直接配置寄存器有时候好像也挺容易的,而且可读性也不会很差。下面分享关于寄存器配置的一些笔记:

* \  s" a0 E& w9 ?

0 L' e/ ~7 R1 c5 }  h' S一、嵌入式中位操作一些常见用法1、一个32bit数据的位、字节读取操作
(1)获取单字节:
#define GET_LOW_BYTE0(x)    ((x >>  0) & 0x000000ff)    /* 获取第0个字节 */
% S6 {7 F, h4 _7 }% A$ K* f$ ]8 @# K# P#define GET_LOW_BYTE1(x)    ((x >>  8) & 0x000000ff)    /* 获取第1个字节 */
/ G% m1 U$ r. |4 s  \#define GET_LOW_BYTE2(x)    ((x >> 16) & 0x000000ff)    /* 获取第2个字节 */
  F% q; q, I: h! y#define GET_LOW_BYTE3(x)    ((x >> 24) & 0x000000ff)    /* 获取第3个字节 */
示例:
001.png
002.png
(2)获取某一位:
#define GET_BIT(x, bit) ((x & (1 << bit)) >> bit)   /* 获取第bit位 */
示例:
003.png
004.png
3 U6 c2 t/ h% k
2、一个32bit数据的位、字节清零操作
(1)清零某个字节:
#define CLEAR_LOW_BYTE0(x)  (x &= 0xffffff00)   /* 清零第0个字节 */5 r# |6 F* j& B) U1 @" w% ~4 s
#define CLEAR_LOW_BYTE1(x)  (x &= 0xffff00ff)   /* 清零第1个字节 */7 K; {' z. G. Y2 K; Y
#define CLEAR_LOW_BYTE2(x)  (x &= 0xff00ffff)   /* 清零第2个字节 */
9 `$ t' G) e$ |) m: G2 V#define CLEAR_LOW_BYTE3(x)  (x &= 0x00ffffff)   /* 清零第3个字节 */
示例:
005.png
006.png
(2)清零某一位:
#define        CLEAR_BIT(x, bit)        (x &= ~(1 << bit))        /* 清零第bit位 */
示例:
=======007
=======008

/ Z% T- i+ j/ `; X( n, ~1 ]3、一个32bit数据的位、字节置1操作
(1)置某个字节为1:
#define        SET_LOW_BYTE0(x)        (x |= 0x000000ff)        /* 第0个字节置1 */        #define        SET_LOW_BYTE1(x)        (x |= 0x0000ff00)        /* 第1个字节置1 */        #define        SET_LOW_BYTE2(x)        (x |= 0x00ff0000)        /* 第2个字节置1 */        #define        SET_LOW_BYTE3(x)        (x |= 0xff000000)        /* 第3个字节置1 */
示例:
009.png
010.png
(2)置位某一位:
#define        SET_BIT(x, bit)        (x |= (1 << bit))        /* 置位第bit位 */
011.png
012.png

0 c3 j$ f2 i& j& X  Y4、判断某一位或某几位连续位的值
(1)判断某一位的值
举例说明:判断0x68第3位的值。
013.png
014.png
也就是说,要判断第几位的值,if里就左移几位(当然别过头了)。在嵌入式编程中,可通过这样的方式来判断寄存器的状态位是否被置位。
(2)判断某几位连续位的值
/* 获取第[n:m]位的值 */#define BIT_M_TO_N(x, m, n)  ((unsigned int)(x << (31-(n))) >> ((31 - (n)) + (m)))
示例:
015.png
016.png
这是一个查询连续状态位的例子,因为有些情况不止有0、1两种状态,可能会有多种状态,这种情况下就可以用这种方法来取出状态位,再去执行相应操作。
以上是对32bit数据的一些操作进行总结,其它位数的数据类似,可根据需要进行修改。
$ v0 B# F, f( R9 `
二、STM32寄存器配置
STM32有几套固件库,这些固件库函数以函数的形式进行1层或者多层封装(软件开发中很重要的思想之一:分层思想),但是到了最里面的一层就是对寄存器的配置。我们平时都比较喜欢固件库来开发,大概是因为固件库用起来比较简单,用固件库写出来的代码比较容易阅读。最近一段时间一直在配置寄存器,越发地发现使用寄存器来进行一些外设的配置也是很容易懂的。使用寄存器的方式编程无非就是往寄存器的某些位置1、清零以及对寄存器一些状态位进行判断、读取寄存器的内容等。
这些基本操作在上面的例子中已经有介绍,我们依旧以实例来巩固上面的知识点(以STM32F1xx为例):
(1)寄存器配置
看一下GPIO功能的端口输出数据寄存器  (GPIOx_ODR) (x=A..E)  :
017.png
假设我们要让PA10引脚输出高、输出低,可以这么做:
方法一:
GPIOA->ODR |= 1 << 10;      /* PA10输出高(置1操作) */GPIOA->ODR &= ~(1 << 10);  /* PA10输出低(清0操作) */
也可用我们上面的置位、清零的宏定义:
SET_BIT(GPIOA->ODR, 10);    /* PA10输出高(置1操作) */CLEAR_BIT(GPIOA->ODR, 10);  /* PA10输出低(清0操作) */
方法二:
GPIOA->ODR |= (uint16_t)0x0400;   /* PA10输出高(置1操作) */GPIOA->ODR &= ~(uint16_t)0x0400;  /* PA10输出低(清0操作) */
貌似第二种方法更麻烦?还得去细心地去构造一个数据。
但是,其实第二种方法其实是ST推荐我们用的方法,为什么这么说呢?因为ST官方已经把这些我们要用到的值给我们配好了,在stm32f10x.h中:
018.png
这个头文件中存放的就是外设寄存器的一些位配置。
所以我们的方法二等价于:
GPIOA->ODR |= GPIO_ODR_ODR10;   /* PA10输出高(置1操作) */GPIOA->ODR &= ~GPIO_ODR_ODR10;  /* PA10输出低(清0操作) */
两种方法都是很好的方法,但方法一似乎更好理解。
配置连续几位的方法也是一样的,就不介绍了。简单介绍配置不连续位的方法,以TIM1的CR1寄存器为例:
019.png
设置CEN位为1、设置CMS[1:0]位为01、设置CKD[1:0]位为10:
TIM1->CR1 |= (0x1 << 1)| (0x1 << 5) |(0x2 << 8);
这是组合的写法。当然,像上面一样拆开来写也是可以的。
(2)判断标志位
以状态寄存器(USART_SR) 为例:
020.png
判断RXNE是否被置位:
/* 数据寄存器非空,RXNE标志置位 */if (USART1->SR & (1 << 5)){        /* 其它代码 */        USART1->SR &= ~(1 << 5);  /* 清零RXNE标志 */}
或者:
/* 数据寄存器非空,RXNE标志置位 */if (USART1->SR & USART_SR_RXNE){        /* 其它代码 */        USART1->SR &= ~USART_SR_RXNE;  /* 清零RXNE标志 */}
END:以上笔记中如有错误,欢迎指出!谢谢

5 x4 ?7 a" E$ k" w8 Z7 ]: x
021.png
022.png
1 收藏 6 评论8 发布时间:2019-11-27 23:31

举报

8个回答
aiherong 回答时间:2019-11-28 03:31:11
对位操作的提取不能单靠左右移位(运行速度会有影响),有时就得与或非运算,另外记下常用外设接口地址
7 L5 }; M, e/ w9 U, `对你决定走这条路有好处
李康1202 回答时间:2019-11-28 09:17:57
每次写寄存器都是翻着手册去写的
mizhinian 回答时间:2019-11-28 09:58:18
aiherong 发表于 2019-11-28 03:31$ ~1 M' L' I) j7 P, f( F
对位操作的提取不能单靠左右移位(运行速度会有影响),有时就得与或非运算,另外记下常用外设接口地址
5 S! I5 U, O8 w6 `对你 ...

. B- a: g# F, E多谢!受教了
mizhinian 回答时间:2019-11-28 09:58:57
likang1202 发表于 2019-11-28 09:17
. s0 Q% A  \4 J$ y) e每次写寄存器都是翻着手册去写的
( r7 A3 j9 h0 h& m
翻手册是个好习惯呀
子曰好人 回答时间:2019-11-28 10:05:34
楼主这个风格是在mac下写代码,在Windows下编译?
mizhinian 回答时间:2019-11-28 23:56:01
子曰好人 发表于 2019-11-28 10:05
9 @' r9 E0 {) H0 t) K* \" \4 R  |楼主这个风格是在mac下写代码,在Windows下编译?

; x6 |( G# }/ S哈哈 没那么闲  只不过是渲染一下代码  让代码好看些。在这可以渲染代码:http://carbon.now.sh/?bg=rgba(48%2C12%2C66%2C0.88)&t=lucario&wt=none&l=text%2Fx-csrc&ds=true&dsyoff=20px&dsblur=68px&wc=true&wa=true&pv=56px&ph=56px&ln=false&fm=Hack&fs=14px&lh=133%25&si=false&es=2x&wm=false
子曰好人 回答时间:2019-11-29 09:02:34
mizhinian 发表于 2019-11-28 23:56
+ N: L; ^: V$ T( M& p哈哈 没那么闲  只不过是渲染一下代码  让代码好看些。在这可以渲染代码:http://carbon.now.sh/?bg=rgb ...
* U3 s! o# v9 Z# I2 @: n
好吧,确实挺好看的,楼主有心了
lcz17569507 回答时间:2019-12-6 08:54:14
总结到位!支持!

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版