大家好,本人在校老菜鸡一个,最近抽空接手了一个项目,其中一个关键点在于“通过输入捕获检测任意引脚、任意顺序高低电平的持续时间”。
咱们直入主题,stm32的具有丰富的外设资源,小编选择用stm32f1系列单片机作为核心控制器,来完成这个项目。
方案有两种:
方案一:采用中断,例如外部引脚中断等,直接在检测到指定电平时,发生跳变进入中断函数,然后进行计时。
方案二:采用定时器输入捕获,在上升沿、下降沿时发生跳变,然后进行计时。
优缺点分析:方案一实行难度较小,但是需要引脚资源较多(一个检测高电平,一个检测低电平),时间精度稍微弱一点。
方案二拥有现成的历程,直接调用即可,通过定时器输入捕获模式,中断里进行计数。
看似使用方案二是最佳的选择,但是,如果这样的话,小编就不用写这篇博客了.
至于方案一、小弟也还没有尝试过,不清楚具体效果如何。
背景介绍(大牛不喜勿喷)
输入捕获模式:输入捕获模式可以用来测量脉冲宽度或者测量频率,Stm32定时器除了定时器6和定时器7,其他定时器都有输入捕获功能,简单来说,就是在边沿信号发生跳变的时候(上升沿、下降沿),将当前定时器的值存放到对应通道的捕获/比寄存器中,完成一次捕获,同时,可以再配置捕获到相应跳变时,是否触发中断/DMA等等。
一、测量高电平脉冲宽度:采用正点原子的代码思路。先将引脚设定为下拉输入,然后设置输入捕获为“上升沿触发”,将当前定时器中的时间存储起来,然后再中断里将触发方式设置为“下降沿触发”,再记录一下触发时间,二者相减,即可得出高电平持续时间。
二、测量低电平脉冲宽度:与测量高电平脉冲宽度正好相反,不过应该如何设置呢?小编找了很久,也没有答案,所以只能自己动手,丰衣足食咯。
先看检测高电平脉冲的代码:
//定时器2中断服务程序
void TIM2_IRQHandler(void)
{
if((TIM2CH1_CAPTURE_STA&0X80)==0)// 这里采用了两个变量作为临时判断条件,这两个变量最初值都为0
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//如果是发生了中断,那么向下执行
{
if(TIM2CH1_CAPTURE_STA&0X40)//如果已经捕获到高电平那么就进一步执行程序。
{
if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//
{
TIM2CH1_CAPTURE_STA|=0X80;/
TIM2CH1_CAPTURE_VAL=0XFFFF;
}else TIM2CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//
{
if(TIM2CH1_CAPTURE_STA&0X40) /
{
TIM2CH1_CAPTURE_STA|=0X80; /
TIM2CH1_CAPTURE_VAL=TIM_GetCapture1(TIM2);
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); /
}else //
{
TIM2CH1_CAPTURE_STA=0;
TIM2CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM2,0);
TIM2CH1_CAPTURE_STA|=0X40; //
TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //
}
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); /
}//////(小小吐槽一下,网站上传图片功能个人感觉有点鸡肋。这一段很重要,必须要认真去揣摩TIM2CH1_CAPTURE_STA的赋值关系。不要做拿来主义,这样只能是拔苗助长,得不偿失。)
通过两个变量的“与”、“赋值”等操作,对高电平进行不同的操作。在输入捕获通道中,设置为上升沿触发。过来一个上升沿,进入中断,检查是否标记位被赋值,如果没有,代表是是第一次检测到高电平,记录当前定时器的值,然后设置为下降沿........
测量低电平脉冲时长的代码:简述一下思路,就是同样定义两个变量,按照上述代码的格式,照猫画虎一次,几乎没有大的改变。
具体情况,请在代码文件中进行查看。
备注:有一个语句 TIM_SetCounter(TIM2,0);具体作用我在代码中也有标注,时间所限,就不再多说了,一切尽在代码中。有空再来补全相关内容。
单片机源程序如下:
- #include "sys.h"
- #include "usart.h"
- #include "delay.h"
- #include "led.h"
- #include "stm32f10x.h"
- #include "usart1.1.h"
- #include "oled.h"
- #include "timer.h"
- //MPU6050
- //串口1发送1个字符
- //c:要发送的字符
- float x,y=0;
- u8 xy[20];//用于接收坐标?
- u8 len;
- u16 led0pwmval=1;
- int main(void)
- {
- int i=0;
- u8 t;
- u16 times=0;
-
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
- delay_init(); //延时函数初始化
- usart_init(19200); //串口初始化为9600
- OLED_Init();
- LED_Init();
- TIM2_Cap_Init(0XFFFF,7199); //以1Mhz的频率计数 0XFFFF----1111 1111 1111 1111(2进制)//10khz计数频率,每计数一下是1ms
- TIM1_PWM_Init(9999,7199);//1MHZ频率输出。
- TIM3_PWM_Init(9999,7199);//10kHZ技术频率。
- while(1)
- {
- //OLED_show();
- //show1_all();这两个暂时取消
- //delay_ms(300);不清楚会造成什么样的后果
- TIM_SetCompare3(TIM3,led0pwmval);
- TIM_SetCompare4(TIM3,led0pwmval);
- // TIM_SetCompare4(TIM1,led0pwmval);
-
- if(USART_RX_STA&0x8000)//判断接收数组的最高位是否为一,本次接收是否完成
- {
- len=USART_RX_STA&0x3fff;//取出u16中的低16 位,得到此次接收到的数据长度
- USART_RX_STA=0;//对数组清零,方便下一次接收
-
- }
- if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)==0)
- {
- delay_ms(1000);
- LED=0;
- printf("1");
- }
- if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)==0)
- {
- delay_ms(1000);
- LED=1;
- printf("2");
- }
- if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)==0)
- {
- delay_ms(1000);
- printf("3");
- }
- convey();
- }
- }
复制代码
目前代码还存在很多问题,求大神指导如何修改:
交替检测高低电平.7z
(215.35 KB, 下载次数: 149)
|