野火霸天虎 STM32F407 学习笔记_3 尝试寄存器映射方式点亮 LED 灯

news2024/10/7 10:16:09

新建工程

寄存器方式

要命啊,一看名字我就不想试。寄存器新建不得麻烦死。

哎算了为了学习原理,干了。

我们尝试自己写一个寄存器的库函数来引用。

首先我们需要引用 st 官方启动文件 stmf4xx.s,具体用途后面章节再展开讲解。然后我们自己新建一个 stm32f4xx.h 文件来映射寄存器。不过只是把这个文件包含进项目,编译会报错:

.\Objects\led_reg.axf: Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f40xx.o).

进入启动文件后,可以看到这么一个函数:

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

import 的作用相当于 extern,所以没有找到这个函数的定义,需要我们自己去定义。这就是为什么简单引入了启动文件会报错。

而 __main 是当我们定义了 main() 函数后,编译器会自动链接一些c语言库定义好的函数,用于初始化堆栈并且调用我们的 main().

注意,如果想要生成 __main 函数,必须勾选下面这一项。

image-20231102200243099

野火你讲的是真好啊。我之前草草学了学 stm32 单片机用法,比赛的时候自己想移植代码,改了启动文件也不好使,就是报错。原来是这个原因。

那么我们只需要定义这么一个函数,哪怕内容是空都无所谓。

最终我们定义的初步项目框架如下:

1698926683862

stm32f4xx.h:内容为空,有这么个东西就行。

main.c:

#include "stm32f4xx.h"

int main(){
	while(1){
		
	}
}

void SystemInit(){
	
}

好了,这个程序可以烧录到板子上的。烧录成功之后没有任何反应(因为本来程序也没做什么哈哈),但是这就是一个大进步了。

点灯——51单片机版

51单片机版就是引用 reg51.h 头文件,在其中声明了各个引脚的地址。我们只需要直接给引脚赋值即可。

调用代码:

#include "reg51.h"

#ifdef 0 
void main(){
	PA0=0xFE;
	while(1){}
}
#endif

接下来我们需要定义 LED 灯的寄存器位置。阅读原理图如下:

1698939342199

大致可以看出,板子上的这个 RGB LED 通过三个引脚来控制 RGB 亮度。输出低电平则导通点亮。

具体输出方式是通过 ODR 进行输出。查找 stm32f4xx 中文参考手册可见:

1698940158585

1698940257044

那么我们就要给 0x4002 1400 +14 的地址赋值,让 1<<6 1<<7 1<<8 的位分别赋值为低电平.

int main(){
	 *(unsigned int *)(0x40021400+14)&=~(1<<6); 
	while(1){
		
	}
}

然而这样也不亮。亮就怪了,stm32 寄存器是需要先做初始化配置的。

点灯——stm32 版

首先我们要设置 GPIO 模式。

1698940961543

想点灯 输出高低电平,是 01 通用输出模式。

*(unsigned int *)(0x40021400+0)&=~(3<<(6*2)); 
*(unsigned int *)(0x40021400+0)|=(1<<(6*2)); 

意思是先把 PF6 模式位置为00,然后赋值为01通用输出。

配置完模式之后,还需要配置时钟,stm32 每个外设都需要配置时钟。

前面提到过 GPIO 是在 AHB1.

1699103516061

1699103724261

全部代码如下:

#include "stm32f4xx.h"

int main(){
    //RCC
    *(unsigned int *)(0x40023800+0x30)|=(1<<5); 
    
    //Mode
    *(unsigned int *)(0x40021400+0)&=~(3<<(6*2)); 
    *(unsigned int *)(0x40021400+0)|=(1<<(6*2)); 
    
    
    *(unsigned int *)(0x40021400+0x14)&=~(1<<6); 
    while(1){
		
	}
}

void SystemInit(){
	
}

接下来,我们把这几个地址值提取出来,宏定义映射寄存器。

//stm32f4xx.h
/* 用来存放寄存器映射相关的代码 */
#define RCC_AHB1_ENR    *(unsigned int *)(0x40023800+0x30)
#define GPIOF_MODER     *(unsigned int *)(0x40021400+0)
#define GPIOF_ODR       *(unsigned int *)(0x40021400+0x14)

//main.c
#include "stm32f4xx.h"

int main(){
    //RCC
    RCC_AHB1_ENR|=(1<<5); 
    
    //Mode
    GPIOF_MODER&=~(3<<(6*2)); 
    GPIOF_MODER|=(1<<(6*2)); 
    
    
    GPIOF_ODR&=~(1<<6); 
    while(1){
		
	}
}

void SystemInit(){
	
}
点灯——流水灯闪烁

利用软件延时实现 RGB 流水灯闪烁。很简单,前面已经看了3个 LED 通道 PF678 了。

#include "stm32f4xx.h"

void delay_ms(int time);

int main(){
    //RCC
    RCC_AHB1_ENR|=(1<<5); 
    
    //Mode
    GPIOF_MODER&=~(3<<(6*2)); 
    GPIOF_MODER|=(1<<(6*2)); 
    GPIOF_MODER&=~(3<<(7*2)); 
    GPIOF_MODER|=(1<<(7*2)); 
    GPIOF_MODER&=~(3<<(8*2));   
    GPIOF_MODER|=(1<<(8*2)); 
    
    while(1){
        GPIOF_ODR|=(7<<6);
        GPIOF_ODR&=~(1<<6);
        delay_ms(1000);
        GPIOF_ODR|=(7<<6);
        GPIOF_ODR&=~(1<<7); 
        delay_ms(1000);
        GPIOF_ODR|=(7<<6);
        GPIOF_ODR&=~(1<<8);
        delay_ms(1000);
	}
}

void SystemInit(){
	
}

//毫秒级的延时
void delay_ms(int time)
{    
   int i=0;  
   while(time--)
   {
      i=4000;
      while(i--) ;    
   }
}
点灯——GPIO 具体功能框图对应

GPIO:通用输入输出引脚。我们可以通过编程来输出或者读取数据。大部分 GPIO 是已经连接、定义好了一些功能(比如上面尝试过的 PF6 LED),有的引脚有多个功能支持重新映射。

STM32 GPIO 除了 adc 是 3.3v,其他 GPIO 都是 5v 容忍。

GPIO 框图(重点)如下:

image-20231104221140325

先从输出开始看。最右侧的 IO 引脚是连接在芯片周围一圈的144个引脚之一。除了 IO 引脚,此图中其他所有部分都是封装在芯片内部我们看不到的。

往左有两个保护二极管。当电压大于 5V,电流会往上 VDD_FT 走。当电压为负电压,电流会由 VSS 往 IO 引脚走。

上下拉电阻:比武外接一个低电平工作的设备,但是我们不希望一上电外设就工作,可以设置上拉电阻,稳定一段时间。

GPIO 输出的数据来源:复位寄存器 BSRR,或者 ODR 设置(图中的3下路部分)。复位寄存器高16位复位(写1置0)低16位置位(写1置1),置位优先级更高。

配置 GPIO 模式(输入/输出,选择哪一路)通过前面用过的 MODER 配置。

输出模式(图中输出控制部分)配置端口输出类型寄存器 OTYPER,比如推挽输出,开漏输出。

推挽输出:有直接驱动能力,输出0就是低电平,输出1就输出可以工作的高电平。原理是采用了一个放大的电路?

1699356797818

输入(INT)为高电平时,反向后 PMOS 导通,输出高电平。输入为低电平时,反向后 NMOS 导通,输出低电平。我们可以用一个小电流去驱动出来一个大电流。

开漏输出:自己本身没有输出高电平的手段。低电平可以接地,高电平没有 PMOS 管,是浮空状态。需要外接一个电阻。

1699357078909

stm32 输出 5V 电压的方法就是开漏输出外接电阻。通过接两个三极管的方式反向。

1699357296750

框图中的模拟部分输入输出则不用配置这些模式信息,直接由外设接到保护二极管再接到输出引脚。

框图中的输入部分经过保护电压后,还需要施密特触发器调整一下。比如原来电压的数值并非精确的0或 3.3V,施密特触发器将高于 1.8V 的全部视作1,低于的全部视作0后输入芯片。模拟部分则不需要经过施密特触发器。

因此配置 GPIO 输出的步骤如下:

  1. GPIO 功能,通用输出、复用功能、模拟输入等 MODER;
  2. 输出推挽 or 开漏 OTYPER;
  3. 输出速度 OSPEEDR;
  4. 上下拉电阻是否需要开启 PUPDR;
  5. 具体输出内容 BSRR or ODR.

输入部分后面输入实验介绍~

按整个流程重新串一遍代码,如下:(其实和前面差不多,就是重新按照流程串了一遍)

/* 用来存放寄存器映射相关的代码 */
#define RCC_BASE    (unsigned int *)    0x40023800
#define GPIOF_BASE  (unsigned int *)    0x40021400
    
#define RCC_AHB1ENR         *(RCC_BASE+0x30)
    
#define GPIOF_MODER         *(GPIOF_BASE+0x00)
#define GPIOF_OSPEEDR       *(GPIOF_BASE+0x08)
#define GPIOF_PUPDR         *(GPIOF_BASE+0x0C)
#define GPIOF_ODR           *(GPIOF_BASE+0x14)
#define GPIOF_BSRR          *(GPIOF_BASE+0x18)

//main.c
#include "stm32f4xx.h"

int main()
{
    RCC_AHB1ENR |= (1<<5);
    GPIOF_MODER &= ~(3<<(6*2));
    GPIOF_MODER |= (1<<(6*2));
    while (1)
    {
    }
}

void SystemInit()
{
}

烧录前记得勾选:use MicroLib.

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

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

相关文章

一种libuv实现websockets服务的解决方案

方法是libuv用多事件循环来驱动。说起来容易&#xff0c;做起来还是比下面的方法更容易&#xff1a; 上图是某位网友的方法代表子大部分网络资料。此方法对部署不友好&#xff0c;因为软件仓库提供的libwebsockets是不能用了。如何简化部署&#xff0c;利用好现有的软件仓库呢&…

ubuntu 安装 zsh、ohmyzsh并配置必要插件

下述记录是完成全部操作后回忆记录得来&#xff0c;或有不准确。我只记录安装中确实用到的指令&#xff0c;参考资料中有扩展内容&#xff0c;记录如下&#xff1a; ubuntu使用zsh终端并安装nerd font字体——nerd font字体不太好安装&#xff0c;使用fonts-powerline替代。 Ub…

基于SpringBoot+Vue的点餐管理系统

基于springbootvue的点餐平台网站系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 菜品详情 个人中心 订单 管理员界面 菜品管理 摘要 点餐管理系统是一种用…

【Mac开发环境搭建】安装HomeBrew、HomeBrew安装Docker、Docker安装Mysql5.7和8

文章目录 HomeBrew安装相关命令安装包卸载包查询可用的包更新所有包更新指定包查看已经安装的包查看包的信息清理包查看brew的版本更新brew获取brew的帮助信息 Brew安装DockerDocker常用命令镜像相关查看已经拉取的所有镜像删除镜像 容器相关停止运行容器启动容器重启容器删除容…

uniapp+uview2.0+vuex实现自定义tabbar组件

效果图 1.在components文件夹中新建MyTabbar组件 2.组件代码 <template><view class"myTabbarBox" :style"{ backgroundColor: backgroundColor }"><u-tabbar :placeholder"true" zIndex"0" :value"MyTabbarS…

【Linux】:文件系统

文件系统 一.认识硬件-磁盘1.磁盘的物理构成2.磁盘的存储构成3.逻辑结构 二.文件系统 文件内容属性&#xff0c;前面我们所说的文件操作都是针对以打开的文件&#xff0c;那么未打开的文件呢&#xff1f;当然是在磁盘上储存着&#xff0c;接下来谈谈它是如何储存的。 一.认识硬…

学完能拿20k的接口自动化测试框架教程 涵盖框架源码+视频教程以及搭建流程

自动化测试 自动化测试&#xff0c;这几年行业内的热词&#xff0c;也是测试人员进阶的必备技能&#xff0c;更是软件测试未来发展的趋势。 特别是在敏捷模式下&#xff0c;产品迭代速度快&#xff0c;市场不断调整&#xff0c;客户需求不断变化&#xff0c;单纯的手工测试越…

【已验证】微信小程序php连接SQL Server数据库代码

微信实现通过PHP连接到数据库&#xff0c;分为三步&#xff1a;首先写index.php的接口代码&#xff0c;然后在微信小程序的js页面上调用php接口方法连接到数据库&#xff08;通过url地址的方式&#xff09;&#xff0c;最后在小程序的wxml页面将控制台的数据显示在页面上。 微信…

口袋参谋:如何挑选淘宝热词?这一招很重要!

​在电商行业待了快十年之久了&#xff0c;据我的了解99.99%的中小卖家&#xff0c;在开店初期根本就不知道如何选词&#xff01; 最后选出来的关键词&#xff0c;无非就一种结果&#xff0c;那就是根本搜不到宝贝&#xff0c;或者就干脆没人搜&#xff0c;根本没流量&#xf…

数据库数据迁移常见方式

数据库数据迁移常见方式 数据库数据迁移常见方式1、通过sql2、通过数据迁移工具3、云服务进行数据迁移什么是DRS服务如何使用DRS服务DRS云服务可以干什么 数据库数据迁移常见方式 1、通过sql 批量导入sql insert into tableName select * 2、通过数据迁移工具 在数据库里面…

概念解析 | 数字通信中的调制技术

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:调制。 数字通信中的调制技术 一、背景介绍 在数字通信系统中,信息源产生的信息信号通常是低频基带信号,而用于传输的载波通常是高频正弦信号。为了将信息信号有效地加载到载波…

Spring RabbitMQ那些事(1-交换机配置消息发送订阅实操)

这里写目录标题 一、序言二、配置文件application.yml三、RabbitMQ交换机和队列配置1、定义4个队列2、定义Fanout交换机和队列绑定关系2、定义Direct交换机和队列绑定关系3、定义Topic交换机和队列绑定关系4、定义Header交换机和队列绑定关系 四、RabbitMQ消费者配置五、Rabbit…

npm ERR! code ERESOLVE,npm ERR! ERESOLVE unable to resolve dependency tree

前言 当你第一次下包&#xff0c;或者删除node_module之后&#xff0c;突然npm i报错&#xff0c;这是因为npm版本导致的 可能是某些包版本跟npm 不兼容导致的&#xff08;peerDependencies&#xff09; npm ERR! code ERESOLVE,npm ERR! ERESOLVE unable to resolve depend…

mysql之高阶语句

1、使用select语句&#xff0c;用order by对表进行排序【尽量用数字列进行排序】 select id,name,score from info order by score desc; ASC升序排列&#xff08;默认&#xff09; DESC降序排列&#xff08;需要添加&#xff09; &#xff08;1&#xff09;order by结合whe…

怎么写好宣传稿件?纯干货

企业宣传稿件撰写并不难&#xff0c;有框架、有模板&#xff0c;再有知识储备就行&#xff0c;今天伯乐网络传媒和大家分享新闻稿写作套路&#xff0c;超实用的新闻稿套路➕模板&#xff0c;教你从0到1学会企业宣传稿写作&#xff01;纯干货&#xff0c;建议收藏起来慢慢看&…

uniapp原生插件之安卓友盟消息推送原生插件

插件介绍 安卓友盟消息推送原生插件&#xff0c;支持自定义响铃&#xff0c;震动&#xff0c;免打扰时间段&#xff0c;厂商离线推送等 插件地址 安卓友盟消息推送原生插件 - DCloud 插件市场 详细使用文档 uniapp 安卓友盟消息推送原生插件使用文档 超级福利 uniapp 插…

深度学习_10_softmax_实战

由于网上代码的画图功能是基于jupyter记事本&#xff0c;而我用的是pycham,这导致画图代码不兼容pycharm,所以删去部分代码&#xff0c;以便能更好的在pycharm上运行 完整代码&#xff1a; import torch from d2l import torch as d2l"创建训练集&创建检测集合"…

STM32 TIM定时器,配置,详解(1)

计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR)。 PSC预分频器&#xff0c;顾名思义&#xff0c;先预备一下分频&#xff0c;有时候频率过高&#xff0c;后面的定时器承受不住&#xff0c;就先用PSC先分频一下。如何分频的&#xff1f;将每接受到…

PTE作文练习(一)

目录 65分备考建议 WE模版 范文 Supporting ideas: SWT 65分备考建议 RA重在多听标准的正确的示范&#xff0c;RS重在抓大放小&#xff0c;WFD重在整理错题&#xff0c;以及反反复复的车轮战&#xff0c;FIBRW重在“以对代记” 就是直接看答案&#xff0c;节约时间&#…

Python编程的四个关键点——都知道吗?快来查漏补缺!

文章目录 前言一、Python 中的类型提示二、Python 虚拟环境和包管理三、新的 Python 语法四、Python 测试关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小…