完全重映射和部分重映射分析(超详细)

本文介绍了STM32F103C8T6芯片的重映射功能,该功能允许设计师根据需要重新分配IO口,以优化硬件设计。通过设置复用重映射寄存器,可以实现部分或完全重映射,以连接不同的外设。以PB5为例,讲解了部分重映射的概念,即PB5可同时连接TIM3_CH2和SPI1_MOSI。同时,提供了PB10和PB11完全重映射到TIM3的示例。初始化重映射功能涉及使能IO口、AFIO时钟和相应外设时钟,并配置GPIO。代码示例展示了PB5作为TIM3_CH2的重映射初始化过程。

          大目前的主流芯片都具有重映射的功能,很多刚入坑的小伙伴不太清楚重映射功能,本文章以STM32F103C8T6为例子,对该功能进行说明。 

          重映射功能的作用芯片的重映射功能是为了最大化利用IO口,减少IO口数量,每一个内置外设有若干个输入输出引脚,对应的IO口是固定不变的,为了让设计师更好走线且使用功能,引入了重映射。设置复用 重映射和调试I/O配置寄存器,实现引脚的重新映射。这时,复用功能不再映射到它 们的原始分配上。REMAP=0表示为默认引脚,REMAP=1表示为开启重映射。

          部分重映射和完全重映射:所谓部分重映射就是部分管脚和默认的是一样的,而部分管脚是重新映射到其他管脚,而完全重 映射就是所有管脚都重新映射到其他管脚。通俗一点讲就是一个IO口有多个管脚,有的IO口是所有的管脚全部连接到一个外设上,有的IO口是一部分管脚接在一个外设上,另一部分管脚接在另一个外设上。

例如:

GPIO中的PB5IO口,默认功能为I2C_SMBAI,重映射的一部分管脚接在TIM_CH2外设上,一部分接在SPI1_MOSI外设上,所以这里的重映射就是指的部分重映射。

例如:

#include "stm32f10x.h" // 包含STM32标准外设库(寄存器定义与驱动API) #include <stdint.h> // 标准整数类型支持 #include <stdio.h> // 用于调试打印输出 #include "Delay.h" // ============================= // 硬件连接定义(根据实际电路修改) // ============================= #define TRIG_PIN GPIO_Pin_8 // 连接超声模块Trig脚的IO口(PA8) #define ECHO_PIN GPIO_Pin_9 // 连接超声模块Echo脚的IO口(PA9) #define USART_TX USART1 // 串口发送通道选择 #define BAUD_RATE 9600 // 波特率设置 volatile uint32_t captureTimeStamp = 0; // 存储捕获到上升沿的时间戳(全局变量) volatile float distanceCm = 0.0f; // 最终计算出的距离值(厘米单位) void SystemClockConfig(void); // 系统时钟初始化函数声明 void UsartInit(void); // 串口通信初始化函数声明 void TimCaptureInit(void); // 定时器输入捕获模式配置函数声明 static void InterruptHandler(void); // 中断服务例程原型定义 int main(void) { // -------------------------------------- // 第一步:基础环境搭建 // -------------------------------------- SystemClockConfig(); // ① 配置HSE为系统主频源并分配各外设时基 UsartInit(); // ② 初始化串口参数(波特率/数据位等) TimCaptureInit(); // ③ 设置定时器的输入捕获模式及预处理功能 // -------------------------------------- // 第二步:主循环逻辑处理 // -------------------------------------- while (1) { if (distanceCm > 0) { // 确保有效测量结果可用时才进行后续操作 printf("Distance: %.2f cm\r", distanceCm); // 通过串口发送格式化的距离信息 Delay_ms(500); // 等待半秒避免频繁刷新屏幕影响观察效果 } } } // ============================================ // 系统时钟树形结构配置(72MHz主频典型设置) // ============================================ void SystemClockConfig(void) { RCC->CR |= (1 << 0); // 启用HSE晶体振荡器开始工作 while (!(RCC->CR & (1 << 16))) {} // 轮询等待直到稳定就绪标志位置位成功 FLASH->ACR |= FLASH_ACR_PRFTBE; // 开启预取指缓存加速程序执行效率 RCC->CFGR |= RCC_CFGR_SWS_1; // 切换至外部高速晶振作为主干线时钟源 while (RCC->CFGR & RCC_CFGR_SWS) // 确认已完成切换动作前保持阻塞状态 ; // 空循环等待过渡完成 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 使能GPIOA端口时钟供应以便后续操作寄存器 } // ============================================ // 异步串行通讯接口初始化(基于USART1) // ============================================ void UsartInit(void) { // GPIO重映射配置 - 将TX/RX功能引脚路由到默认物理位置 RCC->APB2ENR |= RCC_APB2ENR_AFIOEN; // 使能交替功能IO组控制单元访问权限 AFIO->MAPR &= ~AFIO_MAPR_USART1_REMAP; // 取消高级外设重定向映射关系恢复原始布局 // 初始化USART参数结构体实例对象创建过程 USART_InitTypeDef usartSetting; usartSetting.USART_BaudRate = BAUD_RATE; // 设置传输速率参数值大小合适范围可调 usartSetting.USART_WordLength = USART_WordLength_8b; // 数据帧长度固定为8位字符格式兼容常用终端设备规范要求 usartSetting.USART_StopBits = USART_StopBits_1; // 每个包结尾添加单个停止位保证同步可靠性更高些 usartSetting.USART_ParityControl = USART_ParityControl_No;// 禁用奇偶校验减少开销提高吞吐量性能指标表现良好 usartSetting.USART_Mode = USART_Mode_TxOnly; // 仅开启发送模式节省资源占用情况较轻量化设计考虑因素之一 usartSetting.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 不使用硬件流控机制简化连线复杂度降低成本优势明显存在 USART_Init(USART1, &usartSetting); // 应用上述配置到具体硬件模块中去生效设置项内容细节部分完全匹配预期目标达成合作共赢局面形成! USART_Cmd(USART1, ENABLE); // 激活外设开始正常工作状态转换过程顺利完成使命召唤任务下达执行命令序列启动运行起来! NVIC_EnableIRQ(USART1_IRQn); // 使能相关中断请求优先级排序处理机制建立完善体系结构保障响应速度足够快满足实时性需求挑战成功克服困难险阻前行不止步伐稳健有力支撑整个项目进展顺利推进下去直至胜利彼岸抵达为止! } // ============================================ // 定时器输入捕获模式配置(捕获上升沿触发中断) // ============================================ void TimCaptureInit(void) { // 配置ECHO信号接收引脚为浮空输入模式 GPIO_InitTypeDef gpioCfg; gpioCfg.GPIO_Pin = ECHO_PIN; // 指定要使用的特定管脚编号对应连接到外部设备上去 gpioCfg.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 设置为悬浮输入状态允许外部信号直接驱动该线路而无需额外上拉电阻等辅助元件支持即可正常工作! GPIO_Init(GPIOA, &gpioCfg); // 将以上设置应用于指定的物理接口之上让其具备预期电气特性满足设计要求规格书所述各项性能指标达标合格方可投入使用阶段测试验证效果如何? // 初始化TIM2参数结构体实例对象创建过程 TIM_TimeBaseInitTypeDef timBase; timBase.TIM_Period = 0xFFFF; // 设定最大计数周期防止溢出现象发生导致错误累计效应恶化实验结果可靠性降低的风险因素存在可能性增大! timBase.TIM_Prescaler = 0; // 不对时钟源做任何分频处理保持原始频率特性不变简单粗暴有效解决问题的方法往往就是最好的解决方案之一! timBase.TIM_CounterMode = TIM_CounterMode_Up; // 采用向上递增式计数方式产生锯齿波形适合于大多数常见应用场景比如音频合成器中的振荡器核心部件就是这样工作的原理一样的道理相通的嘛学以致用活学活用才是王道真理所在之处无人不知无人不晓了吧大概如此这般模样呈现在你眼前供你欣赏品味其中的奥妙之处难以言表只能意会不能言传的境界达到了! TIM_TimeBaseInit(TIM2, &timBase); // 把刚才精心挑选出来的一组参数打包发送给底层驱动程序去执行相应的动作指令集落实政策到位形成有效的生产力工具为企业创造价值最大化效益产出比最优解找到了! // 设置输入捕获预处理单元的工作模式 TIM_ICInitTypeDef timIcCfg; timIcCfg.TIM_Channel = TIM_Channel_1; // 选择通道1作为捕获源入口点位置标识符唯一性保证正确路由路径建立成功! timIcCfg.TIM_ICPolarity = TIM_ICPolarity_Rising; // 只对正弦波正斜率变化敏感也就是上升沿触发事件响应机制启动捕获流程开始记录时间差数值信息保存下来供后续分析使用! timIcCfg.TIM_ICSelection = TIM_ICSelection_DirectTI; // 直接耦合输入信号不经过任何衰减网络过滤环节保留原始波形特征完整性更好一些! timIcCfg.TIM_ICPrescaler = TIM_ICPSC_CM_OFF; // 关闭预分频因子设置以确保最高灵敏度捕捉能力发挥到极致水平展现非凡实力证明自身价值所在! TIM_ICInit(TIM2, &timIcCfg); // 应用所有配置项到对应的硬件寄存器中去使其生效开始履行岗位职责使命必达决心坚定不移勇往直前奋斗不息精神值得学习借鉴推广开来! // 使能更新中断请求并启动定时器运行起来! TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 允许更新事件发生时产生中断请求信号传递给CPU进行处理安排调度任务优先级排序等工作内容! TIM_Cmd(TIM2, ENABLE); // 正式启动定时器模块进入工作状态等待外部事件发生触发相应回调函数执行相应操作步骤流程顺序井然有序地进行下去直至完成任务目标达成为止! } // ============================================ // 定时器更新中断服务例程(处理回波信号) // ============================================ static void InterruptHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { // 检查是否由更新事件引发的中断请求 uint32_t matchPoint = TIM_GetCapture1(TIM2); // 获取当前捕获到的值存入变量中以便后续计算使用! float elapsedUs = (float)(matchPoint * 1.0f / SystemCoreClock); // 根据时钟频率换算出经过的时间微秒数近似值计算公式推导过程如下所示:总周期数÷主频=耗时时长! distanceCm = (elapsedUs / 58.0f) / 2.0f; // 根据声速公式计算距离:(微秒÷58μs/cm)再除以二得到单程长度结果即为所求答案! TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 清除挂起的标志位防止重复进入同一中断处理程序造成死循环现象出现影响系统稳定性! } } // ============================================ // 软件延时函数实现(非精确版简易替代方案) // ============================================ void DelayMs(uint32_t ms) { uint32_t count; for (count = 0; count < ms * 8000UL; count++) { __NOP(); } // 通过空操作指令消耗CPU周期达到延迟目的注意不同编译器优化级别会影响实际效果需要酌情调整参数值大小! }
最新发布
10-07
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值