本文主要讲了在用STM32F103C8T6时发现的一些问题,对这些问题的解决方案或者是理解,而不是写如何敲代码的,那样的文章在CSDN上已经很多很完善了。将问题记录在此,为了存档。更是可以和大家一起分享。
以下是本篇文章正文内容,本人才疏学浅,如有错误,还请大家多多指教。
配置IIC的时候更改源文件中IIC_Init()里的GPIO配置、头文件中位带操作是不用多说的,但是在头文件中还有一处寄存器值需要更改。如下所示。
//驱动接口,GPIO模拟IIC
//SCL-->PB6
//SDA-->PB7
#define SDA_IN() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)8<<28;}
#define SDA_OUT() {GPIOB->CRL&=0X0FFFFFFF;GPIOB->CRL|=(u32)3<<28;}
CRL是端口配置低寄存器,含有32位,如下图所示。(详见STM32中文参考手册8.2小节寄存器描述)
对第一行代码进行解释,第二行请读者自行思考:
STM32F103C8T6每个GPIO口有十六个引脚,PA0-PA15;PB0-PB15等等。CRL寄存器控制低八位引脚,每4位寄存器值控制一个引脚,比如说CRL寄存器的0-3控制GPIOB的PB0;CRL寄存器的28-37则控制PB7;
首先是GPIOB->CRL这个寄存器与上0x0FFFFFFF,这是一个8位的16进制数(刚好对应八个引脚),所以对应的就是32位的2进制数(1个16进制是4位2进制数)。所以说这个寄存器是32位的,这分句的意思是先将最后4位置0,其余位不改变.后面有GPIOB->CRL|=(u32)8<<28;这个分句的意思是将1000左移28位也就是移到了控制PB7的28-31位,这时根据下方的功能表可以得出此时将PB7配置成了上拉/下拉输入模式,也对应了SDA_IN的IN,下面一行代码则是将PB7配置成了通用推挽输出。
所以在配置IIC的时候还要看自己现在的端口是几号引脚,更改置位的寄存器位数和左移的位数。
这次用的是定时器1作为PWM输出,定时器1是高级定时器,高级就高级在用起来麻烦,哈哈。 至于高级在何处可以在CSDN上搜索一下,有详细的解释与说明。在PWM输出时,需要在输出比较初始化之后和预装载前加一行代码,当然不一定非要放在这个位置,但可以保证放在这个位置可以用。
代码如下(第三行):
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
TIM_CtrlPWMOutputs(TIM1,ENABLE);
TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);
还有一点是,如果在输出PWM波的时候如果发现高低电平的时间与自己预想的结果恰恰相反,那很有可能是PWM的输出模式写错了。
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
如果是PWM1的话改成2,如果是2的话改成1。
每个定时器只能用作一种功能,而编码器又尤其的喜欢占位置,STM32F103定时器1、2、3、4、5、8有编码器的功能,而在这几个定时器中也只有CH1和CH2有编码器模式,所以当你把一个定时器用作编码器之后,CH3和CH4只能当作普通IO口来用了。我之前就将自己的PWM输出和编码器放在同一个定时器下,这就产生了问题。一个定时器只能干一件事。
复用:当我们不是单纯把引脚当作默认功能的时候就称之为复用(绝大多数引脚的默认功能都是IO口),这时候需要开启复用时钟,比如说将IO口用作定时器。
代码如下:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
虽然很多时候不写这行代码也能用。
重映射:以TIM3为例(更多可见STM32中文参考手册8.3小节)
没有重映射时TIM3的CH1、CH2默认在PA6、PA7上,但是可以把PC6、PC7用作TIM3的CH1和CH2,也就是下表写的完全重映射,只需要在GPIO配置后加上重映射配置。
代码如下(复用时钟是第三行,完全重映射是最后一行):
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);
如果想要使用部分重映射则需要将重映射的第一个入口参数改成GPIO_PartialRemap_TIM3
PA15,一个神奇的引脚,默认功能是JTAG,因为我用不到JTAG下载器。所以想用PA15这个引脚的时候都需要将JATG关闭并开启复用时钟。
代码如下(第一行开启复用时钟,第二行关闭JTAG):
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //ID口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA15
定时器可以同时用作计数器和串口使用。
刚刚不是还说一个定时器只能用作一个功能,这就来打自己的脸了。
因为当定时器用作计数器的时候只需要用到定时器的配置和定时器中断,而串口则是需要端口配置、串口配置和串口中断,所以说这两个功能完全没有互相干扰的情况,是可以同时使用。下表就列一下哪两个功能是肯定不能同时使用的。
功能 |
---|
PWM输入/输出 |
输入捕获 |
输出比较 |
强制输出 |
输入异或 |
计数器 |
编码器 |
本文介绍了几个在使用STM32F103C8T6时发现的几个小问题,国赛将至,应该有一段时间不会使用F1了,记录在此,方便回忆。