恩,中午吃过饭,花了点时间写了一下DSM501A的驱动,蛮简单,说白了还是msp430好用,寄存器清晰,头文件定义好,都不要怎么看UG的。
先来看下这个传感器,集成度很高,用户接口也比较简单,看起来像数字传感器,其实很有模拟的味道。
1)电气参数
2)内部结构
3)数据输出接口和曲线
恩基本上比较清晰了,对了这个传感器默认可以测量2.5um和1um的颗粒个数,有两个PWM输出端,其中有一个端可以调节测量颗粒的大小。
看输出波形的图可知,测量主要在传感器稳定工作后在任意的30s内测量到输出波形的低电平时间对这个时间进行累计,最后计算出低脉冲率即可换算成粒子数,这里调试我选择比较简单的曲线也就是MIN这条曲线,便于计算。
顺便说一下,这个传感器是5V供电的,所以我在我的扩展板上面添加了5V电源接口,也通过LDO转换到3.3v供板子使用,因为我的WIFI用板载电源起不来。
所以这里也需要注意传感器出来的波形参考电压高电平时5V基准,默认和msp430通讯是需要做点平转换的ti有蛮多这种芯片,当然用两个三极管搭个电路也简单或者电阻分压。其实通过对PWM输出信号的分析可以用更简单的方式来做,串联一个10k的限流电阻就行了,根据实际情况而定,灵活应对。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
好了,继续说说驱动如何写,很简单,没做什么接口函数,基本上寄存器操作,涉及到两个定时器,一个用于定时30s一个用于捕获输入测量时间。
这里说一下捕获低电平的时间测量方法吧,认为默认的捕获点评为高,需要捕获到低的那一部分。需要设置两次捕获的条件,分别为下降沿和上升沿,当然也可以采用IO中断配合的方式。我这里采用两次设置捕获条件。
--------------- ------------------------- ---------
---------- ------
1 2
我采用P1.3为捕获引脚,这个是TA1的CCR2通道
看我上面的草图吧,设置两个捕获点分别为1和2,具体设置
1)默认是采用fall edge捕获中断
2)在1的位置fall edge捕获到,这时候改变为rise edge捕获中断,同时清除CCR2的值,需要清除TA1的计数器
3)在2的位置rise edge捕获到,这时候记录CCR2的值,并再次切换为fall edge捕获中断,一直这样就行了
整个测量周期受30s定时控制,细节的我贴个程序,有兴趣的可以看下。
- /**
- * @brief Timer1_A1_ISR
- * @note Timer1_A1中断
- * @param none
- * @retval none
- */
- #pragma vector = TIMER1_A1_VECTOR
- __interrupt void Timer1_A1_ISR(void)
- {
- switch ( __even_in_range(TA1IV, TA0IV_TAIFG) )
- {
- case TA1IV_TA1CCR1:
- break;
- case TA1IV_TA1CCR2:
- {
- /* 判断是否为下降沿捕获中断,切换到上升沿捕获中断,并清除CCR2 */
- if ( (TA1CCTL2&0xC000) == CM_2 ) {
- TA1CCTL2 = CM_1 | CCIS_0 | SCS | CAP | CCIE;
- TA1CCR2 = 0;
- TA1CTL |= TACLR;
- } else if ( (TA1CCTL2&0xC000) == CM_1 ) {
- TA1CCTL2 = CM_2 | CCIS_0 | SCS | CAP | CCIE;
- DSM501A_LOW_PULSE_TIME += (TA1CCR2/32);
- }
- } break;
- case TA1IV_TA1IFG:
- break;
- default:
- break;
- }
- }
复制代码
- /**
- * @brief Timer0_A0_ISR
- * @note Timer0_A0中断
- * @param none
- * @retval none
- */
- #pragma vector = TIMER0_A1_VECTOR
- __interrupt void Timer0_A1_ISR(void)
- {
- switch(__even_in_range(TA0IV, TA0IV_TAIFG))
- {
- case TA0IV_NONE:
- break; // No interrupt
- case TA0IV_TACCR1:
- DSM501A_Measu_Cycle++;
- /* 一次DSM501测量结束,转换为百分比 ,
- * 低脉冲率:RT=LT/UTx100%
- */
- if (DSM501A_Measu_Cycle >= 30) {
- DSM501A_Measu_Cycle = 0;
- DSM501A_PM2P5_VALUE = DSM501A_LOW_PULSE_TIME/300.0;
- DSM501A_LOW_PULSE_TIME = 0;
- DSM501A_PM2P5_SENS = (DSM501A_PM2P5_VALUE/2.0)*1000;
- DHT_Read(DHT11_Measu_Data);
- }
- break; // CCR1 not used
- case TA0IV_TACCR2:
- DHT11_Measu_Cycle++;
- if (DHT11_Measu_Cycle >= 10) {
- DHT11_Measu_Cycle = 0;
- DHT_Read(DHT11_Measu_Data);
- }
- break; // CCR2 not used
- case TA0IV_3:
- break; // reserved
- case TA0IV_4:
- break; // reserved
- case TA0IV_5:
- break; // reserved
- case TA0IV_6:
- break; // reserved
- case TA0IV_TAIFG:
- break; // overflow
- default: break;
- }
- }
复制代码暂时没有做功耗控制的思想,我也只能说是低功耗控制的思想了,因为我的外设很费电,不过不影响,低功耗还是要做的。
一些定时器配置:
- /**
- * brief Timer0_A0_Init
- * note Timer0_A0初始化---led闪烁freq定时器
- * param None
- * retval None
- */
- void Timer0_A0_Init(void)
- {
- TA0CCTL0 = CCIE; // TACCR0 interrupt enabled
- TA0CCR0 = 32768;
- TA0CTL = TASSEL__ACLK | MC__UP | TACLR; // ACLK, up mode, clear TAR
- }
- /**
- * brief Timer0_A1_Init
- * note Timer0_A1初始化---DSM501A测量周期
- * param None
- * retval None
- */
- void Timer0_A1_Init(void)
- {
- TA0CCR1 = 32768;
- TA0CTL = TASSEL__ACLK | MC__UP | TACLR; // ACLK, up mode, clear TAR
- TA0CCTL1 = CCIE; // TACCR1 interrupt enabled
- }
- /**
- * brief Timer0_A2_Init
- * note Timer0_A2初始化---DHT11测量周期
- * param None
- * retval None
- */
- void Timer0_A2_Init(void)
- {
- TA0CCR2 = 32768;
- TA0CTL = TASSEL__ACLK | MC__UP | TACLR; // ACLK, up mode, clear TAR
- TA0CCTL2 = CCIE;
- }
- /**
- * brief Timer1_A2_Init
- * note Timer1_A2初始化---CCR2捕获DSM501A传感器
- * param None
- * retval None
- */
- void Timer1_A2_Init(void)
- {
- P1SEL0 |= BIT3;
- P1SEL1 &= ~BIT3;
- P1DIR &= ~BIT3;
- TA1CCTL2 = CM_2 | CCIS_0 | SCS | CAP | CCIE; // Fall edge, CCI2A, Sync capture, Capture mode, Capture interrupt
- TA1CTL = TASSEL__ACLK | MC__CONTINUOUS | TACLR; // ACLK, up mode, clear TAR
- }
复制代码
这里需要注意对端口的设置,这个不能凭感觉拉,要看数据手册
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PM2.5测试:
数据1
数据2
数据3
关于PM2.5单位问题不做解释,有兴趣的可以关注一下相关资料,贴一个百度知道的问答。
- x pcs=x particles 意思是x个粒子
- /283ml=每283毫升
- 用283ml是因为国内的标准都是在追逐美国的标准,而美国一般用ft3作为体积单位,也就是立方英尺,一个立方英尺=28.3L 283ml=0.01ft3,美国人用起来得心应手,我们就会觉得别扭了。
- x pcs/283ml的意思是每283毫升里面有多少个粒子
- 而毫克/立方的单位是指每立方里的粒子有多重。
- 这两个单位的换算,除非是单分散的粒子(所有的粒子大小基本相当),否则需要根据粒子大小,所占比例等情况,结合粒子重量,才能计算出x pcs/283ml 的毫克/立方的值。
- 目前,市面上好像还没有一款仪器能同时测量粒子数浓度和粒子质量浓度的,原因就是计算太麻烦。
- 如果要得到毫克/立方的数,推荐选择能够直接测量毫克/立方的仪器。
- 计算关系可参考资料:http://wenku.baidu.com/view/1de7f4f77c1cfad6195fa715.html
复制代码