当前位置: 首页 > article >正文

STM32 - 笔记3

1 开发有基于寄存器和HAL库

在开发 STM32 系列微控制器时,你可以选择基于寄存器的开发方法或使用 STM32 HAL(硬件抽象层)库进行开发。两者各有优缺点,适用于不同的场景和开发需求。下面详细介绍两种方法的特点、使用场景以及示例代码。

1. 基于寄存器的开发

特点
  • 精细控制: 基于寄存器的开发允许你直接操作硬件寄存器,因此你可以对微控制器的每个细节进行精细控制。
  • 高效性: 由于不依赖抽象层,代码执行效率更高,适用于对性能要求极高的应用。
  • 轻量化: 代码体积小,没有多余的库文件,适用于资源受限的应用场景。
  • 复杂性: 需要深入理解芯片手册,直接操作寄存器,学习曲线较陡。
使用场景
  • 资源有限的应用: 如对 Flash、RAM 等资源要求苛刻的项目。
  • 高性能实时控制: 需要精确控制硬件的场景,如工业控制、信号处理等。
  • 特殊硬件操作: HAL 库可能无法直接支持某些特殊的硬件操作,寄存器编程可以实现自定义控制。
示例代码

下面是一个基于寄存器的简单示例,设置 PA5 为输出并控制 LED 的亮灭:

#include "stm32f10x.h"

int main(void)
{
    // 启用 GPIOA 时钟
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

    // 配置 PA5 为推挽输出,速度为 50MHz
    GPIOA->CRL &= ~GPIO_CRL_CNF5; // 清除 CNF5 位
    GPIOA->CRL |= GPIO_CRL_MODE5_1 | GPIO_CRL_MODE5_0; // 设置 MODE5 位为 50MHz 输出

    while (1)
    {
        // 设置 PA5 输出高电平
        GPIOA->BSRR = GPIO_BSRR_BS5;
        for (int i = 0; i < 1000000; i++); // 简单延时

        // 设置 PA5 输出低电平
        GPIOA->BSRR = GPIO_BSRR_BR5;
        for (int i = 0; i < 1000000; i++); // 简单延时
    }
}

2. 基于 HAL 库的开发

特点
  • 易于使用: HAL 库封装了对寄存器的操作,提供了更高级的 API,易于理解和使用,减少了开发者的工作量。
  • 可移植性: 使用 HAL 库可以更轻松地在不同 STM32 芯片之间移植代码。
  • 代码维护性: 由于 HAL 库有 ST 官方的长期支持,代码维护和更新相对容易。
  • 抽象层的开销: HAL 库的抽象层会引入一定的开销,可能在某些对性能要求较高的应用中不太适用。
使用场景
  • 快速开发: 对于产品开发周期较短的项目,HAL 库能显著加快开发速度。
  • 复杂外设操作: HAL 库提供了对复杂外设的支持,如 USB、CAN、以太网等,使用这些外设时 HAL 库更为方便。
  • 代码可读性和维护性: 适用于需要多人协作和长期维护的项目。
示例代码

下面是同样控制 PA5 引脚的代码示例,但使用了 HAL 库:

#include "stm32f1xx_hal.h"

int main(void)
{
    // 初始化 HAL 库
    HAL_Init();

    // 启用 GPIOA 时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 配置 PA5 为推挽输出
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    while (1)
    {
        // 设置 PA5 输出高电平
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
        HAL_Delay(500); // 延时 500ms

        // 设置 PA5 输出低电平
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
        HAL_Delay(500); // 延时 500ms
    }
}

2 蓝牙电路 

蓝牙耳机及其放大电路实用设计汇总-电子发烧友网

3. 寄存器-1 通过绝对地址访问内存单元

// GPIOH 端口全部输出 高电平
*(unsigned int*)(0x4002 1C14)=0xFFFE;

 0x4002 1C14在我们看来是 GPIOH 端口 ODR 的地址,但是在编译器看来,这只是一个普通的变量,是一个立即数,要想让编译器也认为是指针,我们得进行强制类型转换,把它转换成指针即(unsigned int *)0x4002 1C14,然后再对这个指针进行*操作

4 4GB 的地址空间是以字节为单位进行寻址的

4GB 的地址空间是以字节为单位进行寻址的,这意味着每个地址对应一个字节(8位)。在现代计算机系统中,内存地址通常是按字节(Byte)来表示的,这也是为什么通常说 4GB 的地址空间能够寻址 4 * 1024^3 = 4,294,967,296 个字节。

详细解释:
字节寻址: 在大多数现代计算机中,内存是以字节为基本单位进行寻址的,也就是说,每一个地址值代表内存中的一个字节(8位)。因此,地址 0x00000000 指向内存中的第一个字节,地址 0x00000001 指向第二个字节,依此类推。

32位系统的4GB地址空间: 在32位系统中,地址由32位二进制数表示,因此可以表示的最大地址范围是从 0x00000000 到 0xFFFFFFFF,即4GB的地址空间。每个地址对应一个字节,因此可以寻址4GB的内存。

64位系统的更大地址空间: 在64位系统中,地址是由64位二进制数表示的,理论上可以表示的内存地址空间远大于4GB,实际上可以达到 2^64 字节(16EB,Exabytes)。不过,实际支持的内存大小还取决于操作系统和硬件的具体实现。

总结:
不论是 32 位还是 64 位系统,地址空间的步长通常都是 1 字节,也就是说,一个内存地址对应内存中的 1 个字节。

#include <stdio.h>
#include <stdlib.h>

char global_char;  // 8位
char global_char_1;  

short global_short;  // 16位
short global_short_1; 

int global_int;  // 32位
int global_int_1; 

float global_float;  // 32
float global_float_1; 

int main() {
    // 栈变量 -  8位
    char stack_char = 'a';
    char stack_char_1 = 'a';
    
    // 16位
    int stack_short = 42;
    int stack_short_1 = 42;
    
    // 32位
    int stack_int = 42;
    int stack_int_1 = 42;
    
    // 32位
    float stack_float = 42.2;
    float stack_float_1 = 42.2;
    
    // 打印地址
    
    // global 
    printf("Address of global_char: %p\n", (void *)&global_char);
    printf("Address of global_char_1: %p\n", (void *)&global_char_1);
    printf("Address of global_short: %p\n", (void *)&global_short);
    printf("Address of global_short_1: %p\n", (void *)&global_short_1);
    printf("Address of global_int: %p\n", (void *)&global_int);
    printf("Address of global_int_1: %p\n", (void *)&global_int_1);
    printf("Address of global_float: %p\n", (void *)&global_float);
    printf("Address of global_float_1: %p\n", (void *)&global_float_1);
    
    // 栈变量
    printf("Address of stack_char: %p\n", (void *)&stack_char);
    printf("Address of stack_char_1: %p\n", (void *)&stack_char_1);
    printf("Address of stack_short: %p\n", (void *)&stack_short);
    printf("Address of stack_short_1: %p\n", (void *)&stack_short_1);      
    printf("Address of stack_int: %p\n", (void *)&stack_int);
    printf("Address of stack_int_1: %p\n", (void *)&stack_int_1);
    printf("Address of stack_float: %p\n", (void *)&stack_float);
    printf("Address of stack_float_1: %p\n", (void *)&stack_float_1);
    
    return 0;
}

5 比如,一块1000毫安时(mAh)的电池,如果设备的功耗是1瓦(W),在3.7伏的电压下,大约可以运行3.7小时;如果功耗增加到2瓦,运行时间则会缩短到1.85小时左右。 这个是如何计算的

6示波器比较

https://item.jd.com/62196675887.html

价格 - 374

5012H是一款单通道手持示波器,配备2.4寸高清液晶屏,带宽100mhz,采样率为500ms/s,具有完整的触发功能(单次,自动,常规),带有智能防烧可最高容忍400V持续电压和600V峰值电压,
支持一键自动调节波形,支持波形图片保存方便二次进行分析,可适用于家电维修,汽车维修,科研教育等各个领域。

https://item.jd.com/10111504192641.html

价格 - 219

DSO-510是一款集示波器和信号发生器二合一的仪器 示波器是10MHz带宽,48MS/s的实时采样率,有完整的触发功能(单次,正常,自动)。对于周期模拟信号及非周期的数字信号都能运用自如,
最高可测量±400V的电压,配备一键AUTO,无需繁琐调节即可显示被测波形~支持余晖,触发电平显示,波形移动,波形保存等功能,方便进行二次分析! 还带有多种函数信号发生器(50KHz),
支持14种信号波形输出,频率、占空比、幅值可调。 搭载2.8英寸320*240分辨率的高清液晶屏,内置1000mAh高品质锂电池,充满电后可连续使用4小时左右


http://www.kler.cn/a/284427.html

相关文章:

  • 基于海思soc的智能产品开发(两个图像处理来源)
  • 缓存与数据库不一致的解决方案:深入理解与实践
  • Spring Boot中的自动装配机制
  • 今日 AI 简报 | 开源 RAG 文本分块库、AI代理自动化软件开发框架、多模态统一生成框架、在线图像背景移除等
  • 使用etl工具kettle的日常踩坑梳理之二、从Hadoop中导出数据
  • css:盒子模型
  • mysql启动失败问题汇总
  • 黑马点评——商户查询缓存(P37店铺类型查询业务添加缓存练习题答案)redis缓存、更新、穿透、雪崩、击穿、工具封装
  • ES(Elasticsearch)可视化界面-浏览器插件
  • python-春游
  • 【Qt窗口】—— 对话框
  • 操作系统面试真题总结(二)
  • Mac下的压缩包和Win看到的不一样怎么办 Mac压缩后Win电脑看文件名会乱码
  • 利用Leaflet.js创建交互式地图:多种形状单个区域绘制
  • 揭秘!糖尿病:从绝望到希望的治愈之路
  • mysql实用系列:coalesce函数的使用
  • 【GIT】idea中实用的git操作,撤回commit,撤回push、暂存区使用
  • 一些好用的网站和api合集
  • 【Python机器学习】NLP词频背后的含义——隐性狄利克雷分布(LDiA)
  • JavaWeb - Maven
  • GMS——利用 ChatGPT 和扩散模型进行制造业革命
  • css-functions-图形函数
  • 08:Logic软件原理图添加元件
  • 【Java设计模式】指挥官模式:轻松编排复杂命令
  • zookeeper命令 及 ACL控制
  • 什么是计算机视觉?