1.问题描述
最近在画一个小板子,引脚有点多,使用的芯片是STM32F103VET6,100脚的封装。在选择脚的的时候,没有仔细看
Default和Remap这两栏,就直接把PD0和PD1当作了CAN的收发脚。结果码代码的时候发现这玩意居然需要重映射(如下图),
欲哭无泪,只好硬着头皮学习一波了.
参考了一波原子PWM引脚重映射的程序,我以为是这样的就完事了。
第一步:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_AFIO, ENABLE);//使能PORTD时钟,使能引脚复用时钟
第二步:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟
第三步:
GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE); //定时器1部分重映射:CH1->PE9 CH1N->PE8
当我好奇的在Keil里跳转到GPIO_Remap1_CAN1这个参数时,我开始懵了,奇怪的东西出现了,这里有GPIO_Remap1_CAN1和GPIO_Remap2_CAN1,让我在这两个中选一个!难道我要抓阄?
2.解决问题
冷静一波,开始解决问题,首先还是做做功课,说一说stm32的引脚重映射功能。虽然别人讲的比我好,但我还是要自己写,哈哈哈。
2.1 端口复用和重映射
端口复用好比我有一把瑞士军刀,我拿出啥他就是啥功能。类似的,stm32的一个IO除了做普通IO口,一般会有多个功能,普通功能就是输出高低电平,读取输入高低电平之类,串口,CAN,IIC等属于高级功能,也就是端口可以复用的功能。
重映射,从本质上来讲,相当于一个水池连接了很多根管道,本来我默认从某一管道接水喝,但是某一天,这根管道坏了或者被占用了,我只好从另外一根管道接水,但是注意水还是原来的水。回到32上来。一个外设的引脚除了具有默认的端口外,还可以通过设置重映射寄存器的方式,把这个外设的引脚映射到其它的端口。意思是假设本来我串口默认脚是PA9,PA10,我可以通过重映射,把串口的脚变成PD10,PD11(只做举例)
2.2 寄存器(AFIO_MAPR)
通过查看《STM32中文参考手册》8.4.2,我们知道复用重映射由AFIO_MAPR寄存器配置,而CAN引脚的重映射,由该寄存器的14位和13位配置,如下图所示,回到我的问题,我需要把CAN重映射到PD0和PD1引脚,需要配置该寄存器的第14位和13位为1,该寄存器是32位的,也就是0000 0000 0000 0000 0110 0000 0000 0000,即0x6000。
然而,库函数里面给的是0x001D4000和0x001D6000.
而0X1D6000=0000 0000 0001 1101 0110 0000 0000 0000 ,第13位14位是11,使用PD0,PD1
而0x1D4000=0000 0000 0001 1101 0100 0000 0000 0000, 第13位14位是01,使用PB8,PB9
#define GPIO_Remap1_CAN1 ((uint32_t)0x001D4000) /*!< CAN1 Alternate Function mapping */
#define GPIO_Remap2_CAN1 ((uint32_t)0x001D6000) /*!< CAN1 Alternate Function mapping */
至此,谜团解开,不过其他位也被配置了,有兴趣的同学可以自己去深究~