这几天在做超声波模块在STM32上的应用,事实证明不论在arduino上还是stm32上超声波模块对比红外和蓝牙都是最麻烦的。在我们的不懈努力下,今天终于找到了能用的超声波模块驱动代码?。废话不多说先上代码。
#include "sys.h"
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "time.h"
void HCSR04_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<0; //TIM2时钟使能
RCC->APB2ENR|=1<<2; //使能端口A时钟
GPIOA->CRL&=0XFFFFFFF0;
GPIOA->CRL|=0X00000008; //将PA0设置为输入模式
GPIOA->ODR|=0<<0; //对ODR寄存器进行操作将PA0设置为下拉输入
GPIOA->CRL&=0XFFF0FFFF;
GPIOA->CRL|=0X00030000; //将PA4设置为推挽输出
GPIOA->ODR|=1<<5;
TIM2->ARR=arr; //设定计数器重装值为arr
TIM2->PSC=psc; //预分频系数为psc
TIM2->CCMR1|=1<<0; //CC1S=01,选择输入端
TIM2->CCMR1|=1<<4; //IC1F=0001配置滤波器 以Fck_int采样,两个事件后有效
TIM2->CCMR1|=0<<2; //IC1PS=00 配置输入分频 ,不分频
TIM2->CCER|=0<<1; //CC1P=0上升沿捕获
TIM2->CCER|=1<<0; //CC1E=1 允许捕获计数器的值到捕获寄存器中
TIM2->DIER|=1<<1; //允许捕获中断
TIM2->DIER|=1<<0; //允许更新中断
TIM2->CR1|=0X01; //使能定时器2
MY_NVIC_Init(2,0,TIM2_IRQn,2); //抢占2 子优先级0 组2
}
u8 TIM2CH1_CAPTURE_STA=0; //输入捕获状态
u16 TIM2CH1_CAPTURE_VAL; //输入捕获值
//定时器2中断服务程序
void TIM2_IRQHandler(void)
{
u16 tsr;
tsr=TIM2->SR;
if((TIM2CH1_CAPTURE_STA&0X80)==0) //还未成功捕获
{
if(tsr&0X01) //溢出
{
if(TIM2CH1_CAPTURE_STA&0X40) //已经捕获到高电平
{
if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F) //高电平太长
{
TIM2CH1_CAPTURE_STA|=0X80; //标记成功捕获了一次
TIM2CH1_CAPTURE_VAL=0XFFFF;
}else TIM2CH1_CAPTURE_STA++;
}
}
if(tsr&0x02) //捕获1发生捕获事件
{
if(TIM2CH1_CAPTURE_STA&0X40) //捕获到一个下降沿
{
TIM2CH1_CAPTURE_STA|=0X80; //标记成功捕捉到一次高电平脉宽
TIM2CH1_CAPTURE_VAL=TIM2->CCR1; //获取当前的捕获值
TIM2->CCER&=~(1<<1); //CC1P=0设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM2CH1_CAPTURE_VAL=0;
TIM2CH1_CAPTURE_STA=0X40; //标记捕获到了上升沿
TIM2->CNT=0; //计数器清空
TIM2->CCER|=1<<1; //CC1P设置为下降沿捕获
}
}
}
TIM2->SR=0; //设置为中断标志位
}
#define Trig PAout(4)
int main(void)
{
u32 temp=0;
u32 length;
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
uart_init(72,9600); //串口初始化
HCSR04_Init(0XFFFF,72-1); //以1MHZ的频率计数
while(1)
{
Trig=1;
delay_us(20); //输入20us的高电平
Trig=0;
if(TIM2CH1_CAPTURE_STA&0X80) //成功捕获到了一次高电平
{
temp=TIM2CH1_CAPTURE_STA&0X3F;
temp*=65536; //溢出时间总和
temp+=TIM2CH1_CAPTURE_VAL; //得到总的高电平时间
length=temp*0.017; //计算距离
printf("HIGH:%d cm\r\n",length); //打印距离
TIM2CH1_CAPTURE_STA=0; //开启下一次捕获
}
delay_ms(200);
}
}
该代码将PA0作为输入口、PA4作为输出口。
对于“MY_NVIC_Init(NVIC_PreemptioPriority,NVIC_SubPriority,NVIC_Channel,NVIC_Group)”这一函数,自己从前没用过。在网上搜索后才知道,该函数在设置其所在中断的抢占优先级和响应优先级时也会设置中断优先级分组(由第四个参数确定)。所以,对于同一段代码中出现的不同“MY_NVIC_Init”函数它们的第四个参数都要相同以保证中断优先级分组相同不会出错。
对各个参数的解释:
(1)NVIC_PreemptionPriority:这个参数是用来设定抢占优先级的
(2)NVIC_SubPriority:这个参数是用来设定响应优先级的
(3)NVIC_Channel:这个参数是用来设定中断编号的(范围是0~59)
(4)NVIC_Group:这个参数是用来设定中断分组的(范围是0~4)
对于超声波测距模块的驱动算法来说自己在上次做arduino小车时就有了解。在这里麻烦的不只是超声波模块的算法,还要对各种各样的寄存器进行操作。有些寄存器的功能本来不了解,看过STM32的中文参考手册后更是一头雾水,只能硬着头皮往上怼。等到能够运行之后再逐个寄存器地在网上查资料。本人对代码的理解分析