#85_库函数开发

前言

在很久很久很久以前

C 语言和 STM32

走在一条幽静的道路上

他们在一起过上了幸福的生活

一、 问题引入... 1

二、 寄存器的基础概念... 1

三、 STM32 寄存器实例解析... 3

  1. GPIO 输入/输出 → 对应 GPIOx_CRL / GPIOx_CRH / GPIOx_IDR /... 3
  2. 定时器(Timer)→ 对应 TIMx_ARR / TIMx_PSC / TIMx_CNT 等... 4
  3. 串口通信(UART)→ 对应 USARTx_SR / USARTx_DR /... 4
  4. ADC 模数转换 → 对应 ADCx_CR1 / ADCx_CR2 / ADCx_SQR1 等... 5
  5. PWM 输出(脉宽调制)→ 对应 TIMx_CCR1 / TIMx_ARR... 6
  6. 复位与时钟 → 对应 RCC_CR / RCC_CFGR 等...6
    四、 从软件层面理解地址与封装... 7
    五、 地址值与寄存器位使能的关系...11
    六、 地址值的封装... 13
    七、 CAN 初始化函数--"CAN_Init"的解析...16
  7. 首先看这个语句... 16
    第 156 行定义的是定义初始化状态,跳转对应的宏定义得到下面的图片
    这里定义了两个地址值 0X 00 和 0X01 将其转化位二进制可以知道... 16
    在对应寄存器可知(如下)...17
  8. 接着就看这一句... 17
  9. 再接着... 18
    3.1 先查看"CAN_MCR_SLEEP"的宏定义...18
    3.2 解除睡眠模式的方法... 19
    3.3 初始化的方法... 19
    1
    4.判断是否初始化是否成功... 22
    八、 对".hex"文件的解析...25
    九、 浅谈寄存器寻址的方式... 27
    十、 寄存器方式启动 GPIOA 总线下的 Pin_0... 29
  10. 源代码... 30
  11. 源代码寄存器启动的代码... 30
  12. 现象如下... 31
    十一、 总线方式启动 GPIOA 总线下的 Pin

关于 C 程序在 STM32 下具体做了什么事情

一、问题引入

在华清学习的这一段时间,首先在老师的带领下巩固了 C 语言相关知识。本

人在大学就读机械相关专业期间,运用课余时间自学 STM32 并率领成员落地相关

自动化项目。并取得设计专年级第一的成绩。

但在自学期间有很多的问题,这些问题有幸在华清远见的老师的带领下解决

了。非常感谢。

言归正传

大学自学期间,最令我头疼的事情是,区区几行 C 语言代码怎么能控制我们

的硬件。驱动传感器、LED、甚至是网络的呢?

二、寄存器的基础概念

在华清学习期间令我听到最多的关键字就是"寄存器",结合 AI 我们先梳理

寄存器是什么?

(好!这个 AI 解释我看不懂)

一、但是我可以很负责任的跟你们说,寄存器就是存放相关的工具的小盒子。

为了解释这个概念。我给你们看一下由华清老师提供的技术文档

1

(在这里感谢这名名老工程师从业十几年的资源,非常实用。感谢!感谢!)

 TOP1:

名称:CAN 主控制寄存器

作用:用于配置和控制 CAN(Controller Area Network,控制器局域网)

外设核心工作模式与关键行为的重要寄存器

 TOP2:

名称:ADC 状态寄存器(ADC_SR)

作用:ADC 状态寄存器(ADC_SR)用于反映 ADC 转换状态与监测模拟看

门狗情况,具体作用如下:

 TOP3:

名称:GPIOx_CRL

作用:具体作用如下用于配置 GPIO 端口的低 8 位引脚 (Pin0 ~ Pin7)

的工作模式和输出类型。

2

所以看明白了吗?

关键就是华清上课一直所说的"寄"!"存"!"器"!

寄存器内封装了相关对应的功能。这些功能对应了相关的功能。比如说

下面这些例子,都是单片机/STM32 里最常见的"寄存器 - 功能"对应,你

可以对应着理解"寄存器是如何封装硬件能力的"

三、STM32 寄存器实例解析

  1. GPIO 输入/输出 → 对应 GPIOx_CRL / GPIOx_CRH / GPIOx_IDR /
     GPIOx_CRL / GPIOx_CRH (端口配置寄存器):
    就像你给引脚"选职业"(参照玩王者荣耀)------让 Pin0 是当"输入引脚"
    还是"输出引脚",输出时速度多快,输入时是浮空/上拉/下拉......写这些
    寄存器的值,就是在给引脚"分配工作"。
     GPIOx_IDR (输入数据寄存器):
    像"看引脚现在干啥呢"------读取 IDR 寄存器,就能知道外部电路给这
    个引脚灌了高电平还是低电平(比如按键有没有被按下)。
     GPIOx_ODR (输出数据寄存器):
    像"指挥引脚干啥呢"------往 ODR 写 0 或 1,引脚就会输出低电平或
    高电平(比如让 LED 亮/灭)。
    3
  2. 定时器(Timer)→ 对应 TIMx_ARR / TIMx_PSC / TIMx_CNT 等
    定时器就像"芯片里的电子秒表",用来计时、产生周期性中断、输出 PWM
    波......靠的就是一系列寄存器配合:
     TIMx_ARR (自动重装载寄存器):
    相当于"定闹钟的时间"------写这个寄存器的值,就是设置定时器"数
    到多少后触发事件"(比如数到 1000 就溢出)。
     TIMx_PSC (预分频器寄存器):
    相当于"给秒表调快慢"------写这个值,能改变定时器计数的"基准频
    率"(比如把 72MHz 主频分成 7200 分频,计数速度就变慢,计时更久)。
     TIMx_CNT (计数器寄存器):
    相当于"秒表现在走到多少了"------读这个寄存器,就能知道定时器当
    前计了多少个数;写这个寄存器,还能"重置秒表"(比如清零重新开始计
    时)。
  3. 串口通信(UART)→ 对应 USARTx_SR / USARTx_DR /
    串口用来和外设/电脑收发数据,全靠寄存器控制"啥时候发、啥时候收、
    发多快、收没收到":
     USARTx_SR (状态寄存器):
    相当于"串口的「状态指示灯」"------读这个寄存器,能知道"有没有
    收到数据?发送缓冲区空没空?有没有出错?"(比如 RXNE=1 表示"收到
    新数据啦,可以读了")。
     USARTx_DR (数据寄存器):
    4
    相当于"串口的「收发缓冲区」"------往 DR 写数据,串口就会自动把
    这个数据发出去;读 DR,就能拿到串口刚收到的数据。
     USARTx_BRR (波特率寄存器):
    相当于"串口的「说话速度调节器」"------写这个寄存器的值,就能设
    置串口通信的波特率(比如 9600、115200),决定每秒发多少个 bit。
  4. ADC 模数转换 → 对应 ADCx_CR1 / ADCx_CR2 / ADCx_SQR1 等
    ADC 是把"模拟电压(比如传感器输出的 0~3.3V)"转成"数字量(芯
    片能处理的 0~4095)"的模块,靠寄存器控制"采哪个通道、多快速度采、
    采多少次平均":
     ADCx_CR1 (控制寄存器 1):
    相当于"ADC 的「总开关+模式选择」"------写这个寄存器,能打开/关
    闭 ADC,选择是单次转换还是连续转换,选择扫描模式(一次采多个通道)
    等。
     ADCx_CR2 (控制寄存器 2):
    相当于"ADC 的「触发方式+对齐方式」"------写这个寄存器,能设置 ADC
    是软件触发还是外部引脚触发,设置转换结果左对齐还是右对齐(方便读数)。
     ADCx_SQR1~SQR4 (序列寄存器):
    相当于"ADC 的「通道队列」"------写这些寄存器,能设置"先采哪个
    通道、再采哪个通道、一共采多少个通道",让 ADC 按顺序自动扫描多个
    模拟输入。
     ADCx_DR (数据寄存器):
    5
    相当于"ADC 的「转换结果缓存区」"------ADC 完成一次转换后,数字
    量结果会自动存在 DR 里,软件读 DR 就能拿到这次采样的电压对应的数
    字值。
  5. PWM 输出(脉宽调制)→ 对应 TIMx_CCR1 / TIMx_ARR
    PWM 是用来输出"高低电平占空比可调"的脉冲信号(比如控制电机转
    速、LED 亮度),核心也是寄存器配合:
     TIMx_ARR (自动重装载寄存器):
    相当于"PWM 的「周期长度」"------写这个值,决定 PWM 一个周期
    有多长(比如 ARR=1000,就是 1000 个计数周期为一个 PWM 周期)。
     TIMx_CCR1 (捕获/比较寄存器 1):
    相当于"PWM 的「占空比调节」"------写这个值,决定在一个 ARR 周
    期内,高电平持续多久(比如 CCR1=500,ARR=1000,那占空比就是 50%)。
     TIMx_CCER (捕获/比较使能寄存器):
    相当于"PWM 的「通道开关」"------写这个寄存器的位,能打开/关闭
    某个 PWM 通道(比如只让 CH1 输出 PWM,CH2 不输出)。
  6. 复位与时钟 → 对应 RCC_CR / RCC_CFGR 等
    芯片要正常工作,得先"上电复位""配置时钟频率",这些都靠 RCC
    (Reset and Clock Control)寄存器:
     RCC_CR (时钟控制寄存器):
    相当于"芯片的「电源开关+时钟源选择」"------写这个寄存器,能启动
    /关闭 HSE(外部高速晶振)、HSI(内部高速 RC 振荡器)等时钟源,还能
    看时钟有没有稳定(比如 PLLRDY=1 表示锁相环已经稳定,可以用 PLL 时
    6
    钟)。
     RCC_CFGR (时钟配置寄存器):
    相当于"芯片的「时钟分频器+外设总线选择」"------写这个寄存器,能
    把高速时钟(比如 72MHz)分频后,分配给 APB1、APB2 等不同外设总线
    (比如让 GPIO 总线跑 36MHz,让定时器总线跑 72MHz),还能选择系统
    时钟是用 HSE 还是 PLL 倍频后的时钟。
    好!
    四、从软件层面理解地址与封装
    这里仅仅只是我们从硬件层面上理解一块芯片如何让,一堆元器件完成
    对应的功能的。接着为了解开这个疑惑。
    我开始第二轮 STM32 的学习。终于,真相大白!
    还是这三张图
     TOP1:
     TOP2:
    7
    8
     TOP3:
    看到了吗?
    地址值!
    这是关键!
    接着再看老师经常操作的库文件,未来追根溯源我又有了重大发现
     这里的地址值与官方提供的《STM32F1XX 中文参考手册》一一对应。
     譬如:
    宏定义 地址值 说明
    9
    CAN_MCR_INRQ ((uint16_t)0x0001) 初始化请求
    CAN_MCR_SLEEP ((uint16_t)0x0002) 睡眠模式请求
    CAN_MCR_TXFP ((uint16_t)0x0004) 发送 FIFO 优先级
    CAN_MCR_RFLM ((uint16_t)0x0008) 接收 FIFO 锁定模式
    CAN_MCR_NART ((uint16_t)0x0010) 禁止自动重传
    CAN_MCR_AWUM ((uint16_t)0x0020) 自动唤醒模式
    CAN_MCR_ABOM ((uint16_t)0x0040) 自动总线关闭管理
    CAN_MCR_TTCM ((uint16_t)0x0080) 时间触发通信模式
    CAN_MCR_RESET ((uint16_t)0x8000) CAN 软件主复位
    我们重点关注"地址值"这一列,再结合中文参考手册
相关推荐
sz4972385991 小时前
双网卡通过路由器实现外网和内网同时上网
网络·tcp/ip·智能路由器·hmi
大肥羊学校懒羊羊1 小时前
FAST-LIVO2 一键复现教程(Ubuntu 20.04 / ROS Noetic )
linux·运维·ubuntu
郝亚军1 小时前
libmodbus在Ubuntu 22.04上按arm64架构编译方法
linux·运维·ubuntu
绛橘色的日落(。・∀・)ノ1 小时前
深度学习 反向传播与计算图实验
算法
Tisfy1 小时前
LeetCode 1914.循环轮转矩阵:大模拟(数组原地轮转) —— 附O(1)空间版本
算法·leetcode·矩阵·大模拟
Hello.Reader1 小时前
算法基础(三)—— 插入排序从整理扑克牌到有序数组
java·算法·排序算法
50万马克的面包1 小时前
C语言:三大基础排序算法模板 冒泡 / 选择 / 插入)
c语言·笔记·算法·排序算法
罗超驿1 小时前
3.快乐数专题学习笔记——双指针法在LeetCode 202题中的应用
java·算法·leetcode·职场和发展
亚远景aspice1 小时前
亚远景-AI系统的V模型开发:基于ISO/PAS 8800的安全需求导出、架构措施与验证确认
网络·安全·汽车