一、STM32的bxCAN控制器
bxCAN是基本扩展CAN(Basic Extended CAN)的缩写,它支持CAN协议2.0A和2.0B。它的设计目标是,以最小的CPU负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。对于安全紧要的应用, bxCAN提供所有支持时间触发通信模式所需的硬件功能。
STM32至少配备一个bxCAN控制器,它具有如下几个特点:
* 支持CAN协议2.0A和2.0B主动模式
* 波特率最高可达1Mbps
* 支持时间触发通信功能
* 11位的标准帧格式和29位的扩展帧格式的接收和发送
发送
* 3个发送邮箱
* 发送报文的优先级特性可软件配置
* 记录发送SOF时刻的时间戳
接收
* 3级深度的2个接收FIFO,每个FIFO都可以放3个完整报文,它们由硬件管理
* 14个位宽可变的过滤器组-由整个CAN共享
* 标识符列表
* FIFO溢出处理方式可配置
* 记录接收SOF时刻的时间戳
可支持时间触发通信模式
* 禁止自动重传模式
* 16位自由运行定时器
* 定时器分辨率可配置
* 可在最后2个数据字节发送时间戳
管理
* 中断可屏蔽
* 邮箱占用单独1块地址空间,便于提高软件效率
二、CAN通信实验过程
2.1 功能描述
2.1.1 发送处理
发送报文的流程为:应用程序选择1个空发送邮箱;设置标识符,数据长度和待发送数据;然后对CAN_TIxR寄存器的TXRQ位置1, 来请求发送。 TXRQ位置1后, 邮箱就不再是空邮箱;而一旦邮箱不再为空,软件对邮箱寄存器就不再有写的权限。 TXRQ位置1后,邮箱马上进入挂号状态,并等待成为最高优先级的邮箱,参见发送优先级。一旦邮箱成为最高优先级的邮箱,其状态就变为预定发送状态。一旦CAN总线进入空闲状态,预定发送邮箱中的报文就马上被发送(进入发送状态)。一旦邮箱中的报文被成功发送后,它马上变为空邮箱;硬件相应地对CAN_TSR寄存器的RQCP和TXOK位置1,来表明一次成功发送。
如果发送失败,由于仲裁引起的就对CAN_TSR寄存器的ALST位置1,由于发送错误引起的就对TERR位置1。
2.1.2 时间触发通信模式
在该模式下, CAN硬件的内部定时器被激活,并且被用于产生时间戳,分别存储在CAN_RDTxR/CAN_TDTxR寄存器中。内部定时器在接收和发送的帧起始位的采样点位置被采样,并生成时间戳。
2.1.3 接收管理
接收到的报文,被存储在3级邮箱深度的FIFO中。 FIFO完全由硬件来管理,从而节省了CPU的处理负荷,简化了软件并保证了数据的一致性。应用程序只能通过读取FIFO输出邮箱,来读取FIFO中最先收到的报文。
有效报文
根据CAN协议, 当报文被正确接收(直到EOF域的最后1位都没有错误), 且通过了标识符过滤,那么该报文被认为是有效报文。
FIFO的管理
FIFO从空状态开始,在接收到第1个有效的报文后, FIFO状态变为挂号_1( pending_1),硬件相应地把FMP[1:0]设置为01(二进制01b)。软件可以读取FIFO输出邮箱来读出邮箱中的报文,然后通过对CRFR寄存器的RFOM位设置1来释放邮箱,这样FIFO又变为空状态了。
如果在释放邮箱的同时,又收到了1个有效的报文,那么FIFO仍然保留在挂号_1状态,软件可以读取FIFO输出邮箱来读出新收到的报文。
如 果 应 用 程 序 不 释 放 邮 箱 , 在 接 收 到 下 1 个 有 效 的 报 文 后 , FIFO 状 态 变 为 挂 号 _2( pending_2),硬件相应地把FMP[1:0]设置为10(二进制10b)。重复上面的过程,第3个有效的报文把FIFO变为挂号_3状态( FMP[1:0]=11b)。此时,软件必须对RFOM位设置1来释放邮箱,以便FIFO可以有空间来存放下1个有效的报文;否则,下1个有效的报文到来时就会导致1个报文的丢失。
溢出
当FIFO处于挂号_3状态(即FIFO的3个邮箱都是满的),下1个有效的报文就会导致溢出,并且1个报文会丢失。此时,硬件对CAN_RFxR寄存器的FOVR位进行置1来表明溢出情况。至于哪个报文会被丢弃,取决于对FIFO的设置:
* 如果禁用了FIFO锁定功能( CAN_MCR寄存器的RFLM位被清0),那么FIFO中最后收到的报文就被新报文所覆盖。这样,最新收到的报文不会被丢弃掉。
* 如果启用了FIFO锁定功能( CAN_MCR寄存器的RFLM位被置1),那么新收到的报文就被丢弃,软件可以读到FIFO中最早收到的3个报文。
接收相关的中断
一旦往FIFO存入1个报文,硬件就会更新FMP[1:0]位,并且如果CAN_IER寄存器的FMPIE位为1,那么就会产生一个中断请求。
当FIFO变满时(即第3个报文被存入), CAN_RFxR寄存器的FULL位就被置1,并且如果CAN_IER寄存器的FFIE位为1,那么就会产生一个满中断请求。
在溢出的情况下, FOVR位被置1,并且如果CAN_IER寄存器的FOVIE位为1,那么就会产生一个溢出中断请求。
2.2 bxCAN通信工作模式
bxCAN有3个主要的工作模式: 初始化、正常和睡眠模式。在硬件复位后, bxCAN工作在睡眠模式以节省电能,同时CANTX引脚的内部上拉电阻被激活。软件通过对CAN_MCR寄存器的INRQ或SLEEP位置’1’,可以请求bxCAN进入初始化或睡眠模式。一旦进入了初始化或睡眠模式,bxCAN就对CAN_MSR寄存器的INAK或SLAK位置’1’来进行确认,同时内部上拉电阻被禁用。当INAK和SLAK位都为’0’时,bxCAN就处于正常模式。在进入正常模式前,bxCAN必须跟CAN总线取得同步;为取得同步,bxCAN要等待CAN总线达到空闲状态,即在CANRX引脚上监测到11个连续的隐性位。以下只做三种模式介绍,具体请参考STM32中文参考手册。
2.2.1 初始化模式
软件初始化应该在硬件处于初始化模式时进行。设置CAN_MCR寄存器的INRQ位为’1’,请求bxCAN进入初始化模式,然后等待硬件对CAN_MSR寄存器的INAK位置’1’来进行确认。清除CAN_MCR寄存器的INRQ位为’0’,请求bxCAN退出初始化模式,当硬件对CAN_MSR寄存器的INAK位清’0’就确认了初始化模式的退出。
当bxCAN处于初始化模式时,禁止报文的接收和发送,并且CANTX引脚输出隐性位(高电平)。初始化模式的进入,不会改变配置寄存器。软件对bxCAN的初始化,至少包括位时间特性(CAN_BTR)和控制(CAN_MCR)这2个寄存器。
在对bxCAN的过滤器组(模式、位宽、FIFO关联、激活和过滤器值)进行初始化前,软件要对CAN_FMR寄存器的FINIT位设置’1’。对过滤器的初始化可以在非初始化模式下进行。
注: 当FINIT=1时,报文的接收被禁止。可以先对过滤器激活位清’0’(在CAN_FA1R中),然后修改相应过滤器的值。如果过滤器组没有使用,那么就应该让它处于非激活状态(保持其FACT位为清’0’状态)。
2.2.2 正常模式
在初始化完成后,软件应该让硬件进入正常模式,以便正常接收和发送报文。软件可以通过对CAN_MCR寄存器的INRQ位清’0’,来请求从初始化模式进入正常模式,然后要等待硬件对CAN_MSR寄存器的INAK位置’1’的确认。在跟CAN总线取得同步,即在CANRX引脚上监测到11个连续的隐性位(等效于总线空闲)后, bxCAN才能正常接收和发送报文。
不需要在初始化模式下进行过滤器初值的设置,但必须在它处在非激活状态下完成(相应的FACT位为0)。而过滤器的位宽和模式的设置,则必须在初始化模式中进入正常模式前完成。
2.2.3 环回模式
通过对CAN_BTR寄存器的LBKM位置’1’,来选择环回模式。在环回模式下, bxCAN把发送的报文当作接收的报文并保存(如果可以通过接收过滤)在接收邮箱里。环回模式可用于自测试。为了避免外部的影响,在环回模式下CAN内核忽略确认错误(在数据/远程帧的确认位时刻,不检测是否有显性位)。在环回模式下, bxCAN在内部把Tx输出回馈到Rx输入上,而完全忽略CANRX引脚的实际状态。发送的报文可以在CANTX引脚上检测到。
2.3 代码部分
2.3.1 初始化设置
初始化包括三个部分:
① 配置相关引脚复用功能,使用CAN时钟
② 设置CAN工作模式和波特率
③ 设置滤波器
初始化RCC寄存器组,配置PLL输出72MHz时钟,APB1总线的频率为36MHz,分别打开CAN/GPIOA/USARIT的设备时钟。
//时钟配置
GPIO_InitTypeDef GPIO_InitStructure;
CAN_InitTypeDef CAN_InitStrucutre;
NVIC_InitTypeDef NVIC_InitStructure;
CAN_FilterInitTypeDef CAN_FilterInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
查看芯片手册,发现STM32F103ZET6版本的CAN总线TX和RX引脚分别是PA12和PA11,TX采用复用推挽输出,RX采用上拉输入:
//串口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure); //
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
由于实验采用中断接收,所以需进行中断初始化配置
//中断配置
CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 次优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//CAN配置
CAN_InitStrucutre.CAN_TTCM = DISABLE; //禁止时间触发通信模式
CAN_InitStrucutre.CAN_ABOM = DISABLE; //软件对CAN_MCR寄存器的INRQ位置1
CAN_InitStrucutre.CAN_AWUM = DISABLE; //睡眠模式通过清除CAN_MCR寄存器SLEEP位
CAN_InitStrucutre.CAN_NART = ENABLE; //CAN报文只被发送一次
CAN_InitStrucutre.CAN_RFLM = DISABLE; // 报文不锁定,新的覆盖原有
CAN_InitStrucutre.CAN_TXFP = DISABLE; //发送FIFO优先级由报文标识符决定
CAN_InitStrucutre.CAN_Mode = CAN_Mode_LoopBack ; //采用环回模式
//波特率设置
CAN_InitStrucutre.CAN_SJW = CAN_SJW_1tq; //重新同步跳跃宽度1个时间单位
CAN_InitStrucutre.CAN_BS1 = CAN_BS1_9tq; //时间段1为8个时间单位
CAN_InitStrucutre.CAN_BS2 = CAN_BS2_8tq; // 时间段2为7个时间单位
CAN_InitStrucutre.CAN_Prescaler = 4; //分频系数
CAN_Init(CAN1, &CAN_InitStrucutre); // 36M/((8+9+1)*4)=500kbps
//过滤器设置
CAN_FilterInitStructure.CAN_FilterNumber=0;
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; // 屏蔽模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; // 过滤器宽度32位
CAN_FilterInitStructure.CAN_FilterIdHigh= 0x00AA<<3; // 过滤器标识符0xAA
CAN_FilterInitStructure.CAN_FilterIdLow =0x0000;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x00FF<<3; //屏蔽位标识符0x00FF
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000;
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
CAN_FilterInit(&CAN_FilterInitStructure);
2.3.2 发送部分
2.3.3 接收部分
2.3.4 主函数接收反馈
三、CAN波特率计算
四、关于过滤器的设置
Typedef struct
{
uint32_t StdId; //标准帧ID,如果要发送扩展帧,可以不理
uint32_t ExtId; //扩展帧ID,如果要发送标准帧,可以不理
uint8_t IDE; //发送标准帧还是扩展帧
uint8_t RTR; //发送远程帧还是数据帧
uint8_t DLC; //发送数据的长度
uint8_t Data[8]; //想要发送的数据
}CanTxMsg;
StdId
StdId用来设定标准标识符。它的取值范围为0到0x7FF。
ExtId
ExtId用来设定扩展标识符。它的取值范围为0到0x1FFFFFFF。
IDE
IDE用来设定消息标识符的类型。
IDE值
RTR
RTR用来设定待传输消息的帧类型。它可以设置为数据帧或者远程帧。
RTR值
DLC
DLC用来设定待传输消息的帧长度。它的取值范围是0到0x8。
Data[8]
Data[8]包含了待传输数据,它的取值范围为0到0xFF
接下来了解它是如何接收的。
STM32参考手册中提到: bxCAN控制器为应用程序提供了14个位宽可变的、 可配置的过滤器组(13~0)。(互联型有28个)。 每个过滤器组的位宽都可以独立配置。可以配置成16位或者32位。过滤器组还可配置为屏蔽位模式或标识符列表模式。
每个过滤器组x由2个32位寄存器, CAN_FxR1和CAN_FxR2组成。
这样的话,就只能过滤出ID为0x317(与CAN_FxR1必须一样)和0x00F(与CAN_FxR2必须一样)两种标准数据帧了。
以上是32位模式下标识符屏蔽模式和标识符列表模式下的设置方法。
在16位模式下,只不过把两个32位寄存器拆成了4个16位的而已,原理和32位模式下是一样的。就不赘述了。
接收数据是通过指向CanRxMsg 结构体变量的指针传递的。直接调用 CAN_Receive 即可轻松完成。
typedef struct
{
uint32_t StdId;
uint32_t ExtId;
uint8_t IDE;
uint8_t RTR;
uint8_t DLC;
uint8_t Data[8];
uint8_t FMI;
} CanRxMsg;
CanRxMsg结构与CanTxMsg差不多。只是多了一个FMI域。
FMI
FMI设定为消息将要通过的过滤器索引, 这些消息存储于邮箱中。该参数取值范围0到0xFF。
五、硬件设计
若采用正常工作模式,从上图可以看出: STM32 的 CAN 通过 P13 的设置,连接到 TJA1050 收发芯片,然后通过接线端子( CAN)同外部的 CAN 总线连接。图中可以看出,在战舰 STM32 开发板上面是带有120Ω的终端电阻的,如果我们的开发板不是作为 CAN 的终端的话,需要把这个电阻去掉,以免影响通信。
这里还要注意,我们要设置好开发板上 P13 排针的连接,通过跳线帽将 PA11 和 PA12 分别连接到 CRX( CAN_RX)和 CTX( CAN_TX)上面,最后,我们用 2 根导线将两个开发板 CAN 端子的 CAN_L 和 CAN_L, CAN_H 和 CAN_H连接起来。这里注意不要接反了( CAN_L 接 CAN_H), 接反了会导致通讯异常!
附,下面根据设置的参数不同来决定can总线can总线的配置情况:
1、对扩展数据帧进行过滤:(只接收扩展数据帧)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
(注:标准帧数据帧、标准远程帧和扩展远程帧均被过滤)
2、对扩展远程帧过滤:(只接收扩展远程帧)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<3)|CAN_ID_EXT|CAN_RTR_REMOTE)&0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
3、对标准远程帧过滤:(只接收标准远程帧)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_REMOTE)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
4、对标准数据帧过滤:(只接收标准数据帧)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFF;
5、对扩展帧进行过滤:(扩展帧不会被过滤掉)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<3)&0xFFFF0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<3)|CAN_ID_EXT)&0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFC;
6、对标准帧进行过滤:(标准帧不会被过滤掉)
CAN_FilterInitStructure.CAN_FilterIdHigh = (((u32)slave_id<<21)&0xffff0000)>>16;
CAN_FilterInitStructure.CAN_FilterIdLow = (((u32)slave_id<<21)|CAN_ID_STD)&0xffff;
CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0xFFFF;
CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0xFFFC;
注:slave_id为要过滤的id号。
串口输入输出模式
在串口设置过程中,有必要了解它的输入输出模式
1、普通推挽输出(GPIO_Mode_Out_PP):
使用场合:一般用在0V和3.3V的场合。线路经过两个P_MOS 和N_MOS 管,负责上拉和下拉电流。
使用方法:直接使用
输出电平:推挽输出的低电平是0V,高电平是3.3V。
2、普通开漏输出(GPIO_Mode_Out_OD):
使用场合:一般用在电平不匹配的场合,如需要输出5V的高电平。
使用方法:就需要再外部接一个上拉电阻,电源为5V,把GPIO设置为开漏模式, 当输出高组态时,由上拉电阻和电源向外输出5V的电压。
输出电平:在开漏输出模式时,如果输出为0,低电平,则使N_MOS 导通,使输出接地。若控制输出为1(无法直接输出高电平),则既不输出高电平 也不输出低电平,为高组态。为正常使用,必须在外部接一个上拉电 阻。
特性: 它具“线与”特性,即很多个开漏模式 引脚连接到一起时,只有当所有 引脚都输出高阻态,才由上拉电阻提供高电平,此高电平的电压为外部 上拉电阻所接的电源的电压。若其中一个引脚为低电平,那线路就相当 于短路接地,使得整条线路都为低电平,0 伏。
3、复用推挽输出(GPIO_Mode_AF_PP):
用作串口的输出。
4、复用开漏输出(GPIO_Mode_AF_OD):
用在IIC。
STM32中GPIO的8种工作模式
(1)GPIO_Mode_AIN 模拟输入
(2)GPIO_Mode_IN_FLOATING 浮空输入
(3)GPIO_Mode_IPD 下拉输入
(4)GPIO_Mode_IPU 上拉输入
(5)GPIO_Mode_Out_OD 开漏输出
(6)GPIO_Mode_Out_PP 推挽输出
(7)GPIO_Mode_AF_OD 复用开漏输出
(8)GPIO_Mode_AF_PP 复用推挽输出
推挽输出:
可以输出高,低电平,连接数字器件; 推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源低定。
推挽电路是两个参数相同的三极管或MOSFET,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小、效率高。输出既可以向负载灌电流,也可以从负载抽取电流。推拉式输出级既提高电路的负载能力,又提高开关速度。
开漏输出:
输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行。适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
开漏形式的电路有以下几个特点:
1、利用外部电路的驱动能力,减少IC内部的驱动。当IC内部MOSFET导通时,驱动电流是从外部的VCC流经上拉电阻、MOSFET到GND。IC内部仅需很小的栅极驱动电流。
2、一般来说,开漏是用来连接不同电平的器件,匹配电平用的,因为开漏引脚不连接外部的上拉电阻时,只能输出低电平,如果需要同时具备输出高电平的功能,则需要接上拉电阻,很好的一个优点是通过改变上拉电源的电压,便可以改变传输电平。比如加上上拉电阻就可以提供TTL/CMOS电平输出等。(上拉电阻的阻值决定了逻辑电平转换的速度。阻值越大,速度越低功耗越小,所以负载电阻的选择要兼顾功耗和速度。)
3、开漏输出提供了灵活的输出方式,但是也有其弱点,就是带来上升沿的延时。因为上升沿是通过外接上拉无源电阻对负载充电,所以当电阻选择小时延时就小,但功耗大;反之延时大功耗小。所以如果对延时有要求,则建议用下降沿输出。
4、可以将多个开漏输出连接到一条线上。通过一只上拉电阻,在不增加任何器件的情况下,形成“与逻辑”关系,即“线与”。可以简单的理解为:在所有引脚连在一起时,外接一上拉电阻,如果有一个引脚输出为逻辑0,相当于接地,与之并联的回路“相当于被一根导线短路”,所以外电路逻辑电平便为0,只有都为高电平时,与的结果才为逻辑1。
关于推挽输出和开漏输出,最后用一幅最简单的图形来概括:该图中左边的便是推挽输出模式,其中比较器输出高电平时下面的PNP三极管截止,而上面NPN三极管导通,输出电平VS+;当比较器输出低电平时则恰恰相反,PNP三极管导通,输出和地相连,为低电平。右边的则可以理解为开漏输出形式,需要接上拉。
由于浮空输入一般多用于外部按键输入,结合图上的输入部分电路,我理解为浮空输入状态下,IO的电平状态是不确定的,完全由外部输入决定,如果在该引脚悬空的情况下,读取该端口的电平是不确定的。
上拉输入/下拉输入/模拟输入:
这几个概念很好理解,从字面便能轻易读懂。
复用开漏输出、复用推挽输出:
可以理解为GPIO口被用作第二功能时的配置情况(即并非作为通用IO口使用)
总结在STM32中选用IO模式
1、浮空输入GPIO_IN_FLOATING ——浮空输入,可以做KEY识别,RX1
2、带上拉输入GPIO_IPU——IO内部上拉电阻输入
3、带下拉输入GPIO_IPD—— IO内部下拉电阻输入
4、模拟输入GPIO_AIN ——应用ADC模拟输入,或者低功耗下省电
5、开漏输出GPIO_OUT_OD ——IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模 式,这样IO口也就可以由外部电路改变为低电平或不变。可以读IO输入电平变化,实现C51的IO双向功能
6、推挽输出GPIO_OUT_PP ——IO输出0-接GND, IO输出1 -接VCC,读输入值是未知的
7、复用功能的推挽输出GPIO_AF_PP ——片内外设功能(I2C的SCL,SDA)
8、复用功能的开漏输出GPIO_AF_OD——片内外设功能(TX1,MOSI,MISO.SCK.SS)
STM32设置实例:
1、模拟I2C使用开漏输出_OUT_OD,接上拉电阻,能够正确输出0和1;读值时先GPIO_SetBits(GPIOB, GPIO_Pin_0);拉高,然后可以读IO的值;使用GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0);
2、如果是无上拉电阻,IO默认是高电平;需要读取IO的值,可以使用带上拉输入_IPU和浮空输入_IN_FLOATING和开漏输出_OUT_OD;
通常有5种方式使用某个引脚功能,它们的配置方式如下:
1、作为普通GPIO输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时不要使能该引脚对应的所有复用功能模块。
2、作为普通GPIO输出:根据需要配置该引脚为推挽输出或开漏输出,同时不要使能该引脚对应的所有复用功能模块。
3、作为普通模拟输入:配置该引脚为模拟输入模式,同时不要使能该引脚对应的所有复用功能模块。
4、作为内置外设的输入:根据需要配置该引脚为浮空输入、带弱上拉输入或带弱下拉输入,同时使能该引脚对应的某个复用功能模块。
5、作为内置外设的输出:根据需要配置该引脚为复用推挽输出或复用开漏输出,同时使能该引脚对应的所有复用功能模块。
注意如果有多个复用功能模块对应同一个引脚,只能使能其中之一,其它模块保持非使能状态。比如要使用STM32F103VBT6的47、48脚的USART3功能,则需要配置47脚为复用推挽输出或复用开漏输出,配置48脚为某种输入模式,同时使能USART3并保持I2C2的非使能状态。如果要使用STM32F103VBT6的47脚作为TIM2_CH3,则需要对TIM2进行重映射,然后再按复用功能的方式配置对应引脚。
来源:oschina
链接:https://my.oschina.net/u/4301815/blog/4275372