OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5448|回复: 1

使用定时器2的CH1输入捕获和CH2输出比较来对UART断帧检测

[复制链接]

18

主题

62

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
264
金钱
264
注册时间
2012-10-26
在线时间
27 小时
发表于 2015-12-24 15:39:15 | 显示全部楼层 |阅读模式
5金钱
接收大量不定长的串口数据(或是SPI等),常规的方法不太适用,串口的空闲中断如果可以自己设置空闲时长的话可能会好点,但是丢帧率略高。
我现在用STM32F407来接收GPS数据(1秒大概发送五六百字节),不定长,一开始调试的时候用串口的空闲中断配合DMA倒是不错,但是我加上了DMA
双通道缓冲之后发现数据丢失了或者说一大段数据被误认为空闲了,所以打算用定时器来做一个可以自由控制空闲时长的断帧检测(参考ST官方的资料,
《UART断帧检测》)

代码思路:当TIM2_CH1捕获到上升沿的时候清零计数器的值,开启CH2输出捕获,因为TIM2设置为Slave Reset模式,上升沿自动清零,这样如果有
高电平保持时间长于设定值(计数器分频84,即每次计数器加一为1us,输出比较值10ms即0x2710)即TIM2_CH2的CC2中断产生即检测到空闲帧了
测试需要我打开了CC1和CC2中断并在中断中输出,发现CC1中断后CC2 立即也中断了(读出CNT的值也就500以下(us)不可能与0x2710匹配啊),
一直搞不明白错在哪里额,即是在CCA中断中手动清楚CNT也不能阻止CC2中断

[mw_shl_code=c,true] [/mw_shl_code] [mw_shl_code=c,true]static TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure; static NVIC_InitTypeDef NVIC_InitStructure; static GPIO_InitTypeDef GPIO_InitStructure; static TIM_ICInitTypeDef TIM2_ICInitStructure; static TIM_OCInitTypeDef TIM2_OCInitStructure;[/mw_shl_code]

[mw_shl_code=c,true]void TIM2_Int_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); ///使能TIM2时钟 RCC_APB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0,1 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //IO速率100MHz GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推免复用输出 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //下拉 GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0 GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM2); //PA0?PA1复用定时器2 TIM_TimeBaseInitStructure.TIM_Period =0xffffffff; //定时器分频 计数器加1为1ms TIM_TimeBaseInitStructure.TIM_Prescaler=83; //自动重装载值 TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //先上计数 TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; //时钟分频1(84MHz) TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);// //输入捕获配置 TIM2_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端IC1映射到TI1上 TIM2_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获 TIM2_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1 TIM2_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频 TIM2_ICInitStructure.TIM_ICFilter = 0x0;//IC1F=0000 不配置滤波器,提高捕获响应速度 TIM_ICInit(TIM2, &TIM2_ICInitStructure); //输出比较设置 TIM2_OCInitStructure.TIM_OCMode=TIM_OCMode_Timing; TIM2_OCInitStructure.TIM_Pulse=0x2710; //TIM2_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High; //TIM2_OCInitStructure.OCFastMode= TIM_OC2Init(TIM2,&TIM2_OCInitStructure); TIM_SelectSlaveMode(TIM2,TIM_SlaveMode_Reset);//TIM2配置成SLAVE RESET,模式 TIM_SelectInputTrigger(TIM2,TIM_TS_TI1FP1);//TIM2触发模式为ED TIM_SelectMasterSlaveMode(TIM2,TIM_MasterSlaveMode_Enable); TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE); //开启更新中断和CC1IE捕获中断 TIM_Cmd(TIM2,ENABLE); //使能定时器2 NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn; // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=4; //抢占优先级4 NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; //子优先级0 NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); } [/mw_shl_code] [mw_shl_code=c,true]
[mw_shl_code=c,true]void TIM2_IRQHandler(void) { if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//溢出 { if(TIM2CH1_Rising)//已经捕获到高电平 { TIM2CH1_Rising++; } } if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发生捕获事件 { printf("\r\n###############CC1\r\n"); // if(TIM2CH1_Rising) //捕获到一个下降沿 // { // TIM2CH1_Falling=1; //标记成功捕获到一次高电平脉宽 // TIM2CH1_Rising=0; // TIM2CH1_Counter=TIM_GetCapture1(TIM2);//获取当前的捕获值. //printf("\r\n%d",TIM2CH1_Rising*4294); // if(TIM2CH1_Counter>1000) // printf(" %d",TIM2CH1_Counter); // TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获 // } // if(TIM2CH1_Falling) //第一次捕获上升沿 // { // TIM2CH1_Counter=0; //清空 // TIM2CH1_Falling=0; // TIM2CH1_Rising=1; //标记捕获到上升沿 // TIM_Cmd(TIM2,ENABLE ); //使能定时器 TIM_SetCounter(TIM2,0); TIM_ITConfig(TIM2,TIM_IT_CC1,DISABLE); TIM_ITConfig(TIM2,TIM_IT_CC2,ENABLE); // TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获 // TIM_Cmd(TIM2,ENABLE ); //使能定时器 // } } if(TIM_GetITStatus(TIM2,TIM_IT_CC2)!=RESET) { printf(" CC2"); printf(" %d",TIM_GetCapture1(TIM2)); TIM_ITConfig(TIM2,TIM_IT_CC1,ENABLE); TIM_ITConfig(TIM2,TIM_IT_CC2,DISABLE); } TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位 }[/mw_shl_code]


[/mw_shl_code] [mw_shl_code=c,true] [/mw_shl_code] [mw_shl_code=c,true] [/mw_shl_code]

UART的断帧检测.pdf

112.26 KB, 下载次数: 135

最佳答案

查看完整内容[请看2#楼]

结帖结贴,忘记清除CC2的中断标志位了,草!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
无个性,不签名
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

18

主题

62

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
264
金钱
264
注册时间
2012-10-26
在线时间
27 小时
 楼主| 发表于 2015-12-24 15:39:16 | 显示全部楼层
结帖结贴,忘记清除CC2的中断标志位了,草!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
无个性,不签名
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-25 21:21

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表