|
这个套件中有两个传感器是模拟(电压输出)的,读取简单,只用电压表也能测结果。当然用带ADC的单片机是常规做法了。SensorShield要使用模拟通道,我将传感器小板接在 ANALOG_2 的插座位,模拟输出就是 ANA3 了,对应 STM32 Nucleo 上的PA4.
温度传感器 BD1210HFV
温度传感器可以说是最多的半导体传感器了,最简单的方法用一个二极管就可以测温,不少器件的内部都集成了温度传感器作为附带功能用来作校准等用途。作为单独的一个温度传感器,需要有它的特色,才能在市场占定位置。
ROHM这个 BD1210HFV 从精度上来看+/- 1.5度的最大误差是不如常用的 DS18B20 的,测温范围 -30~+100 也不如 DS18B20 宽。不过4uA的工作电流是它的强项,可以实现低功耗的在线测量。输出电压和温度的关系在手册中有图给出:
典型是 8.2mV/K 的温度系数,不难写ADC结果的转换公式。用 STM32 的 12-bit ADC 作采样,基准电压是 3.3V 的,传感器工作电压 3.0V,不会有量程问题。我的测试程序:
- [mw_shl_code=c,false]void setup_adc(void)
- {
- RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
- __NOP();
- ADC->CCR = 0; // default: ADCPRE=0, ADC clock = PCLK/2
- ADC1->CR1 = ADC_CR1_DISCEN|ADC_CR1_EOCIE; // discontinuous mode, EOC interrupt
- ADC1->SQR3 = ADC_SQR3_SQ1&4; // only 1st conversion in sequence, Ch 4
- ADC1->CR2 = ADC_CR2_ADON|ADC_CR2_EXTEN_0 // enable, trigger rise edge
- |ADC_CR2_EXTSEL_0|ADC_CR2_EXTSEL_1; // Timer2 CC2
- }
- volatile uint16_t adc_ch4;
- int main(void)
- {
- int i;
- gpio_config();
- uart_setup();
- uart_wstr("\r\nUSART2 initialized.");
- setup_adc();
- NVIC_EnableIRQ(ADC_IRQn);
- RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // enable timer 2
- __NOP();
- TIM2->PSC = 999; // prescaler
- TIM2->ARR = 199; // auto reload value
- TIM2->CCR2 = 100;
- TIM2->CCMR1 = TIM_CCMR1_OC2M_0|TIM_CCMR1_OC2M_1|TIM_CCMR1_OC2M_2;
- TIM2->CCER = TIM_CCER_CC2E; // must enable CC2
- TIM2->CR1 = TIM_CR1_URS|TIM_CR1_CEN; // start counter
- while(1)
- {
- int x=0;
- for(i=0;i<32;i++)
- {
- __WFI();
- x+=adc_ch4;
- }
- double volt=x*3.3f/(32*4096);
- double degree=30-(volt-1.3)/0.0082;
- int d=round(degree*10);
- uart_wstr("\r\nTemperature (degree): ");
- uart_wdec(d/10);
- uart_wstr(".");
- uart_wdec(d%10);
- }
- }
- void ADC_IRQHandler(void)
- {
- adc_ch4=ADC1->DR; // reading clears flag automatically
- }
复制代码 [/code]
因为 STM32 ADC 的噪声大,用了32次采样结果算平均值之后再进行计算。ADC速度不成问题,我最终输出数据零点几秒钟一次。
这是在室内的测量,考虑到ADC和Nucleo板子电压基准的误差,结果的波动完全可以接受。因为我没有标定的实验条件,就不评估这个结果的准确度了。
紫外线传感器 ML8511A
日常防紫外线的用品是不少,测紫外线的功能却很少见到。有了它至少可以做个提醒“注意防晒”装置了。测量范围(我没概念)是 15mW/cm^2,如下图:
把程序稍加改动就可以读数了:
- [mw_shl_code=c,false] while(1)
- {
- int x=0;
- for(i=0;i<32;i++)
- {
- __WFI();
- x+=adc_ch4;
- }
- double volt=x*3.3f/(32*4096);
- double intensity=(volt-1.0)/1.2*10;
- int i=round(intensity*100);
- if(i<0)
- i=0;
- uart_wstr("\r\nUV Intensity (mW/cm^2): ");
- uart_wdec(i/100);
- uart_wstr(".");
- if(i%100<10)
- uart_wstr("0");
- uart_wdec(i%100);
- }
复制代码 [/code]
数据输出次数和上一个程序一样。在室内,读数几乎就是0。今天外面有阳光照射,在窗口的地方有阳光射进来,于是可以做一些测试。
这是隔着窗玻璃的结果(双层玻璃,上面还有严重的擦不掉的污渍):
已经有明显的紫外线了。然后把窗推开呢?
紫外线强了几倍。有趣的是,在阳光直射下这个数字也会变,有云过来的时候明显会降低。试了下一把太阳伞,隔了伞之后降到0.3的样子。
突然想到我的墨镜了,拿出来试!
墨镜果然厉害!
|
|