记录STM32中的配置

一、DMA

1. 各个外设使用的通道

在这里插入图片描述
在这里插入图片描述

2.配置参数

地址&来源

在这里插入图片描述

缓存大小
外设地址寄存器递增(通道接入多个外设)、内存地址寄存器递增(接入多块内存)

在这里插入图片描述
在这里插入图片描述
通常外设会被Disable,内存是Enable

设定外设数据宽度、内存数据宽度

在这里插入图片描述
在这里插入图片描述

工作模式

在这里插入图片描述

软件优先级

在这里插入图片描述

内存到内存

在这里插入图片描述

3. CODE EXAMPLE

配置DMA的函数,打开从内存到USARTy、USARTz的TX寄存器的DMA发送通道

  • 地址&来源:
  DMA_InitStructure.DMA_PeripheralBaseAddr = USARTy_DR_Base;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer1;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

在这里插入图片描述
在这里插入图片描述

  • 缓存大小DMA_InitStructure.DMA_BufferSize = TxBufferSize1; 即为发送的字符串长度
  • 增长:
      DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
      DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable
  • 数据宽度:一个字节
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  • 模式&优先级&内存到内存
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  • 根据不同的外设查表选通道,并且使能这个通道
DMA_Init(USARTy_Tx_DMA_Channel, &DMA_InitStructure);
DMA_Cmd(USARTy_Tx_DMA_Channel, ENABLE);

汇总为一个Configuration的函数:

void DMA_Configuration(void)
{
  DMA_InitTypeDef DMA_InitStructure;

  /* USARTy_Tx_DMA_Channel (triggered by USARTy Tx event) Config */
  DMA_DeInit(USARTy_Tx_DMA_Channel);
  DMA_InitStructure.DMA_PeripheralBaseAddr = USARTy_DR_Base;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer1;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_BufferSize = TxBufferSize1;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  DMA_Init(USARTy_Tx_DMA_Channel, &DMA_InitStructure);
  
  /* USARTz_Tx_DMA_Channel (triggered by USARTz Tx event) Config */
  DMA_DeInit(USARTz_Tx_DMA_Channel);
  DMA_InitStructure.DMA_PeripheralBaseAddr = USARTz_DR_Base;
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer2;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_BufferSize = TxBufferSize2;
  DMA_Init(USARTz_Tx_DMA_Channel, &DMA_InitStructure);
  
  /* Enable USARTy DMA TX Channel */
  DMA_Cmd(USARTy_Tx_DMA_Channel, ENABLE);

  /* Enable USARTz DMA TX Channel */
  DMA_Cmd(USARTz_Tx_DMA_Channel, ENABLE);
}

注意:DMA一边打开了通道,外设一边也同样需要打开通道才能进行DMA传输
在这里插入图片描述

  /* Enable USARTy DMA TX request */
  USART_DMACmd(USARTy, USART_DMAReq_Tx, ENABLE);
  

为什么要这样层层瞎几把起名字。。。。

二、USART

1.配置

  • 基本属性配置:波特率,字长,停止位,校验位,控制流,输入or输出
  • 初始化具体的USART
  • 使能UASART
void USART_Configuration(void)
{
	 /* USARTy and USARTz configured as follow:
        - BaudRate = 230400 baud  
        - Word Length = 8 Bits
        - One Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and CTS signals)
        - Receive and transmit enabled */
  USART_InitStructure.USART_BaudRate = 230400;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  
  /* Configure USARTz */
  USART_Init(USARTz, &USART_InitStructure);
  
  /* Enable the USARTz Receive Interrupt */
  USART_ITConfig(USARTz, USART_IT_RXNE, ENABLE);
	
  /* Enable USARTz */
  USART_Cmd(USARTz, ENABLE);
}

配置完后,若TX内有数据,就会直接发出。需要通过导线将TX引脚与RX引脚接在一起。

2.接收处理

中断的接收方式:

我们先前以及运行接收器发出中断:USART_ITConfig(USARTz, USART_IT_RXNE, ENABLE);
RXNE即为RX not empty,也就是RX接收到数据,立即发出中断请求。

先设置

uint8_t RxCounter = 0;
extern uint8_t RxBuffer2[];  # 引用main中设置的缓存区间
extern uint8_t NbrOfDataToRead;  # NumberOfDataToRead

再找到void USART3_IRQHandler(void)进行编写

  • 读取数据,先进行USART_GetITStatus(USART3, USART_IT_RXNE) != RESET判断以确定有数据可以读入。再使用 RxBuffer2[RxCounter++] = USART_ReceiveData(USART3);读入一个单位的数据。
  • 关闭中断:如果RxCounter == NbrOfDataToRead,则读完了全部的数据,那么USART_ITConfig(USART3, USART_IT_RXNE, DISABLE); 关闭这个中断
/**
  * @brief  This function handles USART3 global interrupt request.
  * @param  None
  * @retval None
  */
void USART3_IRQHandler(void)
{
  if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
  {
    /* Read one byte from the receive data register */
    RxBuffer2[RxCounter++] = USART_ReceiveData(USART3);

    if(RxCounter == NbrOfDataToRead)
    {
      /* Disable the USART3 Receive interrupt */
      USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);
    }
  }
}

三、NVIC

1.配置:

在这里插入图片描述
记录了各个中断请求编号
在这里插入图片描述
为了打开USART2、USART3的中断请求,选择出USART2_IRQn, USART3_IRQn
再配置

void NVIC_Configuration(void)
{
   NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the USARTz Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USARTz_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
	
  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
  NVIC_Init(&NVIC_InitStructure);
}

2.外设允许中断:

NVIC只是一个控制器。虽然配置完了NVIC,但是还是需要在响应的外设中打开中断和确定具体的中断方式。

USART_ITConfig(USARTz, USART_IT_RXNE, ENABLE);

以上代表USARTz会发出接收器非空的中断。

3.编写中断函数

找到void USART3_IRQHandler(void)进行函数功能编写.
中断函数内部首先进行中断类型判断,再分别执行不同的功能。
例如:if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)判断是否是接收器非空的中断响应。

四、GPIO

1. 输入输出方式:

(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 复用推挽输出
在这里插入图片描述
①上拉输入、下拉输入可以用来检测外部信号;例如,按键等;
②浮空输入模式,由于输入阻抗较大,一般把这种模式用于标准通信协议的I2C、USART的接收端;
③普通推挽输出模式一般应用在输出电平为0和3.3V的场合。而普通开漏输出模式一般应用在电平不匹配的场合,如需要输出5V的高电平,就需要在外部一个上拉电阻,电源为5V,把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5V电平。
④对于相应的复用模式(复用输出来源片上外设),则是根据GPIO的复用功能来选择,如GPIO的引脚用作串口的输出(USART/SPI/CAN),则使用复用推挽输出模式。如果用在I2C、SMBUS这些需要线与功能的复用场合,就使用复用开漏模式。
⑤在使用任何一种开漏模式时,都需要接上拉电阻。

2.配置

  • 选定管脚:GPIO_InitStructure.GPIO_Pin = USARTy_TxPin;
  • 选定输入输出方式:GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  • 选定频率:GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  • 选定端口号并初始化:GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* Enable the USART3 Pins Software Remapping */
  GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE);
  
  /* Enable the USART2 Pins Software Remapping */
  GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);  

  /* Configure USARTy Rx as input floating */
  GPIO_InitStructure.GPIO_Pin = USARTy_RxPin;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);
  
  /* Configure USARTz Rx as input floating */
  GPIO_InitStructure.GPIO_Pin = USARTz_RxPin;
  GPIO_Init(USARTz_GPIO, &GPIO_InitStructure);  
  
  /* Configure USARTy Tx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = USARTy_TxPin;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(USARTy_GPIO, &GPIO_InitStructure);

  /* Configure USARTz Tx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Pin = USARTz_TxPin;
  GPIO_Init(USARTz_GPIO, &GPIO_InitStructure);  
}

五、ADC

1. 资源

(a) STM32VC107一共有三个ADC
在这里插入图片描述
(b) 每个ADC是12位,十进制为0-4095,十六进制为0x000-0xFFF。
如果我们要转换的电压范围是0v-3.3v的话,转换器就会把0v-3.3v平均分成4096份。设转换器所得到的值为x,所求电压值为y。y=x/4096。

© 16个外部通道:简单的说就是芯片上有16个引脚是可以接到模拟电压上进行电压值检测的。16个通道不是独立的分配给ADC1、ADC2、ADC3使用,有些通道是被多个转换器共用的。
在这里插入图片描述
除此之外,还有俩内部通道,分别接到温度传感器与内部参考电压上。
在这里插入图片描述
(d) 连到PC4 的10K 欧姆的电位器RV1

2. ADC模式

在这里插入图片描述
在这里插入图片描述

3、栗子

1. 三通道+DMA(copy)

配置DMA:
ADCx将转换结果放在:ADCx->DR内,因此

/*基于DMA的ADC多通道采集*/

volatile uint16 ADCConvertedValue[10][3];
//用来存放ADC转换结果,也是DMA的目标地址,3通道,每通道采集10次后面取平均数
//ADCConvertedValue的定义用了volatile修饰词,因为这样可以保证每次的读取都是从绝对地址读出来的值,不会因为被会编译器进行优化导致读取到的值不是实时的AD值。         

void DMA_Init(void)
{
    DMA_InitTypeDef DMA_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//使能时钟

    DMA_DeInit(DMA1_Channel1);    //将通道一寄存器设为默认值
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);//该参数用以定义DMA外设基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;//该参数用以定义DMA内存基地址(转换结果保存的地址)
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//该参数规定了外设是作为数据传输的目的地还是来源,此处是作为来源
    DMA_InitStructure.DMA_BufferSize = 3*10;//定义指定DMA通道的DMA缓存的大小,单位为数据单位。这里也就是ADCConvertedValue的大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//设定外设地址寄存器递增与否,此处设为不变 Disable
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//用来设定内存地址寄存器递增与否,此处设为递增,Enable
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//数据宽度为16位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度为16位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;//DMA通道拥有高优先级 分别4个等级 低、中、高、非常高
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//使能DMA通道的内存到内存传输
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);//根据DMA_InitStruct中指定的参数初始化DMA的通道

    DMA_Cmd(DMA1_Channel1, ENABLE);//启动DMA通道一
}

配置ADC:

在确定完所选择的通道,以及其对应的管脚后,ADC配置通常分为5步骤:

  • 初始化选定的GPIO管脚
  • 初始化ADC(模式,通道数目)
  • 为ADC配置通道,确定各个通道的扫描先后顺序
  • 开启
  • 校准等待

注释:

  • 通过查询引脚表,可知PA0,PA1,PA2分别对应于ADC通道0,1,2。因此初始化这些GPIO管脚。
  • 通常RCC_APB2PeriphClockCmd给ADC接入72MHz高速时钟。
  • ADC的采样时钟最快14MHz。用RCC_ADCCLKConfig(RCC_PCLK2_Div6)进行分频:72M/6=12。
  • ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    在多通道转换的时候,扫描模式与连续转换需要被ENABLE。单通道则DISABLE。
void Adc_Init(void)
{
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
   
    /*3个IO口的配置(PA0、PA1、PA2)*/
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    /*IO和ADC使能时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA,ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 3;
    ADC_Init(ADC1, &ADC_InitStructure);
    
    ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_239Cycles5);//通道一转换结果保存到ADCConvertedValue[0~10][0]
	ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_239Cycles5););//通道二转换结果保存到ADCConvertedValue[0~10][1]
	ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_239Cycles5); );//通道三转换结果保存到ADCConvertedValue[0~10][2]

	  
    ADC_DMACmd(ADC1, ENABLE);//开启ADC的DMA支持
    ADC_Cmd(ADC1, ENABLE);

    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));

}

注释:

  • 由于选择了软件触发,所以ADC转换开启不是自动进行的,而是通过函数ADC_SoftwareStartConvCmd(ADC1, ENABLE);进行触发的
int main(void)
{
	int sum;
	u8 i,j;
	float ADC_Value[3];//用来保存经过转换得到的电压值
	ADC_Init();
	DMA_Init();
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//开始采集

	while(1)
	{
		for(i=0;i<3;i<++)
		{
			sum=0;
			for(j=0;j<10;j++)
			{
				sum+=ADCConvertedValue[j][i];
			}
			ADC_Value[i]=(float)sum/(10*4096)*3.3;//求平均值并转换成电压值
			//打印(略)
		}
		//延时(略)
	}
}

2.WatchDog
  • 超出阈值范围,发生中断ADC_IT_AWD。AWD:analog watch dog.
  /* Configure high and low analog watchdog thresholds */
  ADC_AnalogWatchdogThresholdsConfig(ADC1, 0x0B00, 0x0300);
  /* Configure channel14 as the single analog watchdog guarded channel */
  ADC_AnalogWatchdogSingleChannelConfig(ADC1, ADC_Channel_14);
  /* Enable analog watchdog on one regular channel */
  ADC_AnalogWatchdogCmd(ADC1, ADC_AnalogWatchdog_SingleRegEnable);

  /* Enable AWD interupt */
  ADC_ITConfig(ADC1, ADC_IT_AWD, ENABLE);
void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Configure and enable ADC interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}
void ADC1_2_IRQHandler(void)
{
  /* Toggle LED1 */
  STM_EVAL_LEDOn(LED1);
  printf("interrupt occur\r");
  STM_EVAL_LEDOff(LED1);
  printf("               \r");
  /* Clear ADC1 AWD pending interrupt bit */
  ADC_ClearITPendingBit(ADC1, ADC_IT_AWD);
}

六、时钟

系统时钟

1.HSE高速外部时钟(常用8MHz无源晶振);
2.PLL时钟源(来源有HSE和HSI/2,一般选HSE作为时钟来源);
3.PLL时钟PLLCLK(通过设置PLL的倍频因子,一般8Mx9=72MHz,72MHz是官方推荐稳定运行时钟,最高128MHz);
4.系统时钟SYSCLK(一般SYSCLK=PLLCLK=72MHz);
5.AHB总线时钟HCLK(是系统时钟SYSCLK经过AHB分频器分频后得到的时钟,也就是APB总线时钟,一般设置1分频,HCLK=SYSSCLK=72MHz);
6.APB2总线时钟HCLK2(APB2总线时钟PCLK2由 HCLK经过高速APB2预分频器得到,分频因子可以是:[1,2,4,8,16],具体由时钟配置寄存器CFGR的位13-11:PPRE2[2:0]决定,一般设置为 1 分频,即 PCLK2 = HCLK =72M);
7.APB1总线时钟HCLK1(APB1 总线时钟 PCLK1 由 HCLK 经过低速 APB 预分频器得到,HCLK1 属于低速的总线时钟,最高为 36M,这里只需粗线条的设置好 APB1 的时钟即可。我们这里设置为 2分频,即 PCLK1 = HCLK/2 = 36M)设置系统时钟函数在库函数system_stm32f10x.c
在这里插入图片描述

设置

  • 设置系统时钟SYSCLK、
  • 设置AHB分频因子(决定HCLK是多少)、
  • 设置APB2分频因子(设定PCLK2等于多少)、
    设置APB1分频因子(决定PCLK1等于多少)、
    控制AHB/APB2/APB1这3条总线开启,控制每个外设时钟的开启。

对于SYSCLK、HCLK、PCLK2、PCLK1这4个时钟的配置一般是:
PCLK2=HCLK=SYSCLK=PLLCLK=72MHz,PCLK1=HCLK/2=36MHz.这个配置是库函数的标准配置。

注意:除了RCC_APB2PeriphClockCmd还有RCC_APB1PeriphClockCmd,那么该如何选择?
APB2:高速时钟,最高72MHz,主要负责AD输入,I/O,串口1,高级定时器TIM
APB1:低速时钟,最高36MHz,主要负责DA输出,串口2、3、4、5,普通定时器TIM,USB,IIC,CAN,SPI

  /* RCC system reset(for debug purpose) */
  RCC_DeInit();

  /* Enable HSE */
  RCC_HSEConfig(RCC_HSE_ON);

  /* Wait till HSE is ready */
  HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)
  {
    /* Enable Prefetch Buffer */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

    /* Flash 2 wait state */
    FLASH_SetLatency(FLASH_Latency_2);
	
    /* HCLK = SYSCLK */
    RCC_HCLKConfig(RCC_SYSCLK_Div1); 
  
    /* PCLK2 = HCLK */
    RCC_PCLK2Config(RCC_HCLK_Div1); 

    /* PCLK1 = HCLK/2 */
    RCC_PCLK1Config(RCC_HCLK_Div2);

    /* ADCCLK = PCLK2/4 */
    RCC_ADCCLKConfig(RCC_PCLK2_Div4); 
  
#ifndef STM32F10X_CL  
    /* PLLCLK = 8MHz * 7 = 56 MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_7);

#else
    /* Configure PLLs *********************************************************/
    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
    RCC_PREDIV2Config(RCC_PREDIV2_Div5);
    RCC_PLL2Config(RCC_PLL2Mul_8);

    /* Enable PLL2 */
    RCC_PLL2Cmd(ENABLE);

    /* Wait till PLL2 is ready */
    while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET)
    {}

    /* PLL configuration: PLLCLK = (PLL2 / 5) * 7 = 56 MHz */ 
    RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
    RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_7);
#endif

    /* Enable PLL */ 
    RCC_PLLCmd(ENABLE);

    /* Wait till PLL is ready */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }

    /* Select PLL as system clock source */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

    /* Wait till PLL is used as system clock source */
    while(RCC_GetSYSCLKSource() != 0x08)
    {
    }
    /* Enable peripheral clocks --------------------------------------------------*/
    ...
  }
void RCC_Configuration(void)
{
  /* Setup the microcontroller system. Initialize the Embedded Flash Interface,  
     initialize the PLL and update the SystemFrequency variable. */
  SystemInit();

  /* Enable TIM2, TIM3 and TIM4 clocks */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3 |
                         RCC_APB1Periph_TIM4, ENABLE);
}

七、TIM

1.资源

STM32F1 系列共有八个TIM,分为基本定时器,通用定时器和高级定时器。
基本定时器 TIM6/7是一个 16 位的只能向上计数的定时器,只能定时,没有外部 IO。
通用定时器 TIM2/3/4/5 是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部 IO。
高级定时器 TIM1/8是一个 16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有 8 个外部 IO。
在这里插入图片描述
输入捕捉和输出比较是共用相同的IO引脚,所以名称标注是一模一样。也就是说,每个通用定时器都只有四个独立通道,当某一通道作为了输入触发功能那就不能再作为输出匹配功能。
中断标记如下:

TIM_IT_Update: TIM update Interrupt source

TIM_IT_CC1: TIM Capture Compare 1 Interrupt source

TIM_IT_CC2: TIM Capture Compare 2 Interrupt source

TIM_IT_CC3: TIM Capture Compare 3 Interrupt source

TIM_IT_CC4: TIM Capture Compare 4 Interrupt source

TIM_IT_COM: TIM Commutation Interrupt source

TIM_IT_Trigger: TIM Trigger Interrupt source

TIM_IT_Break: TIM Break Interrupt source

可以看出输入捕捉,输出比较是共用一种中断标记的。
在这里插入图片描述
在这里插入图片描述
1、时钟源
定时器时钟TIMxCLK,即内部时钟CK_INT,经APB1预分频器后分频提供,如果APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,即 PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M 。
在这里插入图片描述
2、计数器时钟
定时器时钟经过 PSC 预分频器之后,即 CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。
具体计算方式为:CK_CNT=TIMxCLK/(PSC+1)。
3.计数器
计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
4、自动重装载寄存器
自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。

2. 定时时间的计算

定时器的定时时间等于计数器的中断周期乘以中断的次数。
计数时钟:CK_CNT = TIMxCLK/(PSC+1) MHz
计一个数的时间则是 CK_CLK 的倒数:T = 1/CK_CNT s
计数满ARR后产生一次中断,经历的时间则等于:interupt_T = T * (ARR+1) s
若变量 times记录了中断的次数,定时时间等于: interupt_T * times

3.基本配置

typedef struct
{
  uint16_t TIM_Prescaler;         /* 预分频器的值,时钟源的时钟经过该预分频后产生计数时钟CNT_CLK,存储在TIMx_PSC ,0x0000-0xFFFF (0-65535)*/

  uint16_t TIM_CounterMode;       /*定时器计数方式,可是在为向上计数、向下计数以及三种中心对齐模式。基本定时器只能是向上计数,即 TIMx_CNT只能从 0开始递增,并且无需初始化。 */

  uint16_t TIM_Period;            /*定时器周期,实际就是设定自动重载寄存器的值,在事件生成时更新到影子寄存器。可设置范围为 0至 65535。 */ 

  uint16_t TIM_ClockDivision;     /*时钟分频,设置定时器时钟 CK_INT 频率与数字滤波器采样时钟频率分频比,基本定时器没有此功能,不用设置。*/

  uint8_t TIM_RepetitionCounter;  /*设置重复溢出次数,就是多少次溢出后会给你一次中断,一般设置为0,只有高级定时器才有用;*/
} TIM_TimeBaseInitTypeDef;  

例如:

void Timer2_Configuration(void)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_DeInit(TIM2);//使用缺省值初始化TIM外设寄存器
  TIM_TimeBaseStructure.TIM_Period=1;//自动重装载寄存器值为1
  TIM_TimeBaseStructure.TIM_Prescaler=(36000-1);//时钟预分频数为36000
  TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//采样分频倍数1,未明该语句作用。
  TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//上升模式
  TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
  TIM_ClearFlag(TIM2,TIM_FLAG_Update);//清除更新标志位
  TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//使能中断
  TIM_Cmd(TIM2,ENABLE);//使能TIM2定时器
  TIM_PrescalerConfig(TIM2, 0xEA5F, TIM_PSCReloadMode_Immediate); //可选?@brief  Configures the TIMx Prescaler.
}

3.输入捕捉

引脚上一旦出现一个有效边沿(可以配置为上升、下降或者上升下降均触发),那么定时器计数器CNT里面的值就会被相应的Capture/Compare X Register保存下来。这里X可以是1,2,3,4任何一个。并且中断标志位被置位。但是此时TIM的计数寄存器CNT却不管这一事件的发生,继续自己的计数。此功能可以用来测量外部信号的脉宽或者是周期。
TIMx_ICInitStructure的属性有:

  • TIM_Channel:通道选择,TIM_Channel_1,TIM_Channel_2,TIM_Channel_3,TIM_Channel_4
  • TIM_ICPolarity:捕捉信号的高低电平,TIM_ICPolarity_BothEdge,TIM_ICPolarity_Rising,TIM_ICPolarity_Falling
  • TIM_ICSelection:定时器的4个通道并不是完全独立的,而是1、2一组,3、4一组,同组之间的通道是有联系的。也就是可以出现交叉触发。而TIM_ICSelection就是选择要不要使用交叉来触发。
    TIM_ICSelection_DirectTI ,TIM Input 1, 2, 3 or 4 is selected to be connected to IC1, IC2, IC3 or IC4, respectively;
    TIM_ICSelection_IndirectTI, TIM Input 1, 2, 3 or 4 is selected to be connected to IC2, IC1, IC4 or IC3, respectively;
    TIM_ICSelection_TRC ,TIM Input 1, 2, 3 or 4 is selected to be connected to TRC.
  • TIM_ICPrescaler:预分频
  • TIM_ICFilter:滤波器
    例如:
	TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //通道1
  	TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//上升沿捕获
  	TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1
  	TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;	 //无预分频器 
  	TIM5_ICInitStructure.TIM_ICFilter = 0x00; //IC1F=0000 //无滤波器
  	TIM_ICInit(TIM5, &TIM5_ICInitStructure);

4. 输出比较

计数值达到一共预存数后,将会产生一次输出。
可以用于产生PWM波形。
例如:

  TIM_OCInitStructure.TIM_OCMode= TIM_OCMode_PWM1;      //TIM脉冲宽度调制模式1   
  TIM_OCInitStructure.TIM_OutputState= TIM_OutputState_Enable;//这个暂时不知道,stm32固件库里没有搜到。应该是定时器输出声明使能的意思      
  TIM_OCInitStructure.TIM_Pulse =CCR1_Val;//设置了待装入捕获比较寄存器的脉冲值       
  TIM_OCInitStructure.TIM_OCPolarity= TIM_OCPolarity_High; //TIM输出比较极性高
  TIM_OC1Init(TIM3,&TIM_OCInitStructure);
  TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能或者失能TIMx在CCR1上的预装载寄存器

八、EXTI

EXTI管理了控制器的23个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。EXTI可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值