找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5132

积分

0

好友

659

主题
发表于 1 小时前 | 查看: 5| 回复: 0

我们需要在外部定义一个 SystemInit 函数来设置 STM32 的时钟。STM32 上电后,会先执行 SystemInit 函数,最后再进入我们 C 语言中的 main 函数。

下面就开始使用寄存器来操作 STM32,让 PC0 输出一个低电平。要操作 STM32 的寄存器,我们就需要用 C 语言 对其进行封装,这部分程序我们都放在 stm32f10x.h 中。具体代码如下:

#define PERIPH_BASE ((unsigned int)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00)
#define GPIOC_CRH *(unsigned int*)(GPIOC_BASE+0x04)
#define GPIOC_IDR *(unsigned int*)(GPIOC_BASE+0x08)
#define GPIOC_ODR *(unsigned int*)(GPIOC_BASE+0x0C)
#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10)
#define GPIOC_BRR *(unsigned int*)(GPIOC_BASE+0x14)
#define GPIOC_LCKR *(unsigned int*)(GPIOC_BASE+0x18)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)

要控制 PF9 输出低电平,首先得搞清楚 GPIO 这个外设挂接在哪个总线上。

通过 Block2 外设基地址以及 APB2 总线的偏移地址,就可以得到 APB2 外设的基地址。GPIO 正是挂接在 APB2 总线上的,再根据 GPIOC 的偏移地址,就能得到 GPIOC 外设的基地址。GPIOC 外设内部含有很多个寄存器,比如 GPIOC_CRL、GPIOC_CRH 端口配置寄存器、GPIOC_BSRR 置位复位寄存器等,通过它们各自的偏移地址就可以获取对应的寄存器地址。要操作这些地址里面的内容,就需要用到指针——将其强制转换为 unsigned int* 指针类型,然后再通过 * 指针来操作该地址里面的内容。

在 STM32 中,凡是使用外设功能,都要使能对应的外设时钟,否则即使配置好端口初始化也无法正常使用。因此还需要知道时钟 RCC 外设的基地址。通过数据手册“存储器映射”章节可以知道,RCC 时钟外设挂接在 AHB 总线上,根据其偏移值可以得到 RCC 时钟外设的基地址。然后查阅《STM32F1xx 中文参考手册》的“6 小容量、中容量和大容量产品的复位和时钟控制(RCC)”中“6.3.7 APB2 外设时钟使能寄存器(RCC_APB2ENR)”,就能找到对应的端口 RCC 使能寄存器,只要把 GPIOC 端口时钟使能即可。

用 C 语言封装好寄存器后,就可以开始编写 main 函数了。

main.c 代码:

#include "stm32f10x.h"

#define GPIOC_BSRR *(unsigned int*)(GPIOC_BASE+0x10) 
//在引用的头文件中声明过GPIOC_BASE
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)
#define GPIOC_CRL *(unsigned int*)(GPIOC_BASE+0x00)

void SystemInit(){}
u32 i;

void Delay(i)
{
while(i--);
}

int main()
{
RCC_APB2ENR =(0X01<<4); //使能时钟
while(1)
{
//D1点亮  
GPIOC_CRL &= ~( 0x0F<< (4*0)); //设置推挽输出模式
GPIOC_CRL |= (3<<4*0);
GPIOC_BSRR = (0x01<<(16+0));   //PC0管脚输出低电平
Delay(0x3FFFF);   //延时
GPIOC_BSRR = (0x0000ffff);//D1输出高电平

//D2亮
GPIOC_CRL &= ~( 0x0F<< (4*1));
GPIOC_CRL |= (3<<4*1);
GPIOC_BSRR = (0x01<<(16+1));
Delay(0x3FFFF); 
GPIOC_BSRR = (0x0000ffff);

//D3
GPIOC_CRL &= ~( 0x0F<< (4*2));
GPIOC_CRL |= (3<<4*2);
GPIOC_BSRR = (0x01<<(16+2));
Delay(0x3FFFF);  
GPIOC_BSRR = (0x0000ffff);

//D4
GPIOC_CRL &= ~( 0x0F<< (4*3));
GPIOC_CRL |= (3<<4*3);
GPIOC_BSRR = (0x01<<(16+3));
Delay(0x3FFFF); 
GPIOC_BSRR = (0x0000ffff);

//D5
GPIOC_CRL &= ~( 0x0F<< (4*4));
GPIOC_CRL |= (3<<4*4);
GPIOC_BSRR = (0x01<<(16+4));
Delay(0x3FFFF);  
GPIOC_BSRR = (0x0000ffff);

//D6
GPIOC_CRL &= ~( 0x0F<< (4*5));
GPIOC_CRL |= (3<<4*5);
GPIOC_BSRR = (0x01<<(16+5));
Delay(0x3FFFF); 
GPIOC_BSRR = (0x0000ffff);

//D7
GPIOC_CRL &= ~( 0x0F<< (4*6));
GPIOC_CRL |= (3<<4*6);
GPIOC_BSRR = (0x01<<(16+6));
Delay(0x3FFFF);   
GPIOC_BSRR = (0x0000ffff);

//D8
GPIOC_CRL &= ~( 0x0F<< (4*7));
GPIOC_CRL |= (3<<4*7);
GPIOC_BSRR = (0x01<<(16+7));
Delay(0x3FFFF);   
GPIOC_BSRR = (0x0000ffff);
}
}

几点注意:

  1. 包含 stm32f10x.h 头文件。在这个头文件中我们定义的都是寄存器,因此如果要在其他文件中使用这些寄存器,就需要把这个头文件包含进来,否则编译就会报错。

  2. SystemInit 函数。在前面讲解启动文件时已经说明,程序运行的时候会先进入这个函数进行 STM32 的初始化,如果不写这个函数编译器就会报错。这里我们编写这个函数,里面并不对其做任何操作。

  3. 开启 GPIOC 时钟。要使 PC0 正常工作输出一个低电平,必须要打开它的时钟。RCC_APB2ENR 寄存器是在 stm32f10x.h 头文件中定义好的,只要查阅《STM32F1xx 中文参考手册》RCC 时钟使能寄存器内容就可以知道,此寄存器的第 4 位是控制 GPIOC 外设的时钟使能位,该位为 1 时才使能,为 0 则关闭 GPIOC 时钟。所以要让 1 左移 4 位。

  4. 配置 GPIOC 为通用推挽输出模式。STM32 的 GPIO 模式有很多,可根据 CRx 寄存器设置,CRL 对应 GPIO 的低 8 位,CRH 对应 GPIO 的高 8 位。如果不是特殊需求,一般输出采用推挽输出模式。我们要让 PC0 管脚输出一个低电平,故使用推挽输出模式。查阅《STM32F1xx 中文参考手册》GPIO 配置寄存器内容即可知道,此寄存器内每 4 位控制一个管脚。

  5. 使 PC0 输出低电平。GPIOC_BSRR 为置位、复位寄存器,查阅《STM32F1xx 中文参考手册》GPIO 置位复位寄存器内容可以知道,其高 16 位用于复位,当高 16 位某位为 1 时,表示那一位管脚输出低电平,为 0 不影响其输出电平。当低 16 位的某位为 1 时,表示那一位管脚输出高电平,为 0 不影响其输出电平。所以要让 1 左移 16+0 位。

如果你正在从寄存器层面理解 STM32,对照 官方技术文档 中的存储映射图和寄存器描述表来阅读,会更容易理清这些地址与位操作之间的关系。




上一篇:嵌入式学习与职业发展:从计算机基础到软硬件分工的实践路线
下一篇:X99老平台游戏实测:RTX 3080低画质16套配置差距与装机账本
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-2 22:47 , Processed in 0.462685 second(s), 38 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表