OpenEdv-开源电子网

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

超声波测距模块驱动

[复制链接]

6

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
81
金钱
81
注册时间
2013-9-15
在线时间
0 小时
发表于 2014-6-5 15:24:06 | 显示全部楼层 |阅读模式
5金钱
原子哥,我仿照开发指南上的捕获实验写了这个超声波测距模块的驱动,我用的定时器1触发超声波,用定时器2的通道2捕获高电平时间,我已经确定寄存器配置没有问题,用PA0输出信号,PA1输入信号,现在问题是对于溢出处理这不是很懂,现在测距的时候会间隔输出一个错误的值,测得的距离正确,但是每一个正确的数值下一个数据就是错误的,我用硬件调试貌似是溢出这里的问题,我同学用通道一映射到通道二来捕获没有问题,他说通道一捕获会出错,不知道怎么回事,还有我发现例程里面用的通道1捕获但是设置分频时却设置的通道2的分频,不知道是不是写错了,下面附上我的代码,希望能指导一下:
这是定时器驱动代码,用到的是TIM2的捕获初始化和TIM1的初始化,我吧定时器的相关驱动都整理了一下,所以其他的在这里没用到,这是四个定时器的初始化函数,
[mw_shl_code=c,true]/* ********************************************************************************************************* * Embedded Systems Building Blocks * Complete and Ready-to-Use Modules in C * * TIMER Module Driver * * (c) Copyright 2014, Fisher * * Filename : timer.c * Programmer : Fisher ********************************************************************************************************* * DESCRIPTION * * 这个模块提供各个定时器的初始化接口,以及定时器的中断服务程序 * * 消耗的IO口:PA11 下拉输入,作为TIM1的通道四输入捕获口 * PA1 下拉输入,作为TIM2的通道二输入捕获口 * PA0 下拉输出,作为超声波模块的触发信号,在定时器1中断中 ********************************************************************************************************* */ /*$PAGE*/ /* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */ #include "timer.h" #include "led.h" #include "usart.h" #include "delay.h" /*$PAGE*/ /* ********************************************************************************************************* * CONSTANTS ********************************************************************************************************* */ /* ** 捕获状态 ** [7]:0,没有成功的捕获;1,成功捕获到一次. ** [6]:0,还没捕获到高电平;1,已经捕获到高电平了. ** [5:0]:捕获高电平后溢出的次数 */ u8 TIM1CH4_CAPTURE_STA = 0; /* 输入捕获状态 */ u16 TIM1CH4_CAPTURE_VAL; /* 输入捕获值 */ u8 TIM2CH2_CAPTURE_STA = 0; /* 输入捕获状态 */ u16 TIM2CH2_CAPTURE_VAL; /* 输入捕获值 */ float high = 0.0; /*$PAGE*/ /* ********************************************************************************************************* * 定时器1中断服务程序 * * 描述: 此函数提供定时器3的中断服务程序 * 参数: 无 * 返回值:无 ********************************************************************************************************* */ void TIM1_UP_IRQHandler(void) { if(TIM1->SR & 0X0001) /* 溢出中断 */ { /* 中断处理程序 */ LED_GRE = !LED_GRE; PAout(0) = 1; /* 脉冲触发 */ delay_us(10); /* 手册中需要至少给10us的高电平脉冲 */ PAout(0) = 0; } TIM1->SR &= ~(1 << 0); /* 清除中断标志位 */ } /*$PAGE*/ /* ********************************************************************************************************* * 初始化定时器输入捕获功能 * * 描述: 此函数初始化STM32定时器1的输入捕获功能 * Tout = ((arr+1) * (psc+1))/ Tclk * 参数: arr 自动重装值。 * psc 时钟预分频数 * 返回值:无 ********************************************************************************************************* */ void TIM1_Cap_Init(u16 arr,u16 psc) { RCC->APB2ENR |= 1 << 11; /* TIM1时钟使能 */ RCC->APB1ENR |= 1 << 2; /* GPIOA 时钟使能 */ GPIOA->CRH &= 0XFFFF0FFF; GPIOA->CRH |= 0X00008000; /* PA11下拉输入 */ GPIOA->ODR |= 0 << 11; /* ** 自动重装载值,计数器计数到这个值就会触发溢出中断 */ TIM1->ARR = arr; /* ** 预分频器,得到计数时钟, ** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s */ TIM1->SC = psc; TIM1->CCMR2 |= 1 << 8; /* CC4S = 01, CC4通道配置为输入,IC4映射到TI4上 */ TIM1->CCMR2 |= 0 << 12; /* IC4F=0000 配置输入滤波器 不滤波 */ TIM1->CCMR2 |= 0 << 10; /* IC4PS=00 配置输入分频,不分频 */ TIM1->CCER |= 0 << 13; /* CC4P=0 上升沿捕获 */ TIM1->CCER |= 1 << 12; /* CC4E=1 允许捕获计数器的值到捕获寄存器中 */ /* 这两个东东要同时设置才可以使用中断 */ TIM1->DIER |= 1 << 0; /* 允许更新中断 */ TIM1->DIER |= 1 << 4; /* 允许捕获4中断 */ TIM1->CR1 |= 0x01; /* 使能定时器1 */ MY_NVIC_Init(1,0,TIM1_UP_IRQChannel,1); /* 抢占1,子优先级2,组1 */ } /*$PAGE*/ /* ********************************************************************************************************* * 初始化定时器输入捕获功能 * * 描述: 此函数初始化STM32定时器2的输入捕获功能 * Tout = ((arr+1) * (psc+1))/ Tclk * 参数: arr 自动重装值。 * psc 时钟预分频数 * 返回值:无 ********************************************************************************************************* */ void TIM2_Cap_Init(u16 arr,u16 psc) { RCC->APB1ENR |= 1 << 0; /* TIM2时钟使能 */ RCC->APB2ENR |= 1 << 2; /* GPIOA 时钟使能 */ GPIOA->CRL &= 0XFFFFFF0F; GPIOA->CRL |= 0X00000080; /* PA1下拉输入 */ GPIOA->ODR |= 0 << 1; /* ** 自动重装载值,计数器计数到这个值就会触发溢出中断 */ TIM2->ARR = arr; /* ** 预分频器,得到计数时钟, ** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s */ TIM2->SC = psc; TIM2->CCMR1 |= 1 << 8; /* CC2S = 01, CC2通道配置为输入,IC2映射到TI2上 */ TIM2->CCMR1 |= 0 << 12; /* IC2F=0000 配置输入滤波器 不滤波 */ TIM2->CCMR1 |= 0 << 10; /* IC2PS=00 配置输入分频,不分频 */ TIM2->CCER |= 0 << 5; /* CC2P=0 上升沿捕获 */ TIM2->CCER |= 1 << 4; /* CC2E=1 允许捕获计数器的值到捕获寄存器中 */ /* 这两个东东要同时设置才可以使用中断 */ TIM2->DIER |= 1 << 0; /* 允许更新中断 */ TIM2->DIER |= 1 << 2; /* 允许捕获2中断 */ TIM2->CR1 |= 0x01; /* 使能定时器2 */ MY_NVIC_Init(2,2,TIM2_IRQChannel,2); /* 抢占2,子优先级2,组2 */ } /*$PAGE*/ /* ********************************************************************************************************* * 初始化定时器1 * * 描述: 此函数初始化STM32定时器1 * Tout = ((arr+1) * (psc+1))/ Tclk * 参数: arr 自动重装值。 * psc 时钟预分频数 * 返回值:无 ********************************************************************************************************* */ void Timer1_Init(u16 arr,u16 psc) { RCC->APB2ENR |= 1 << 11; /* TIM1时钟使能 */ /* ** 自动重装载值,计数器计数到这个值就会触发溢出中断 */ TIM1->ARR = arr; /* ** 预分频器,得到计数时钟, ** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s */ TIM1->SC = psc; /* 这两个东东要同时设置才可以使用中断 */ TIM1->DIER |= 1 << 0; /* 允许更新中断 */ TIM1->DIER |= 1 << 6; /* 允许触发中断 */ TIM1->CR1 |= 0x01; /* 使能定时器4 */ MY_NVIC_Init(2,1,TIM1_UP_IRQChannel,2); /* 抢占2,子优先级1,组2 */ } /*$PAGE*/ /* ********************************************************************************************************* * 定时器2中断服务程序 * * 描述: 此函数提供定时器3的中断服务程序 * 参数: 无 * 返回值:无 ********************************************************************************************************* */ void TIM2_IRQHandler(void) { u16 tsr; tsr = TIM2->SR; if((TIM2CH2_CAPTURE_STA & 0X80) == 0) /* 还未成功捕获 */ { if(tsr & 0X01) /* 溢出 */ { if(TIM2CH2_CAPTURE_STA & 0X40) /* 已经捕获到高电平了 */ { if((TIM2CH2_CAPTURE_STA & 0X3F) == 0X3F) /* 高电平太长了 */ { TIM2CH2_CAPTURE_STA |= 0X80; /* 标记成功捕获了一次 */ TIM2CH2_CAPTURE_VAL = 0XFFFF; } else TIM2CH2_CAPTURE_STA++; } } if(tsr & (1 << 2)) /* 捕获 2 发生捕获事件 */ { if(TIM2CH2_CAPTURE_STA & 0X40) /* 捕获到一个下降沿 */ { TIM2CH2_CAPTURE_STA |= 0X80; /* 标记成功捕获到一次高电平脉宽 */ TIM2CH2_CAPTURE_VAL = TIM2->CCR2; /* 获取当前的捕获值. */ high = TIM2CH2_CAPTURE_STA & 0X3F; high *= 65536; /* 溢出时间总和 */ high += TIM2CH2_CAPTURE_VAL; /* 得到总的高电平时间 */ high = high * 170 / 1000000; printf("High:%lf m\r\n",high); /* 打印总的高点平时间 */ TIM2CH2_CAPTURE_STA = 0; /* 开启下一次捕获 */ TIM2->CCER &= ~(1 << 5); /* CC2P=0 设置为上升沿捕获 */ } else { /* 还未开始,第一次捕获上升沿 */ TIM2CH2_CAPTURE_STA = 0; /* 清空 */ TIM2CH2_CAPTURE_VAL = 0; TIM2CH2_CAPTURE_STA |= 0X40; /* 标记捕获到了上升沿 */ TIM2->CNT = 0; /* 计数器清空 */ TIM2->CCER |= 1 << 5; /* CC2P=1 设置为下降沿捕获 */ } } } TIM2->SR &= ~(1 << 0); /* 清除中断标志位 */ } /*$PAGE*/ /* ********************************************************************************************************* * 初始化定时器2 * * 描述: 此函数初始化STM32定时器2,因为System_Clock_Init()函数将APB1的分频系数设置为2, * 所以TIM2的时钟频率为APB1的2倍,而APB1为36M * Tout = ((arr+1) * (psc+1))/ Tclk * 参数: arr 自动重装值。 * psc 时钟预分频数 * 返回值:无 ********************************************************************************************************* */ void Timer2_Init(u16 arr,u16 psc) { RCC->APB1ENR |= 1 << 0; /* TIM2时钟使能 */ /* ** 自动重装载值,计数器计数到这个值就会触发溢出中断 */ TIM2->ARR = arr; /* ** 预分频器,得到计数时钟, ** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s */ TIM2->SC = psc; /* 这两个东东要同时设置才可以使用中断 */ TIM2->DIER |= 1 << 0; /* 允许更新中断 */ TIM2->DIER |= 1 << 6; /* 允许触发中断 */ TIM2->CR1 |= 0x01; /* 使能定时器2 */ MY_NVIC_Init(1,2,TIM2_IRQChannel,2); /* 抢占1,子优先级2,组2 */ } /*$PAGE*/ /* ********************************************************************************************************* * 定时器3中断服务程序 * * 描述: 此函数提供定时器3的中断服务程序 * 参数: 无 * 返回值:无 ********************************************************************************************************* */ void TIM3_IRQHandler(void) { if(TIM3->SR & 0X0001) /* 溢出中断 */ { /* 中断处理程序 */ LED_GRE = !LED_GRE; } TIM3->SR &= ~(1 << 0); /* 清除中断标志位 */ } /*$PAGE*/ /* ********************************************************************************************************* * 初始化定时器3 * * 描述: 此函数初始化STM32定时器3,因为System_Clock_Init()函数将APB1的分频系数设置为2, * 所以TIM3的时钟频率为APB1的2倍,而APB1为36M * Tout = ((arr+1) * (psc+1))/ Tclk * 参数: arr 自动重装值。 * psc 时钟预分频数 * 返回值:无 ********************************************************************************************************* */ void Timer3_Init(u16 arr,u16 psc) { RCC->APB1ENR |= 1 << 1; /* TIM3时钟使能 */ /* ** 自动重装载值,计数器计数到这个值就会触发溢出中断 */ TIM3->ARR = arr; /* ** 预分频器,得到计数时钟, ** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s */ TIM3->SC = psc; /* 这两个东东要同时设置才可以使用中断 */ TIM3->DIER |= 1 << 0; /* 允许更新中断 */ TIM3->DIER |= 1 << 6; /* 允许触发中断 */ TIM3->CR1 |= 0x01; /* 使能定时器3 */ MY_NVIC_Init(1,3,TIM3_IRQChannel,2); /* 抢占1,子优先级3,组2 */ } /*$PAGE*/ /* ********************************************************************************************************* * 定时器4中断服务程序 * * 描述: 此函数提供定时器3的中断服务程序 * 参数: 无 * 返回值:无 ********************************************************************************************************* */ void TIM4_IRQHandler(void) { if(TIM4->SR & 0X0001) /* 溢出中断 */ { /* 中断处理程序 */ LED_GRE = !LED_GRE; } TIM4->SR &= ~(1 << 0); /* 清除中断标志位 */ } /*$PAGE*/ /* ********************************************************************************************************* * 初始化定时器4 * * 描述: 此函数初始化STM32定时器3,因为System_Clock_Init()函数将APB1的分频系数设置为2, * 所以TIM4的时钟频率为APB1的2倍,而APB1为36M * Tout = ((arr+1) * (psc+1))/ Tclk * 参数: arr 自动重装值。 * psc 时钟预分频数 * 返回值:无 ********************************************************************************************************* */ void Timer4_Init(u16 arr,u16 psc) { RCC->APB1ENR |= 1 << 2; /* TIM4时钟使能 */ /* ** 自动重装载值,计数器计数到这个值就会触发溢出中断 */ TIM4->ARR = arr; /* ** 预分频器,得到计数时钟, ** 比如预分频器为7200,计数时钟就为10KHz,即计数到10000为1s */ TIM4->SC = psc; /* 这两个东东要同时设置才可以使用中断 */ TIM4->DIER |= 1 << 0; /* 允许更新中断 */ TIM4->DIER |= 1 << 6; /* 允许触发中断 */ TIM4->CR1 |= 0x01; /* 使能定时器4 */ MY_NVIC_Init(1,1,TIM4_IRQChannel,2); /* 抢占1,子优先级3,组2 */ } [/mw_shl_code]
这是超声波初始化函数
[mw_shl_code=c,true]/* ********************************************************************************************************* * Embedded Systems Building Blocks * Complete and Ready-to-Use Modules in C * * ULTRASOUND Module Driver * * (c) Copyright 2014, Fisher * * Filename : ultrasound.c * Programmer : Fisher ********************************************************************************************************* * DESCRIPTION * * 这个模块 * 提供的接口: * 消耗的IO口: ********************************************************************************************************* */ /*$PAGE*/ /* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */ #include "ultrasound.h" #include "timer.h" // float high = 0.0; /*$PAGE*/ /* ********************************************************************************************************* * 超声波初始化 * * 描述: 此函数初始化超声波相关的IO口 * 参数: 无 * 返回值:无 ********************************************************************************************************* */ void ultrasound_init(void) { TIM2_Cap_Init(0XFFFF,71); /* 1MHz频率计数 */ Timer1_Init(4999,7199); RCC->APB2ENR |= 1 << 2; /* 使能PORTA时钟 */ GPIOA->CRL &= 0XFFFFFFF0; /* PA0 清除之前设置 */ GPIOA->CRL |= 0X00000003; /* PA0 输出 */ GPIOA->ODR |= 0 << 0; /* PA0 下拉 */ }[/mw_shl_code] [mw_shl_code=c,true] [/mw_shl_code] [mw_shl_code=c,true]这是main函数[/mw_shl_code] [mw_shl_code=c,true]#include "sys.h" #include "usart.h" #include "delay.h" #include "timer.h" #include "led.h" #include "ultrasound.h" int main() { Stm32_Clock_Init(9); /* 系统时钟设置 */ delay_init(72); /* 延时初始化 */ usart1_init(72, 9600); ultrasound_init();   LED_Init(); while(1) { LED_RED = !LED_RED; delay_ms(20); } }
下面附上整个工程[/mw_shl_code] [mw_shl_code=c,true] [/mw_shl_code]

超声波.rar

466.65 KB, 下载次数: 920

最佳答案

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

 找出问题了,TIM2->SR &= ~(1 << 0); 这一句应该改为TIM2->SR = 0; 不知道问什么,其他中断标志清零都是前者啊,不知道问什么,现在上传改好了的附件,把超声波用到的定时器提取出来了
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

6

主题

37

帖子

0

精华

初级会员

Rank: 2

积分
81
金钱
81
注册时间
2013-9-15
在线时间
0 小时
 楼主| 发表于 2014-6-5 15:24:07 | 显示全部楼层
 找出问题了,TIM2->SR &= ~(1 << 0); 这一句应该改为TIM2->SR = 0; 不知道问什么,其他中断标志清零都是前者啊,不知道问什么,现在上传改好了的附件,把超声波用到的定时器提取出来了

超声波140605.rar

465.45 KB, 下载次数: 1389

回复

使用道具 举报

170

主题

917

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1824
金钱
1824
注册时间
2013-4-13
在线时间
63 小时
发表于 2014-6-5 15:55:48 | 显示全部楼层
感觉代码很规范。
手艺人要内外兼修。
回复

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2015-3-22
在线时间
8 小时
发表于 2015-7-25 14:14:27 | 显示全部楼层
谢谢,楼主(我的回复,希望是你开源的不竭动力,我也会把自己学到的东西开源的)
知行和一
回复

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2015-3-22
在线时间
8 小时
发表于 2015-7-25 16:43:57 | 显示全部楼层
TIM2->SR &= ~(1 << 0); 和TIM2->SR = 0区别可能在于捕获中断标志有没有清除的差别
知行和一
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-19 11:55

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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