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

通过操作地址,来进行STM32的写入GPIO端口值

在STM32F103C8T6中通过操作地址的方式进行端口写入,就是直接操作GPIO的寄存器地址。这是最底层、最高效的控制方式。

一.预先准备

1. 首先找到GPIO端口的基地址

#define GPIOA_BASE    0x40010800
#define GPIOB_BASE    0x40010C00
#define GPIOC_BASE    0x40011000
#define GPIOD_BASE    0x40011400

2. GPIO相关寄存器偏移地址

// 每个GPIO端口的寄存器偏移量
#define GPIO_CRL_OFFSET    0x00  // 端口配置低寄存器
#define GPIO_CRH_OFFSET    0x04  // 端口配置高寄存器 
#define GPIO_IDR_OFFSET    0x08  // 端口输入数据寄存器
#define GPIO_ODR_OFFSET    0x0C  // 端口输出数据寄存器
#define GPIO_BSRR_OFFSET   0x10  // 端口位设置/清除寄存器
#define GPIO_BRR_OFFSET    0x14  // 端口位清除寄存器

二. 通过ODR寄存器写入1

方法1:直接操作ODR寄存器

// 定义GPIOA的ODR寄存器地址
#define GPIOA_ODR    (*(volatile uint32_t *)(GPIOA_BASE + GPIO_ODR_OFFSET))

// 向PA0写入1
void Write_PA0_High(void)
{
    GPIOA_ODR |= (1 << 0);  // 将第0位置1,其他位保持不变
}

// 向PA5写入1
void Write_PA5_High(void)
{
    GPIOA_ODR |= (1 << 5);  // 将第5位置1
}

方法2:使用BSRR寄存器

// 定义GPIOA的BSRR寄存器地址
#define GPIOA_BSRR   (*(volatile uint32_t *)(GPIOA_BASE + GPIO_BSRR_OFFSET))

// 向PA0写入1(设置位)
void Set_PA0_High(void)
{
    GPIOA_BSRR = (1 << 0);  // 设置第0位为1
}

// 向PA5写入1
void Set_PA5_High(void)
{
    GPIOA_BSRR = (1 << 5);  // 设置第5位为1
}

三. 完整的使用示例

1.方法1

#include "stm32f10x.h"

// 定义寄存器地址
#define GPIOA_BASE    0x40010800
#define GPIOA_CRL     (*(volatile uint32_t *)(GPIOA_BASE + 0x00))
#define GPIOA_ODR     (*(volatile uint32_t *)(GPIOA_BASE + 0x0C))
#define GPIOA_BSRR    (*(volatile uint32_t *)(GPIOA_BASE + 0x10))

// 开启时钟的地址
#define RCC_BASE      0x40021000
#define RCC_APB2ENR   (*(volatile uint32_t *)(RCC_BASE + 0x18))

void GPIO_Init_By_Address(void)
{
    // 1. 开启GPIOA时钟
    RCC_APB2ENR |= (1 << 2);  // 开启IOPA时钟

    // 2. 配置PA5为推挽输出,最大速度50MHz
    // CRL寄存器每4位控制一个引脚(0-7),PA5在[23:20]位
    GPIOA_CRL &= ~(0xF << 20);  // 先清零配置位
    GPIOA_CRL |= (0x3 << 20);   // 输出模式,最大速度50MHz
    GPIOA_CRL |= (0x0 << 22);   // 推挽输出模式
}

// 向PA5写入1
void PA5_Set_High(void)
{
    GPIOA_BSRR = (1 << 5);  // 使用BSRR设置位
}

// 向PA5写入0
void PA5_Set_Low(void)
{
    GPIOA_BSRR = (1 << (5 + 16));  // 使用BSRR清除位(位16-31是清除位)
}

// 翻转PA5电平
void PA5_Toggle(void)
{
    if (GPIOA_ODR & (1 << 5)) {
        PA5_Set_Low();   // 当前为高,设为低
    } else {
        PA5_Set_High();  // 当前为低,设为高
    }
}

这样子就可以写入了。

2.方法2

// 同时设置多个引脚为1
void Set_Multiple_Pins_High(void)
{
    // 同时设置PA0、PA5、PA10为1
    GPIOA_BSRR = (1 << 0) | (1 << 5) | (1 << 10);
}

// 使用ODR寄存器同时设置多个引脚(会影响到其他位)
void Set_Multiple_Pins_ODR(void)
{
    // 设置PA0、PA5为1,其他位保持不变
    GPIOA_ODR |= (1 << 0) | (1 << 5);
}

3.LED闪烁

// 假设LED连接在PC13上
#define GPIOC_BASE    0x40011000
#define GPIOC_CRH     (*(volatile uint32_t *)(GPIOC_BASE + 0x04))
#define GPIOC_BSRR    (*(volatile uint32_t *)(GPIOC_BASE + 0x10))
#define RCC_APB2ENR   (*(volatile uint32_t *)(0x40021000 + 0x18))

void LED_Init(void)
{
    // 开启GPIOC时钟
    RCC_APB2ENR |= (1 << 4);  // 开启IOPC时钟

    // 配置PC13为推挽输出
    // PC13在CRH寄存器[23:20]位
    GPIOC_CRH &= ~(0xF << 20);  // 清零配置位
    GPIOC_CRH |= (0x3 << 20);   // 输出模式,最大速度50MHz
    GPIOC_CRH |= (0x0 << 22);   // 推挽输出模式
}

void LED_On(void)
{
    GPIOC_BSRR = (1 << 13);  // PC13置1,LED亮
}

void LED_Off(void)
{
    GPIOC_BSRR = (1 << (13 + 16));  // PC13清0,LED灭
}

void LED_Toggle(void)
{
    // 简单的延时函数
    volatile uint32_t i;
    for(i = 0; i < 1000000; i++);

    // 翻转LED
    if (GPIOC_ODR & (1 << 13)) {
        LED_Off();
    } else {
        LED_On();
    }
}

int main(void)
{
    LED_Init();

    while(1)
    {
        LED_Toggle();  // LED闪烁
    }
}

四. 关键要点总结

  1. BSRR vs ODR

    • BSRR:原子操作,只影响指定的位,推荐使用

    • ODR:需要读-修改-写操作,可能影响其他位

  2. BSRR寄存器特点

    • 位0-15:设置位(写1对应引脚输出高电平)

    • 位16-31:清除位(写1对应引脚输出低电平)

    • 写0的位没有任何效果

  3. 操作步骤

    • 开启对应GPIO端口的时钟

    • 配置GPIO为输出模式

    • 通过BSRR或ODR寄存器控制输出电平

最后我们来看一看数据手册

这也是详细的介绍过程。

http://www.dtcms.com/a/585642.html

相关文章:

  • 压力测试详解
  • 网站 怎么备案佛山营销型网站设计
  • 网站关键字被百度收录外链群发
  • Qt点击信号全解析:QTreeWidget交互指南
  • C++ 头文件:语言功能的 “模块化工具箱”(第三章)
  • 系统架构设计师学习大纲目录
  • 网站建设百度推广说词网站服务器在本地是指
  • Highcharts 3D图:深入解析与实际应用
  • 全景图制作工具( 10 种)
  • 虚拟位置映射(标签鸽
  • Pytorch 学习之Transforms
  • 中国建设银行网站的社保板块在哪里徐州专业网站制作公司
  • 免费建立移动网站吗模拟百度搜索词进入网站
  • Windows 如何安装 Chocolatey
  • 江苏高端网站建设一个网站怎么赚钱
  • 鸿蒙 ArkTS 入门教程:小白实战 List 列表开发(详解 @State, ForEach, @Builder)
  • Redis_8_List
  • excel VBA应用
  • 第十六章 SDN与NFV概述
  • C++ STL:阅读list源码|list类模拟|优化构造|优化const迭代器|优化迭代器模板|附源码
  • 《uni-app跨平台开发完全指南》- 05 - 基础组件使用
  • 公司网页网站建设 ppt网站前置审批类型
  • Macom将生产HRL的GaN-on-SiC工艺
  • 从零开始写算法-栈-柱状图中最大的矩形
  • Flova.ai实战:AI视频创作平台的开发与应用指南
  • 网站推广是什么岗位济南建站网站
  • SEO入门
  • 异腾910B NPU实战:vLLM模型性能优化深度指南
  • 移动网站备案微信里的小程序占内存吗
  • easy_RSA(攻防世界)