历史上的今天
返回首页

历史上的今天

今天是:2024年08月26日(星期一)

正在发生

2018年08月26日 | STM32寄存器操作简单介绍

2018-08-26 来源:eefocus

STM32单片机可以使用库函数进行操作,再加上现在越来越强大的MDK ARM编译环境,使用库函数开发简直是不二的选择,但是工具越来越强大的同时意味着对编程人员降低了要求,在很大程度上降低了准入门槛,我们因此高兴吗?我倒是觉得这很像温水煮青蛙,所以库函数固然好用却也不应该抛弃最初的做法——寄存器操作。

先从启动文件开始介绍:这里介绍比较常见的一种启动方式(从内部的的FLASH启动,至于另外两个是否常用本人不甚了解),在启动代码了首先对栈和堆的大小进行定义,并在代码的起始处建立中断向量表,其第一个表项是栈顶(__initial_sp )地址,第二个表项是复位中断服务( Reset_Handler )入口地址。然后在复位中断服务程序中跳转C/C++标准实时库的__main函数,完成用户堆栈等的初始化后,跳转.c文件中的main函数开始执行C程序。STM32从内部FLASH启动,中断向量表起始地位为0x8000000,则栈顶地址存放于0x8000000处,而复位中断服务入口地址存放于0x8000004处。当STM32遇到复位信号后,则从0x80000004处取出复位中断服务入口地址,继而执行复位中断服务程序,然后跳转__main函数,完成这些事情在才始进入最耗费我们精力的main函数。以上内容是否重要,因项目而异,不过栈大小和堆大小可能会需要改动的,如果有机会学习cortex-A系列的SoC,比如三星的S5PV210之类一定会接触到启动文件(bootloader)的。

一个插曲,就是systeminit ,这个函数在官方提供的3.5版本的固件库的启动文件里是在main函数之前运行的,也就是说在官方给的库函数里面是有这个函数的,并且里面的内容是官方给出的,目的是设置系统的频率,一般是72M,但是我希望直接操作寄存器一定要写这个函数吗,或者一定要在main函数之前执行吗,答案是不一定,一个简单粗暴的办法就是直接写一个空的systeminit函数,写一个空的并不建议因为毕竟要调整这个SoC各个总线的频率,不如添加上。直接在启动文件里删去关于systeminit的代码也是可以的,在之后的操作里面写main函数的时候先调用systeminit函数,自己设置频率。

进入主题,说说寄存器,从官方给出的存储器映像可以看出各个外设的的基地址,这些基地址在加上相应的偏移量就是我们希望的寄存器的地址,之后修改寄存器的内容就可以,原理就是这样,关键是如何构造好的数据结构对这些寄存器进行操作。下面通过实例介绍三种方法:

实例:让GPIOB0置位,方式推挽输出,思路是1、开GPIOB的时钟 2、设置输出方式 3、端口置位


第一种:直接宏定义精确到各个具体的寄存器。GPIOB开始的地址是0X40010C00,其中端口配置低寄存器(GPIOx_CRL)偏移地址是0x00,这样(0X40010C00+0x00)就是CRL寄存器的地址,使用(long *)(0X40010C00+0x00),将这个地址强制转换成指针类型,在利用*((long *)(0X40010C00+0x00))操作(0X40010C00+0x00)地址里的内容。


#define GPIOB_CRL    (*((long *)(0X40010C00+0x00)))

#define RCC_APB2ENR  (*((long *)(0x40021000+0x18)))

#define GPIOB_ODR    (*((long *)(0X40010C00+0x0C)))

这样就可以像上面的思路操作了。


RCC_APB2ENR|=(1<<3);//开GPIOB的时钟

GPIOB_CRL=3;//设置输出方式

GPIOB_ODR=0XFFFF;//端口置位

这样操作直观,但是需要的宏太多,容易出现问题,稍不留神偏移量写错就前功尽弃了。

第二种:构造结构体,将GPIO的寄存器全部写进结构体,相比上面的方法让编译器帮我们进行计算,减少出错的可能,本来像上面那样体现不出C语言这个工具的强大。首先构造


typedef struct

{

  int CRL;

  int CRH;

  int IDR;

  int ODR;

  int BSRR;

  int BRR;

  int LCKR;

} GPIO_TypeDef;

之后


#define GPIOB ((GPIO_TypeDef*)(0X40010C00))

这样就可以用指针的方式操作GPIOB的各个寄存器了,这里的GPIO_TypeDef类型的数据结构保证操作的寄存器全是GPIO的寄存器不会越界,具体的原因是C语言的问题,这里不做过多的解释,以免跑题。下面按照最开始的操作思路进行:


RCC->APB2ENR|=(1<<3);//开GPIOB的时钟

GPIOB->CRL=3;//设置输出方式

GPIOB->ODR=0XFFFF;//端口置位

显然这种方式借助C语言这个工具和编译器帮我们解决了很多的问题。

第三种方法:查看库文件stm32f10x.h有以下的宏定义


#define PERIPH_BASE           ((uint32_t)0x40000000)

#define APB2PERIPH_BASE       (PERIPH_BASE + 0x10000)

#define GPIOB_BASE            (APB2PERIPH_BASE + 0x0C00)

#define GPIOB               ((GPIO_TypeDef *) GPIOB_BASE)

要知道define定义就是简单的字符串替换,替换之后的结果是


#define GPIOB   ((GPIO_TypeDef *) 0x40000000 + 0x10000 + 0x0C00)

可以看出就是第二种方法里面的


#define GPIOB ((GPIO_TypeDef*)(0X40010C00))

所以既然官方已经帮我们做好了我们为什么不用呢。所以直接包含头文件#include “stm32f10x.h” 就可以了。说到这里似乎又回到了起点,这不是还是使用了官方的库函数吗?但是这和#include 是一样的道理,只是用到了官方已经做好的寄存器名字的定义,以及一种简单的调用寄存器的方法。

使用库函数还是直接操作寄存器更好,以上的例子并没有说明问题,我们看到的只是库函数无外乎是操作寄存器,没有看到的是库函数的函数多级调用,这里不做说明。

最后一句,对于我们使用的人来说一定不要被层层的外包装所迷惑。


推荐阅读

史海拾趣

Gigarams Semiconductor Device Corp公司的发展小趣事
这可能是由于定位力量不够或初始力矩过大导致的。解决方案包括调整定位参数、优化启动策略或增加缓冲装置以减少振动。
Allegro公司的发展小趣事
这可能是由于定位力量不够或初始力矩过大导致的。解决方案包括调整定位参数、优化启动策略或增加缓冲装置以减少振动。
台湾固锝(GD)公司的发展小趣事
避免输入功率过大导致放大器过热。
Ecera Comtek Corp公司的发展小趣事

在快速发展的过程中,Ecera Comtek Corp公司始终关注企业社会责任的践行。公司积极参与各种公益活动,为社会做出积极贡献。例如,在自然灾害发生时,Ecera Comtek Corp公司积极捐赠通信设备,帮助灾区恢复通信联系;在偏远地区,公司还捐建了多所希望小学,为当地的孩子们提供了良好的学习环境。这些公益活动不仅提升了Ecera Comtek Corp公司的品牌形象,也增强了员工的凝聚力和归属感。

Gemmy Electronics Co Ltd公司的发展小趣事
捕鼠器应放置在儿童和宠物无法触及的地方,以免发生意外。
FARNELL公司的发展小趣事

随着业务的不断发展,FARNELL公司开始寻求全球化拓展。公司陆续在欧洲、美洲、亚洲等地设立分公司和办事处,形成了覆盖全球的销售网络。这一过程中,FARNELL公司始终坚持“供货可靠、方便快捷、物超所值”的经营理念,为全球客户提供优质的产品和服务。

问答坊 | AI 解惑

运算放大器稳定性

  作者:Tim Green,德州仪器 Burr-Brown 产品线线性应用工程经理   在写“保持容性负载稳定的六种方法”部分时发生了一件有趣的事情。我们选择了具有“轨至轨”输出的 CMOS 运算放大器并测量了 ROUT,但在高频区域没有环路增益,因而无 ...…

查看全部问答>

向阳1号油耗GPS和普通GPS的区别在哪里

北京向阳天科技有限公司(www.xiangyangtian.com) 是一家专业从事数据传输及全球卫星定位产品(GPS)研发、 应用的专业公司。其产品在全国车辆GPS定位市场上占有一席地位。 公司产品包括车载GPS定位仪、车载GPS导航仪、车辆油耗型GPS定位仪、 ...…

查看全部问答>

关于,电源、地的问题?

是不是LM3SXXXX的电源、地引脚是否必须连接到一起,并在每对上加上旁路电容??可不可以只有部分连接电源,而其它的不连接电源呢??会不会供电不足啊?PS:顺便问下由LM3S1138移植其它型号,要改些什么?工程模板可以直接用1138的吗?…

查看全部问答>

android的g-sensor驱动

请问谁有Freescale MMA7455的android驱动啊,挂在I2C上。有的请发我邮箱tigerhily@163.com 谢谢了…

查看全部问答>

c# 关于rfid读取的问题

我的rfid是能读出RFID卡内的序列号并通过PS/2输出至电脑,相当于自动键盘输号。 我用C#怎么才能实现读取阿? 产品说可用常用的《WORD》、《记事本》等软件记录卡号,为什么读不出来?? …

查看全部问答>

请教各位兄弟,南京福特的工程研究中心怎么样?

如题, 网上看到FORD正在搞SYNC系统,主要是体现更好的的人机交互,包含语音识别,TTS语音合成,触摸等多种交互形式。 周五去要面试一下…

查看全部问答>

STM32F103VBT6也有Y版么?

                                 问了国内某代理商,销售到技术都不清楚这个,真是晕!我要最新的Z版,可是他们却不清楚这些,我发现很多代理商对ST ...…

查看全部问答>

TI例程enet_io用到的CGI函数有谁能介绍吗

以太网中网页控制,enet-io这个例程里用到了SSI和CGI的结合,但是有些函数跟本不是一下子就能理解的,参数调来调去不好理解,有谁能给解释吗?  …

查看全部问答>

LPC800 开发板 I2C 的使能问题。

我把周立功的LPC800例子里面的I2C中的I2C_EEPROM的程序改了一下,还是无法运行,请帮忙看一下。 void I2CInit (void) {     //原始程序用的最适宜做I2C的口,小板上没有        //LPC_IOCON->PIO0_10   ...…

查看全部问答>