问题原由
粉丝提问,NPN型脉冲风速
变送器怎么求得风速
,平时支持小哈哥工作的小伙伴有需求,小哈哥一定要安排,这次发文总结一下,希望对大家有所帮助。
开发环境和工具
展示视频
NPN脉冲风速变送器的使用见以下视频教程:
程序源码
在上面显示的视频中获取测试工程源码的方法。
,请期待更多精彩。
主要参数
- 直流供电:5V DC
- 脉冲输出:脉冲输出
- 分辨率:0.0875 m/s
- 精度:±(0.2 0.03V) m/s V表示风速
- 测量范围:0~70 m/s
- 动态响应时间: ≤0.5s
- 启动风速:≤0.2 m/s
产品选型
产品型号命名规则如下:
根据上述风速变送器上的标签,该风速变送器的型号为:,与命名规则相比,我们可以知道这是一个没有内部上拉电阻的人NPN风速变送器的输出。
换算关系
脉冲输出风速变送器风速与脉冲数量的转换关系如下:
从上面我们可以得出结论,我们只需要在一秒钟内计算脉冲N。通过脉冲N和上述截图中的已知信息,我们可以得到风速的转换关系如下:
风速=(1.75 / 20) * N
因此,本模块应用的难点在于如何准确计算单位时间内的脉冲数。
引脚定义
因为这个模块是NPN所以我们只需要用棕色( 5V)、黑色(GND)、蓝色(和一个GPIO连接)三条线即可。
等效电路 输出电路图
在编写代码之前,我们必须首先确定风速变送器的脉冲输出,以及输出的脉冲波形的特性,所以我们需要使用示波器来查看输出的脉冲信号。
将棕色线与 5V电源连接,黑线接地,蓝线进入示波器。
查询手册,NPN类型输出的等效电路如下:
必须在图中进行测试位置添加一个上拉电阻才能输出正常的方波!!!
蓝线输出的方波信号如下:
从上面可以看出,风速变送器输出的脉冲为0~5V脉冲信号,所以为了系统的稳定性,我们需要选择一个标识的引脚。
FT:five volt tolerant 意思的兼容5V信号电压。因为一般STM32 的引脚是3.3V,后面带有FT标识可容忍5V。
我们选择这个例子为例。
接线
棕色线 | 5V | 电源正 |
黑色线 | GND | 电源负 |
蓝色线 | PB12 | NPN-OUT |
代码实现
1. 初始化外部中断
为了计算脉冲的数量,我们使用外部中断来计算脉冲,每个脉冲,外部中断执行一次。
void NPNInit() { EXTI_InitTypeDef EXTI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; ///使用外部中断需要打开RCC_APB2Periph_AFIO时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); //初始化IO口为输入 GPIO_InitStructure.GPIO_Pin = NPN_Pin; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(NPN_PORT, &GPIO_InitStructure); //GPIOB.12中断线 EXTI_ClearITPendingBit(EXTI_Line12); GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12); EXTI_InitStructure.EXTI_Line=EXTI_Line12; EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising; ///上升沿中断 EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_InitStructure); //中断初始配置 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
2. 外部中断函数
在外部中断函数中,自定义全局变量加1,该值记录了收到的脉冲数。
void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line12)==SET) { msNPNCount ; EXTI_ClearITPendingBit(EXTI_Line12); // 清除中断标志 } }
3. 定时器初始化
因为我们需要记录单位时间内收到的脉冲数量,所以我们需要占用一个定时器来计时。我们可以随意选择一个定时器我们选择,下面代码对TIM四是初始化:
//// //arr:自动重装值。 //psc:时钟预分频率 void TIM4_Init(u16 arr,u16 psc) { NVIC_InitTypeDef NVIC_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////TIM4时钟使能 //定时器TIM初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置TIMx时钟频率的预分频值,16位
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化NVIC寄存器
TIM_Cmd(TIM4,DISABLE);
}
main函数中调用定时器4的初始化函数如下:
TIM4_Init(1000-1,7200-1); //7200分频,10KHz,计数1K耗时100ms
TIM4_Set(1); //开启定时器
TIM4每100ms执行一次中断。
4. 定时器中断
我们定义了两个全局变量,一个数组用于记录每100ms内收到的脉冲数,一个用于记录当前数组的索引:
u32 CounterArr[10];
u8 CounterIndex = 0;
在TIM4的定时器中断函数中,每次中断发生时,将脉冲计数保存在数组中,然后脉冲计数清零。
//定时器4中断
void TIM4_IRQHandler(void)
{
if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update );
//保存NPN脉冲计数
CounterArr[CounterIndex] = msNPNCount;
msNPNCount = 0;
CounterIndex++;
if(CounterIndex>=10)
CounterIndex=0;
}
}
5. 脉冲数与风速转换
在函数中,周期计算风速值,数组中存的十个脉冲数,即1秒中内的脉冲总数,然后将,所得的结果即为风速值。
if(times%200==0)
{
//计算风速值
nTotalNPNCounter = 0;
for(i=0;i<9;i++)
{
nTotalNPNCounter += CounterArr[i];
}
printf("风速为 %.2f m/s\r\n",nTotalNPNCounter*0.0875);
}
相关常识
参考阅读
红外遥控功能的实现
485型风速和风向变送器数据包解析
欢迎关注
程序员小哈带你玩转嵌入式,微信搜索:,更多干货等着你。