一、定时器和外部触发的同步
TIMx定时器能够在多种模式下和一个外部的触发同步:复位模式、门控模式和触发模式。
- 从模式:复位模式
复位模式时序图如下所示:
配置通道1以检测TI1的上升沿,配置定时器为复位模式,计数器为向上计数模式,选择T1位输入源。每一个计数器时钟周期计数器寄存器自增。当TI1产生一个上升沿时,计数器寄存器清0重新开始计数。
- 从模式:门控模式
门控模式时序图如下所示:
配置通道1以检测TI1的低电平,配置定时器为门控模式,计数器为向上计数模式,选择T1为输入源。每一个计数器时钟周期计数器寄存器自增。只要TI1为低,计数器开始依据内部时钟计数,在TI1为高电平时停止计数。
- 从模式:触发模式
配置通道2检测TI2的上升沿。配置定时器为触发模式,选择TI2为输入源。当TI2出现一个上升沿时,计数器开始在内部时钟的驱动下计数。
二、利用复位模式串口接收不定长数据
利用复位模式串口接收不定长数据的思路为:将定时器通道引脚与串口RX引脚硬件上连接,串口接收使用DMA方式,定时器在串口未收到数据时不工作,当串口收到数据时,配置定时器,关闭串口中断,当串口上还有数据未接收完成时,计数器不断清0重新开始计数,一旦串口无接收数据时,计数器不再复位,知道产生计数器中断,然后将收到的数据读出。
- 串口配置:
这里都是些常规配置。
/***************************************************************************
* @fn Usart1_Configuration
*
* @brief
*
* @data
*
* @param BaudRate -
* NewState - ENABLE/DISABLE
*
* @return void
***************************************************************************
*/
void Usart1_Configuration(uint32_t BaudRate,uint16_t parity, uint16_t wordlength, uint16_t stopbits,FunctionalState NewState)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* config USART1 clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);
/* USART1 GPIO config */
/* Configure USART1 Tx (PA.9) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 Rx (PA.10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_DeInit(USART1);
USART_InitStructure.USART_BaudRate = BaudRate ; //
USART_InitStructure.USART_WordLength = wordlength; //
USART_InitStructure.USART_StopBits = stopbits; //´
USART_InitStructure.USART_Parity = parity ; //
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//Ó²¼þÁ÷ʧÄÜ
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //
USART_Init(USART1, &USART_InitStructure); //´
USART_ITConfig(USART1,USART_IT_RXNE,NewState); //
__nop(); __nop();
USART_Cmd(USART1, NewState); //
}
/***************************************************************************
* @fn USART1_NVIC_Configuration
*
* @brief ÅäÖô®¿Ú1Öжϡ£
* USART1ÖжÏ×éΪµÚ3×飬ÇÀÕ¼ÓÅÏȼ¶1£¬ÏìÓ¦ÓÅÏȼ¶0
*
* @data 2015Äê08ÔÂ05ÈÕ
*
* @param NewState - ENABLE/DISABLE
*
* @return void
***************************************************************************
*/
void USART1_NVIC_Configuration(FunctionalState NewState)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_SetVectorTable (NVIC_VectTab_FLASH, NVIC_VECTTAB_FLASH_OFFSET);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = NewState;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/***************************************************************************
* @fn Usart1_DMA_Configuration
*
* @brief ÅäÖÃUSART1µÄDMA½ÓÊպͷ¢ËÍ,USART2->TXʹÓÃDMA1_Channel6,
* USART2->RXʹÓÃDMA1_Channel7¡£
*
* @data 2015Äê08ÔÂ05ÈÕ
*
* @param void
*
* @return void
***************************************************************************
*/
void Usart1_DMA_Configuration(void)
{
DMA_InitTypeDef DMA_InitStructure;
/* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//DMA1
/* DMA1 Channel5 (triggered by USART1 Rx event) Config */
DMA_DeInit(DMA1_Channel5);
DMA_InitStructure.DMA_PeripheralBaseAddr = 0x40013804;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart1_recv_data.RecvData;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = USART1_DMA_BUFFER_SIZE;
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_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);
//DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
//DMA_ITConfig(DMA1_Channel6, DMA_IT_TE, ENABLE);
/* Enable USART1 DMA RX request */
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);
DMA_Cmd(DMA1_Channel5, ENABLE);
}
- 定时器配置:
定时器配置比较重要,我这里设置了输出比较,并且开了CC2中断,当计数器寄存器的值达到输出比较寄存器的值时会产生中断。然后选择TI2为输入源,且为复位模式,当TI2有信号时则计数器清零,这样不会产生CC1比较中断。
/***************************************************************************
* @fn TIM4_Configuration
*
* @brief TIM4ÅäÖÃ,ʹÓø´Î»Ä£Ê½¡£TIM4µÄ²¶»ñ/±È½ÏÊäÈë2ºÍ´®¿Ú2µÄRXÔÚÓ²¼þ
* ÉÏÏàÁ¬, ´®¿ÚÓÐÊý¾Ýʱ£¬TIM4Ò»Ö±¸´Î»£¬Ò»µ©´®¿ÚûÓÐÊý¾Ý£¬ÔòTIM4
* ²»ÔÙ¸´Î»¡£TIM4³¬Ê±ºó£¬»á²úÉúÒ»¸ö³¬Ê±Öжϡ£
*
* @data 2015Äê08ÔÂ05ÈÕ
*
* @param void
*
* @return void
***************************************************************************
*/
void TIM4_Configuration(uint32_t bandrate)
{
uint16_t tim_pluse = bandrate == 2400? 80: 40;//2400²¨ÌØÂÊʱ ¼ÆÊý80¸öÖÜÆÚ ÆäÓà40¸öÖÜÆÚ
/* TIM4 configuration -------------------------------------*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable TIM4 clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4 , ENABLE);
TIM_DeInit(TIM4);
TIM_TimeBaseStructure.TIM_Period = 65535; //65535
TIM_TimeBaseStructure.TIM_Prescaler = (7200 - 1); //3600
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM_ARRPreloadConfig(TIM4, DISABLE);
/* Output Compare Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;
TIM_OCInitStructure.TIM_Pulse = tim_pluse;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC2Init(TIM4, &TIM_OCInitStructure);
/* TIM4 Channel 1 Input Capture Configuration */
// TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
// TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
// TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
// TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
// TIM_ICInitStructure.TIM_ICFilter = 0;
// TIM_ICInit(TIM4, &TIM_ICInitStructure);
/* TIM4 Input trigger configuration: External Trigger connected to TI2 */
TIM_SelectInputTrigger(TIM4, TIM_TS_TI2FP2);
/* TIM4 configuration in slave reset mode where the timer counter is
re-initialied in response to rising edges on an input capture (TI2) */
TIM_SelectSlaveMode(TIM4, TIM_SlaveMode_Reset);
/* TIM4 IT CC1 enable */
TIM_ITConfig(TIM4, TIM_IT_CC2, ENABLE);
NVIC_SetVectorTable (NVIC_VectTab_FLASH, NVIC_VECTTAB_FLASH_OFFSET);
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM4, ENABLE);
}
- 串口中断:
/***************************************************************************
* @fn USAR1_IRQHandler
*
* @brief ½ÓÊÕµ½Ò»¸öByteµÄÊý¾Ýºó£¬²úÉú´®¿ÚÖжϡ£¹Ø±Õ´®¿ÚÖжϣ¬Ê¹Äܶ¨Ê±Æ÷.
*
* @data 2015Äê08ÔÂ05ÈÕ
*
* @param
*
* @return
***************************************************************************
*/
void USART1_IRQHandler()
{
RS485_recving = 1;
globalFlag.uart1_dma_flag = 1;
uint32_t rs485_bandrate = 0;
USART1_NVIC_Configuration(DISABLE);
change_to_rate(rs485_para.band_rate, &rs485_bandrate);
TIM4_Configuration(rs485_bandrate);
}
- 定时器中断:
定时器中断产生后将DMA缓冲区数据提取出来。
/***************************************************************************
* @fn TIM4_IRQHandler
*
* @brief TIM4³¬Ê±ÖжÏ
*
* @data 2015Äê08ÔÂ05ÈÕ
*
* @param void
*
* @return void
***************************************************************************
*/
void TIM4_IRQHandler(void)
{
TIM_Cmd(TIM4, DISABLE);
TIM_ClearFlag(TIM4, TIM_IT_CC2);
TIM_SetCounter(TIM4,0);
NVIC_ClearPendingFlag(USART1_IRQn);
USART1_NVIC_Configuration(ENABLE);
Iterates_usart1_buffer();
}