STM32基于寄存器编程

news2024/12/29 10:44:27

在51中让一个引脚输出高低电平只需要一个步骤,而在32中至少需要三个步骤。

  1. 开启对应GPIO的时钟
  2. 配置对应IO口
  3. 设置IO口

本文将一步步进阶的讲解,三种寄存器编程的方法。

  1. 使用地址赋值进行配置
  2. 使用ST的宏进行配置
  3. 只控制需要的位(位运算)
    1. 与(&),或(|)
    2. 左移<<,右移>>
  4. 使用ST的宏进行位运算

使用地址赋值进行配置 

第一步:启动对应IO口时钟,这里我们以PA0,PA1,PA8为例。

 从数据手册上可以看出,GPIOA在APB2时间线上,所以启动对应IO口时钟线,就是启动APB2。

如何打开寄存器时钟?

        这里以APB2外设使能寄存器(RCC_APB2ENR) 为例。启动寄存器本质上就是,找到寄存器的地址后赋值。当赋值的时候可以看上图,有0~31,它们从0开始,4个为一组为二进制数组,32个函数组成8个二进制数组,而把每组二进制转化为十六进制,就是赋值的值了。

从上图可得,当我们 区要启动GPIOA的时钟时,位2需要置位成1。

位3位2位1位0
0100

0100的二进制转化十六进制为4,所以等等给RCC_APB2ENR赋值的值为4。 

而从第一张图我们可以看到RCC_APB2ENR的偏移地址:0x18,其地址=偏移地址+基地址。

打开STM32F10x参考手册里面有一个“存储器映像”里面可以看到其基地址。

 

从上图可以看出我们需要的“复位和时钟控制”基地址为0x4002100。

所以RCC_APB2ENR的地址=0x40021000+0x18。

#include <stm32f10x.h>

int main(void)
{
	//1.开启对应GPIO的时钟
	*(uint32_t*)(0x40021000+0x18)=4;
	//2.配置对应IO口
	//3.设置IO口
}

右边的*是强制类型转换,左边的*是声明指针。

        从位0开始看,MODE0和CNF0为一组,控制GPIO0,那具体是GPIOA还是B还是其他的,就要看配置是GPIOx_CRL的x是什么了,可能是A,B或者其他的。CPIOx_CRL只能控制0-7寄存器,所以被叫做端口配置低寄存器。GPIOx_CRL控制8-15寄存器,所以被称为端口配置高寄存器。

         配置PA0,为输出模式所以MODE0=11,CNF0=00,00为通用推挽输出模式,可以去搜一下GPIO的八种工作模式。所以现在GPIOA_CRL=3,这里注意如果此时我们还是按上面的(unit32_t*)去强制转换的话3可能机会变成0x00000003,这就不对了,因为其他口的模式全部都被配置为00了,正常情况下应该是要保留的。后续会写到,如何保留,这里还是先用地址赋值的方式配置一下PA0。

 

 这里可以看到GPIOA的基地址为0x40010800。同理:

#include <stm32f10x.h>

int main(void)
{
	//1.开启对应GPIO的时钟
	*(uint32_t*)(0x40021000+0x18)=4;
	//2.配置对应IO口
	*(uint32_t*)(0x40010800+0x00)=3;
	//3.设置IO口
}

 这里把PA0设置0,其他PA设置为1,即15~0为1111 1111 1111 1110,转化为十六进制即为fffe。

#include <stm32f10x.h>

int main(void)
{
	//1.开启对应GPIO的时钟
	*(uint32_t*)(0x40021000+0x18)=4;
	//2.配置对应IO口
	*(uint32_t*)(0x40010800+0x00)=3;
	//3.设置IO口
	*(uint32_t*)(0x40010800+0x0C)=0xfffe;
}

使用ST的宏进行配置

这里以RCC(Reset Clock Controller)为例。

通过右击RCC,转到定义。

 RCC_TypeDef一看就是一个结构体。RCC_BASE和结构体我们都打开看一下。

 一层一层打开后发现,就是一个大的地址,一点点通过分块,定位到小的地址。

        在刚才启动GPIO口的时钟就是这样的。

PERIPH_BASE=0x40000000,

APB2PERIPH_BASE(PERIPH_BASE+0x20000),

RCC_BASE=(APB2PERIPH_BASE+0x1000);

这样一计算,我们就可以得到基地址=0x40000000+0x200000+0x1000=0x40021000

        结构体的第一个成员的地址和结构体的地址是一样的。所以CR的地址就是结构体的地址。而结构体又有一个特征,结构体的成员的地址是连续的。假设CR=0,则CFGR=4;明明是连续的为什么CFGR不等于1呢?因为这里是uint32_t,4个字节。所以CIR=8,以此类推APB2ENR=24。

	//1.开启对应GPIO的时钟
	*(uint32_t*)(0x40021000+0x18)=4;

        可是为什么这里是0x18呢?因为这个是十六进制。十进制的24转化成十六进制就是18。

所以我们可以这样写程序。

	RCC->APB2ENR=4;

        两个代码是一模一样的。下面这种可读性也很好。

        同理GPIOA的配置也是一样的。

         所以代码就可以换成下面这种。

	//1.开启对应GPIO的时钟
	*(uint32_t*)(0x40021000+0x18)=4;
	//2.配置对应IO口
	*(uint32_t*)(0x40010800+0x00)=3;
	//3.设置IO口
	*(uint32_t*)(0x40010800+0x0C)=0xfffe;

	RCC->APB2ENR=4;
	GPIOA->CRL=3;
	GPIOA->ODR=0xfffe;

只控制需要的位(位运算)

与(&),或(|)

RCC->APB2ENR = (RCC->APB2ENR+4); 
RCC->APB2ENR |=4;
	//1.开启对应GPIO的时钟
	*(uint32_t*)(0x40021000+0x18)=4;
	//2.配置对应IO口
	*(uint32_t*)(0x40010800+0x00)=3;
	//3.设置IO口
	*(uint32_t*)(0x40010800+0x0C)=0xfffe;

	RCC->APB2ENR=4;
	GPIOA->CRL=3;
	GPIOA->ODR=0xfffe;

	RCC->APB2ENR |=4;
//这四步就等于GPIOA->CRL = 3;一步
	GPIOA->CRL |=1;
    GPIOA->CRL |=2;
	GPIOA->CRL &=~4;
    GPIOA->CRL &=~8;
//
    GPIOA->ODR &=~1;

         上下两个代码是一样的。建议写下面那个,这样改参数的时候就不会改到其他东西。

1001=9

原式1010
| 91011
& 91000

        也就是说,如果你先把某一位写1 那就或(|)一下,想写0你就取反后与(&)一下。

        在以后可能会遇到更改GPIO的情况,建议先把你想编写的位置清零其余位置不变,再去编写,不仅可以让代码更加直观,也能减少错误,而且不用像上面那种一步要分为四步。

例如:

#define SDA_OUT()		{GPIOB->CRL &= 0x0FFFFFFF; GPIOB->CRL |= 0x30000000;}
#define SDA_IN()		{GPIOB->CRL &= 0x0FFFFFFF; GPIOB->CRL |= 0x40000000;}

        当GPIOB_CRL&0x0FFFFFFF时,因为与(&)必须都为 1才能是1,所以前面0的位置位15,14,13,12被全部清零了,然后再去通过或(|)更改CRL。

左移(<<),右移(>>)

	RCC->APB2ENR |= 1<<2;
	GPIOA->CRL |=1<<0;
	GPIOA->CRL |=1<<1;
	GPIOA->CRL &=~(1<<2);
	GPIOA->CRL &=~(1<<3);
	GPIOA->ODR &=~(1<<0);

这种就非常直观了,只需要对着操作手册,改哪就位移哪,1用(|),0用(&)。

        上面几种,已经非常方便了,但是如果不看数据手册,根本看不出来改了什么。所以就有更好的一种方式,不仅更改了配置,还能一样看出来改了什么。所以我们就可以用下面这个方法。

使用ST的宏进行位运算

	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
	GPIOA->CRL |= GPIO_CRL_MODE0_0;
	GPIOA->CRL |= GPIO_CRL_MODE0_1;
//也可以放一起GPIOA->CRL |=(GPIO_CRL_MODE0_0|GPIO_CRL_MODE0_1)
	GPIOA->ODR &=~GPIO_CRL_CNF0_0;
	GPIOA->ODR &=~GPIO_CRL_CNF0_1;
	GPIOA->ODR &=~GPIO_ODR_ODR0;

 举个例子:

GPIOA->CRL |= GPIO_CRL_MODE0_0;

控制GPIOA_CRL的mode0中的0,(|)则表示将其置1。

我们转到定义看一下

可以看出方法4和方法3其实是一样的,只不过方法4是ST已经帮我们定义好了,我们直接用就可以了。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1462936.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无/自监督去噪(2)——Noise2Noise (N2N) 理论分析(从损失函数入手)

目录 读前须知1. 前置知识——L1和L2 loss的特性2. additive Gaussian noise (spatial independent noise), L 2 L_2 L2​首杀3. brown Gaussian noise (spatial dependent noise), L 2 L_2 L2​双杀4. blind text removal, L 2 L_2 L2​导致结果偏灰, L 1 L_1 L1​前来破局…

刚开的抖店怎样推广?找主播带货,积累资源/渠道,拉动自然流量成交

我是王路飞。 2024年&#xff0c;依旧有很多人想入局抖音小店。 刚复工没几天&#xff0c;我就已经收到好多粉丝朋友的私信了&#xff0c;纷纷表示自己已经开通了抖店了&#xff0c;但是不会运营&#xff0c;现在新店应该怎样进行推广呢&#xff1f; 这篇内容就给你们详细说…

交换瓶子【第七届】【省赛】【A组】

题目描述 有N个瓶子&#xff0c;编号 1 ~ N&#xff0c;放在架子上。 比如有5个瓶子&#xff1a; 2 1 3 5 4 要求每次拿起2个瓶子&#xff0c;交换它们的位置。 经过若干次后&#xff0c;使得瓶子的序号为&#xff1a; 1 2 3 4 5 对于这么简单的情况&#xff0c;显然&#…

stm32——hal库学习笔记(DAC)

这里写目录标题 一、DAC简介&#xff08;了解&#xff09;1.1&#xff0c;什么是DAC&#xff1f;1.2&#xff0c;DAC的特性参数1.3&#xff0c;STM32各系列DAC的主要特性 二、DAC工作原理&#xff08;掌握&#xff09;2.1&#xff0c;DAC框图简介&#xff08;F1&#xff09;2.2…

用结构减法比较平面上4点结构的顺序

( A, B )---6*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有6个节点&#xff0c;AB训练集各由6张二值化的图片组成&#xff0c;A有4个点&#xff0c;B全是0.收敛误差7e-4&#xff0c;收敛199次&#xff0c;统计迭代次数平均值并排序。 如果行和列自由变换&#xff0c;迭代次数不…

英伟达推出免训练,可生成连贯图片的文生图模型

目前&#xff0c;多数文生图模型皆使用的是随机采样模式&#xff0c;使得每次生成的图像效果皆不同&#xff0c;在生成连贯的图像方面非常差。 例如&#xff0c;想通过AI生成一套图像连环画&#xff0c;即便使用同类的提示词也很难实现。虽然DALLE 3和Midjourney可以对图像实现…

【UI自动化】使用poco框架进行元素唯一定位

直接选择&#xff1a; 1.poco(text买入).click() 2.poco("android.widget.ImageView").click()相对选择、空间选择&#xff1a; 3.poco(text/name).parent().child()[0].click()正则表达式&#xff1a; 4.listpoco(textMatches".*ETF")今天主要想记录下…

门控时钟基础知识

什么是门控时钟 RTL中的门控时钟 通常情况下&#xff0c;时钟树由大量的缓冲器和反相器组成&#xff0c;时钟信号为设计中翻转率最高的信号&#xff0c;时钟树的功耗可能高达整个设计功耗40%。 加入门控时钟电路后&#xff0c;由于减少了时钟树的翻转&#xff0c;节省了翻转功…

windows下采用 nginx配置websocket支持wss流程

第一步、安装OpenSSL &#xff08;1&#xff09;下载OpenSSL软件包 地址&#xff1a;https://slproweb.com/products/Win32OpenSSL.html OpenSSL版本说明&#xff1a; Win64 OpenSSL v1.1.1wLight&#xff0c;安装Win64 OpenSSL v1.1.1w最常用的软件包 Win64 OpenSSL v1.1…

真实的数据如何获取

数据 在信息过载的互联网信息中挖掘有价值的信息是非常难的。 我自己退一步&#xff0c;要想寻求真实的信息也是非常难的。 那么关于个人博客具体浏览量的真实信息到底如何呢&#xff1f; 请看下图&#xff1a; 真相残酷&#xff0c;现实骨感。 核心 如果要抛开自欺欺人&a…

第二证券:5天骤降14!转融券市场再降温

转融券存量在快速下降。 到2月21日&#xff0c;转融券的存量股数为50.36亿股&#xff0c;近5个交易日内下降超20%。券商两融人士向券商我国记者表明&#xff0c;2月6日&#xff0c;证监会表明暂停转融券新增规划&#xff0c;存量逐渐了断&#xff0c;从目前的数据来看&#xf…

[corCTF 2022] CoRJail: From Null Byte Overflow To Docker Escape

前言 题目来源&#xff1a;竞赛官网 – 建议这里下载&#xff0c;文件系统/带符号的 vmlinux 给了 参考 [corCTF 2022] CoRJail: From Null Byte Overflow To Docker Escape Exploiting poll_list Objects In The Linux Kernel – 原作者文章&#xff0c;poll_list 利用方式…

7 数据迁移至达梦数据库

无论使用哪种解决方案很大可能性都需要进行数据迁移&#xff0c;即将旧的非 达梦数据库的数据迁移到达梦数据库。 我们要把 Nacos 的数据或者 SQL 语句迁移到达梦数据库。借助 DM 数据迁移工具 &#xff0c;完成 Nacos 配置数据表迁移到达梦数据库。

ros自定义action记录

文章目录 自定义action1. 定义action文件2. 修改 package.xml3. 修改 CMakeLists.txt4. 运行 catkin build5. simple_action_server.py6. simple_action_client.py 测试 自定义action ros 版本&#xff1a;kinetic 自定义test包的文件结构如下 |-- test | |-- CMakeLists.t…

【9-1】实验——Neo4j实战操作

目录 一、Neo4j操作——CQL 1、常用CQL命令 2.常用CQL函数 3.图数据的形式 二、实战代码1.create命令 2. MATCH命令 三、使用neo4j工具导入知识图谱 1、工具&#xff1a;neo4j-admin 2、图谱导入&#xff1a; 3、更新图谱&#xff1a; 一、Neo4j操作——CQL 1、常用…

RMAN备份与恢复

文章目录 一、RMAN介绍二、全量备份三、增量备份0级备份1级增量备份累积性差量备份总结 四、压缩备份压缩备份介绍压缩备份操作压缩备份优缺点 五、异常恢复1、恢复前的准备2、恢复数据库 六、RMAN相关参数 一、RMAN介绍 RMAN&#xff08;Recovery Manager&#xff09;是Oracl…

啤酒:精酿啤酒与炸鸡的香脆搭配

炸鸡与啤酒&#xff0c;这对美食界的黄金搭档&#xff0c;早已成为了人们心目中的经典。而当Fendi Club啤酒遇上炸鸡&#xff0c;一场味觉的狂欢就此展开。 Fendi Club啤酒&#xff0c;以其醇厚的口感和淡淡的麦芽香气而著称。这款啤酒在酿造过程中采用了特别的工艺&#xff0c…

Android加载富文本

直接用webview加载&#xff1a; package com.example.testcsdnproject;import androidx.appcompat.app.AppCompatActivity;import android.annotation.SuppressLint; import android.graphics.Color; import android.os.Bundle; import android.util.Log; import android.webk…

模型转换案例学习:等效替换不支持算子

文章介绍 Qualcomm Neural Processing SDK &#xff08;以下简称SNPE&#xff09;支持Caffe、ONNX、PyTorch和TensorFlow等不同ML框架的算子。对于某些特定的不支持的算子&#xff0c;我们介绍一种算子等效替换的方法来完成模型转换。本案例来源于https://github.com/quic/qidk…

js谐音梗创意小游戏《望子成龙》

&#x1f33b; 前言 龙年到来&#xff0c;祥瑞满天。愿您如龙般矫健&#xff0c;事业腾飞&#xff1b;如龙鳞闪耀&#xff0c;生活美满。祝您龙年大吉&#xff0c;万事如意&#xff01; 龙年伊始&#xff0c;我给各位设计了一款原创的小游戏&#xff0c;话不多说&#xff0c;直…