江协STM32学习笔记+自测--新建工程
#include "stm32f10x.h" // Device header
int main(void)
{
/*寄存器操作法
RCC->APB2ENR =0X00000010; //开启时钟
GPIOC->CRH = 0X00300000; //把 PC13 配置为输出模式
GPIOC->ODR = 0X00002000; //给 PC13 引脚输出高电平
*/
//库函数版本 / 标准外设库写法
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE); //先开时钟!!
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC, GPIO_Pin_13); //高电平点亮PC13口LED
//GPIO_ResetBits(GPIOC, GPIO_Pin_13); //低电平
while(1)
{
}
}
&+变量名 = 取变量地址; F12或者右键 跳转到定义;

Start放启动文件根据芯片型号选择,Library导入封装好的库函数,User放自己的工程

自测题目:
-
启动文件
A. High Density(大容量芯片)B. Half Duplex(半双工)C. High Speed(高速)D. Hardware Debug(硬件调试)startup_stm32f10x_hd.s里的hd代表什么? -
你写
A. 因为GPIO_Init(GPIOC, &GPIO_InitStructure);时,为什么要加&?GPIO_InitStructure是指针B. 因为函数参数要求传地址,&是取地址符C. 因为库函数规定必须加D. 因为不加会编译报错 -
寄存器写法
A. 完全一致,都是让 PC13 输出高电平B. 不一致,库函数写法更慢C. 不一致,寄存器写法更安全D. 不一致,只有库函数写法能控制电GPIOC->ODR = 0x00002000;和库函数写法GPIO_SetBits(GPIOC, GPIO_Pin_13);功能是否一致?
请按功能匹配文件:
startup_stm32f10x_hd.sstm32f10x_gpio.cmain.cstm32f10x_conf.h
功能选项:
A. 存放你的主程序逻辑
B. 芯片启动初始化,负责跳转到 main()
C. 库函数实现文件,封装 GPIO 寄存器操作
D. 库的总开关,控制哪些外设头文件被包含
答案:ABA 、BCAD
加强版
第一部分(基础概念)
- 我们用的
STM32F103C8T6是 LD、MD、HD 哪一种? - 启动文件的作用是什么?一句话说。
GPIO_InitTypeDef是什么东西?- 函数里看到
*代表什么?传参要加什么符号?
第二部分(寄存器理解)
GPIOC->ODR是干嘛的?GPIOC->CRH是干嘛的?RCC->APB2ENR是干嘛的?0x00002000是控制第几个引脚?
第三部分(库函数理解)
- 配置 GPIO 一共分几步?(库函数版)
RCC_APB2PeriphClockCmd是干嘛的?GPIO_SetBits和GPIO_ResetBits区别?- 下面这句对吗?错在哪?GPIO_Init(GPIOC, GPIO_InitStructure);
代码实操题(2 题)
-
请写出:用库函数方式,让 PB5 引脚输出低电平的完整代码片段(提示:需要先开时钟 → 配置 GPIO 为推挽输出 → 输出低电平)
-
请写出:用寄存器方式,让 PA0 引脚输出高电平的代码片段(提示:需要先开 GPIOA 时钟 → 配置 PA0 为输出模式 → 给 ODR 对应位置 1)
豆老师参考答案:
一、概念题(原答题 + 正确答案修正)
第一部分 基础概念
- STM32F103C8T6 是 LD/MD/HD?→ MD(中密度)(你答对)
- 启动文件的作用?→ 正确答案:初始化芯片堆栈、中断向量表,引导程序从复位跳转到 main () 函数(你答 “配置芯片整体功能”,核心意思对)
- GPIO_InitTypeDef 是什么?→ 正确答案:GPIO 配置参数的结构体类型,用于存放引脚、模式、速度等配置信息(你答 “定义一个结构型变量”,混淆了 “类型” 和 “变量”,修正后即懂)
- 函数里看到 * 代表什么?传参加什么符号?→ 正确答案:
*代表指针(函数要求接收变量地址),传参必须加 **&(取地址符)**(你后半段答对)
第二部分 寄存器理解(全对,附精准描述)
- GPIOC->ODR → GPIO 端口输出数据寄存器,直接控制引脚高低电平
- GPIOC->CRH → GPIO 端口配置高寄存器,配置 8~15 号引脚的工作模式和速度
- RCC->APB2ENR → RCC 的 APB2 总线外设时钟使能寄存器,用于开启对应外设的时钟
- 0x00002000 → 控制 13 号引脚(PC13)
第三部分 库函数理解(全对,附精准步骤)
- 库函数配置 GPIO 步骤 → ①开对应 GPIO 时钟 ②定义 GPIO_InitTypeDef 结构体变量 ③给结构体赋值(引脚 / 模式 / 速度) ④调用 GPIO_Init () 初始化 ⑤设置引脚高低电平
- RCC_APB2PeriphClockCmd → 库函数版的 APB2 总线外设时钟使能函数,用于开启指定 GPIO / 外设的时钟
- GPIO_SetBits & GPIO_ResetBits 区别 → 前者给指定引脚输出高电平,后者给指定引脚输出低电平
- 错误代码
GPIO_Init(GPIOC, GPIO_InitStructure);→ 错误原因:第二个参数是指针类型,必须加 & 取地址,正确写法为 GPIO_Init (GPIOC, &GPIO_InitStructure);
二、代码实操题(原错误代码 + 完整正确代码)
题 1:库函数方式 让 PB5 引脚输出低电平
#include "stm32f10x.h" // 器件头文件
int main(void)
{
// 1. 开启GPIOB时钟(必须匹配引脚组,不能开GPIOC)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 2. 定义GPIO配置结构体变量
GPIO_InitTypeDef GPIO_InitStructure;
// 3. 给结构体赋值:PB5、推挽输出、50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; // 引脚号匹配组内编号5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 通用推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;// 引脚最大输出速度50MHz
// 4. 初始化GPIOB(传地址&)
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 5. PB5输出低电平
GPIO_ResetBits(GPIOB, GPIO_Pin_5);
while(1) // 死循环,保持程序运行
{
}
}
题 2:寄存器方式 让 PA0 引脚输出高电平
#include "stm32f10x.h" // 器件头文件
int main(void)
{
// 1. 开启GPIOA时钟:APB2ENR的bit2置1,对应值0x00000004
RCC->APB2ENR = 0x00000004;
// 2. 配置PA0为推挽输出50MHz:PA0是0号引脚用CRL,0~3位置0011(0x3)
GPIOA->CRL = 0x00000003;
// 3. PA0输出高电平:ODR的bit0置1,对应值0x00000001
GPIOA->ODR = 0x00000001;
while(1) // 死循环,保持程序运行
{
}
}
三、核心困惑点精准解答
困惑 1:物理引脚号 41(PB5),代码为什么写 GPIO_Pin_5?
核心规则:代码中的GPIO_Pin_x的x 是引脚在组内的编号,和芯片物理引脚号(1~48)完全无关,只看引脚名称最后的数字!
- 物理引脚 41 → 引脚名称 PB5 → 组内编号 5 → 代码写
GPIO_Pin_5 - 物理引脚 18 → 引脚名称 PB0 → 组内编号 0 → 代码写
GPIO_Pin_0 - 物理引脚 2 → 引脚名称 PC13 → 组内编号 13 → 代码写
GPIO_Pin_13
困惑 2:RCC->APB2ENR 的数值怎么确定?(如 GPIOA=0x00000004)
核心规则:APB2ENR 寄存器的每一位对应一个外设,置 1 即开启对应外设时钟,GPIO 对应位固定,数值为 2 的对应位次方:
- GPIOA → 对应 bit2 → 2²=4 → 0x00000004
- GPIOB → 对应 bit3 → 2³=8 → 0x00000008
- GPIOC → 对应 bit4 → 2⁴=16 → 0x00000010口诀:A4/B8/C16,直接背会即可。
困惑 3:什么时候用 GPIOx->CRL,什么时候用 GPIOx->CRH?
核心规则:按组内引脚编号划分,寄存器分工固定,无例外:
- CRL(配置低寄存器):控制组内0~7 号引脚(如 PA0、PB5、PC7)
- CRH(配置高寄存器):控制组内8~15 号引脚(如 PA8、PB10、PC13)举例:PA0(0 号)→ 用 CRL;PC13(13 号)→ 用 CRH。
困惑 4:GPIOx->ODR 的数值怎么确定?(如 PA0=0x00000001,PC13=0x00002000)
核心规则:ODR 寄存器的bitx 对应组内 x 号引脚,该位置 1 输出高电平,置 0 输出低电平,数值为 2 的 x 次方:
- PA0 → bit0 → 2⁰=1 → 0x00000001
- PB5 → bit5 → 2⁵=32 → 0x00000020
- PC13 → bit13 → 2¹³=8192 → 0x00002000
困惑 5:为什么 GPIO_Init () 第二个参数必须加 &?
核心规则:函数声明
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
中,第二个参数GPIO_InitTypeDef*的*代表指针类型,要求接收变量的地址,而&变量名是 C 语言的取地址符,用于获取变量在内存中的地址:
- 定义的
GPIO_InitStructure是结构体变量,不是地址 - 加
&后&GPIO_InitStructure才是变量的地址,匹配函数的指针参数要求口诀:函数参数带 *,传参必须带 &!
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)