# 01| MCU 与嵌入式:基础概率
# 1.1| 选型和比较
# 1.1| 特性比较
# 温度特性:
设计产品的工作温度区间,是民用级,还是军工级,单片机芯片在一些高 / 低温的环境下,会出现代码起飞,内部 FLASH 莫名丢失等问题。
# 低功耗特性
芯片是否有较好的休眠模式,大多芯片厂家都非常注重硬件低功耗模式,提出了各种各样的睡眠方式,TI 就是把低功耗做的很好的厂家。如果是设计电池供电的产品,一定要考虑低功耗。低功耗更多需要代码去优化,具体可以学习专门的低功耗优化方式
一个纽扣电池,产品用一年
# 芯片热度
比如 STM32 的技术支持非常丰富,由 Datasheet 直接开发吃力的话,一定要选选用社区维护和热度高这样的芯片。
而冷门芯片则是一个挑战,搜索引擎的资料较少,通常得写 e-mail 给原厂工程师,开发效率有所低下。
# 开发环境
IAR 或者 MDK(Keli)CORTEX-Mx 系列的单片机多半都是用 MDK 开发的。TI 的产品大多是用 IAR。一个熟悉的开发环境能够更快的上手。
# 抗干扰性
选用单片机要选择抗干扰性能好的,特别是用在干扰比较大的工业环境中,单片机加密后的保密性能也要好,这样可保证知识产权不容易被侵犯
# 操作系统
# No-OS
No-OS 单片机,可以从启动时的汇编代码开始,到配置好时钟,配置好各样的寄存器,所有的代码都是你自己写的,出了问题自己找,这样能最大程度的提高 debug 效率。No-OS 的单片机代码,虽然简单,但是所能做的功能也会有局限。
# 实时操作系统
- 当需要用复杂协议栈的时候,操作系统变得非常有用
- 当需要运行多个复杂任务的时候,操作系统很有用
- 可移植性高
# 封装
单片机常见的封装形式有:
- DIP(双列直插式封装)
- PLCC(PLCC 要对应插座)
- QFP(四侧引脚扁平封装,一般采用 SMD)
- QFN(无引线四方形扁平无引脚封装)
- SOP(双列小外形贴片封装)
- BGA 技术(球栅阵列封装,底部植球)
- PQFP(塑封四角扁平封装)
- Flip Chip(倒装片)
做实验时一般选用 DIP 封装的,如果选用其它封装,用编程器编程时还配专用的适配器。如果对系统的体积有要求,如遥控器中用的单片机,往往选用 QFP 和 SOP 封装的。
# 1.2| 架构分布(ARM 为例)
- 款式 A:设计用于高性能的 “开放应用平台”——PC
- 款式 R:用于高端的嵌入式系统,尤其是那些带有实时要求的 —— 车载
- 款式 M:用于深度嵌入的,单片机风格 的系统中 ——stm32
"
# Cortex-M3
CM3 采用了哈佛结构,拥有独立的指令总线和数据总线,可以让取指与数据访问并行不悖。
流水线的 3 级分别是:取指,解码和执行
# MPU(Memory Protect Unit)
Cortex‐M3 有一个可选的存储器保护单元。配上它之后,就可以对特权级访问和用户级访问分别施加不同的访问限制。当检测到(violated)时,MPU 就会产生一个 fault 异常,可以由 fault 异常的服务例程来分析该错误,并且在可能时改正它。
# FPU(Foating point unit)
专门作为浮点运算的处理单元,能够大幅度提供浮点运算的速度和减小误差,提高准确度的问题。
# 1.2| 存储器和总线架构
# 1.2.1| 存储器整体架构
# I-Code 总线
该总线将 Cortex™-M3 内核的指令总线与闪存指令接口相连接。指令预取在此总线上完成。
# D-Code 总线
该总线将 Cortex™-M3 内核的 D-Code 总线与闪存存储器的数据接口相连接 (常量加载和调试访问)。
# 系统总线
此总线连接 Cortex™-M3 内核的系统总线 (外设总线) 到总线矩阵,总线矩阵协调着内核和 DMA 间的访问。
# DMA 总线
此总线将 DMA 的 AHB 主控接口与总线矩阵相联,总线矩阵协调着 CPU 的 D-Code 和 DMA 到 SRAM、闪存和外设的访问。
# 总线矩阵
总线矩阵协调内核系统总线和 DMA 主控总线之间的访问仲裁,仲裁利用轮换算法。
AHB 外设通过总线矩阵与系统总线相连,允许 DMA 访问。
# AHB/APB 桥 (APB)
两个 AHB/APB 桥在 AHB 和 2 个 APB 总线间提供同步连接。APB1 操作速度限于 36MHz,APB2 操作于全速 (最高 72MHz)。
闪存的指令和数据访问是通过 AHB 总线完成的。预取模块是用于通过 I-Code 总线读取指令的。仲裁是作用在闪存接口,并且 D-Code 总线上的数据访问优先。
注意: 当对 APB 寄存器进行 8 位或者 16 位访问时,该访问会被自动转换成 32 位的访问:桥会自动将 8 位或者 32 位的数据扩展以配合 32 位的向量
# 1.2.2| 存储器的映像
# 映射表 (见手册)
# 位带操作
位带操作就是把位带区中一个地址的 8 个位分别映射到位带别名区的 8 个地址(LSB 有效,即最低位有效),通过操作相应地址的方式实现操作某个位,如图。其支持位带操作的两个内存区域为:
0x20000000 的第 0 位对应 0x22000000,第 1 位对应 0x22000004 等。前文提到,别名区地址的 LSB 有效,可理解为位带区里每个位的状态只与别名区里地址存储的字的奇偶性有关,通过换算可知,奇数的 LSB 为 1,偶数的 LSB 为 0。
(以字节为单位时,n∈[0,7];以字为单位时,n∈[0,31]))
A:位带区字节地址(GPIOX_BASE + 偏移地址);
n:操作位号;
“*32”:前文提到,位带区每 1 位膨胀为别名区里一个 32 位的字,1 字 = 4 字节 = 32bit;
“*4”:1 字 = 4 字节
#define GPIOA_ODR (GPIOA_BASE + 0x0C) // 位带区字节地址,即为公式中的 “A” | |
#define GPIOA_IDR (GPIOA_BASE + 0x08) | |
... | |
#define GPIOE_ODR (GPIOE_BASE + 0x0C) | |
#define GPIOE_IDR (GPIOE_BASE + 0x08) | |
#define BitBand(Addr, BitNum) *((volatile unsigned long *)((Addr & 0xF0000000) + 0x2000000 + ((Addr & 0xFFFFF) << 5) + (BitNum << 2))) // 表达式 | |
#define PAout(n) BitBand(GPIOA_ODR, n) // 输出 | |
#define PAin(n) BitBand(GPIOA_IDR, n) // 输入 | |
if(PAin(12) == 1){ | |
PAout(4) = 1; | |
}else{ | |
PAout(4) = 0; | |
} |
# FSMC
待补充
# 1.2.3| CRC 计算单元
循环冗余校验 (CRC) 计算单元是根据固定的生成多项式得到任一 32 位全字的 CRC 计算结果。在其他的应用中, CRC 技术主要应用于核实数据传输或者数据存储的正确性和完整性。标准 EN/IEC 60335-1 即提供了一种核实闪存存储器完整性的方法。CRC 计算单元可以在程序运行时计算出软件的标识,之后与在连接时生成的参考标识比较,然后存放在指定的存储器空间。
使用 CRC-32 (以太网) 多项式:0x4C11DB7
# 1.3| 电源控制
# 1.3.1| 电源系统
- STM32 的工作电压 (V DD ) 为 2.0~3.6V。
- 内置的电压调节器提供所需的 1.8V 电源
- 当主电源 V DD 掉电后,通过 V BAT 脚为实时时钟 (RTC) 和备份寄存器提供电源
- 为了提高转换的精确度,ADC 使用一个独立的电源供电,过滤和屏蔽来自印刷电路板上的毛刺
干扰。 - ADC 的电源引脚为 VDDA
- 独立的电源地 VSSA
如果有 VREF- 引脚 (根据封装而定),它必须连接到 VSSA
# 电压调节器
复位后调节器总是使能的。根据应用方式它以 3 种不同的模式工作。
● 运转模式:调节器以正常功耗模式提供 1.8V 电源 (内核,内存和外设)。
● 停止模式:调节器以低功耗模式提供 1.8V 电源,以保存寄存器和 SRAM 的内容。
● 待机模式:调节器停止供电。除了备用电路和备份域外,寄存器和 SRAM 的内容全部丢失。
# 1.3.2| 电源管理
# PVD (可编程电压检测器)
用户可以利用 PVD 对 VDD 电压与电源控制寄存器 (PWR_CR) 中的 PLS [2:0] 位进行比较来监控电源,这几位选择监控电压的阀值。通过设置 PVDE 位来使能 PVD。
电源控制 / 状态寄存器 (PWR_CSR) 中的 PVDO 标志用来表明 V DD 是高于还是低于 PVD 的电压阀值。该事件在内部连接到外部中断的第 16 线,如果该中断在外部中断寄存器中是使能的,该事件就会产生中断。当 V DD 下降到 PVD 阀值以下和 (或) 当 V DD 上升到 PVD 阀值之上时,根据外部中断第 16 线的上升 / 下降边沿触发设置,就会产生 PVD 中断。例如,这一特性可用于用于执行紧急关闭任务
识别电压是否下降到安全电压以下,电压正常时程序进行其他任务的运行;电压异常时程序进行保护模式,对相关寄存器、外设进行保护操作。这种方法会占用 MCU 的处理时间,同时使用 ADC 增加了系统的功耗
#系统启动后启动PVD,并开启相应的中断 | |
PWR_PVDLevelConfig(PWR_PVDLevel_2V8); // 设定监控阀值 | |
PWR_PVDCmd(ENABLE); // 使能 PVD | |
EXTI_StructInit(&EXTI_InitStructure); | |
EXTI_InitStructure.EXTI_Line = EXTI_Line16; // PVD 连接到中断线 16 上 | |
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 使用中断模式 | |
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Raising;// 电压低于阀值时产生中断 | |
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能中断线 | |
EXTI_Init(&EXTI_InitStructure); // 初始化中断控制器 | |
/* 当工作电压低于设定阀值时,将产生一个中断,在中断程序中进行相应的处理:*/ | |
void PVD_IRQHandler(void) { | |
EXTI_ClearITPendingBit(EXTI_Line16); | |
… … // 用户添加紧急处理代码处 | |
} |
# 1.33| 低功耗
在系统或电源复位以后,微控制器处于运行状态。当 CPU 不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。
睡眠状态
停止状态
待机状态
在待机模式下,所有 IO 口引脚处于高阻状态,除了以下一些情况:
- 复位引脚 (始终有效);
- 防侵入引脚,如果被设置为检测侵入或校准;
- 唤醒引脚,如果使能
唤醒源:
- 唤醒引脚的上升沿
- RTC 警告
- 复位引脚外部复位信号
- IWDG 复位
#进入睡眠模式的代码: | |
#define SysCtrl_SLEEPONEXIT_Set ((u32)0x00000002) | |
void PWR_EnterSLEEPMode(u32 SysCtrl_Set, u8 PWR_SLEEPEntry){ | |
if(SysCtrl_Set) // 对 Cortex-M3 中系统控制寄存器的 SLEEPONEXIT 位置位 | |
*(vu32 *) SCB_SysCtrl |= SysCtrl_SLEEPONEXIT_Set; | |
else // 对 Cortex-M3 中系统控制寄存器的 SLEEPONEXIT 位复位 | |
*(vu32 *) SCB_SysCtrl &= ~SysCtrl_SLEEPONEXIT_Set; | |
// 对 Cortex-M3 中系统控制寄存器的 SLEEPDEEP 位复位 | |
*(vu32 *) SCB_SysCtrl &= ~SysCtrl_SLEEPDEEP_Set; | |
if (PWR_SLEEPEntry == PWR_SLEEPEntry_WFI) | |
__WFI(); // 等待中断请求 | |
else | |
__WFE(); // 等待事件请求 | |
} | |
#进入停止模式的代码 | |
#使能PWR的时钟 | |
void PWR_EnterSTOPMode(u32 PWR_Regulator, u8 PWR_STOPEntry) | |
{ | |
PWR->CR &= CR_DS_Mask; // 清除 PDDS 和 LPDS 位 | |
PWR->CR |= PWR_Regulator; // 根据 PWR_Regulator 的值设置 LPDS 位 | |
*(vu32 *) SCB_SysCtrl |= SysCtrl_SLEEPDEEP_Set; // 置位 SLEEPDEEP 位 | |
// 选择进入 STOP 模式的入口 | |
if (PWR_STOPEntry == PWR_STOPEntry_WFI) | |
__WFI(); // 请求等待中断 | |
else | |
__WFE(); // 请求等待事件 | |
} | |
#进入待机模式 | |
void PWR_EnterSTANDBYMode(void) | |
{ | |
PWR->CR |= CR_CWUF_Set; // 清除 Wake-up 标志 | |
PWR->CR |= CR_PDDS_Set; // 选择进入 STANDBY 模式 | |
// 置位 SLEEPDEEP 位 | |
*(vu32 *) SCB_SysCtrl |= SysCtrl_SLEEPDEEP_Set; | |
__WFI(); // 等待中断请求 | |
} |
除了低功耗模式可以通过
- 降低时钟频率
- 关闭 APB 和 AHB 上的外设时钟
# 低功耗模式下的 AWU
RTC 可以在不需要依赖外部中断的情况下唤醒低功耗模式下的微控制器 (自动唤醒模式)。RTC 提供一个可编程的时间基数,用于周期性从停止或待机模式下唤醒。通过对备份区域控制寄存器 (RCC_BDCR) 的 RTCSEL [1:0] 位的编程,三个 RTC 时钟源中的二个时钟源可以选作实现功能。
# 1.4| 复位和时钟控制
# 1..4.1| 系统复位
当以下事件中的一件发生时,产生一个系统复位:
NRST 引脚上的低电平 (外部复位)
窗口看门狗计数终止 (WWDG 复位)
独立看门狗计数终止 (IWDG 复位)
软件复位 (SW 复位)
低功耗管理复位
# 1.4.2| 电源复位
当以下事件中之一发生时,产生电源复位:
上电 / 掉电复位 (POR/PDR 复位)
从待机模式中返回
# 1.4.3| 时钟类型
# HES 时钟
HSE 外部晶体 / 陶瓷谐振器
HSE 用户外部时钟
为了减少时钟输出的失真和缩短启动稳定时间,晶体 / 陶瓷谐振器和负载电容器必须尽可能地靠近振荡器引脚。负载电容值必须根据所选择的振荡器来调整。
外部时钟源 (HSE 旁路) 在这个模式里,必须提供外部时钟。它的频率最高可达 50MHz。
# HSI 时钟
HSI 时钟信号由内部 8MHz 的 RC 振荡器产生,可直接作为系统时钟或在 2 分频后作为 PLL 输入。HSI RC 振荡器能够在不需要任何外部器件的条件下提供系统时钟。它的启动时间比 HSE 晶体振荡器短。然而,即使在校准之后它的时钟频率精度仍较差
# LSE 时钟
LSE 晶体是一个 32.768kHz 的低速外部晶体或陶瓷谐振器。它为实时时钟或者其他定时功能提供一个低功耗且精确的时钟源。
# LSI 时钟
LSI RC 担当一个低功耗时钟源的角色,它可以在停机和待机模式下保持运行,为独立看门狗和自动唤醒单元提供时钟。LSI 时钟频率大约 40kHz (在 30kHz 和 60kHz 之间)。
可以通过校准内部低速振荡器 LSI 来补偿其频率偏移,从而获得精度可接受的 RTC 时间基数,以及独立看门狗 (IWDG) 的超时时间 (当这些外设以 LSI 为时钟源)。校准可以通过使用 TIM5 的输入时钟 (TIM5_CLK) 测量 LSI 时钟频率实现。测量以 HSE 的精度为保证,软件可以通过调整 RTC 的 20 位预分频器来获得精确的 RTC 时钟基数,以及通过计算得到精确的独立看门狗 (IWDG) 的超时时间。
LSI 校准步骤如下:
- 打开 TIM5,设置通道 4 为输入捕获模式;
- 设置 AFIO_MAPR 的 TIM5_CH4_IREMAP 位为’1’,在内部把 LSI 连接到 TIM5 的通道 4;
- 通过 TIM5 的捕获 / 比较 4 事件或者中断来测量 LSI 时钟频率;
- 根据测量结果和期望的 RTC 时间基数和独立看门狗的超时时间,设置 20 位预分频器。
# CSS
时钟安全系统被激活后,时钟监控器将实时监控外部高速振荡器;如果 HSE 时钟发生故障,外部振荡器自动被关闭,产生时钟安全中断,
此中断被连接到 Cortex-M3 的 NMI 的中断;与此同时 CSS 将内部 RC 振荡器切换为 STM32 的系统时钟源
#启动时钟安全系统CSS: | |
RCC_ClockSecuritySystemCmd(ENABLE); //(NMI 中断是不可屏蔽的!) | |
#外部振荡器实现时,产生中断,对应的中断程序: | |
void NMIException(void) | |
{ | |
if(RCC_GetITStatus(RCC_IT_CSS) != RESET) | |
{ // HSE、PLL 已被禁止 (但是 PLL 设置未变) | |
{}// 客户添加相应的系统保护代码处 | |
// 下面为 HSE 恢复后的预设置代码 | |
RCC_HSEConfig(RCC_HSE_ON); // 使能 HSE | |
RCC_ITConfig(RCC_IT_HSERDY, ENABLE); // 使能 HSE 就绪中断 | |
RCC_ITConfig(RCC_IT_PLLRDY, ENABLE); // 使能 PLL 就绪中断 | |
RCC_ClearITPendingBit(RCC_IT_CSS); // 清除时钟安全系统中断的挂起位 | |
// 至此,一旦 HSE 时钟恢复,将发生 HSERDY 中断,在 RCC 中断处理程序里,系统时钟可以设置到以前的状态 | |
} | |
} |
# RTC 时钟
实时时钟是一个独立的定时器。RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。RTC 模块和时钟配置系统 (RCC_BDCR 寄存器) 处于后备区域,即在系统复位或从待机模式唤醒后,RTC 的设置和时间维持不变。
可以选择以下三种 RTC 的时钟源:
- HSE 时钟除以 128
- LSE 振荡器时钟
- LSI 振荡器时钟
3 个专门的可屏蔽中断:
- 闹钟中断,用来产生一个软件可编程的闹钟中断。
- 秒中断,用来产生一个可编程的周期性中断信号 (最长可达 1 秒)。
- 溢出中断,指示内部可编程计数器溢出并回转为 0 的状态
# 系统时钟
系统复位后,HSI 振荡器被选为系统时钟。当时钟源被直接或通过 PLL 间接作为系统时钟时,它将不能被停止。
只有当目标时钟源准备就绪了 (经过启动稳定阶段的延迟或 PLL 稳定),从一个时钟源到另一个时钟源的切换才会发生。在被选择时钟源没有就绪时,系统时钟的切换不会发生。直至目标时钟源就绪,才发生切换。
在时钟控制寄存器 (RCC_CR) 里的状态位指示哪个时钟已经准备好了,哪个时钟目前被用作系统时钟
应用:精确延时
使用 Cortex-M3 内核的 SYSTICK 作为定时时钟,设定每一毫秒产生一次中断,在中断处理函数里对 N 减一,在 Delay (N) 函数中循环检
测 N 是否为 0,不为 0 则进行循环等待;若为 0 则关闭 SYSTISK 时钟,退出函数条件:
- 外部晶振为 8MHz
- 系统时钟为 72MHz
- SYSTICK 的频率 9MHz 产生 1ms 的中断。
SysTick_SetR eload(9000);// 设定 SysTick 达到 1ms 计数结束 | |
SysTick_ITConf ig(ENABLE);// 使能 SysTick 中断 | |
#中断处理函数 | |
void SysTickHa ndler(void){ | |
if (TimingDelay!= 0x00) | |
TimingDelay--; // 全局变量 TimingDelay 必须定义为 volatile | |
} | |
void Delay(u 32 nTime) { | |
SysTick_CounterCm d(SysTick_Coun ter_Enable);// 使能 SysTick 计数器 | |
TimingDelay = nTime;// 读取延时时间 | |
while(TimingDelay!= 0);// 判断延时是否结束 | |
SysTick_CounterCm d(SysTick_Coun ter_Disable);// 关闭 SysTick 计数器 | |
SysTick_CounterCmd(Sy sTick_Counter_Clear);// 清除 SysTick 计数器 | |
} |
# 时钟输出
微控制器允许输出时钟信号到外部 MCO 引脚。
相应的 GPIO 端口寄存器必须被配置为相应功能。以下 8 个时钟信号可被选作 MCO 时钟:
● SYSCLK
● HSI
● HSE
● 除 2 的 PLL 时钟
● PLL2 时钟
● PLL3 时钟除以 2
● XT1 外部 3~25MHz 振荡器 (用于以太网)
● PLL3 时钟 (用于以太网)
#设置PA.8为复用Push-Pull模式。 | |
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; | |
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; | |
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; | |
GPIO_Init(GPIOA, &GPIO_InitStructure); | |
#输出时钟: | |
#时钟的选择由时钟配置寄存器(RCC_CFGR)中的MCO[2:0]位控制。 | |
RCC_MCOConfig(RCC_MCO); | |
#参数RCC_MCO为要输出的内部时钟: | |
RCC_MCO_NoClock //--- 无时钟输出 | |
RCC_MCO_SYSCLK //--- 输出系统时钟(SysCLK) | |
RCC_MCO_HSI //--- 输出内部高速 8MHz 的 RC 振荡器的时钟(HSI) | |
RCC_MCO_HSE //--- 输出高速外部时钟信号(HSE) | |
RCC_MCO_PLLCLK_Div2 //--- 输出 PLL 倍频后的二分频时钟(PLLCLK/2) |
# 1.5| DMA
直接存储器存取 (DMA) 用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须 CPU 干预,数据可以通过 DMA 快速地移动,这就节省了 CPU 的资源来做其他操作。两个 DMA 控制器有 12 个通道 (DMA1 有 7 个通道,DMA2 有 5 个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个 DMA 请求的优先权。
三大因素
- 传输源:DMA 控制器从传输源读出数据;
- 传输目标:DMA 控制器将数据传输的目标;
- 触发信号:用于触发一次数据传输的动作,执行一个单位的传输源至传输目标的数据传输;可以用来控制传输的时机
# 1.5.1| DMA 处理
在发生一个事件后,外设向 DMA 控制器发送一个请求信号。DMA 控制器根据通道的优先权处理请求。当 DMA 控制器开始访问发出请求的外设时,DMA 控制器立即发送给它一个应答信号。当从 DMA 控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求,DMA 控制器同时撤销应答信号。如果有更多的请求时,外设可以启动下一个周期。
# 1.5.2| 仲裁器
仲裁器根据通道请求的优先级来启动外设 / 存储器的访问。
# 1.5.3| 实例
# 1.6| GPIO
# 1.6.1| 工作模式
# 单向
输入:
- 输入浮空
- 输入上拉
- 输入下拉
输出:
- 开漏输出
- 推挽式输出
- 推挽输出能够输出高或者低,而开漏输出只能输出低,或者关闭输出,因此开漏输出总是要配一个上拉电阻使用。
- 开漏输出的上拉电阻不能太小,太小的话,当开漏输出的下管导通时,电源到地的电压在电阻上会造成很大的功耗,因此这个阻阻值通常在 10k 以上,这样开漏输出在从输出低电平切换到高电平时,速度是很慢的
- 推挽输出任意时刻的输出要么是高,要么是低,所以不能将多个输出线接,而开漏输出可以将多个输出线接,共用一个上拉此时这些开漏输出的驱动其实是与非的关系
- 推挽输出输出高时,其电压等于推挽电路的电源,通常为一个定值,而开漏输出的高取决于上拉电阻接的电压,不取决于前级电压,所以经常用来做电平转换,用低电压逻辑驱动高电压逻辑,比如 3.3v 带 5v
# 双向
总线握手
# 模拟信号输入输出
# 1.6.2| IO 的连接
# 单向传输
输入
- 使用专用芯片 (ST1G3234,74LVC2t45 等),或使用分立器件
- 对于可承受 5V 的 STM32 I/O,可直接连接
输出
- 使用专用芯片 (ST1G3234,74LVC2t45 等) ,或使用分立器件
- 如对方可兼容 TTL,可考虑直接连接
- 对于可承受 5V 的 STM32 I/O,可使用开漏输出上拉电阻连接
# 双向握手
- 使用专用芯片 (MAX3378 等) ,或使用分立器件
- 对于可承受 5V 的 STM32 I/O 端口,可使用开漏输出加上拉电阻连接
# 1.6.3| 重映射
# 重映射和好处
- I/O 的复用:GPIO 和内置外设共用引出管脚
- I/O 的重映射:复用功能 (AFIO) 从不同的 GPIO 管脚引出
- 方便了 PCB 的设计,潜在地减少了信号的交叉干扰
- 分时复用某些外设,虚拟地增加了端口数目
# 重映射的步骤
- 使能被重新映射到的 I/O 端口时钟
- 使能被重新映射的外设时钟
- 使能 AFIO 功能的时钟
- 进行重映射
# 实例
#USART2的TX/RX在PA.2/3 | |
#PA.2已经被Timer2的channel3使用 | |
#需要把USART2的TX/RX重映射到PD.5/6 | |
//(1) 使能被重新映射到的 I/O 端口时钟 | |
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); | |
//(2) 使能被重新映射的外设时钟 | |
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); | |
//(3) 使能 AFIO 功能的时钟 | |
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); | |
//(4) 进行重映射 | |
GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE); |
# 1.6.4| SDIO
待更新
# 参考文献
[1] Clarence. 浅谈单片机特征和选型 [EB/OL].https://zhuanlan.zhihu.com/p/67681832,2019-5-31.
[2] 上海利邦高技术有限公司。单片机选型指南 [M]. 上海利邦高技术有限公司:上海,2019:1.
[3] 陈小挺.stm32 中的 “位带操作” 浅析 [EB/OL].https://zhuanlan.zhihu.com/p/22935354,2017-02-06.
[4] 阏男秀。如何正确的理解漏极开路输出跟推挽输出?[EB/OL].https://www.zhihu.com/question/28512432,2017-03-15.
[5] well xiong. 如何正确的理解漏极开路输出跟推挽输出?[EB/OL].https://www.zhihu.com/question/28512432,2016-06-17.
[6] ST.STM32 中文手册 [M/CD].ST 公司,2019-1-1.
[7] ARM.Cortex 权威指南 [M/CD].ST,2015-1-1.